OpenCV实战用Python手撸一个HOG行人检测器附完整代码在计算机视觉领域行人检测一直是个经典而实用的课题。虽然深度学习已经在这个领域取得了显著成果但理解传统方法依然有其独特价值——它们计算量小、原理直观非常适合嵌入式设备和实时系统。本文将带你用Python和OpenCV从零实现一个基于HOG特征和SVM分类器的行人检测系统。1. 环境准备与数据收集首先确保你的Python环境已安装以下库pip install opencv-python numpy matplotlib scikit-learn我们将使用INRIA行人数据集作为训练样本这个经典数据集包含正样本有行人的图像和负样本无行人的图像。下载后解压到项目目录dataset/ ├── pos/ # 正样本64x128像素 └── neg/ # 负样本任意尺寸注意如果使用自定义数据集建议统一正样本尺寸为64×128像素这是HOG检测的标准输入尺寸。2. HOG特征提取原理精要HOG方向梯度直方图的核心思想可以用三个关键词概括局部梯度捕捉图像边缘和纹理信息方向统计将梯度方向量化为直方图块归一化增强对光照变化的鲁棒性具体实现时OpenCV已经为我们封装好了HOG计算器。但理解其参数对调优至关重要import cv2 hog cv2.HOGDescriptor( _winSize(64,128), # 检测窗口尺寸 _blockSize(16,16), # 块尺寸 _blockStride(8,8), # 块滑动步长 _cellSize(8,8), # 细胞单元尺寸 _nbins9 # 直方图bin数量 )提示blockStride通常设为cellSize的一半这样块之间会有重叠能提升特征质量。3. 训练SVM分类器有了HOG特征后我们需要训练一个分类器来区分行人和非行人。SVM是个不错的选择from sklearn.svm import SVC import numpy as np def extract_features(image_paths): features [] for path in image_paths: img cv2.imread(path, 0) # 灰度读取 hog_feature hog.compute(img) features.append(hog_feature.flatten()) return np.array(features) # 加载数据集 pos_samples extract_features(glob(dataset/pos/*.png)) neg_samples extract_features(glob(dataset/neg/*.png)) # 创建标签1表示行人0表示非行人 X np.vstack([pos_samples, neg_samples]) y np.hstack([np.ones(len(pos_samples)), np.zeros(len(neg_samples))]) # 训练SVM svm SVC(kernellinear, probabilityTrue) svm.fit(X, y)关键点使用线性核SVM因为HOG特征本身已经具有很好的线性可分性。4. 检测器实现与优化现在我们将训练好的模型集成到检测流程中def detect_pedestrians(image, threshold0.7): # 多尺度滑动窗口 found [] for scale in np.linspace(0.5, 1.5, 5): resized cv2.resize(image, None, fxscale, fyscale) # 滑动窗口 for y in range(0, resized.shape[0]-128, 32): for x in range(0, resized.shape[1]-64, 32): window resized[y:y128, x:x64] if window.shape[0] ! 128 or window.shape[1] ! 64: continue # 提取特征并预测 feat hog.compute(window).reshape(1,-1) prob svm.predict_proba(feat)[0][1] if prob threshold: found.append(( int(x/scale), int(y/scale), int(64/scale), int(128/scale), prob )) # 非极大值抑制 boxes [f[:4] for f in found] scores [f[4] for f in found] indices cv2.dnn.NMSBoxes(boxes, scores, threshold, 0.3) # 绘制结果 result image.copy() for i in indices: x,y,w,h boxes[i] cv2.rectangle(result, (x,y), (xw,yh), (0,255,0), 2) return result性能优化技巧使用图像金字塔处理多尺度设置合理的滑动窗口步长太大漏检太小耗时采用非极大值抑制NMS消除重叠框在GPU上使用OpenCV的DNN模块加速5. 实战测试与效果评估让我们在真实场景中测试我们的检测器test_img cv2.imread(street.jpg) result detect_pedestrians(test_img) cv2.imshow(Detection, result) cv2.waitKey(0)常见问题及解决方案问题现象可能原因解决方法误检多负样本不足增加负样本数量漏检多正样本质量差检查标注准确性检测框偏移窗口步长太大减小滑动步长速度慢图像分辨率高先下采样再检测对于更严格的评估可以使用精确率-召回率曲线from sklearn.metrics import precision_recall_curve import matplotlib.pyplot as plt probs svm.predict_proba(X_test)[:,1] precision, recall, _ precision_recall_curve(y_test, probs) plt.plot(recall, precision) plt.xlabel(Recall) plt.ylabel(Precision) plt.show()6. 进阶扩展方向虽然我们的基础检测器已经能工作但还有多种改进空间特征融合结合LBP纹理特征添加颜色直方图信息模型优化# 使用带权重的SVM处理样本不平衡 svm SVC(class_weightbalanced) # 尝试核函数组合 from sklearn.pipeline import make_pipeline from sklearn.preprocessing import StandardScaler pipe make_pipeline( StandardScaler(), SVC(kernelrbf, gammaauto) )工程优化实现异步处理流水线使用Cython加速关键代码段集成OpenCL并行计算部署方案# 保存模型供后续使用 import joblib joblib.dump(svm, hog_svm.pkl) # 在C中加载 # 使用OpenCV的FileStorage接口在实际项目中我发现将检测器与跟踪算法如KCF结合能显著提升视频处理的稳定性。另外对于监控场景背景减除预处理可以大幅减少误检。