【OpenCV】场景中人的识别与前端计数

news2024/9/24 5:09:51

1.OpenCV代码设计讲解

突发奇想,搞个摄像头,识别一下实验室里面有几个人,计数一下(最终代码是累加计数,没有优化),拿OpenCV来玩一玩

首先,还是优先启动电脑摄像头,本项目将使用SSD进行人体检测。
deploy.prototxt与mobilenet_iter_73000.caffemodel自行从官网下载。

完整代码如下:

import cv2
import numpy as np

# 加载MobileNet-SSD模型
net = cv2.dnn.readNetFromCaffe('deploy.prototxt', 'mobilenet_iter_73000.caffemodel')


# 打开摄像头
cap = cv2.VideoCapture(0)

while cap.isOpened():
    ret, frame = cap.read()
    if ret:
        # 创建blob,预处理输入数据
        # cv2.resize(frame, (300, 300)),将输入的 frame 图像调整为 300x300 像素的大小
        # 神经网络通常要求输入图像的尺寸固定,因此需要调整图像大小
        # frame:要处理的原始图像,(300, 300):目标图像的宽度和高度
        # 0.007843:这是一个缩放因子,用于将像素值缩放到适合神经网络的范围。
		# 127.5:是一个均值值,用于对像素进行归一化处理,使用 Caffe 训练的模型,输入图像通常会减去均值以中心化数据。
        blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 0.007843, (300, 300), 127.5)
        net.setInput(blob)
        
        # 进行前向传播,得到检测结果
        detections = net.forward()
        
        # 获取帧的宽度和高度
        # 在 OpenCV 中,图像通常被表示为一个 NumPy 数组,其维度是 (height, width, channels)
        (h, w) = frame.shape[:2]
        
        # 具体结构由 cv2.dnn 模块的输出格式决定。
        # 对于物体检测任务,网络输出的数据维度一般是一个 4D 的张量 (NumPy 数组),其形状大致为(1, 1, N, 7)
        # 1 (Batch size):处理的图像批次数量,通常为 1,因为我们处理的是单张图像。
        # 1 (Number of classes):如果是单类检测,这里也是 1,表示输出的类别信息(可能是分类器的层数)。
		# N (Number of detections):这是该图像中检测到的对象数量。例如,网络可能检测到 100 个对象,N 就是 100。
		# 7 (Detection details):每个检测结果包含 7 个值,分别表示:
			# 第1个值: 检测结果的标签索引(通常是类别ID)。
			# 第2个值: 置信度 (confidence score)。
			# 第3-7个值: 边界框的坐标 (bounding box coordinates: x1, y1, x2, y2)。
        # 遍历检测结果
        for i in range(detections.shape[2]):
            confidence = detections[0, 0, i, 2]
            
            # 设置最低置信度阈值
            if confidence > 0.4:
                idx = int(detections[0, 0, i, 1])
                
                # 只检测人类(index 15是人类类别)
                if idx == 15:
                    box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
                    (startX, startY, endX, endY) = box.astype("int")
                    
                    # 画框标记人类
                    cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 255, 0), 2)
        
        # 显示结果
        cv2.imshow("Human Detection", frame)
        
        # 按 'q' 键退出
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

cap.release()
cv2.destroyAllWindows()

2.升级一下

给判定到的人数记录下来,因为不是什么重要数据,拿redis存一下,然后通过前端展示出来,效果如下:

在这里插入图片描述

代码如下:

import cv2
import numpy as np
import redis
from flask import Flask, jsonify
from flask_cors import CORS  # 引入 CORS

# 初始化 Flask 应用
app = Flask(__name__)
CORS(app)  # 启用 CORS 支持

# 连接 Redis 服务器
r = redis.Redis(host='localhost', port=6379, db=0)

# 加载 MobileNet-SSD 模型
net = cv2.dnn.readNetFromCaffe('deploy.prototxt', 'mobilenet_iter_73000.caffemodel')

