基于Python的行人识别系统:从HOG+SVM到YOLO部署调优 简介基于Python的行人识别系统设计与实现是一份面向计算机视觉方向本科毕业设计的完整学位论文文档。内容围绕行人检测、特征提取与跟踪算法展开从研究背景、国内外现状到系统框架、模块实现和实验对比均有覆盖适合需要完成相关课题论文撰写或理解行人识别技术流程的读者参考。文档为docx格式共1个文件整体大小为35KB便于直接下载使用。资源以万字级论文正文为主体包含摘要、目录、各章节论述及参考文献结构已做降重处理可用于论文框架搭建、算法原理解读和写作思路参考。目前已有311人学习下载兼具实用性与参考价值。该论文还详细说明了HOG、YOLO、Faster R-CNN等常用检测算法以及SVM、深度学习模型在数据预处理、特征提取和分类训练中的应用并配套数据集与评价指标介绍读者可从中获得从系统设计到实验分析的完整闭环思路。1. 行人识别系统的应用入口与 Python 技术选型行人识别系统在智能安防、门店客流统计、无人驾驶辅助里都是最先落地的视觉需求。基于 Python 的行人识别系统核心不是把模型搭出来而是把相机输入变成可统计的检测框再决定误报和漏报哪个更不可接受。我见过不少项目把精力全放在训练精度上忽略了数据集分布、IOU 阈值、帧率换算这些工程参数结果模型在测试集上好看上线后业务不可用。这里按一条可复现的路线把设计、传统 HOG 特征、深度学习迁移、部署调优串起来讲给正在做课程设计或小型产品原型的开发者作参考。2. 把系统需求拆成数据流标注格式、IOU 与训练集设计碰到“基于 Python 的行人识别系统”这类题目我通常先不急着选模型而是先画数据流。一路 RTSP 视频流进来经过抽帧、检测、跟踪、统计最后写数据库或告警链路里每个环节的输入输出必须明确。常见做法是拆成四层接入层负责解码和抽帧检测层负责输出[x1, y1, x2, y2, score, class]决策层过滤和关联目标存储层记录结果。如果目标是统计员工通道人数检测层可以不 24 小时全帧跑只在有人进入 ROI 区域时触发高分辨率检测算力消耗会低一个数量级。2.1 功能模块与工程目录一个能维护的项目目录结构通常长这样video_stream/ detector/ hog_svm.py yolo_detector.py tracker/ iou_tracker.py pipeline/ frame_processor.py config/ params.yaml utils/ nms.py这是模块化后的最小骨架。detector只管输出检测框tracker根据 IOU 关联前后帧的同一目标pipeline负责串联业务逻辑单独放 service 层不要在检测脚本里写告警余量判断。下表是每一层需要守住的接口边界模块责任边界输出格式接入层解码、抽帧、分辨率归一化BGR frame检测层目标定位与分类[x1, y1, x2, y2, score, class]决策层区域过滤、置信度过滤结构化事件存储层结果落库或截图JSON、数据库记录这样设计的好处是以后换检测算法只替换detector内部实现上层接口不变。无论项目是课程设计还是产品原型这一层抽象直接决定后期改造成本。实际开发中我还会在config/params.yaml里单独保存检测阈值、ROI 坐标和抽帧间隔避免每次调参都改代码。2.2 数据集标注与 IOU 的判定标准行人识别属于监督学习数据集决定精度上限。用 LabelImg 标注时常见错误是把人体框到紧贴身体导致框的高宽比不稳定。稳妥做法是统一采用直立行人框左边界从腋下开始右边界到腋下上边界接近头顶留 2 到 3 像素下边界到鞋底。编码时先定义数据结构from dataclasses import dataclass dataclass class BBox: class_id: int score: float 1.0 x1: int 0 y1: int 0 x2: int 0 y2: int 0 def area(self) - int: return max(0, self.x2 - self.x1) * max(0, self.y2 - self.y1) def compute_iou(a: BBox, b: BBox) - float: ix1 max(a.x1, b.x1); iy1 max(a.y1, b.y1) ix2 min(a.x2, b.x2); iy2 min(a.y2, b.y2) iw max(0, ix2 - ix1); ih max(0, iy2 - iy1) inter iw * ih union a.area() b.area() - inter return inter / union if union 0 else 0.0compute_iou的返回值在训练指标和 NMS 里都会用到mAP 计算默认把 IOU0.5 作为正样本阈值而 NMS 的 IOU 阈值通常会设得更高比如 0.45。两者的用途不同不要混用。如果发现训练集里标注框大面积互相重叠先检查数据采集的时间间隔是否过大同一行人出现两个半身框这种质量噪声比模型参数量更能决定最终精度。2.3 数据增强先解决样本不平衡再谈网络结构行人识别最常见的失败是漏检穿深色衣服、遮挡和俯拍视角。常见做法是复制正样本后做左右翻转、随机裁剪和 HSV 扰动但有一条必须注意增强后的样本要避开物理上不合理的组合。右向左行走的人翻成左向右没问题俯拍视角下按 90 度旋转就可能生成现实中不存在的姿态。使用 albumentations 或 torchvision 的 transform 都行关键参数我会这样设亮度扰动范围 ±20%对比度 ±10%随机裁剪比例 0.8 到 1.0避免行人被截断过半。负样本建议单独留一批不裁剪的原图防止模型通过背景纹理识别人。3. 基于 Python 的 HOGSVM 最快跑通行人识别系统3.1 为什么老牌 HOG 仍然值得写在第一版HOG 统计图像局部梯度方向对边缘和轮廓敏感。行人在直立姿态下轮廓特征稳定所以 HOGSVM 仍是 CPU 成本最低的方案。OpenCV 的HOGDescriptor直接提供了特征提取和检测接口不需要自己实现梯度直方图。如果系统只需要在固定机位、固定视角下检测行人HOGSVM 在 1080P 图像上也能跑出可接受的实时性适合作为没有 GPU 环境时的第一版。3.2 训练分类器的骨干代码与参数用 OpenCV 训练自己的行人分类器需要两步从训练图片提取 HOG 特征再喂给 SVM。下面的代码把样本统一缩放到 64x128特征维度约 3780import cv2 import numpy as np from sklearn.svm import LinearSVC # winSize, blockSize, blockStride, cellSize, nbins hog cv2.HOGDescriptor((64, 128), (16, 16), (8, 8), (8, 8), 9) def extract_features(imgs): features [] for img in imgs: img cv2.resize(img, (64, 128)) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) features.append(hog.compute(gray).flatten()) return np.array(features, dtypenp.float32) X extract_features(pos_imgs neg_imgs) y np.array([1] * len(pos_imgs) [0] * len(neg_imgs)) # 线性 SVM特征维度高径向基核容易过拟合 svm LinearSVC(C0.01, max_iter10000) svm.fit(X, y)注意图片必须统一用cv2.resize不能直接让 HOG 拿到任意大小输入。LinearSVC的正则化参数C对结果影响很大正样本数量少时C从 0.01 降到 0.001 能减少过拟合。下面是这套 HOG 参数的实际含义改动任何一个都会影响特征维度和检测速度参数推荐值作用边界winSize(64, 128)检测窗口对应行人高宽比约 2:1blockSize(16, 16)局部归一化尺寸过大容易丢失细节blockStride(8, 8)区块滑动的重叠步长越小特征越多cellSize(8, 8)梯度直方图单元通常固定 8x8nbins9梯度方向分箱9 是经典取值3.3 滑窗与 NMS 非极大值抑制HOGSVM 检测时会在整张图上做多尺度滑窗同一个行人会被多个窗口命中最后必须用 NMS 合并。NMS 的核心逻辑是按得分排序保留得分最高的框然后删掉所有与它 IOU 超过阈值的框再取下一个。实现如下def nms(boxes, scores, iou_threshold0.4): order np.argsort(scores)[::-1] keep [] while order.size 0: i order[0] keep.append(i) xs1 np.maximum(boxes[i, 0], boxes[order[1:], 0]) ys1 np.maximum(boxes[i, 1], boxes[order[1:], 1]) xs2 np.minimum(boxes[i, 2], boxes[order[1:], 2]) ys2 np.minimum(boxes[i, 3], boxes[order[1:], 3]) w np.maximum(0, xs2 - xs1) h np.maximum(0, ys2 - ys1) inter w * h union (boxes[i, 2] - boxes[i, 0]) * (boxes[i, 3] - boxes[i, 1]) \ (boxes[order[1:], 2] - boxes[order[1:], 0]) * (boxes[order[1:], 3] - boxes[order[1:], 1]) - inter iou inter / np.maximum(union, 1e-6) order order[1 np.where(iou iou_threshold)[0]] return keep这里的iou_threshold越小保留的框越少能压住重叠误检但也会让紧挨着的两个人被误合并成一个目标。处理密集人群时我会把这个阈值放到 0.3 到 0.5 之间观察并用实际视频片段验证不要只对着单张图片调。HOGSVM 的得分严格说不是概率而是 SVM 超平面距离所以分类器阈值通常从 0 开始往正方向调比如 0.2。4. 把识别精度做到可落地PyTorch 与 YOLO 的迁移学习4.1 选型YOLO 与 Faster R-CNN 的边界行程识别系统要覆盖遮挡、拥挤、不同相机角度HOGSVM 很快会到瓶颈这时需要转到深度学习。常用方案分为两派两阶段检测器 Faster R-CNN 和一阶段的 YOLO 系列。它们不是精度和速度的简单二选一而是工程复杂度的取舍方案优点缺点适用场景Faster R-CNN小目标召回率高精度稳定推理慢部署依赖多离线视频分析YOLO 系列推理快生态完善部署资料多小目标仍需要抠细节实时视频流RT-DETR端到端免去 NMS 后处理训练成本高资料少新项目预研如果只需要识别“person”一个类别我一般直接选择轻量 YOLO 版本。原因不是它一定比 Faster R-CNN 准而是 PyTorch 生态里对 YOLO 的导出、量化、TensorRT 加速支持最成熟能少走很多工程弯路。4.2 YOLO 最小推理脚本拿到预训练权重后不需要从零开始训练直接推理即可验证效果。常见做法是用ultralytics包加载权重import cv2 from ultralytics import YOLO # yolov8s.pt 是带了 COCO 预训练权重的模型文件 model YOLO(yolov8s.pt) cap cv2.VideoCapture(test.mp4) while cap.isOpened(): ret, frame cap.read() if not ret: break # conf 控制保留哪些框iou 是 NMS 阈值 results model.predict(frame, conf0.35, iou0.45, imgsz640) boxes results[0].boxes.xyxy.cpu().numpy() scores results[0].boxes.conf.cpu().numpy() classes results[0].boxes.cls.cpu().numpy() # COCO 数据集中类别 0 对应 person person_boxes boxes[classes 0] person_scores scores[classes 0]conf0.35表示只有置信度大于 0.35 的框才输出iou0.45是 NMS 合并阈值imgsz640在保证精度的同时兼顾速度。实际部署时我会把imgsz设成 640 或 1280不建议直接用默认值而不看模型输入尺寸。如果视频里行人很小imgsz1280能显著提升召回但推理时间接近翻倍需要通过conf阈值做补偿。4.3 迁移学习的关键操作业务场景里的行人往往和 COCO 预训练分布不同比如高架摄像头俯拍。迁移学习最有效的方法是冻结主干只训练检测头from ultralytics import YOLO model YOLO(yolov8s.pt) # 冻结 backbone只训练 head 部分 results model.train( datapedestrian.yaml, epochs30, freeze10, batch16, imgsz640, lr00.001, )freeze10表示冻结模型前 10 层特征提取层保留通用特征后面的层用自定义数据微调。训练时我会先跑 10 个 epoch 观察损失曲线如果训练损失持续下降但验证损失不降说明过拟合立即停止并减小lr0到 0.0005。不要把训练直接交到默认参数手里损失值在 0.1 以下时初学者容易过拟合真正要看的是验证集 mAP 是否还在上升。5. 把基于 Python 的行人识别系统部署到业务三个必调参数与 mAP 验证5.1 导出 ONNX 与加速推理模型训练完成后第一步是导出成 ONNX避免生产环境依赖完整 PyTorch 库yolo export modelyolov8s.pt formatonnx imgsz640 halfTruehalfTrue会把权重转成半精度显存占用减半。导出后可以用 ONNX Runtime 加载在 CPU 和 GPU 上都能运行不依赖 PyTorch 版本。部署时不要直接调用模型目录里的 Python 脚本业务代码里只保留 ONNX Session 的run接口。5.2 三个必调参数conf、IoU 和帧率降采样上线后的调参与训练不同以下三个参数几乎决定业务可用性参数推荐区间调参方向conf 阈值0.25 ~ 0.5误报多就调高漏检多就调低NMS IoU 阈值0.4 ~ 0.6人群密集时调低行人稀疏时调高抽帧间隔1 ~ 5 帧按行人通过速度调节取多帧反而产生重复告警我给线上接口建议的做法是先固定 conf0.35用一段 10 分钟真实视频记录漏检与误报再反向修正。很多人会在视频里逐帧检测导致同一个行人被重复计数原因不是模型差而是没有设置抽帧间隔或者没有跟踪关联。加一个 IOU 跟踪器把相邻帧检测框的 IOU 大于 0.3 的目标视为同一行人计数才会稳定。5.3 用 mAP 和 FPS 同时判断系统健康度模型是否值得上线至少要看两个指标模型精度 mAP 和系统吞吐 FPS。mAP 的计算流程是依次枚举置信度阈值以 IOU0.5 判定正负样本画 PR 曲线取积分。不要只依赖训练日志里的 mAP那是在固定测试集上算出来的业务画面的分布可能差别很大。我通常会在推理脚本里挂一个可视化窗口按随机间隔保存检测结果到独立文件夹每天抽看一次。最后补一个很有价值的步骤把漏检片段单独抽出来重新标注加入训练集重复两到三轮。这个长尾闭环比反复调置信度阈值更能提升实际效果。本文还有配套的精品资源点击获取