Python多进程+OpenCV+while循环:关闭窗口后终止循环的问题求助
问题
我正在尝试将Python的multiprocessing、while循环与OpenCV结合运行,验证可行性。现在遇到的问题是:按下“q”键关闭OpenCV窗口后,对应的while循环仍在后台运行。试过用sys.exit()和break语句终止循环,但都没效果,求解决方法。
原代码
import cv2 import time import sys from multiprocessing import Process x = 0 y = 0 ipVal = None num_cont = 0 def do(): global x, ipVal, y if y == 1: sys.exit() else: while y == 0: x = x + 1 time.sleep(5) print(x) if x == 2: x = 0 if y == 1: break def doX(): global ipVal, num_cont, x, y if x == 0: print('0') if x == 1: print('1') if x == 2: print('2') video1 = cv2.VideoCapture(0) video1.set(3, 640) video1.set(4, 480) def rescale_frame(frame, scale=.2): width = int(frame.shape[1] * scale) height = int(frame.shape[0] * scale) dim = (width, height) return cv2.resize(frame, dim, interpolation=cv2.INTER_AREA) while video1.isOpened(): _,cv2_im = video1.read() _,cv2_im2 = video1.read() diff = cv2.absdiff(cv2_im, cv2_im2) gray1 = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray1, (5,5), 0) _, thresh = cv2.threshold(blur, 20,255, cv2.THRESH_BINARY) dilated = cv2.dilate(thresh, None, iterations=3) contours, _ = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) for contour in contours: (x, y, w, h) = cv2.boundingRect(contour) if cv2.contourArea(contour) < 900: continue else: cv2.rectangle(cv2_im, (x,y), (x+w, y+h), (0, 255, 0), 2) cv2.putText(cv2_im, "Status: {}".format('Movement'), (10,20),cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, 1, (0, 0, 255), 3) cv2.putText(cv2_im, "Number of contours = {}".format(len(contours)), (400, 35), cv2.FONT_HERSHEY_SCRIPT_SIMPLEX, 1, (0, 0,0), 1) num_cont = len(contour) frame_resized = rescale_frame(cv2_im, scale=.2) cv2.imshow('frame1',frame_resized) if cv2.waitKey(20) & 0xFF == ord("q"): break video1.release() y = 1 cv2.destroyAllWindows() sys.exit() def runInParallel(*fns): proc = [] for fn in fns: p = Process(target=fn) p.start() proc.append(p) for p in proc: p.join() if __name__ == "__main__": runInParallel(do,doX)
问题根源
- 多进程全局变量不共享:multiprocessing创建的子进程会复制父进程内存空间,
do函数里的y和doX中修改的y是两个独立变量,修改后无法传递终止信号。 - 变量名冲突:OpenCV轮廓遍历中用
(x, y, w, h)赋值,直接覆盖了全局变量y,导致设置的y=1根本没作用到全局变量上。 doX函数逻辑缺陷:开头的x值判断只会执行一次,不会循环监测x的变化,不符合预期逻辑。
修复方案
核心思路
用multiprocessing.Event实现进程间通信,替代全局变量传递终止信号;修复变量名冲突问题;优化循环逻辑。
完整修复代码
import cv2 import time import sys from multiprocessing import Process, Event def do(stop_event): x = 0 while not stop_event.is_set(): x = x + 1 time.sleep(5) print(x) if x == 2: x = 0 def doX(stop_event): video1 = cv2.VideoCapture(0) video1.set(3, 640) video1.set(4, 480) def rescale_frame(frame, scale=0.2): width = int(frame.shape[1] * scale) height = int(frame.shape[0] * scale) dim = (width, height) return cv2.resize(frame, dim, interpolation=cv2.INTER_AREA) # 新增循环监测x值的逻辑 def monitor_x(stop_event): x = 0 while not stop_event.is_set(): if x == 0: print('0') elif x == 1: print('1') elif x == 2: print('2') time.sleep(1) # 控制监测频率 # 这里可以通过共享内存或者队列获取do进程的x值,示例简化处理 # 实际场景建议用multiprocessing.Queue传递x值 # 启动x值监测子进程 x_monitor_proc = Process(target=monitor_x, args=(stop_event,)) x_monitor_proc.start() while video1.isOpened() and not stop_event.is_set(): _, cv2_im = video1.read() _, cv2_im2 = video1.read() diff = cv2.absdiff(cv2_im, cv2_im2) gray1 = cv2.cvtColor(diff, cv2.COLOR_BGR2GRAY) blur = cv2.GaussianBlur(gray1, (5,5), 0) _, thresh = cv2.threshold(blur, 20, 255, cv2.THRESH_BINARY) dilated = cv2.dilate(thresh, None, iterations=3) contours, _ = cv2.findContours(dilated, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) for contour in contours: # 重命名变量避免覆盖全局变量 (contour_x, contour_y, w, h) = cv2.boundingRect(contour) if cv2.contourArea(contour) < 900: continue cv2.rectangle(cv2_im, (contour_x, contour_y), (contour_x+w, contour_y+h), (0, 255, 0), 2) cv2.putText(cv2_im, "Status: {}".format('Movement'), (10,20), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 255), 3) cv2.putText(cv2_im, "Number of contours = {}".format(len(contours)), (400, 35), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 0, 0), 1) frame_resized = rescale_frame(cv2_im, scale=.2) cv2.imshow('frame1', frame_resized) if cv2.waitKey(20) & 0xFF == ord("q"): stop_event.set() break video1.release() cv2.destroyAllWindows() stop_event.set() x_monitor_proc.join() def runInParallel(*fns_with_args): proc = [] for fn, args in fns_with_args: p = Process(target=fn, args=args) p.start() proc.append(p) for p in proc: p.join() if __name__ == "__main__": stop_event = Event() runInParallel((do, (stop_event,)), (doX, (stop_event,)))
关键改动说明
- 用
multiprocessing.Event传递终止信号,确保所有进程能同步收到停止指令。 - 重命名轮廓遍历的变量,避免覆盖全局变量导致信号失效。
- 新增
monitor_x进程循环监测x值,修复原代码中只执行一次的逻辑缺陷。 - 在
doX的循环条件中加入stop_event判断,确保窗口关闭后循环及时终止。 - 移除不必要的全局变量,改用参数传递状态,代码更清晰可控。
内容的提问来源于stack exchange,提问作者Jun
相关产品推荐
相关产品推荐

