SingleTrack_Project(四)传统视觉追踪方法——帧差法 一、基本原理帧差法是运动检测中最简单、最直观的方法之一其核心思想是相邻帧相减差值即为运动区域。简单来说就是连续的两个帧图像之间背景区域基本不变而运动目标区域的像素值会发生明显变化因此将当前帧与前一帧像素相减取绝对值得到”差分图像“差分图像中值大的像素点就属于运动目标。从基本原理中也可以看出对于帧差法来说更适合目标运动明显、背景相对静止的场景。二、关键步骤1.灰度化去噪将色彩帧转化为灰度图再用高斯滤波消除噪声。2.帧差计算用前一帧减去后一帧得到差分图。3.二值化阈值对差分图做阈值处理大于阈值的像素视为前景小于阈值的视为背景。4.形态学处理开运算去除噪点闭运算填补空洞。5.轮廓提取从二值图中寻找联通区域作为候选目标。6.候选筛选通过面积、宽高比、位置距离等条件筛选出最可能的目标。优点计算极快实时性好实现简单无需训练对光照条件有一定的鲁棒性。缺点只能检测运动目标的边缘轮廓对目标运动速度过于敏感对于静止目标接近失效需要连续帧进行分析处理。三、代码实现1.帧差计算gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) gray cv2.GaussianBlur(gray, (5, 5), 0) diff cv2.absdiff(self.prev_frame, gray) _, diff cv2.threshold(diff, 20, 255, cv2.THRESH_BINARY)将当前帧同样转为灰度并高斯滤波然后与上一帧做减法。阈值为20经验值大于20的像素变为255前景其余为0背景。阈值的选取直接影响检测灵敏度太小则噪声多太大则弱运动被忽略。2.形态学处理kernel np.ones((3, 3), np.uint8) diff cv2.morphologyEx(diff, cv2.MORPH_OPEN, kernel) # 开运算 diff cv2.morphologyEx(diff, cv2.MORPH_CLOSE, kernel) # 闭运算开运算先腐蚀后膨胀去除孤立噪点。闭运算先膨胀后腐蚀填补目标区域内部细小空洞。3.ROI区域约束x, y, w, h self.prev_bbox margin int(max(w, h) * 1.0) x1 max(0, x - margin) y1 max(0, y - margin) x2 min(frame.shape[1], x w margin) y2 min(frame.shape[0], y h margin) roi_diff np.zeros_like(diff) roi_diff[y1:y2, x1:x2] diff[y1:y2, x1:x2]以上一帧目标框为中心向外扩展一个 margin大小等于目标框的长边裁剪出一个ROI区域。不在ROI内的差分像素全部置0。这种做法基于运动目标在相邻帧间位移不会太大的假设有效减少背景中其他运动的干扰。4.候选框评估def _motion_bbox(self, diff, frame_shape): contours, _ cv2.findContours(diff, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) best None best_score -1 prev_center self._center(self.prev_bbox) for c in contours: x, y, w, h cv2.boundingRect(c) area w * h # 筛选条件1面积在目标面积的0.1倍到5倍之间 if area self.target_area * 0.1 or area self.target_area * 5: continue # 筛选条件2宽高比变化不超过2 aspect w / (h 1e-6) if abs(aspect - self.target_aspect) 2: continue # 筛选条件3位移不超过目标最大尺寸的2倍 center self._center((x, y, w, h)) dist np.linalg.norm(center - prev_center) max_dim max(self.prev_bbox[2], self.prev_bbox[3]) if dist max_dim * 2: continue # 综合评分距离权重0.5 面积权重0.3 宽高比权重0.2 distance_score 1.0 / (1.0 dist / max_dim) area_score min(area / self.target_area, self.target_area / area) aspect_score 1.0 / (1.0 abs(aspect - self.target_aspect)) score 0.5 * distance_score 0.3 * area_score 0.2 * aspect_score if score best_score: best_score score best (x, y, w, h) return best三个筛选条件一是面积约束排除过大/过小的噪声区域二是宽高比约束保持目标的形状一致性三是位移约束限制搜索范围防止跳变。综合评分函数用加权和的方式将距离、面积相似度、宽高比相似度归一化到 [0,1] 区间。权重分配距离最重要0.5因为运动目标在帧间通常是连续平缓移动的。5.状态更新if cand is None: self.lost_count 1 cand self.prev_bbox # 跟丢时保持上一帧位置 else: self.lost_count 0 self.prev_bbox cand self.prev_frame gray # 更新为下一帧差做准备 self.trajectory.append(self.prev_bbox) return self.prev_bbox当找不到合适候选框时lost_count 递增当前位置保持不动prev_bbox不变。找到候选则重置丢失计数并更新 prev_bbox。最后将当前灰度图保存为 prev_frame 供下一帧使用。四、整体流程第一帧frame → 灰度化 高斯滤波 → 保存为 prev_frame标注框 → 提取area、aspect → 保存为 prev_bbox。后续帧当前帧 → 灰度化 高斯滤波 → gray帧差diff |gray - prev_frame|二值化阈值20形态学开运算 闭运算ROI裁剪以上一帧框为中心找轮廓 → 候选筛选面积/宽高比/位移评分排序 → 选出最优框跟丢处理或不跟丢prev_frame gray, prev_bbox cand返回 (x, y, w, h)。五、局限性1.空洞问题:帧差法只会检测到目标前后两帧位置变化的区域目标重叠部分会被抵消,所以找到的轮廓可能是目标边缘的两块区域而非完整目标.2.目标静止则丢失:当目标停止运动时两帧之间无差异,没有任何轮廓极易造成目标丢失。3.单一阈值阈值 20 是硬编码经验值在不同光照、不同对比度场景下不一定最优。4.缺乏尺度自适应:目标靠近/远离摄像机时面积会变化代码虽然允许面积在 0.1~5 倍范围,但是没有在线更新机制。