浏览器实时播放摄像头数据并通过 Yolo 进行图像识别

news2025/3/1 1:46:37

安装 Ultralytics 之后,可以直接通过本地获取摄像头数据流,并通过 Yolo 模型实时进行识别。大多情况下,安装本地程序成本比较高,需要编译打包等等操作,如果可以直接通过浏览器显示视频,并实时显示识别到的对象类型就会方便很多。本文将通过 JS 原生代码 + 后台 Yolo 识别服务实现浏览器实时显示并识别对象类型的效果。

后发服务

后台服务采用 Python Flask 框架实现图片识别的 Rest API,开发之前,首先安装 Ultralytics 环境,我们使用官方的 DockerImage,用官方镜像作为基础镜像,安装相关依赖。

Dockerfile

# Use the ultralytics/ultralytics image as the base
FROM ultralytics/ultralytics:latest

# Update package lists and install vim
RUN apt-get update && apt-get install -y vim

# Install Flask using pip
RUN pip install flask flask-cors

# Set the working directory
WORKDIR /app

# Copy the current directory contents into the container at /app
COPY . /app

# Expose port 5000 for Flask
EXPOSE 5000

# Command to run the Flask application

App.py
后台 Rest API,/detect,解析 base64 图片,并返回识别到的图片分类和位置信息。

import os
from flask import Flask, request, jsonify
from ultralytics import YOLO
import cv2
import numpy as np

# Initialize Flask app
app = Flask(__name__)

# Load YOLOv8 model
model = YOLO('yolov8n.pt')  # You can change 'yolov8n.pt' to other versions like 'yolov8m.pt' or 'yolov8x.pt'

# Function to perform object detection
def detect_objects(image):
    results = model(image)
    detections = []
    for result in results:
        for box in result.boxes:
            x1, y1, x2, y2 = map(int, box.xyxy)
            class_id = int(box.cls)
            confidence = box.conf
            detections.append({
                'class_id': class_id,
                'label': model.names[class_id],
                'confidence': float(confidence),
                'bbox': [x1, y1, x2, y2]
            })
    return detections

# Route for object detection
@app.route('/detect', methods=['POST'])
def detect():
    if 'image' not in request.files:
        return jsonify({'error': 'No image provided'}), 400

    file = request.files['image']
    if file.filename == '':
        return jsonify({'error': 'No image selected for uploading'}), 400

    # Read image
    image = np.frombuffer(file.read(), np.uint8)
    image = cv2.imdecode(image, cv2.IMREAD_COLOR)

    # Perform detection
    detections = detect_objects(image)
    return jsonify(detections)

# Run Flask app
if __name__ == '__main__':
    app.run(host='0.0.0.0', port=5000)

前端页面

在页面显示摄像头,实时发送图片数据到后台进行识别,获取位置并显示在画布纸上。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Real-Time Object Detection with YOLO</title>
    <style>
        body {
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            margin: 0;
            background-color: #f0f0f0;
            overflow: hidden;
        }
        #camera, #canvas {
            position: absolute;
            width: 50%;
            height: 50%;
            object-fit: cover;
        }
        #camera {
            z-index: 1;
        }
        #canvas {
            z-index: 2;
        }
    </style>
