(全网最详细的可运行的人流统计程序)基于OpenCV的实时视频处理系统

OpenCV人脸检测

OpenCV提供了多种人脸检测方法,包括基于Haar级联的传统方法和基于深度学习的现代方法。Haar级联是一种经典的机器学习算法,适用于实时应用,因为它可以快速处理图像。

  1. 级联(Cascade)结构

    • Cascade分类器由多个简单的分类器组成,这些分类器按照一定的顺序级联起来。
    • 每个分类器都是一个弱分类器,只能对图像中的一部分区域进行简单的判断。
    • 当图像或图像中的某个区域通过所有分类器的判断时,才认为它是一个目标。

深度学习方法,如MTCNN(Multi-Task Cascade Convolutional Networks)和YOLOv3,提供了更高的检测准确度。

本文使用的是Haar特征的Cascade分类器(haarcascade_frontalface_default.xml)进行人脸检测。这是一种基于机器学习的方法,可以快速检测图像中的人脸。

detectMultiScale方法用于在灰度图像上检测多尺度的人脸,返回检测到的人脸矩形框坐标。人流

# 加载人脸检测器(这里使用的是Haar特征的Cascade分类器)
face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')

运动检测

通过比较连续两帧图像的灰度差异来检测运动。这通过计算两帧图像之间的绝对差(cv2.absdiff)实现,对差异图像进行阈值处理(cv2.threshold),将差异较大的区域(即运动区域)转换为白色,其他区域为黑色。使用形态学操作(如膨胀cv2.dilate)来增强运动区域的特征,以便更容易地通过轮廓检测找到运动物体。cv2.findContours方法用于检测并提取图像中的轮廓,这些轮廓对应于运动物体。

    # 如果没有背景图像就将当前帧当作背景图片
    if pre_frame is None:
        pre_frame = gray_pic
    else:
        # absdiff把两幅图的差的绝对值输出到另一幅图上面来
        img_delta = cv2.absdiff(pre_frame, gray_pic)
        # threshold阈值函数(原图像应该是灰度图,对像素值进行分类的阈值,当像素值高于(有时是小于)阈值时应该被赋予的新的像素值,阈值方法)
        thresh = cv2.threshold(img_delta, 30, 255, cv2.THRESH_BINARY)[1]
        # 用一下腐蚀与膨胀
        thresh = cv2.dilate(thresh, None, iterations=2)
        # findContours检测物体轮廓(寻找轮廓的图像,轮廓的检索模式,轮廓的近似办法)
        contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

人流监测

代码能根据人脸检测结果进行相应的处理,若检测到人脸则记录,若当前未检测到人脸但之前检测到过,则认为有人脸移出,并进行计数和显示提示信息。总的来说,可以实现通过摄像头进行实时视频处理,包括运动检测和人脸检测,并对人脸的进入和移出进行计数和提示。

