Aplicación Web para reconocimiento de objetos con IA

ALEJANDRO EDUARDO JARERO MORA
6 min readSep 11, 2024

--

En este artículo, exploraremos el proceso de creación de una aplicación web que tiene la capacidad de detectar objetos en tiempo real, utilizando el sistema de Inteligencia Artificial Claude.ai de la empresa Antropic.

Al igual que otras plataformas como ChatGPT, utilizamos diferentes prompts para llegar a la solución final, la cual se detalla a continuación

Instrucción inicial:

Describimos el concepto general de lo que queremos que realice la Aplicación Web. En este caso queremos simplificar el resultado en un solo archivo HTML que ejecute la tarea de detectar los objetos que se pongan frente a la cámara web integrada a la computadora donde se ejecute este código.

Le damos la instrucción de que queremos que sea en tiempo real, de otra manera podríamos sugerir que lo realice a partir de imágenes o videos, para lo cual la instrucción debería ser diferente.

Por último, indicamos el uso de 2 tecnologías adicionales: TensorFlowjs

Crea un único archivo HTML para una aplicación web de detección de objetos en tiempo real utilizando TensorFlowjs y el modelo COCO-SSD. la página debe:

Damos la instrucción de que se active la cámara web y que muestre la imagen en pantalla.

Acceder a la cámara web del usuario y mostrar la transmisión de video.

Posteriormente indicamos que realice la detección de objetos dentro del video en tiempo real,

Realizar la detección de objetos en la transmisión de video en tiempo real.

Requerimos además que indique la detección de cada objeto mediante cuadros delimitadores. Cada objeto identificado queremos que le coloque una etiqueta con el nombre del objeto y el porcentaje del nivel de confianza con el que detectó el objeto

Dibujar cuadros delimitados alrededor de los objetos detectados y etiquétalos con su clase y nivel de confianza de detención.

Le indicamos que queremos una lista en la parte inferior que indique el momento en el que se detectó el objeto. Solo requerimos la impresión de la primera vez en que se detecta para que no se haga una lista muy grande.

Mostrar una lista de objetos detectados de forma única debajo de la transmisión de video, mostrando la clase de objeto y la hora en la que se detectó por primera vez.

Implementamos una función para mantener una lista de objetos detectados únicos. Cada vez que se detectaba un nuevo objeto, lo añadíamos a la lista junto con la marca de tiempo de su primera detección. Nos aseguramos de que cada clase de objeto apareciera solo una vez en la lista.

Asegúrate de que cada clase de objeto solo aparezca una vez, independientemente de cuántas veces se detecte

La frecuencia de cuadros por segundo generados por la cámara de video consume los recursos de memoria de la computadora por lo que podemos disminuir la tasa de identificación a solo 2 veces por segundo.

Utiliza una frecuencia de detección de 2 FPS para equilibrar el rendimiento y la capacidad de respuesta.

Implementamos un manejo de errores para situaciones como la falta de acceso a la cámara o problemas al cargar el modelo. Esto incluyó mensajes de error informativos para el usuario.

Incluye manejo de errores para el acceso a la cámara y la carga del modelo.

Para darle a nuestra aplicación una apariencia moderna y limpia, implementamos un diseño responsivo utilizando CSS. Prestamos especial atención a la disposición de los elementos para que funcionaran bien en diferentes tamaños de pantalla.

Diseña la aplicación para darle una apariencia limpia y moderna con un diseño responsivo.

Reiteramos la necesidad de que este código se ejecute desde un solo archivo para que no genere la hoja de estilos ni la funcionalidad en archivos independientes.

Incluye todo el HTML, CSS y JavaScript necesarios en un archivo único e independiente que se puede ejecutar abriéndolo en un navegador web.

Existen diferentes repositorios en linea desde los cuales podemos acceder a modelos de inteligencia artificial, librerías, funciones, etc… llamados CDN (Content Delivery Network) Red de Entrega de Contenido. En este caso requerimos los servicios de TensorFlow.js como herramienta que ayuda a gestionar e implementar los procesos de aprendizaje automático. También requerimos del modelo preentrenado de detección de objetos COCO-SSD. Este modelo ya tiene una gran cantidad de objetos disponibles para ayudarnos a identificar aquellos que aparezcan frente a la cámara.

Utiliza enlaces CDN para las bibliotecas de modelos TensorFlow.js y COCO-SSD. Proporciona el archivo HTML ejecutable completo con CSS y JavaScript en línea.