</head>
<body>
    <video id="camera" autoplay playsinline></video>
    <canvas id="canvas"></canvas>

    <script>
        const classColors = {};

        function getRandomColor() {
            const letters = '0123456789ABCDEF';
            let color = '#';
            for (let i = 0; i < 6; i++) {
                color += letters[Math.floor(Math.random() * 16)];
            }
            return color;
        }

        function isMobileDevice() {
            return /Mobi|Android/i.test(navigator.userAgent);
        }

        async function setupCamera() {
            const video = document.getElementById('camera');
            const facingMode = isMobileDevice() ? 'environment' : 'user'; // Use back camera for mobile, front camera for PC

            try {
                const stream = await navigator.mediaDevices.getUserMedia({
                    video: {
                        facingMode: { ideal: facingMode }
                    }
                });
                video.srcObject = stream;
                return new Promise((resolve) => {
                    video.onloadedmetadata = () => {
                        resolve(video);
                    };
                });
            } catch (error) {
                console.error('Error accessing camera:', error);
                alert('Error accessing camera: ' + error.message);
            }
        }

        async function sendFrameToBackend(imageData) {
            const response = await fetch('https://c.hawk.leedar360.com/api/detect', {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json'
                },
                body: JSON.stringify({ image: imageData })
            });
            return await response.json();
        }

        function getBase64Image(video) {
            const canvas = document.createElement('canvas');
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
            const ctx = canvas.getContext('2d');
            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
            return canvas.toDataURL('image/jpeg').split(',')[1];
        }

        function renderDetections(detections, canvas, video) {
            const ctx = canvas.getContext('2d');
            ctx.clearRect(0, 0, canvas.width, canvas.height);
            ctx.drawImage(video, 0, 0, canvas.width, canvas.height);

            detections.forEach(det => {
                const { bbox, confidence, class_id, label } = det;
                if (confidence > 0.5) { // Only show detections with confidence > 0.5
                    const [x, y, w, h] = bbox;

                    if (!classColors[class_id]) {
                        classColors[class_id] = getRandomColor();
                    }

                    const color = classColors[class_id];
                    ctx.beginPath();
                    ctx.rect(x, y, w - x, h - y);
                    ctx.lineWidth = 2;
                    ctx.strokeStyle = color;
                    ctx.fillStyle = color;
                    ctx.stroke();
                    ctx.font = '24px Arial';  // Set font size to 24px
                    ctx.fillText(
                        `${label} (${Math.round(confidence * 100)}%)`,
                        x,
                        y > 24 ? y - 10 : 24  // Adjust position for the larger font size
                    );
                }
            });
        }

        async function main() {
            const video = await setupCamera();
            if (!video) {
                console.error('Camera setup failed');
                return;
            }

            video.play();

            const canvas = document.getElementById('canvas');
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;

            async function processFrame() {
                const imageData = getBase64Image(video);
                const detections = await sendFrameToBackend(imageData);
                renderDetections(detections, canvas, video);
                requestAnimationFrame(processFrame);
            }

            processFrame();
        }

        main();

        // Handle orientation change and resizing
        window.addEventListener('resize', () => {
            const video = document.getElementById('camera');
            const canvas = document.getElementById('canvas');
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
        });

        window.addEventListener('orientationchange', () => {
            const video = document.getElementById('camera');
            const canvas = document.getElementById('canvas');
            canvas.width = video.videoWidth;
            canvas.height = video.videoHeight;
        });
    </script>
</body>
</html>

总结

功能很好实现,效果还要微调,苹果的充电器并没有识别出来。

请添加图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1823235.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2024年6月-Docker配置镜像代理

步骤1&#xff1a;编辑 daemon.json 文件 vim /etc/docker/daemon.json步骤2&#xff1a;添加配置 将以下内容粘贴到文件中&#xff1a; {"insecure-registries": ["192.168.0.99:8800"],"data-root": "/mnt/docker","registr…

【Python】已解决报错:AttributeError: module ‘json‘ has no attribute ‘loads‘解决办法

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 &#x1f913; 同时欢迎大家关注其他专栏&#xff0c;我将分享Web前后端开发、人工智能、机器学习、深…

Python实现任务进度条展示(tqdm库实现进度条)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

高考完的三个月想自学点编程,有没有什么建议

&#x1f446;点击关注 获取更多编程干货&#x1f446; 对于刚刚完成高考的学生来说&#xff0c;无论未来是否选择计算机科学作为专业方向&#xff0c;自学编程技能是一项非常有价值的投资&#xff0c;掌握编程知识能够帮助同学们为将来的学习和科研 实践奠定一个基础。 随着…

计算机网络 —— 运输层(运输层概述)

计算机网络 —— 运输层&#xff08;运输层概述&#xff09; 运输层运输层端口号复用分用复用&#xff08;Multiplexing&#xff09;分用&#xff08;Demultiplexing&#xff09; 常用端口号页面响应流程 我们今天进入到运输层的学习&#xff1a; 运输层 我们之前学习的物理层…

感受光子芯片中试线,如何点亮未来计算与通信的革命之路(2024青岛智能装备与通信技术展)

光子芯片中试线&#xff1a;点亮未来计算与通信的革命之路 在新一代信息技术的浪潮中&#xff0c;光子芯片以其低能耗、高速度的特点备受瞩目。首条光子芯片中试线的建立&#xff0c;标志着我国在光电子领域的重大突破&#xff0c;同时也为即将到来的量子计算时代奠定了坚实基…

【DivineCut 2】Blender商店10周年免费领礼物智能服装布料生成工具限时免费领取。(1个月免费使用)

Blender商店10周年免费领礼物&#xff1a;https://blendermarket.com/birthday DivineCut 2 智能服装生成工具限时免费领取。&#xff08;1个月免费使用&#xff09; &#xff08;免费测试版资源库&#xff09; DivineCut™是一款Blender工具&#xff0c;只需点击几下&#xf…

样本学习:当AI遇上“少见多怪”

东汉名臣牟融在其著作《牟子》写道&#xff1a;“少所见&#xff0c;多所怪&#xff0c;睹橐驼&#xff0c;谓马肿背。”意思是见闻少的人遇到不常见的事物就觉得奇怪&#xff0c;见到骆驼也以为是背肿了的马。因此&#xff0c;后人总用“少见多怪”来嘲笑见识浅陋的人。然而&a…

互联网创业项目,轻资产创业项目。