该代码可实现以下功能:

  • 结合人脸检测和运动检测结果,当检测到人脸且之前未检测到人脸时,认为有人进入。
  • 通过维护一个计数器J来跟踪进入的人数。
  • 如果之前检测到人脸但当前未检测到,且之前进入的人数大于0,则认为有人离开,但在这个实现中只统计了进入的人数。
    # 保存图像
                    TI = time.strftime('%Y-%m-%d', time.localtime(time.time()))
                    cv2.imwrite("D:/aopencv/" + TI + '.jpg', frame)
    
                    # 读取刚才保存的图像进行人脸检测
                    saved_image = cv2.imread("D:/aopencv/" + TI + '.jpg')
                    gray_saved = cv2.cvtColor(saved_image, cv2.COLOR_BGR2GRAY)
                    faces = face_cascade.detectMultiScale(gray_saved, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
    
                    # 检测到人脸
                    if len(faces) > 0:
                        print("检测到人脸!")
                        last_detected_faces +=1
                    else:
                        # 如果上次检测到的人脸数量大于0,且当前没有检测到人脸,则认为有人脸移出
                        if last_detected_faces > 0:
                            cv2.putText(frame, f"enter  {J}  people", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
                            J += 1
                            print(f"进入{J}个人")
                            last_detected_faces = 0  # 重置检测到的人脸数量

    完整代码,该代码可完美运行:

  • import cv2
    import time
    
    # 加载人脸检测器(这里使用的是Haar特征的Cascade分类器)
    face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
    
    # 定义摄像头对象,其参数0表示第一个摄像头
    camera = cv2.VideoCapture(0)
    # 测试用,查看视频size
    width = int(camera.get(cv2.CAP_PROP_FRAME_WIDTH))
    height = int(camera.get(cv2.CAP_PROP_FRAME_HEIGHT))
    size = width, height
    # 打印一下分辨率
    print(repr(size))
    # 设置一下帧数和前背景
    fps = 5
    pre_frame = None
    
    J=0
    C=0
    last_detected_faces = 0
    
    while (1):
        start = time.time()
        # 读取视频流
        ret, frame = camera.read()
        # 转灰度图
        gray_pic = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    
        if not ret:
            print("打开摄像头失败")
            break
        end = time.time()
    
        cv2.imshow("capture", frame)
    
        # 运动检测部分
        seconds = end - start
        if seconds < 1.0 / fps:
            time.sleep(1.0 / fps - seconds)
        gray_pic = cv2.resize(gray_pic, (480, 480))
        # 用高斯滤波进行模糊处理
        gray_pic = cv2.GaussianBlur(gray_pic, (21, 21), 0)
    
        # 如果没有背景图像就将当前帧当作背景图片
        if pre_frame is None:
            pre_frame = gray_pic
        else:
            # absdiff把两幅图的差的绝对值输出到另一幅图上面来
            img_delta = cv2.absdiff(pre_frame, gray_pic)
            # threshold阈值函数(原图像应该是灰度图,对像素值进行分类的阈值,当像素值高于(有时是小于)阈值时应该被赋予的新的像素值,阈值方法)
            thresh = cv2.threshold(img_delta, 30, 255, cv2.THRESH_BINARY)[1]
            # 用一下腐蚀与膨胀
            thresh = cv2.dilate(thresh, None, iterations=2)
            # findContours检测物体轮廓(寻找轮廓的图像,轮廓的检索模式,轮廓的近似办法)
            contours, hierarchy = cv2.findContours(thresh.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    
            for c in contours:
                # 设置敏感度
                # contourArea计算轮廓面积
                if cv2.contourArea(c) < 1000:
                    continue
                else:
                    # 保存图像
                    TI = time.strftime('%Y-%m-%d', time.localtime(time.time()))
                    cv2.imwrite("D:/aopencv/" + TI + '.jpg', frame)
    
                    # 读取刚才保存的图像进行人脸检测
                    saved_image = cv2.imread("D:/aopencv/" + TI + '.jpg')
                    gray_saved = cv2.cvtColor(saved_image, cv2.COLOR_BGR2GRAY)
                    faces = face_cascade.detectMultiScale(gray_saved, scaleFactor=1.1, minNeighbors=5, minSize=(30, 30))
    
                    # 检测到人脸
                    if len(faces) > 0:
                        print("检测到人脸!")
                        last_detected_faces +=1
                    else:
                        # 如果上次检测到的人脸数量大于0,且当前没有检测到人脸,则认为有人脸移出
                        if last_detected_faces > 0:
                            cv2.putText(frame, f"enter  {J}  people", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
                            J += 1
                            print(f"进入{J}个人")
                            last_detected_faces = 0  # 重置检测到的人脸数量
    
                    cv2.imshow("capture", frame)
            pre_frame = gray_pic
        cv2.putText(frame, f"enter  {J}  people", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 2)
        cv2.imshow("capture", frame)
    
    
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    
    # release()释放摄像头
    camera.release()
    # destroyAllWindows()关闭所有图像窗口
    cv2.destroyAllWindows()
    

  • 19
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值