You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, highlightColor = "#00ff00") {
// Create a container to hold our canvas and the overlay panel
const container = document.createElement('div');
container.style.position = 'relative';
container.style.display = 'inline-block';
container.style.fontFamily = 'Arial, sans-serif';
container.style.maxWidth = '100%';
// Create the main scanning canvas
const canvas = document.createElement('canvas');
canvas.width = originalImg.width;
canvas.height = originalImg.height;
canvas.style.display = 'block';
canvas.style.maxWidth = '100%';
canvas.style.height = 'auto';
// Draw the original image onto the canvas
const ctx = canvas.getContext('2d');
ctx.drawImage(originalImg, 0, 0);
container.appendChild(canvas);
// Standard function to dynamically load JS libraries
const loadScript = (src, globalVar) => new Promise((resolve, reject) => {
if (window[globalVar]) {
resolve();
return;
}
const script = document.createElement('script');
script.src = src;
script.crossOrigin = "anonymous";
script.onload = () => resolve();
script.onerror = () => reject(new Error(`Failed to load ${src}`));
document.head.appendChild(script);
});
try {
// Sequentially load TensorFlow.js first, then load the Identifier and Scanner models in parallel
await loadScript("https://cdn.jsdelivr.net/npm/@tensorflow/tfjs", "tf");
await Promise.all([
loadScript("https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd", "cocoSsd"),
loadScript("https://cdn.jsdelivr.net/npm/@tensorflow-models/mobilenet", "mobilenet")
]);
// Load specific trained models
const [cocoModel, mobileModel] = await Promise.all([
cocoSsd.load(),
mobilenet.load()
]);
// Run detection (bounding boxes) and classification (global image identity)
const [predictions, classifications] = await Promise.all([
cocoModel.detect(originalImg),
mobileModel.classify(originalImg)
]);
// Draw bounding boxes stylized to look like an active scanner
predictions.forEach(prediction => {
const [x, y, width, height] = prediction.bbox;
ctx.strokeStyle = highlightColor;
ctx.lineWidth = Math.max(3, canvas.width / 250);
// Draw prominent corner borders (scanner style)
const cl = Math.max(5, Math.min(width, height) * 0.15); // corner length
ctx.beginPath();
// Top left
ctx.moveTo(x, y + cl); ctx.lineTo(x, y); ctx.lineTo(x + cl, y);
// Top right
ctx.moveTo(x + width - cl, y); ctx.lineTo(x + width, y); ctx.lineTo(x + width, y + cl);
// Bottom right
ctx.moveTo(x + width, y + height - cl); ctx.lineTo(x + width, y + height); ctx.lineTo(x + width - cl, y + height);
// Bottom left
ctx.moveTo(x + cl, y + height); ctx.lineTo(x, y + height); ctx.lineTo(x, y + height - cl);
ctx.stroke();
// Draw a thinner full box connecting the corners
ctx.lineWidth = Math.max(1, canvas.width / 600);
ctx.strokeRect(x, y, width, height);
// Configure text labels for the identified bounding boxes
const fontSize = Math.max(12, Math.floor(canvas.width / 50));
ctx.font = `bold ${fontSize}px Arial`;
const label = `${prediction.class.toUpperCase()} (${(prediction.score * 100).toFixed(1)}%)`;
const textWidth = ctx.measureText(label).width;
// Prevent label from drawing outside the top of the canvas
const labelY = y > fontSize + 10 ? y - fontSize - 10 : y;
// Draw label background
ctx.fillStyle = highlightColor;
ctx.fillRect(x, labelY, textWidth + 10, fontSize + 8);
// Draw label text
ctx.fillStyle = '#000000'; // high contrast with highlight color
ctx.fillText(label, x + 5, labelY + fontSize);
});
// Overlay element for classification readouts (identifying the general scene/logos)
const resultsPanel = document.createElement('div');
resultsPanel.style.position = 'absolute';
resultsPanel.style.bottom = '0';
resultsPanel.style.left = '0';
resultsPanel.style.width = '100%';
resultsPanel.style.backgroundColor = 'rgba(0, 0, 0, 0.85)';
resultsPanel.style.color = '#ffffff';
resultsPanel.style.padding = '15px';
resultsPanel.style.boxSizing = 'border-box';
resultsPanel.style.borderTop = `2px solid ${highlightColor}`;
let htmlContent = `<h3 style="margin: 0 0 10px 0; font-size: 18px; color: ${highlightColor}; text-shadow: 0 0 2px ${highlightColor};">Scanner & Identity Results</h3>`;
if (classifications && classifications.length > 0) {
htmlContent += `<div style="display: flex; flex-direction: column; gap: 8px;">`;
classifications.forEach(c => {
const percent = (c.probability * 100).toFixed(1);
// Clean up comma-separated tags
const primaryClass = c.className.split(',')[0].charAt(0).toUpperCase() + c.className.split(',')[0].slice(1);
htmlContent += `
<div style="display: flex; align-items: center; justify-content: space-between; font-size: 14px; letter-spacing: 0.5px;">
<span style="font-weight: bold;">${primaryClass}</span>
<span>${percent}% Match</span>
</div>
<div style="width: 100%; background: #333; height: 6px; border-radius: 3px; overflow: hidden;">
<div style="width: ${percent}%; background: ${highlightColor}; height: 100%; border-radius: 3px; box-shadow: 0 0 5px ${highlightColor};"></div>
</div>
`;
});
htmlContent += `</div>`;
} else {
htmlContent += `<p style="margin: 0; font-size: 14px;">No specific identifying features found.</p>`;
}
resultsPanel.innerHTML = htmlContent;
container.appendChild(resultsPanel);
} catch (e) {
console.error("Scanner Tool Error:", e);
const errorPanel = document.createElement('div');
errorPanel.style.position = 'absolute';
errorPanel.style.top = '10px';
errorPanel.style.left = '10px';
errorPanel.style.backgroundColor = 'rgba(220, 38, 38, 0.9)';
errorPanel.style.color = 'white';
errorPanel.style.padding = '10px 15px';
errorPanel.style.borderRadius = '5px';
errorPanel.style.boxShadow = '0 2px 10px rgba(0,0,0,0.5)';
errorPanel.innerText = 'Failed to load scanning and identifying models. Please check your connection.';
container.appendChild(errorPanel);
}
return container;
}
Apply Changes