<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title>Objectdetection - Tag - Matteo Totaro</title><link>https://www.mtotaro.com/tags/objectdetection/</link><description>Objectdetection - Tag - Matteo Totaro</description><generator>Hugo -- gohugo.io</generator><language>en</language><copyright>This work is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.</copyright><lastBuildDate>Sun, 06 Apr 2025 13:30:00 +0200</lastBuildDate><atom:link href="https://www.mtotaro.com/tags/objectdetection/" rel="self" type="application/rss+xml"/><item><title>Objectify Yourself</title><link>https://www.mtotaro.com/projects/objdetect/</link><pubDate>Sun, 06 Apr 2025 13:30:00 +0200</pubDate><author>xxxx</author><guid>https://www.mtotaro.com/projects/objdetect/</guid><description><![CDATA[<div class="typeit"><h3 id="id-1"></h3></div>



<style>
    :root {
        --camera-bg: #111;
        --camera-accent: #ffffff;  
        --camera-accent-hover: #f0f0f0;
        --record-color: #ff3b30;
        --record-hover: #ff5e54;
    }
    
    .video-app-container {
        position: relative;
        max-width: 100%;
        width: 100%;
        margin: 0 auto;
        background-color: var(--camera-bg);
        border-radius: 16px;
        overflow: hidden;
        box-shadow: 0 10px 25px rgba(0,0,0,0.2);
        aspect-ratio: 9/13;
        height: auto;
    }

    .video-container {
        position: relative;
        width: 100%;
        height: 100%;
        overflow: hidden;
        background-color: black;
    }

    #webcam,
    #canvas {
        position: absolute;
        top: 50%;
        left: 50%;
        width: 100%;
        height: 100%;
        transform: translate(-50%, -50%);
        object-fit: contain;
        z-index: 1;  
         
    }
    #canvas {
        z-index: 2;
        pointer-events: none;
    }
    
    #loading {
        position: absolute;
        top: 0;
        left: 0;
        width: 100%;
        height: 4px;
        background: rgba(255,255,255,0.2);
        z-index: 10;
    }
    
    #loading-progress {
        height: 100%;
        width: 0%;
        background: linear-gradient(90deg, #4CAF50, #8BC34A);
        transition: width 0.3s;
    }

    .controls {
        position: absolute;
        bottom: 0;
        left: 0;
        width: 100%;
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 1rem;
        background: linear-gradient(to top, rgba(0,0,0,0.7), transparent);
        z-index: 4;
    }

    .control-main {
        display: flex;
        justify-content: space-between;
        flex-grow: 1;
        gap: 0.5rem;
        align-items: center;
    }
    .stop-btn {
        background: #ff3b30;
        color: #fff;
        box-shadow: 0 2px 8px rgba(255,59,48,0.15);
        border: 2px solid #ff3b30;
        transition: background 0.2s, color 0.2s, border 0.2s;
        display: inline-flex;
        align-items: center;
        justify-content: center;
        width: 56px;
        height: 56px;
        border-radius: 50%;
        font-size: 1.2rem;
        flex: 0 0 56px;
    }
    .stop-btn:hover {
        background: #fff;
        color: #ff3b30;
        border: 2px solid #ff3b30;
    }
    
    .control-side {
        width: 80px;
        display: flex;
        justify-content: center;
    }
    
    .control-button {
        width: 56px;
        height: 56px;
        border-radius: 50%;
        border: none;
        background: var(--camera-accent);
        color: #333;  
        cursor: pointer;
        transition: all 0.2s;
        display: flex;
        align-items: center;
        justify-content: center;
        font-size: 1.5rem;
        padding: 0;
        flex: 0 0 56px;
        min-width: 56px;
    }
    
    #recordButton {
        background: var(--record-color);
        color: white;
    }
    
    #recordButton:hover {
        background: var(--record-hover);
    }
    
    .control-button.small {
        width: 56px;
        height: 56px;
        font-size: 1rem;
        background: transparent;
        color: white;
        border: 2px solid white;
        padding: 0;
        flex: 0 0 56px;
        min-width: 56px;
    }
    
    .control-button.small:hover {
        background: rgba(255,255,255,0.1);
    }
    
    .control-button:hover {
        background: var(--camera-accent-hover);
    }
    
    .control-button.recording {
        animation: pulse 1.5s infinite;
    }
    
    @keyframes pulse {
        0% { box-shadow: 0 0 0 0 rgba(255, 59, 48, 0.7); }
        70% { box-shadow: 0 0 0 15px rgba(255, 59, 48, 0); }
        100% { box-shadow: 0 0 0 0 rgba(255, 59, 48, 0); }
    }
    
     
    .status-bar {
        position: absolute;
        top: 0;
        left: 0;
        width: calc(100% - 2rem);
        padding: 0.8rem 1rem;
        display: flex;
        justify-content: space-between;
        color: white;
        z-index: 10;
        font-size: 0.9rem;
        font-weight: 600;
    }
    
    #startCameraBtn {
        position: absolute;
        bottom: 100px;
        left: 50%;
        transform: translateX(-50%);
        z-index: 5;
        padding: 0.8rem 1.5rem;
        font-size: 1rem;
        background: var(--camera-accent);
        border: none;
        color: #333;
        border-radius: 30px;
        display: flex;
        align-items: center;
        box-shadow: 0 4px 8px rgba(0,0,0,0.3);
    }
    
    #startCameraBtn:hover {
        background: var(--camera-accent-hover);
    }
    
     
    @media (min-width: 768px) {
        .video-app-container {
            max-width: 400px;
            aspect-ratio: 9/13;
        }
    }
