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

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)

问题根源

  1. 多进程全局变量不共享:multiprocessing创建的子进程会复制父进程内存空间,do函数里的y和doX中修改的y是两个独立变量,修改后无法传递终止信号。
  2. 变量名冲突:OpenCV轮廓遍历中用(x, y, w, h)赋值,直接覆盖了全局变量y,导致设置的y=1根本没作用到全局变量上。
  3. 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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 11:54:24