<!DOCTYPE html>
<html lang="es">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Detección de Objetos en Tiempo Real</title>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd"></script>
<style>
body {
font-family: 'Arial', sans-serif;
margin: 0;
padding: 20px;
background-color: #f0f0f0;
color: #333;
line-height: 1.6;
}
.container {
max-width: 800px;
margin: 0 auto;
background-color: #fff;
padding: 20px;
border-radius: 8px;
box-shadow: 0 0 10px rgba(0,0,0,0.1);
}
h1 {
text-align: center;
color: #2c3e50;
}
#video-container {
position: relative;
max-width: 640px;
margin: 0 auto 20px;
}
#webcam, #canvas {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: auto;
}
#webcam {
background-color: #000;
}
#info {
position: absolute;
top: 10px;
left: 10px;
background-color: rgba(255, 255, 255, 0.7);
padding: 5px 10px;
border-radius: 4px;
font-size: 14px;
}
#object-list {
max-width: 640px;
margin: 20px auto;
background-color: #fff;
border: 1px solid #ddd;
border-radius: 4px;
padding: 15px;
}
#object-list h2 {
margin-top: 0;
color: #2c3e50;
}
#detected-objects {
list-style-type: none;
padding: 0;
}
#detected-objects li {
background-color: #f9f9f9;
margin-bottom: 10px;
padding: 10px;
border-radius: 4px;
display: flex;
justify-content: space-between;
align-items: center;
}
#error-message {
background-color: #f8d7da;
color: #721c24;
padding: 10px;
border-radius: 4px;
margin-bottom: 20px;
text-align: center;
display: none;
}
@media (max-width: 768px) {
body {
padding: 10px;
}
.container {
padding: 10px;
}
}
</style>
</head>
<body>
<div class="container">
<h1>Detección de Objetos en Tiempo Real</h1>
<div id="error-message"></div>
<div id="video-container">
<video id="webcam" autoplay muted playsinline></video>
<canvas id="canvas"></canvas>
<div id="info">FPS: <span id="fps">0</span></div>
</div>
<div id="object-list">
<h2>Objetos Detectados</h2>
<ul id="detected-objects"></ul>
</div>
</div>

<script>
const video = document.getElementById('webcam');
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const fpsDisplay = document.getElementById('fps');
const detectedObjectsList = document.getElementById('detected-objects');
const errorMessage = document.getElementById('error-message');

let model;
let lastDetectionTime = 0;
let frameCount = 0;
let lastFpsUpdateTime = 0;
let detectedObjects = new Map();

async function setupCamera() {
try {
const stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' }, audio: false });
video.srcObject = stream;
return new Promise((resolve) => {
video.onloadedmetadata = () => {
canvas.width = video.videoWidth;
canvas.height = video.videoHeight;
resolve(video);
};
});
} catch (error) {
throw new Error('No se pudo acceder a la cámara. Asegúrese de que tiene una cámara conectada y que ha dado permiso para usarla.');
}
}

async function loadModel() {
try {
model = await cocoSsd.load();
} catch (error) {
throw new Error('No se pudo cargar el modelo de detección. Compruebe su conexión a Internet y vuelva a intentarlo.');
}
}

function updateDetectedObjectsList(className) {
if (!detectedObjects.has(className)) {
const now = new Date();
detectedObjects.set(className, now.toLocaleTimeString());
const listItem = document.createElement('li');
listItem.innerHTML = `<span>${className}</span> <time>Detectado a las ${now.toLocaleTimeString()}</time>`;
detectedObjectsList.appendChild(listItem);
}
}

async function detectObjects() {
try {
const predictions = await model.detect(video);
ctx.clearRect(0, 0, ctx.canvas.width, ctx.canvas.height);
ctx.drawImage(video, 0, 0, ctx.canvas.width, ctx.canvas.height);

predictions.forEach(prediction => {
const [x, y, width, height] = prediction.bbox;
const color = `hsl(${Math.random() * 360}, 100%, 50%)`;
ctx.strokeStyle = color;
ctx.lineWidth = 2;
ctx.strokeRect(x, y, width, height);

ctx.fillStyle = color;
ctx.font = '16px Arial';
ctx.fillText(`${prediction.class} - ${Math.round(prediction.score * 100)}%`, x, y > 20 ? y - 5 : 20);

updateDetectedObjectsList(prediction.class);
});

frameCount++;
const now = performance.now();
if (now - lastFpsUpdateTime >= 1000) {
fpsDisplay.textContent = frameCount.toFixed(1);
frameCount = 0;
lastFpsUpdateTime = now;
}
} catch (error) {
console.error('Error en la detección de objetos:', error);
}
}

async function detectionLoop() {
const now = performance.now();
if (now - lastDetectionTime >= 500) { // 500ms = 2 FPS
await detectObjects();
lastDetectionTime = now;
}
requestAnimationFrame(detectionLoop);
}

async function main() {
try {
await setupCamera();
await loadModel();
video.play();
detectionLoop();
} catch (error) {
errorMessage.textContent = error.message;
errorMessage.style.display = 'block';
}
}

main();
</script>
</body>
</html>

Este es el resultado final.

--

--