# 摄像头检测函数
def detect_humans():
    cap = cv2.VideoCapture(0)

    while cap.isOpened():
        ret, frame = cap.read()
        if ret:
            # 创建 blob,预处理输入数据
            blob = cv2.dnn.blobFromImage(cv2.resize(frame, (300, 300)), 0.007843, (300, 300), 127.5)
            net.setInput(blob)

            # 进行前向传播,得到检测结果
            detections = net.forward()

            # 获取帧的宽度和高度
            (h, w) = frame.shape[:2]

            # 初始化检测到的人数
            human_count = 0

            # 遍历检测结果
            for i in range(detections.shape[2]):
                confidence = detections[0, 0, i, 2]

                # 设置最低置信度阈值
                if confidence > 0.4:
                    idx = int(detections[0, 0, i, 1])

                    # 只检测人类(index 15 是人类类别)
                    if idx == 15:
                        human_count += 1  # 增加检测到的人数
                        box = detections[0, 0, i, 3:7] * np.array([w, h, w, h])
                        (startX, startY, endX, endY) = box.astype("int")

                        # 画框标记人类
                        cv2.rectangle(frame, (startX, startY), (endX, endY), (0, 255, 0), 2)

            # 将人数写入 Redis 缓存
            r.set('human_count', human_count)

            # 显示结果
            cv2.imshow("Human Detection", frame)

            # 按 'q' 键退出
            if cv2.waitKey(1) & 0xFF == ord('q'):
                break
        else:
            break

    cap.release()
    cv2.destroyAllWindows()

# 创建一个 API 路由来返回 Redis 中的人数
@app.route('/get_human_count', methods=['GET'])
def get_human_count():
    # 从 Redis 中获取人数
    human_count = r.get('human_count')
    if human_count:
        human_count = int(human_count)
    else:
        human_count = 0
    return jsonify({'human_count': human_count})

if __name__ == '__main__':
    # 启动摄像头检测
    from threading import Thread
    t = Thread(target=detect_humans)
    t.daemon = True
    t.start()

    # 启动 Flask 服务
    app.run(debug=True, host='0.0.0.0')

前端代码是Online Tutorials上学来的,自己稍微改了一下html的部分:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Human Detection Count</title>
    <link rel="stylesheet" href="human_style.css">
</head>
<body>
    <div class="card">
        <div class="rating">
            <h2><span class="counter" data-target="0">0</span><sup>%</sup><br>Human</h2>
            <div class="block"></div>
        </div>
    </div>

    <script>
        // 初始化区块
        const rating = document.getElementsByClassName('rating')[0];
        const block = document.getElementsByClassName('block');
        for (let i = 1; i < 100; i++) {
            rating.innerHTML += "<div class='block'></div>";
            block[i].style.transform = "rotate(" + 3.6 * i + "deg)";
            block[i].style.animationDelay = `${i / 40}s`;
        }

        // 获取 Redis 中的人数并更新
        function fetchHumanCount() {
            fetch('http://127.0.0.1:5000/get_human_count')  // 后端 API 路由
                .then(response => response.json())
                .then(data => {
                    const counter = document.querySelector('.counter');
                    const target = data.human_count;  // 获取 Redis 中的值

                    counter.setAttribute('data-target', target);

                    // 启动计数器
                    const NumberCounter = () => {
                        const value = +counter.innerText;
                        if (value < target) {
                            counter.innerText = Math.ceil(value + 1);
                            setTimeout(() => {
                                NumberCounter();
                            }, 25);
                        }
                    };
                    NumberCounter();
                })
                .catch(error => console.error('Error fetching human count:', error));
        }

        // 每秒更新一次人数
        setInterval(fetchHumanCount, 1000);
    </script>
</body>
</html>

css全是Online Tutorials大佬写的,跟着视频敲了一遍:

