资讯动态

基于OpenCV与海康威视摄像头的RTSP人体识别方案详解

发布时间:2026/10/4 4:20:55 来源:尧图企业网站定制
简介面向毕业设计与课程设计的计算机视觉学习者这份项目源码以海康威视网络摄像头为输入设备基于OpenCV实现视频流中的人体识别。工程采用HOG特征结合SVM分类器完成检测覆盖摄像头采集、YV12色彩空间转换、人体检测与界面显示的完整链路。资源共229个文件含C源码、头文件、Visual Studio工程配置、exe可执行程序、dll动态库及pdb调试符号压缩包约36.88MB。cpp模块涵盖camera、processpeople、HOGSVM、train_main等关键环节目录清晰便于对照学习。目前已有229人学习适合作为本科毕设或课程项目参考可在此基础上调试参数、扩展功能或更换摄像头完成同类任务。1. 基于海康威视网络摄像头和OpenCV的人体识别为什么我推荐先用RTSP接流再做检测很多做安防集成和客流统计的工程师手里已经有一批海康威视网络摄像头却只让它们在硬盘录像机里录着实时人体识别迟迟没落地。原因不外乎两个一是觉得必须调用海康威视API接口或者SDK才能拿画面被“协议墙”挡在门外二是担心人体识别模型太复杂普通机器带不动。实际上OpenCV就能直接读取海康网络摄像头的RTSP视频流配合一个轻量深度学习模型做人体目标检测既不需要购买商业软件也不需要购买GPU。本文就用一套我常用的方案把海康摄像头接入、OpenCV环境搭建、人体检测模型部署、参数调优和踩坑经验完整讲清楚。适合固定机位、室内外出入口、园区周界这一类场景新手可以照着从零跑通熟手可以直接跳到第五章看边界问题。2. 海康摄像头取流原理RTSP地址、H.264/H.265与人体检测选型做人体识别之前先要把镜头里的画面拿到OpenCV里。这是整个方案最容易被卡住的地方很多项目不是模型不行而是视频流根本打不开。2.1 海康威视网络摄像头的RTSP取流结构海康威视网络摄像头和USB摄像头最大的区别在于视频流不在本地而是通过RTSP协议在网络上传输。RTSP是一种流媒体控制协议OpenCV里的VideoCapture组件通过FFmpeg库解析RTSP然后逐帧解码成OpenCV能处理的BGR图像。只要摄像头和电脑在同一个局域网网络通、端口通、账号密码正确就能像读本地视频文件一样读网络摄像头。海康摄像头的RTSP地址不是随便猜的它有固定的路径规则。主码流路径一般是rtsp://用户名:密码摄像头IP:554/Streaming/Channels/101这里的101代表“通道1的主码流”201是“通道1的子码流”。如果是双通道设备比如带有第二镜头的型号那么第二个通道对应的就是102和202。端口号默认是554除非你在摄像头后台改过。用户名通常是admin密码是你在激活设备时设置的密码不是出厂默认密码。在实际项目中我更建议默认先用子码流做人体识别。子码流分辨率一般是704×576或者640×480码率低、带宽占用少OpenCV解码的压力小很多。人体识别并不需要非要看清人脸只要躯干轮廓能被框出来就够。主码流虽然分辨率更高但1080P甚至4K的画面会让CPU推理速度直线下降。后面第四章会详细说参数取舍这里记住一个原则优先用子码流能极大降低部署成本。补充一点海康威视API接口ISAPI也可以用来获取设备在线状态、抓拍图片、配置区域信息但人体识别是连续的视频帧处理走ISAPI抓图再识别的方式延迟太高不实用。所以这篇文章会以RTSP为主要取流通道ISAPI只作为辅助手段来查询设备信息。2.2 选择人体识别模型HOG、背景建模还是深度学习拿到视频流之后下一个问题是“怎么做人体识别”。这里先把“人体识别”这个概念说清楚它指的是检测画面中的人输出一个矩形框不涉及识别这个人的身份。很多人把它跟人脸识别混在一起实际是两回事。在OpenCV生态里人体识别常见的有四条路线我按实际项目中的推荐程度依次说明。第一种是HOG特征加SVM分类器。OpenCV的cv2.HOGDescriptor里面内置了一个默认的“行人检测”描述子代码非常短CPU也能跑。但问题也很明显它对完整站立的行人效果尚可一旦人弯腰、被遮挡、背对镜头漏检率会非常高。HOG本质上靠梯度直方图描述人体轮廓在密集场景下几乎不可用。第二种是背景建模也就是MOG2或者KNN这些算法。背景建模适合摄像头完全固定的场景通过统计像素在一段时间内的变化把前景运动目标抠出来。听起来很适合安防实际上它把拖影、树叶晃动、光影变化都当成了前景误检率很高。除非你的场景只有一个人在空房间里移动否则不建议单独使用。第三种是用YOLO系列做目标检测比如YOLOv5或者YOLOv8。检测精度高对遮挡、姿态变化鲁棒但部署略重至少需要PyTorch环境。如果在CPU上跑帧率会很难看如果配了NVIDIA显卡确实是最佳方案。第四种是OpenCV的DNN模块加载MobileNet SSD预训练模型这也是我这篇文章要采用的方案。MobileNet SSD的权重文件不大模型在COCO数据集上训练过其中包含person这一类。OpenCV的cv2.dnn.readNetFromCaffe可以直接加载Caffe格式的网络结构和权重不需要安装深度学习框架OpenCV一个库就能跑完整条链路。我在测试机上用CPU推理640×480分辨率的视频流能跑到15到20帧每秒足够做安防预警。先看一个用HOG做检测的最简代码直观感受一下它为什么不适合实战import cv2 hog cv2.HOGDescriptor() hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector()) frame cv2.imread(frame.jpg) rects, weights hog.detectMultiScale( frame, winStride(4, 4), padding(8, 8), scale1.05 ) for (x, y, w, h) in rects: cv2.rectangle(frame, (x, y), (x w, y h), (0, 255, 0), 2)这段代码跑起来很容易但如果你把摄像头里的真实画面喂进去就会发现问题人稍微侧身框就可能断成两截有人群重叠时一个框里塞两个人。winStride是滑动窗口步长步长越小计算量越大scale是图像缩放系数越小检测越精细但更慢。这些参数调来调去效果始终不稳定。所以我的建议是HOG只作为入门练习别用它做正式业务。2.3 为什么用OpenCV DNN加载MobileNet SSD而不是其他方案选型要有理由。MobileNet SSD的模型文件分两部分一个是.prototxt描述网络结构一个是.caffemodel存放训练好的权重。这个组合在OpenCV官方示例中很常见网上很容易找到文件名和对应的模型文件。对比表如下方案CPU帧率抗遮挡部署复杂度适合场景HOGSVM20 FPS以上差极低简单单人场景MOG2背景建模30 FPS以上差极低空旷场景YOLOv5CPU约5 FPSGPU可达实时好高需要PyTorch高性能服务器MobileNet SSD15-20 FPS中低只需OpenCV嵌入式/普通PCMobileNet SSD的误检主要是把贴在墙上的海报人物、远远的假人当成真人但通过NMS和ROI区域可以压制。相比Halcon这类商业视觉库OpenCV虽然精度不一定更高但胜在免费、轻量、社区量大遇到问题搜得到答案。这也是为什么我倾向于在原型项目里用OpenCV而不是一开始就上重型商业工具。3. 准备运行环境OpenCV安装、RTSP连通性与模型文件决定了技术路线之后先把环境准备干净。这一章只要照着做五分钟内就能看到摄像头画面被OpenCV读取出来。3.1 安装OpenCV并确认FFmpeg视频解码支持在Windows和Linux上OpenCV的安装方式不太一样。我最常用的做法是用Python的pip直接安装因为OpenCV官方发布的wheel包已经内置了FFmpeg的依赖RTSP解码能力默认是开启的。如果你的环境是树莓派或者其他ARM板子通常需要自己从源码编译OpenCV这会麻烦一些但这篇文章先不展开。安装命令如下python -m pip install --upgrade opencv-python注意这里用的是python -m pip不是直接敲pip。很多“安装OpenCV成功却找不到cv2”的问题根源就是pip命令指向了某个老版本Python环境而你在终端里输入的python又是另一个环境。用python -m pip可以避免这个坑。安装完成后验证一下OpenCV能不能加载RTSP协议。先打印版本和编译信息python -c import cv2; print(cv2.__version__); print(cv2.getBuildInformation())在输出内容里找到下面这类信息FFMPEG: YES如果显示NO说明当前OpenCV的FFmpeg支持没被编译进去读取RTSP大概率会失败。解决方法是卸载后重新安装官方pip包不要用系统包管理器里的旧版OpenCV。安装好之后可以把后面要用的工具写在同一个环境里。实际项目我还会装numpy因为OpenCV的DNN输出是一个多维数组需要numpy做坐标换算不过opencv-python会自动把numpy带上来一般不需要单独装。3.2 读取海康威视网络摄像头的RTSP视频流最小连通性测试环境就绪后先不急着写模型用一段极短的代码验证摄像头能不能通。import cv2 RTSP_URL rtsp://admin:your_password192.168.1.64:554/Streaming/Channels/201 capture cv2.VideoCapture(RTSP_URL, cv2.CAP_FFMPEG) if not capture.isOpened(): print(RTSP连接失败请检查IP、端口和密码) exit(1) ret, frame capture.read() if ret: print(f取流成功分辨率: {frame.shape[1]}x{frame.shape[0]}) cv2.imwrite(test_from_hikvision.jpg, frame) else: print(取流失败没有读到帧) capture.release()这里重点说几个点。cv2.VideoCapture的第二个参数cv2.CAP_FFMPEG作用是强制使用FFmpeg后端避免系统选择其他后端导致兼容性问题。有些版本默认后端能打开USB摄像头但不一定能正确打开RTSP所以建议显式指定。ret这个返回值是OpenCV里面最容易让人误判的。它只代表capture.read()是否成功从缓冲区拿到一帧不代表摄像头一定在线。如果代码里ret一直是False首先应该怀疑RTSP地址其次看用户名密码。海康摄像头密码错误时isOpened()并不会抛异常它会默默返回False这种“黑匣子”状态就需要用VLC播放器来验证地址。如果你用VLC能播同一串RTSP地址但OpenCV打不开那就是OpenCV的FFmpeg版本问题和摄像头本身无关。反之如果VLC也打不开问题一定出在摄像头设置、防火墙或者账号权限上。3.3 下载人体识别模型文件网络结构文件与权重文件OpenCV DNN模块不能凭空加载模型它需要两个文件。在OpenCV社区里最常见的一套COCO训练模型是MobileNet SSD对应的两个文件名是MobileNetSSD_deploy.prototxt MobileNetSSD_deploy.caffemodelprototxt是文本文件定义了网络的层结构、输入尺寸和输出层caffemodel是二进制文件存储了卷积核的权重。直接在搜索引擎里搜MobileNetSSD_deploy.caffemodel可以找到很多镜像下载源。下载后把这两个文件放在你的项目目录下然后写一段检查脚本import os CHECK_LIST [ MobileNetSSD_deploy.prototxt, MobileNetSSD_deploy.caffemodel ] for name in CHECK_LIST: if not os.path.isfile(name): print(f文件缺失: {name}) else: size_mb os.path.getsize(name) / 1024 / 1024 print(f文件正常: {name}, 大小: {size_mb:.2f} MB)请确认Caffe权重文件不要小于6MB。如果你下载下来只有几百KB那八成是参数错误、没有真正下载到权重数据。这个经验我在别的项目里遇到过不止一次所以每次都先检查文件大小。4. 用OpenCV搭建人体识别主程序加载模型、检测与画框环境通了模型文件也齐了现在可以跑起完整的人体识别程序。这一章是整篇文章的核心代码可以直接复制到你的项目里再根据自己的摄像头地址和阈值做调整。4.1 读取海康RTSP流并逐帧调用DNN推理完整的实现逻辑是循环读取RTSP帧把这一帧resize到模型输入尺寸执行深度学习推理从输出中过滤出person类绘制矩形框并显示。代码如下import cv2 import numpy as np RTSP_URL rtsp://admin:your_password192.168.1.64:554/Streaming/Channels/201 PROTO_FILE MobileNetSSD_deploy.prototxt MODEL_FILE MobileNetSSD_deploy.caffemodel CONF_THRESHOLD 0.5 PERSON_CLASS_ID 15 net cv2.dnn.readNetFromCaffe(PROTO_FILE, MODEL_FILE) capture cv2.VideoCapture(RTSP_URL, cv2.CAP_FFMPEG) capture.set(cv2.CAP_PROP_BUFFERSIZE, 1) while True: ret, frame capture.read() if not ret: print(读取RTSP失败准备重连) break h, w frame.shape[:2] blob cv2.dnn.blobFromImage( frame, scalefactor0.007843, size(300, 300), mean(127.5, 127.5, 127.5), swapRBFalse, cropFalse ) net.setInput(blob) detections net.forward() for i in range(detections.shape[2]): confidence detections[0, 0, i, 2] if confidence CONF_THRESHOLD: continue class_id int(detections[0, 0, i, 1]) if class_id ! PERSON_CLASS_ID: continue box detections[0, 0, i, 3:7] * np.array([w, h, w, h]) x1, y1, x2, y2 box.astype(int) cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) label fperson: {confidence:.2f} cv2.putText(frame, label, (x1, max(0, y1 - 10)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 1) cv2.imshow(Hikvision Person Detection, frame) if cv2.waitKey(1) 0xFF ord(q): break capture.release() cv2.destroyAllWindows()代码逻辑分三步。第一步用readNetFromCaffe加载网络结构文件和权重文件这里不需要TensorFlow或者PyTorchOpenCV内部自带Caffe解析器。第二步把一帧图像转换成blob第三步执行推理。blobFromImage里面有四个参数需要重点理解。scalefactor0.007843是1/127.5目的是把0到255的像素值归一化到-1到1之间size(300, 300)是模型要求的输入分辨率这个值不能随意改MobileNet SSD训练时用的就是300×300mean(127.5, 127.5, 127.5)是每个通道要减去的均值swapRBFalse代表不交换R和B通道因为Caffe模型最初是在BGR色彩空间上训练的OpenCV读图本来就是BGR不需要转换。检测结果的维度是[1, 1, N, 7]其中N表示模型预测出的候选框数量。每一行有7个数字[batch_index, class_id, confidence, x1, y1, x2, y2]。这里x1, y1, x2, y2都是相对坐标范围是0到1所以必须乘上原始帧的宽高才能得到像素坐标。PERSON_CLASS_ID15这是因为MobileNet SSD使用的COCO 20类模型里第15个类别是person0是背景所以实际上有效类别编号从1到20。如果摄像头画面里没有人detections.shape[2]依然会有很多行但它们的置信度都很低全都会被过滤掉。这也是DNN输出和其他检测算法的区别模型永远在尝试找东西即使画面空白也会输出一堆低分框过滤逻辑是必需的。4.2 防止重复人形框NMS非极大值抑制与阈值调整第一次运行时你可能会发现同一个人身上叠了两三个框。这很正常因为MobileNet SSD对同一个目标会产生多个尺度、多个位置的候选框如果不做去重画面会非常乱。OpenCV提供了一个现成的cv2.dnn.NMSBoxes函数专门解决这个问题。把上一节的主循环里的画框部分换掉改成先收集所有person候选框再统一做NMSboxes [] scores [] for i in range(detections.shape[2]): confidence detections[0, 0, i, 2] if confidence CONF_THRESHOLD: continue class_id int(detections[0, 0, i, 1]) if class_id ! PERSON_CLASS_ID: continue box detections[0, 0, i, 3:7] * np.array([w, h, w, h]) x1, y1, x2, y2 box.astype(int) boxes.append([x1, y1, x2 - x1, y2 - y1]) scores.append(float(confidence)) indices cv2.dnn.NMSBoxes(boxes, scores, score_threshold0.5, nms_threshold0.4) if len(indices) 0: for i in indices.flatten(): x1, y1, w_box, h_box boxes[i] x2, y2 x1 w_box, y1 h_box cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2)nms_threshold和score_threshold是两个要调的核心参数。score_threshold0.5表示置信度低于0.5的直接丢弃nms_threshold0.4表示两个矩形框的交并比超过0.4时保留得分更高的那一个。在实际项目里如果误检多可以把置信度拉到0.7如果漏检多就降到0.3。NMS阈值不建议超过0.5否则重叠的人会被合并成一个框。每次调整参数后最好在固定视频流上连续观察5分钟不要只看几帧就下结论。人体姿态变化很快前几帧能检到的人转身之后置信度可能骤降。4.3 降低CPU占用跳帧、ROI与子码流组合使用现在程序已经能识别了但如果你用的是普通办公台式机CPU占用很可能直接拉满。单线程推理加视频解码占用80%以上不稀奇。要把它压下来常见做法是组合使用三个手段。第一判断跳帧。人体运动速度不快不需要每一帧都做检测每2帧甚至每3帧做一次推理效果几乎不受影响。时间开销却降了一半以上。第二缩小推理输入尺寸。当前blob输入是300×300已经是模型下限不能再小但可以把摄像头画面先缩小到更小尺寸再送进网络不过这会牺牲小目标的检测率。第三设置ROI也就是只检测画面中的某个区域。很多场景下人只从特定区域经过比如园区大门、通道、闸机把其他区域遮挡掉可以减少大量误检。把这三者整合成一个优化版frame_skip 2 frame_count 0 while True: if not capture.grab(): break frame_count 1 if frame_count % frame_skip ! 0: continue ret, frame capture.retrieve() if not ret: continue h, w frame.shape[:2] mask np.zeros((h, w), dtypenp.uint8) cv2.rectangle(mask, (0, int(h * 0.4)), (w, h), 255, -1) roi_frame cv2.bitwise_and(frame, frame, maskmask) blob cv2.dnn.blobFromImage( roi_frame, scalefactor0.007843, size(300, 300), mean(127.5, 127.5, 127.5), swapRBFalse, cropFalse ) net.setInput(blob) detections net.forward() # 后续画框逻辑与4.2一致这里用grab()和retrieve()替代原来的read()。grab()只负责把下一帧解码后的数据拉到内存不返回图像retrieve()再把当前内存中的图像取出来。当跳帧时只调用grab()不调用retrieve()视频帧会直接从缓冲区丢掉不会堆积。ROI的mask黑掉了画面最上面的40%区域比如天空、远处建筑不让模型在那上面找“人”。注意blobFromImage的输入是roi_frame黑色区域像素值为0经过归一化之后变成负数模型在这些区域基本不会产生高置信度框。这个方法能明显降低误检率。5. 避坑指南从RTSP取流到模型部署的5个常见问题这一章我把自己在多个项目里踩过的坑整理成现象、原因、解决三个层次希望能让你少走弯路。5.1 RTSP连接超时或401 Unauthorized现象capture.isOpened()返回False或者read()循环一段时间后报错退出。有些项目里日志显示“401 Unauthorized”。原因最常见的是密码里有特殊字符比如、:、/。这些字符直接拼到RTSP的URL里会破坏URL语法导致认证失败。另一个常见原因是摄像头创建的用户只有查看预览权限没有远程取流权限这种情况下VLC也打不开。解决在代码里用urllib.parse.quote对密码做URL编码再拼接RTSP地址。from urllib.parse import quote user admin password pss:w/rd encoded_password quote(password, safe) rtsp_url frtsp://{user}:{encoded_password}{ip}:554/Streaming/Channels/201另外可以在海康摄像头web后台的“用户管理”里给该用户勾选“远程取流”权限。修改之后不需要重启摄像头重新运行程序即可。5.2 H.265编码流在OpenCV中出现花屏或黑屏现象RTSP能连上但画面出现绿色/灰色的条纹或者整个画面是黑色的只有偶尔几帧能看到轮廓。原因海康摄像头的默认编码格式在新型号上可能是H.265而OpenCV自带的FFmpeg在部分平台、部分版本上对H.265的支持是缺失的。尤其是Windows下用pip安装的opencv-python大概率不支持H.265解码。解决最直接的办法是在摄像头web后台把视频编码改成H.264。打开摄像头后台的“视频设置”把“视频编码”从H.265改为H.264保存后等摄像头重启再用OpenCV测试。不想改全局编码的话可以优先使用子码流很多型号的子码流默认是H.264。改完编码后用VLC重新拉流确认画面正常再让OpenCV读取。5.3 人体框抖动、重叠框多置信度不稳定现象一个行人被同时框出三四个矩形框有时候人站在画面边缘框会突然消失画面中有人举手或者蹲下框就整个跳掉。原因一是没有做NMS二是模型本身对小目标、遮挡目标不太敏感三是置信度阈值设得太低。比如0.2或者0.3模型会把广告海报上的人体也当成真人。解决先完成第4.2节的NMS代码。然后把置信度阈值从0.5开始往上涨每涨0.05观察10分钟找到一个既不会把海报误检成真人、又不会漏掉背后走过来的人的值。在我常用的海康摄像头角度下0.6到0.7之间比较合适。如果画面顶部经常有远处的行人可以配合ROI把事情简单化。5.4 内存和延迟持续上涨最终程序卡死现象程序刚启动时延迟不到1秒跑了20分钟以后延迟变成5秒甚至10秒任务管理器看到内存从200MB涨到1GB以上最后摄像头画面卡死。原因OpenCV的VideoCapture在读取RTSP时如果解码速度跟不上输入速度帧会在缓冲区堆积。CAP_PROP_BUFFERSIZE默认值在部分版本里不好用导致旧帧一直没被消费新帧又不断进来。另一个原因是推理线程和处理线程共用同一个循环某一帧耗时过长会影响后续帧的读取。解决在创建VideoCapture后立即设置缓冲区大小为1capture.set(cv2.CAP_PROP_BUFFERSIZE, 1)并在主循环中使用第4.3节的grab()和retrieve()跳帧策略。如果这样还卡就把模型推理放到单独线程使用队列传递帧主线程只负责取帧和显示。在正式部署时我更倾向于不让OpenCV直接读实时流而是先把RTSP流转成低码率的临时视频文件再离线做识别但这是另一个话题了。5.5 安装OpenCV后始终提示No module named cv2现象刚执行完pip install opencv-python马上运行脚本却报ModuleNotFoundError: No module named cv2。有时候显示安装成功但import还是失败。原因大多数情况是Python环境和pip环境不一致。可能你安装了多个Python版本也可能你之前用apt或者系统包管理器装过低版本的OpenCV造成冲突。解决先统一使用python -m pip安装python -m pip install opencv-python安装后再用同一解释器验证python -c import cv2; print(cv2.version)如果项目已经装过opencv-contrib-python又装了opencv-python两个包会互相覆盖先把两个都卸载只保留其中一个。Linux系统如果之前用apt装过python-opencv建议在虚拟环境里重装pip包避开系统路径的干扰。6. 进阶验证用ROI限定检测区域并用离线回放评估准确率程序能跑通只是第一步真正交付给客户之前最好做一些验证和优化。我自己的习惯是先把检测结果和视频同时保存下来方便回看哪里漏检、哪里误检而不是盯着屏幕看几分钟就感觉没问题。在上一章的ROI基础上可以再加一个功能当人体框的中心点落入某个设定区域时保存一张现场快照。简单实现如下ROI_POLY [(200, 400), (600, 400), (600, 700), (200, 700)] def is_in_roi(center_x, center_y): import cv2 point (int(center_x), int(center_y)) inside cv2.pointPolygonTest( np.array(ROI_POLY, dtypenp.int32), point, False ) return inside 0检测到persons框之后取框底部的中心坐标作为人的落脚点判断它是否落在指定的多边形区域中触发报警或者抓拍。这个思路也可以反着用画一个“禁止进入”区域人一旦进入就记录时间戳。另一个值得做的验证是离线回放评估。把一段海康摄像头拍摄的5分钟视频保存成MP4文件然后让识别程序读这个视频而不是读RTSP。这种方式排除了网络波动因素方便对比不同参数设置下的检测结果。人工数一遍视频里实际出现的总人数再和检测结果的总数对比就能得到一个粗略的召回率。我自己的教训是别在摄像头实时流上盲目调参网络随时可能抖动画面也许突然卡顿很难分清是参数问题还是取流问题。先录一段视频把参数在视频上调稳定再切回RTSP实时流这样整个过程会更可控也更容易跟人沟通验收标准。希望这篇笔记能帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