You can edit the below JavaScript code to customize the image tool.
Apply Changes
async function processImage(originalImg, targetLang = 'ru', confidenceThreshold = 0.5, boxColor = '#FF0000') {
// Helper function to dynamically load scripts
const loadScript = (url) => {
return new Promise((resolve, reject) => {
// Check if the script is already on the page
if (document.querySelector(`script[src="${url}"]`)) {
return resolve();
}
const script = document.createElement('script');
script.src = url;
script.onload = () => resolve();
script.onerror = (err) => reject(new Error(`Script load error for ${url}: ${err}`));
document.head.appendChild(script);
});
};
// Create a canvas to draw on
const canvas = document.createElement('canvas');
canvas.width = originalImg.naturalWidth;
canvas.height = originalImg.naturalHeight;
const ctx = canvas.getContext('2d');
// Draw the original image first
ctx.drawImage(originalImg, 0, 0);
// Display a loading message on the canvas
const drawLoadingMessage = (message) => {
ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = 'white';
ctx.font = '24px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(message, canvas.width / 2, canvas.height / 2);
};
try {
drawLoadingMessage('Loading libraries...');
// Load TensorFlow.js and the COCO-SSD model scripts
await loadScript('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@3.11.0/dist/tf.min.js');
await loadScript('https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd@2.2.2/dist/coco-ssd.min.js');
// Store the model in the window object to avoid reloading it on subsequent calls
if (!window.cocoSsdModel) {
drawLoadingMessage('Loading detection model (first time only)...');
window.cocoSsdModel = await cocoSsd.load();
}
const model = window.cocoSsdModel;
// Redraw image to clear loading message
ctx.drawImage(originalImg, 0, 0);
// Perform object detection
const predictions = await model.detect(originalImg);
// Pre-built translation dictionary for COCO-SSD classes
const translations = {
'person': { 'ru': 'человек', 'es': 'persona', 'fr': 'personne' },
'bicycle': { 'ru': 'велосипед', 'es': 'bicicleta', 'fr': 'vélo' },
'car': { 'ru': 'машина', 'es': 'coche', 'fr': 'voiture' },
'motorcycle': { 'ru': 'мотоцикл', 'es': 'motocicleta', 'fr': 'moto' },
'airplane': { 'ru': 'самолет', 'es': 'avión', 'fr': 'avion' },
'bus': { 'ru': 'автобус', 'es': 'autobús', 'fr': 'bus' },
'train': { 'ru': 'поезд', 'es': 'tren', 'fr': 'train' },
'truck': { 'ru': 'грузовик', 'es': 'camión', 'fr': 'camion' },
'boat': { 'ru': 'лодка', 'es': 'barco', 'fr': 'bateau' },
'traffic light': { 'ru': 'светофор', 'es': 'semáforo', 'fr': 'feu de circulation' },
'fire hydrant': { 'ru': 'пожарный гидрант', 'es': 'boca de incendios', 'fr': 'bouche d\'incendie' },
'stop sign': { 'ru': 'знак стоп', 'es': 'señal de stop', 'fr': 'panneau stop' },
'parking meter': { 'ru': 'паркомат', 'es': 'parquímetro', 'fr': 'parcmètre' },
'bench': { 'ru': 'скамейка', 'es': 'banco', 'fr': 'banc' },
'bird': { 'ru': 'птица', 'es': 'pájaro', 'fr': 'oiseau' },
'cat': { 'ru': 'кошка', 'es': 'gato', 'fr': 'chat' },
'dog': { 'ru': 'собака', 'es': 'perro', 'fr': 'chien' },
'horse': { 'ru': 'лошадь', 'es': 'caballo', 'fr': 'cheval' },
'sheep': { 'ru': 'овца', 'es': 'oveja', 'fr': 'mouton' },
'cow': { 'ru': 'корова', 'es': 'vaca', 'fr': 'vache' },
'elephant': { 'ru': 'слон', 'es': 'elefante', 'fr': 'éléphant' },
'bear': { 'ru': 'медведь', 'es': 'oso', 'fr': 'ours' },
'zebra': { 'ru': 'зебра', 'es': 'cebra', 'fr': 'zèbre' },
'giraffe': { 'ru': 'жираф', 'es': 'jirafa', 'fr': 'girafe' },
'backpack': { 'ru': 'рюкзак', 'es': 'mochila', 'fr': 'sac à dos' },
'umbrella': { 'ru': 'зонт', 'es': 'paraguas', 'fr': 'parapluie' },
'handbag': { 'ru': 'сумочка', 'es': 'bolso', 'fr': 'sac à main' },
'tie': { 'ru': 'галстук', 'es': 'corbata', 'fr': 'cravate' },
'suitcase': { 'ru': 'чемодан', 'es': 'maleta', 'fr': 'valise' },
'frisbee': { 'ru': 'фризби', 'es': 'frisbee', 'fr': 'frisbee' },
'skis': { 'ru': 'лыжи', 'es': 'esquís', 'fr': 'skis' },
'snowboard': { 'ru': 'сноуборд', 'es': 'snowboard', 'fr': 'snowboard' },
'sports ball': { 'ru': 'мяч', 'es': 'pelota deportiva', 'fr': 'ballon de sport' },
'kite': { 'ru': 'воздушный змей', 'es': 'cometa', 'fr': 'cerf-volant' },
'baseball bat': { 'ru': 'бейсбольная бита', 'es': 'bate de béisbol', 'fr': 'batte de baseball' },
'baseball glove': { 'ru': 'бейсбольная перчатка', 'es': 'guante de béisbol', 'fr': 'gant de baseball' },
'skateboard': { 'ru': 'скейтборд', 'es': 'monopatín', 'fr': 'skateboard' },
'surfboard': { 'ru': 'доска для серфинга', 'es': 'tabla de surf', 'fr': 'planche de surf' },
'tennis racket': { 'ru': 'теннисная ракетка', 'es': 'raqueta de tenis', 'fr': 'raquette de tennis' },
'bottle': { 'ru': 'бутылка', 'es': 'botella', 'fr': 'bouteille' },
'wine glass': { 'ru': 'бокал', 'es': 'copa de vino', 'fr': 'verre à vin' },
'cup': { 'ru': 'чашка', 'es': 'taza', 'fr': 'tasse' },
'fork': { 'ru': 'вилка', 'es': 'tenedor', 'fr': 'fourchette' },
'knife': { 'ru': 'нож', 'es': 'cuchillo', 'fr': 'couteau' },
'spoon': { 'ru': 'ложка', 'es': 'cuchara', 'fr': 'cuillère' },
'bowl': { 'ru': 'миска', 'es': 'cuenco', 'fr': 'bol' },
'banana': { 'ru': 'банан', 'es': 'plátano', 'fr': 'banane' },
'apple': { 'ru': 'яблоко', 'es': 'manzana', 'fr': 'pomme' },
'sandwich': { 'ru': 'сэндвич', 'es': 'sándwich', 'fr': 'sandwich' },
'orange': { 'ru': 'апельсин', 'es': 'naranja', 'fr': 'orange' },
'broccoli': { 'ru': 'брокколи', 'es': 'brócoli', 'fr': 'brocoli' },
'carrot': { 'ru': 'морковь', 'es': 'zanahoria', 'fr': 'carotte' },
'hot dog': { 'ru': 'хот-дог', 'es': 'perrito caliente', 'fr': 'hot-dog' },
'pizza': { 'ru': 'пицца', 'es': 'pizza', 'fr': 'pizza' },
'donut': { 'ru': 'пончик', 'es': 'dona', 'fr': 'beignet' },
'cake': { 'ru': 'торт', 'es': 'pastel', 'fr': 'gâteau' },
'chair': { 'ru': 'стул', 'es': 'silla', 'fr': 'chaise' },
'couch': { 'ru': 'диван', 'es': 'sofá', 'fr': 'canapé' },
'potted plant': { 'ru': 'растение в горшке', 'es': 'planta de maceta', 'fr': 'plante en pot' },
'bed': { 'ru': 'кровать', 'es': 'cama', 'fr': 'lit' },
'dining table': { 'ru': 'обеденный стол', 'es': 'mesa de comedor', 'fr': 'table à manger' },
'toilet': { 'ru': 'унитаз', 'es': 'inodoro', 'fr': 'toilettes' },
'tv': { 'ru': 'телевизор', 'es': 'televisión', 'fr': 'télévision' },
'laptop': { 'ru': 'ноутбук', 'es': 'portátil', 'fr': 'ordinateur portable' },
'mouse': { 'ru': 'мышь', 'es': 'ratón', 'fr': 'souris' },
'remote': { 'ru': 'пульт', 'es': 'control remoto', 'fr': 'télécommande' },
'keyboard': { 'ru': 'клавиатура', 'es': 'teclado', 'fr': 'clavier' },
'cell phone': { 'ru': 'сотовый телефон', 'es': 'teléfono móvil', 'fr': 'téléphone portable' },
'microwave': { 'ru': 'микроволновка', 'es': 'microondas', 'fr': 'four à micro-ondes' },
'oven': { 'ru': 'духовка', 'es': 'horno', 'fr': 'four' },
'toaster': { 'ru': 'тостер', 'es': 'tostadora', 'fr': 'grille-pain' },
'sink': { 'ru': 'раковина', 'es': 'fregadero', 'fr': 'évier' },
'refrigerator': { 'ru': 'холодильник', 'es': 'refrigerador', 'fr': 'réfrigérateur' },
'book': { 'ru': 'книга', 'es': 'libro', 'fr': 'livre' },
'clock': { 'ru': 'часы', 'es': 'reloj', 'fr': 'horloge' },
'vase': { 'ru': 'ваза', 'es': 'jarrón', 'fr': 'vase' },
'scissors': { 'ru': 'ножницы', 'es': 'tijeras', 'fr': 'ciseaux' },
'teddy bear': { 'ru': 'плюшевый мишка', 'es': 'oso de peluche', 'fr': 'ours en peluche' },
'hair drier': { 'ru': 'фен', 'es': 'secador de pelo', 'fr': 'sèche-cheveux' },
'toothbrush': { 'ru': 'зубная щетка', 'es': 'cepillo de dientes', 'fr': 'brosse à dents' }
};
// Draw bounding boxes and labels for each prediction
for (let i = 0; i < predictions.length; i++) {
const prediction = predictions[i];
if (prediction.score > confidenceThreshold) {
const [x, y, width, height] = prediction.bbox;
// Get translated label or fallback to English
const englishClass = prediction.class;
const translatedClass = (translations[englishClass] && translations[englishClass][targetLang])
? translations[englishClass][targetLang]
: englishClass;
const label = `${translatedClass} (${Math.round(prediction.score * 100)}%)`;
// Set styles for the bounding box and label
ctx.strokeStyle = boxColor;
ctx.lineWidth = 2;
ctx.fillStyle = boxColor;
ctx.font = '16px Arial';
ctx.textBaseline = "top";
// Draw bounding box
ctx.strokeRect(x, y, width, height);
// Draw label background
const textWidth = ctx.measureText(label).width;
const textHeight = 16; // Approximation for 16px font
ctx.fillRect(x, y, textWidth + 8, textHeight + 4);
// Draw label text
ctx.fillStyle = '#FFFFFF';
ctx.fillText(label, x + 4, y + 2);
}
}
} catch (error) {
console.error("Error during image processing:", error);
ctx.drawImage(originalImg, 0, 0); // Redraw original image on error
drawLoadingMessage('An error occurred. See console for details.');
}
return canvas;
}
Apply Changes