@import url('https://fonts.googleapis.com/css?family=Poppins:200,300,400,500,600,700,800,900&display=swap');
*
{
    margin: 0;
    padding: 0%;
    box-sizing: border-box;
    font-family: 'Poppins', sans-serif;
}
body
{
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    background: radial-gradient(#444,#222);

}
.card
{
    position: relative;
    width: 200px;
    height: 200px;

}
.card .rating
{
    position: relative;
    width: 100%;
    height: 100%;
    /* background: rgba(107, 170, 221, 0.2); */
}
.card .rating .block
{
    position: absolute;
    width: 2px;
    height: 15px;
    background: #000;
    left: 50%;
    transform-origin: 50% 100px;
    opacity: 0;
    animation: animate 0.1s linear forwards;
}
.card .rating .block:nth-child(-n+90)
{
    background:#0f0;
    box-shadow: 0 0 15px #0f0,0 0 30px #0f0;
}
@keyframes animate {
    to
    {
        opacity: 1;
    }
}

.card .rating h2{
    position: absolute;
    top:50%;
    left: 50%;
    transform:translate(-50%,-50%);
    color: #fff;
    font-size: 1.2em;
    font-weight: 500;
    text-align: center;
    line-height: 1.5em;
}

.card .rating h2 span{
    font-size: 2.5em;
    font-weight: 700;
}

.card .rating h2 sup
{
    font-size: 1.5em;
    font-weight: 300;
}

今天就先不写详解了,歇会~

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

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

相关文章

react hooks--useCallback

概述 useCallback缓存的是一个函数&#xff0c;主要用于性能优化!!! 基本用法 如何进行性能的优化呢&#xff1f; useCallback会返回一个函数的 memoized&#xff08;记忆的&#xff09; 值&#xff1b;在依赖不变的情况下&#xff0c;多次定义的时候&#xff0c;返回的值是…

MySQL record 07 part

索引 注意&#xff0c;是排序&#xff0c;有序就会加快查找的速度。 优势&#xff1a; 劣势 索引会单独占用存储空间索引虽然可以提高排序和查找的速度&#xff0c;但同时也会降低更新、删除、新增数据的速度&#xff0c;因为MySQL此时既要更改表&#xff0c;也要维护更改表后…

ubuntu安装无线网卡驱动(非虚拟机版)

本文不是基于虚拟机&#xff0c;是双系统 太夸张了 实验室居然没网线 只有一个师兄留下来的无线网卡 装完了ubuntu结果没网 make都用不了 然后搜了下大概发现是没有预装gcc和make 参考如下 https://zhuanlan.zhihu.com/p/466440088 https://wwsk.lanzouj.com/iAj4t2ao46zc…

电脑配置不够,想玩老头环可以上ToDesk云电脑体验一下

最近&#xff0c;《艾尔登法环》游戏更新了好多新东西&#xff0c;让玩家特别兴奋。比如说&#xff0c;FromSoftware工作室一直在改进游戏&#xff0c;让游戏运行得更稳、更流畅。而且&#xff0c;《艾尔登法环&#xff1a;黄金树幽影》这个扩展包一出&#xff0c;游戏世界变得…

【Python报错已解决】AttributeError: ‘list‘ object has no attribute ‘attribute‘

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 专栏介绍 在软件开发和日常使用中&#xff0c;BUG是不可避免的。本专栏致力于为广大开发者和技术爱好者提供一个关于BUG解决的经…

调用JS惰性函数问题

第一次调用这个函数时 console.log(a) 会被执行&#xff0c;打印出 a&#xff0c;全局变量 a 被重定义并被赋予了新的函数&#xff0c;当再一次调用时&#xff0c;console.log(b) 被执行。 用处&#xff1a;因为各浏览器之间的行为差异&#xff0c;经常会在函数中包含了大量的…

Kafka技术详解[1]:简介与基础概念

目录 1. Kafka入门 1.1 概述 1.1.1 初识Kafka 1.1.2 消息队列 1.1.3 生产者-消费者模式 1.1.4 消息中间件对比 1.1.5 ZooKeeper 1. Kafka入门 1.1 概述 1.1.1 初识Kafka Kafka是由Scala和Java语言开发的高吞吐量分布式消息发布和订阅系统&#xff0c;也是大数据技术领…

《汇编语言》第14章——实验 14访问CMOS RAM

编程&#xff0c;以“年/月/日 时&#xff1a;分&#xff1a;秒”的格式&#xff0c;显示当前的日期、时间 assume cs:code data segment db 2024/09/23 00:00:00,$ data endscode segment start:mov ax,datamov es,axcall get_hms_funccall get_ymd_funcmov dh,12 ;dh中存放…

黑马头条day3-2 自媒体文章管理

前边还有一个 素材列表查询 没什么难度 就略过了 查询所有频道和查询自媒体文章也是和素材列表查询类似 就是普通的查询 所以略过了 文章发布 这个其实挺复杂的 一共三张表 一个文章表 一个素材表 一个文章和素材的关联表 区分修改与新增就是看是否存在id 如果是保存草稿…

实现一个基于nio的discard server

写在前面 源码 。 为了能够进一步的熟悉下nio相关的api操作&#xff0c;本文来实现一个基于nio的discard server。 discard server的意思是&#xff0c;server接收到来自client的一个消息之后&#xff0c;直接就将连接关闭&#xff0c;即discard。 1&#xff1a;正戏 1.1&…

MySQL深度探索:掌握触发器自动化与精细用户权限管理,提升数据库效能与安全

作者简介&#xff1a;我是团团儿&#xff0c;是一名专注于云计算领域的专业创作者&#xff0c;感谢大家的关注 座右铭&#xff1a; 云端筑梦&#xff0c;数据为翼&#xff0c;探索无限可能&#xff0c;引领云计算新纪元 个人主页&#xff1a;团儿.-CSDN博客 目录 前言&#x…

gitlab集成CI/CD,shell方式部署

目录 1.首先安装好gitlab和gitlab-runner&#xff0c;这两个&#xff0c;看我以往的教程 2.注册新的 Runner 3. 步骤 3.1 Enter the GitLab instance URL (for example, https://gitlab.com/): 3.2 Enter the registration token: 3.3 Enter a description for the runner: 3…

【2024.09】关于 UMLS 在支持大型语言模型提出的诊断生成中的作用

生物医学信息学杂志 链接&#xff1a;https://www.sciencedirect.com/science/article/abs/pii/S1532046424001254?via%3Dihub On the role of the UMLS in supporting diagnosis generation proposed by Large Language Models Author links open overlay panelMajid Afsh…

线上搭子小程序:随时随地找搭子!

搭子作为当下流行的一种社交方式&#xff0c;受到了年轻人的讨论关注&#xff0c;不管做什么都可以找不同的“搭子”。追剧、考试、健身、减肥、旅游等都可以找到志趣相投的搭子&#xff0c;满足年轻人的社交需求。 在互联网的发展下&#xff0c;年轻人找搭子也逐渐倾向于线上…

ubuntu22 解决docker无法下载镜像问题

参考在 Ubuntu 中安装 Docker_ubuntu安装docker-CSDN博客 安装docker完成后&#xff0c;运行如下命令验证 Docker 服务是否在运行&#xff1a; systemctl status docker 运行&#xff08;sudo docker run hello-world&#xff09;例子报错&#xff1a; 问题&#xff1a;Docker…

ubuntu内网穿透后在公网使用ssh登录

需求&#xff1a; 我有一台内网可以通过ssh 22端口访问的设备操作系统是ubuntu server我还有1台拥有公网IP的服务器&#xff0c;IP地址是 6.66.666.6666我想随时从其他网段通过ssh访问我的ubuntu server设备 实现&#xff1a; 工具准备&#xff1a;frp 网址&#xff1a;https…

一看就会!PS2024下载安装教程详解

PS2024下载方法&#xff1a; PS2024安装教程&#xff1a; 1、右击【PS2024.zip】&#xff0c;选择【解压到PS2024】 2、右击【Set-up.exe】&#xff0c;选择【以管理员身份运行】 3、点击右下角灰色的小文件夹图标&#xff0c;选择【更改位置】 4、选择安装路径后&#xff0c;…

【每日刷题】Day130

【每日刷题】Day130 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. 144. 二叉树的前序遍历 - 力扣&#xff08;LeetCode&#xff09; 2. 94. 二叉树的中序遍历 - 力扣…

注册安全分析报告:闪送

前言 由于网站注册入口容易被黑客攻击&#xff0c;存在如下安全问题&#xff1a; 暴力破解密码&#xff0c;造成用户信息泄露短信盗刷的安全问题&#xff0c;影响业务及导致用户投诉带来经济损失&#xff0c;尤其是后付费客户&#xff0c;风险巨大&#xff0c;造成亏损无底洞…

C#测试调用Ghostscript.NET浏览PDF文件

Ghostscript.NET是针对Ghostscript的C#封装库&#xff0c;支持解析PostScript语言、操作PDF文件等。使用Ghostscript.NET的GhostscriptViewer 模块可以以图片形式查看PDF文档。本文学习并测试调用Ghostscript.NET模块打开及浏览PDF文件的基本用法。   Ghostscript.NET目前主要…