目录 前言&#xff1a; 一、当前有哪些热门的互联网轻资产创业项目&#xff1f; 二、这些项目是做什么的&#xff1f; 三、项目一般都是怎么做的&#xff1f; 前言&#xff1a; 当前互联网创作项目多多&#xff0c;该怎么选择合适自己的项目去做呢&#xff1f; 一、当前有哪…

Windows 文件夹(文件)备份脚本bat

使用xcopy 来实现 1、新建一个bat脚本 重命名文件为 windows_log_bak.bat 后缀也成修改为.bat 2、备份代码 xcopy参数&#xff1a; #可在命令窗口执行这个命今&#xff0c;查看所有参数详细 xcopy /? 使用的参数&#xff1a; /e&#xff1a;拷贝所有子目录&#xff0c;包括…

编译结果处理的shell脚本

#!/bin/bash WEB"web" DIST"dist" RED\033[0:31m GREEN\033[0;32m NC\033[0m #生产打包传参 BUILD"b" if [ -e ${WEB} ];then#删历史文件rm -r ${WEB}rm ${WEB}.zip fi #编辑文件 npm run build #检查构建是否成功 if[ -e ${DIST} ];then#改名mv…

Java基础:Stream流和方法引用

一、Stream流 1.引言 Test&#xff1a;给定一个集合&#xff0c;如果想要筛选出其中以 "a" 开头且长度为3的元素&#xff0c;并添加到新集合中去&#xff0c;最后遍历打印&#xff0c;如何实现&#xff1f; public class Test {public static void main(String[] …

【机器学习300问】118、循环神经网络(RNN)的基本结构是怎样的?

将讲解循环神经网络RNN之前&#xff0c;我先抛出几个疑问&#xff1a;为什么发明循环神经网络&#xff1f;它的出现背景是怎样的&#xff1f;这些问题可以帮助我们更好的去理解RNN。下面我来逐一解答。 一、循环神经网络诞生的背景 循环神经网络&#xff08;RNN&#xff09;的…

OrangePi Kunpeng Pro 安装 ROS2 + Gazebo

文章目录 1. 初识1.1 到手开箱1.2 OrangePi Kunpeng Pro1.2 上电 2. 安装Ubuntu2.1 准备工作2.2 安装 3. 安装ROS23.1 设置支持UTF-8的locale编码3.2 添加证书3.3 安装ROS3.4 设置环境变量3.5 小海龟来啦 4. 运行实例4.1 安装Gazebo4.2 安装turtlebot 总结 1. 初识 1.1 到手开…

springboot、springcloud、springcloudalibaba版本组件之间对应关系

参考 https://github.com/alibaba/spring-cloud-alibaba/wiki/%E7%89%88%E6%9C%AC%E8%AF%B4%E6%98%8E#%E6%AF%95%E4%B8%9A%E7%89%88%E6%9C%AC%E4%BE%9D%E8%B5%96%E5%85%B3%E7%B3%BB%E6%8E%A8%E8%8D%90%E4%BD%BF%E7%94%A8 毕业版本依赖关系(推荐使用) 由于 Spring Boot 3.0&…

linux服务器网络配置

目录 1、centos的网络配置1.1 静态Ipv4配置方法&#xff1a;1.2 动态Ipv4的设置方法1.3 常见ping不通网关的原因&#xff1a;1.4 查看操作系统版本1.5 查看一台服务器的所有服务1.6 猜测所在房间网关ip 2、 Ubuntu的网络配置&#xff08;静态ipv4&#xff09;3、2024.6.14 解决…

《精通ChatGPT:从入门到大师的Prompt指南》第6章:日常对话与问答

第6章&#xff1a;日常对话与问答 6.1 提问技巧 提问技巧在使用ChatGPT时至关重要&#xff0c;因为高质量的提问能够得到更为准确和有价值的回答。以下是一些关键技巧和方法&#xff0c;帮助你掌握提问的艺术。 1. 明确问题目标 在提问之前&#xff0c;首先要明确你希望从C…

干G货,性能测试基本方法和原则,

一、性能测试关键点 评估性能指标——线程tps&#xff08;可架构给&#xff09; 吞吐量qps&#xff08;可架构给&#xff09; 错误率&#xff08;可架构给&#xff09; 平均响应时间&#xff08;可架构给&#xff09;模拟线上数据量了解接口有没有缓存&#xff0c;有缓存的需要…

同三维T80005EHS-4K60 4K60 HDMI/SDI编码器

1路4K60 HDMI或12G SDI输入&#xff0c;2路3.5MM音频输入&#xff0c;对应HDMI或SDI&#xff0c;1个USB口和1个SD卡槽&#xff0c;可录像到U盘/移动硬盘/SSD硬盘/TF卡 产品简介&#xff1a; 同三维T80005EHS-4K60 4K60HDMI/SDI H.265编码器采用最新高效H.265高清数字视频压缩…