You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于OpenCV与Python的移动物体检测代码故障排查求助

移动物体检测代码排查问题

问题背景

我找到两篇关于移动物体检测的相关文章,参照实现了移动物体检测代码(含背景帧生成逻辑)。代码可运行,但输出视频无内容(仅1KB),测试发现循环仅执行一次,print(ret)和print(frame.shape)仅输出一次True和(360, 640, 3),print(frame_diff_list)也仅输出一次,请求排查问题。

主代码

import cv2
import numpy as np
import matplotlib.pyplot as plt
from Background_Image_Creation import get_background

cap = cv2.VideoCapture("video_1.mp4")
# print(cap.get(cv2.CAP_PROP_FRAME_COUNT))
# print(cap.get(cv2.CAP_PROP_FPS))

frame_width = int(cap.get(3))
frame_height = int(cap.get(4))
save_name = "Result.mp4"
# define codec and create VideoWriter object
out = cv2.VideoWriter(save_name, cv2.VideoWriter_fourcc(*'mp4v'), 10, (frame_width, frame_height))

background_frame = get_background("video_1.mp4")
background = cv2.cvtColor(background_frame, cv2.COLOR_BGR2GRAY)
print(background.shape)

frame_count = 0
consecutive_frame = 8
# frame_diff_list =[]

while cap.isOpened():
    ret, frame = cap.read()
    print(ret)
    print(frame.shape)
    if ret == True:
        frame_count += 1
        orig_frame = frame.copy()
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        
        if frame_count % consecutive_frame == 0 or frame_count == 1:
            frame_diff_list = []
        
        frame_diff = cv2.absdiff(gray, background)
        ret, thresh = cv2.threshold(frame_diff, 50, 255, cv2.THRESH_BINARY)
        dilate_frame = cv2.dilate(thresh, None, iterations=2)
        frame_diff_list.append(dilate_frame)
        print(frame_diff_list)
        
        if len(frame_diff_list) == consecutive_frame:
            # add all the frames in the `frame_diff_list`
            sum_frames = sum(frame_diff_list)
            print(sum_frames)
            # find the contours around the white segmented areas
            contours, hierarchy = cv2.findContours(sum_frames, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
            # draw the contours, not strictly necessary
            for i, cnt in enumerate(contours):
                cv2.drawContours(frame, contours, i, (0, 0, 255), 3)
            for contour in contours:
                # continue through the loop if contour area is less than 500...
                # ... helps in removing noise detection
                if cv2.contourArea(contour) < 500:
                    continue
                # get the xmin, ymin, width, and height coordinates from the contours
                (x, y, w, h) = cv2.boundingRect(contour)
                # draw the bounding boxes
                cv2.rectangle(orig_frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

            cv2.imshow('Detected Objects', orig_frame)
            out.write(orig_frame)
            if cv2.waitKey(100) & 0xFF == ord('q'):
                break
        else:
            break

cap.release()
cv2.destroyAllWindows()

背景帧生成代码

import numpy as np
import cv2
import matplotlib.pyplot as plt

def get_background(path):
    cap = cv2.VideoCapture(path)
    frame_indices = cap.get(cv2.CAP_PROP_FRAME_COUNT) * np.random.uniform(size=50)
    frames = []
    for idx in frame_indices:
        cap.set(cv2.CAP_PROP_POS_FRAMES, idx)
        ret, frame = cap.read()
        frames.append(frame)
    median_frame = np.median(frames, axis=0).astype(np.uint8)
    return median_frame

# median_frame = get_background("video_1.mp4")
# cv2.imshow("Median_Background", median_frame)
# cv2.waitKey(0)
# cv2.destroyAllWindows()
# plt.show()

问题排查与修复

核心问题

循环仅执行一次的根源是**else: break**语句:当len(frame_diff_list) != consecutive_frame时,直接触发break终止循环。第一次循环时frame_count=1,frame_diff_list长度为1,不等于consecutive_frame=8,因此执行break,循环直接结束。

修复步骤

  1. 移除错误的else: break:删除主循环中的else: break,让循环持续读取视频帧,直到视频读取完毕或用户按下q键退出。
  2. 提前初始化frame_diff_list:在循环外定义frame_diff_list = [],避免未定义的潜在报错。
  3. 增强背景帧生成鲁棒性:在get_background函数中添加ret判断,仅将有效帧加入列表:
    for idx in frame_indices:
        cap.set(cv2.CAP_PROP_POS_FRAMES, idx)
        ret, frame = cap.read()
        if ret:  # 仅添加成功读取的帧
            frames.append(frame)
    
  4. 调整循环退出逻辑:在循环开头判断ret,若为False直接退出,确保视频读取完毕时正常终止。

修复后主循环示例

frame_count = 0
consecutive_frame = 8
frame_diff_list = []  # 提前初始化

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break  # 视频读取完毕,退出循环
    
    frame_count += 1
    orig_frame = frame.copy()
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    
    if frame_count % consecutive_frame == 0 or frame_count == 1:
        frame_diff_list = []
    
    frame_diff = cv2.absdiff(gray, background)
    ret, thresh = cv2.threshold(frame_diff, 50, 255, cv2.THRESH_BINARY)
    dilate_frame = cv2.dilate(thresh, None, iterations=2)
    frame_diff_list.append(dilate_frame)
    
    if len(frame_diff_list) == consecutive_frame:
        sum_frames = sum(frame_diff_list)
        contours, hierarchy = cv2.findContours(sum_frames, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
        
        for contour in contours:
            if cv2.contourArea(contour) < 500:
                continue
            (x, y, w, h) = cv2.boundingRect(contour)
            cv2.rectangle(orig_frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
        
        cv2.imshow('Detected Objects', orig_frame)
        out.write(orig_frame)
    
    if cv2.waitKey(10) & 0xFF == ord('q'):
        break

内容的提问来源于stack exchange,提问作者AI researcher

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 13:15:24