基于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,循环直接结束。
修复步骤
- 移除错误的
else: break:删除主循环中的else: break,让循环持续读取视频帧,直到视频读取完毕或用户按下q键退出。 - 提前初始化
frame_diff_list:在循环外定义frame_diff_list = [],避免未定义的潜在报错。 - 增强背景帧生成鲁棒性:在
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) - 调整循环退出逻辑:在循环开头判断
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
相关产品推荐
相关产品推荐