</style>

<div class="video-app-container">
    <div class="status-bar">
        <span class="current-time">14:30</span>
        <div class="status-icons">
            <i class="fas fa-signal"></i>
            <i class="fas fa-battery-three-quarters" style="margin-left: 8px;"></i>
        </div>
    </div>
    
    <div id="loading"><div id="loading-progress"></div></div>
    
    <div class="video-container">
        <button id="startCameraBtn">
            <i class="fas fa-camera" style="margin-right: 8px;"></i> Start Camera
        </button>
        <video id="webcam" autoplay playsinline style="display: none;"></video>
        <canvas id="canvas"></canvas>
    </div>

    <div class="controls">
        <div class="control-main">
            <button class="control-button small" id="flipButton" title="Flip Camera">
                <i class="fas fa-camera-rotate"></i>
            </button>
            <button class="control-button" id="photoButton" title="Take Photo">
                <i class="fas fa-camera"></i>
            </button>
            <button class="control-button" id="recordButton" title="Record Video">
                <i class="fas fa-video"></i>
            </button>
            <button id="stopCameraBtn" class="control-button small stop-btn" title="Stop Camera">
                <i class="fas fa-power-off"></i>
            </button>
        </div>
    </div>
</div>

<script>
    
    let model;
    let mobileNetModel;
    let webcam;
    let canvas;
    let ctx;
    let isModelLoading = false;
    let isCameraOn = false;
    let isRecording = false;
    let mediaRecorder;
    let recordedChunks = [];
    let isFrontCamera = false;
    let loadingProgress = 0;
    let loadingInterval;
    let currentModel = 'coco-ssd'; 

    
    const loadingElement = document.getElementById('loading');
    const loadingProgressElement = document.getElementById('loading-progress');
    const startCameraBtn = document.getElementById('startCameraBtn');
    const stopCameraBtn = document.getElementById('stopCameraBtn');
    const webcamElement = document.getElementById('webcam');
    const canvasElement = document.getElementById('canvas');
    const photoButton = document.getElementById('photoButton');
    const recordButton = document.getElementById('recordButton');
    const flipButton = document.getElementById('flipButton');

    
    document.addEventListener('DOMContentLoaded', () => {
        updateTime();
        setInterval(updateTime, 1000);
        
    });

    
    function loadScript(src) {
        return new Promise((resolve, reject) => {
            if (document.querySelector(`script[src="${src}"]`)) return resolve();
            const s = document.createElement('script');
            s.src = src;
            s.async = true;
            s.onload = () => resolve();
            s.onerror = (e) => reject(e);
            document.head.appendChild(s);
        });
    }

    async function ensureMlScripts() {
        if (window.tf && window.cocoSsd && window.mobilenet) return;
        startLoadingAnimation();
        try {
            await loadScript('https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@4.15.0/dist/tf.min.js');
            await loadScript('https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd@2.2.2/dist/coco-ssd.min.js');
            await loadScript('https://cdn.jsdelivr.net/npm/@tensorflow-models/mobilenet@2.1.0');
            
            await new Promise(r => setTimeout(r, 150));
            await loadModels();
        } catch (err) {
            console.error('Failed to load ML scripts:', err);
        } finally {
            stopLoadingAnimation();
        }
    }

    function adjustCanvasSize() {
            const containerWidth = webcamElement.offsetWidth;
            const containerHeight = webcamElement.offsetHeight;
            
            
            canvasElement.width = webcamElement.videoWidth;
            canvasElement.height = webcamElement.videoHeight;
            
            
            const videoAspect = webcamElement.videoWidth / webcamElement.videoHeight;
            const containerAspect = containerWidth / containerHeight;
            
            
            let scaleX = 1;
            let scaleY = 1;
            
            if (containerAspect > videoAspect) {
                
                scaleX = containerHeight * videoAspect / containerWidth;
            } else {
                
                scaleY = containerWidth / videoAspect / containerHeight;
            }
            
            ctx = canvasElement.getContext('2d');
            
            
            ctx.setTransform(1, 0, 0, 1, 0, 0);
            
            
            if (isFrontCamera) {
                ctx.scale(-1, 1);
                ctx.translate(-canvasElement.width, 0);
            }
            
            
            ctx.scale(scaleX, scaleY);
        }

    
    function updateTime() {
        const now = new Date();
        const hours = now.getHours().toString().padStart(2, '0');
        const minutes = now.getMinutes().toString().padStart(2, '0');
        document.querySelector('.current-time').textContent = `${hours}:${minutes}`;
    }

    
    function startLoadingAnimation() {
        loadingProgress = 0;
        loadingElement.style.display = 'block';
        loadingInterval = setInterval(() => {
            loadingProgress += Math.random() * 5;
            if (loadingProgress > 95) loadingProgress = 95;
            loadingProgressElement.style.width = `${loadingProgress}%`;
        }, 200);
    }

    function stopLoadingAnimation() {
        clearInterval(loadingInterval);
        loadingProgressElement.style.width = '100%';
        setTimeout(() => {
            loadingElement.style.display = 'none';
        }, 300);
    }

    
    async function loadModels() {
        if (isModelLoading) return;
        isModelLoading = true;
        
        try {
            
            model = await cocoSsd.load(window.modelConfig);
            mobileNetModel = await mobilenet.load();
            console.log("All models loaded successfully");
        } catch (error) {
            console.error("Failed to load models:", error);
        }
    }

    
    async function toggleModel() {
        currentModel = currentModel === 'coco-ssd' ? 'mobilenet' : 'coco-ssd';
        
        
        if (isCameraOn) {
            
            detectObjects();
        }
    }

    
    async function startCamera() {
        if (isCameraOn) return;
        
        try {
            startCameraBtn.style.display = 'none';
            stopCameraBtn.style.display = 'inline-flex';
            
            const stream = await navigator.mediaDevices.getUserMedia({
                video: {
                    facingMode: isFrontCamera ? "user" : "environment",
                    width: { ideal: 1280 },
                    height: { ideal: 720 }
                }
            });
            
            webcamElement.srcObject = stream;
            webcamElement.style.display = 'none'; 
            canvasElement.style.display = 'block'; 
            
            webcamElement.onloadedmetadata = () => {
                webcamElement.play();
                adjustCanvasSize();
                isCameraOn = true;
                detectObjects();
            };
            
        } catch (error) {
            console.error("Camera error:", error);
            startCameraBtn.style.display = 'flex';
            stopCameraBtn.style.display = 'none';
        }
    }

    async function stopCamera() {
        if (!isCameraOn) return;
        
        if (isRecording) {
            stopRecording();
        }
        
        const stream = webcamElement.srcObject;
        const tracks = stream.getTracks();
        tracks.forEach(track => track.stop());
        
        webcamElement.srcObject = null;
        ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
        isCameraOn = false;
        startCameraBtn.style.display = 'flex';
        stopCameraBtn.style.display = 'none';
    }

    function adjustCanvasSize() {
        const containerWidth = webcamElement.offsetWidth;
        const containerHeight = webcamElement.offsetHeight;
        
        
        canvasElement.width = webcamElement.videoWidth;
        canvasElement.height = webcamElement.videoHeight;
        
        
        const videoAspect = webcamElement.videoWidth / webcamElement.videoHeight;
        const containerAspect = containerWidth / containerHeight;
        
        
        let scaleX = 1;
        let scaleY = 1;
        
        if (containerAspect > videoAspect) {
            
            scaleX = containerHeight * videoAspect / containerWidth;
        } else {
            
            scaleY = containerWidth / videoAspect / containerHeight;
        }
        
        ctx = canvasElement.getContext('2d');
        
        
        ctx.setTransform(1, 0, 0, 1, 0, 0);
        
        
        if (isFrontCamera) {
            ctx.scale(-1, 1);
            ctx.translate(-canvasElement.width, 0);
        }
        
        
        ctx.scale(scaleX, scaleY);
    }

    
    async function detectObjects() {
        if (!isCameraOn || !model || !mobileNetModel) return;
        
        try {
            
            ctx.save();
            ctx.setTransform(1, 0, 0, 1, 0, 0);
            ctx.clearRect(0, 0, canvasElement.width, canvasElement.height);
            ctx.restore();
            
            
            ctx.drawImage(webcamElement, 0, 0, canvasElement.width, canvasElement.height);
            
            
            let predictions;
            if (currentModel === 'coco-ssd') {
                predictions = await model.detect(webcamElement);
            } else {
                predictions = await mobileNetModel.classify(webcamElement);
                predictions = predictions.map(pred => ({
                    bbox: [0, 0, 0, 0],
                    class: pred.className,
                    score: pred.probability
                }));
            }
            
            
            drawDetections(predictions);
        } catch (error) {
            console.error("Detection error:", error);
        }
        
        requestAnimationFrame(detectObjects);
    }

    function getColorForClass(name) {
        
        let h = 0;
        for (let i = 0; i < name.length; i++) {
            h = (h * 31 + name.charCodeAt(i)) % 360;
        }
        const s = 70; 
        const l = 50; 
        return `hsl(${h}, ${s}%, ${l}%)`;
    }

    function drawDetections(predictions) {
        
        const baseFont = Math.max(14, Math.round(canvasElement.width / 480 * 18));

        predictions.forEach((prediction, idx) => {
            const label = `${prediction.class} ${Math.round(prediction.score * 100)}%`;
            const color = getColorForClass(String(prediction.class || 'obj'));
            ctx.font = `${baseFont}px Arial`;
            const textWidth = ctx.measureText(label).width;
            const padding = 8;

            if (currentModel === 'coco-ssd' && prediction.bbox && prediction.bbox.length === 4) {
                const [x, y, width, height] = prediction.bbox;

                
                ctx.strokeStyle = color;
                ctx.lineWidth = Math.max(2, Math.round(baseFont / 6));
                ctx.strokeRect(x, y, width, height);

                
                const labelHeight = baseFont + 6;
                const labelX = x;
                const labelY = (y - labelHeight > 0) ? (y - labelHeight) : y;

                ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
                ctx.fillRect(labelX, labelY, textWidth + padding, labelHeight);

                
                ctx.fillStyle = color;
                ctx.fillText(label, labelX + padding/2, labelY + baseFont - 2);
            } else {
                
                const x = 10;
                const y = 10 + idx * (baseFont + 12);

                ctx.fillStyle = 'rgba(0, 0, 0, 0.6)';
                ctx.fillRect(x, y, textWidth + padding, baseFont + 6);

                ctx.fillStyle = color;
                ctx.fillText(label, x + padding/2, y + baseFont - 2);
            }
        });
    }

    
    async function takePhotoWithDetection() {
        if (!isCameraOn) return;
        
        const photoCanvas = document.createElement('canvas');
        photoCanvas.width = canvasElement.width;
        photoCanvas.height = canvasElement.height;
        const photoCtx = photoCanvas.getContext('2d');
        
        
        photoCtx.drawImage(canvasElement, 0, 0);
        
        
        const link = document.createElement('a');
        link.download = `detection-${new Date().toISOString()}.png`;
        link.href = photoCanvas.toDataURL('image/png');
        link.click();
    }

    
    function toggleRecording() {
        if (!isCameraOn) return;
        
        if (!isRecording) {
            startRecording();
        } else {
            stopRecording();
        }
    }

    function startRecording() {
        recordedChunks = [];
        const stream = webcamElement.srcObject;
        mediaRecorder = new MediaRecorder(stream);
        
        mediaRecorder.ondataavailable = (e) => {
            if (e.data.size > 0) recordedChunks.push(e.data);
        };
        
        mediaRecorder.onstop = () => {
            const blob = new Blob(recordedChunks, { type: 'video/webm' });
            const url = URL.createObjectURL(blob);
            const link = document.createElement('a');
            link.download = `recording-${new Date().toISOString()}.webm`;
            link.href = url;
            link.click();
        };
        
        mediaRecorder.start();
        isRecording = true;
        recordButton.classList.add('recording');
    }

    function stopRecording() {
        mediaRecorder.stop();
        isRecording = false;
        recordButton.classList.remove('recording');
    }

    
    async function flipCamera() {
        if (!isCameraOn) return;
        
        isFrontCamera = !isFrontCamera;
        await stopCamera();
        await startCamera();
    }

    
    startCameraBtn.addEventListener('click', () => {
        
        
        startCamera();
        ensureMlScripts();
    });
    stopCameraBtn.addEventListener('click', stopCamera);
    photoButton.addEventListener('click', takePhotoWithDetection);
    recordButton.addEventListener('click', toggleRecording);
    flipButton.addEventListener('click', flipCamera);
</script>
<div class="typeit"><h4 id="id-2"></h4></div>

]]></description></item></channel></rss>