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

如何从父进程向子进程的OpenCV waitKey发送交互信号?

问题

我想通过Python的subprocess.Popen()和subprocess.Popen.send_signal(),从父脚本向作为子进程运行的另一个脚本发送字符输入。子进程通过cv2.waitKey(x) == ord('y')判断何时执行特定操作。

我知道OpenCV的waitKey并不监听控制台输入,那该怎么和它交互?有没有更好的方式向子进程的OpenCV窗口发送信号?

补充:子进程不需要和父进程通信,父进程只需向子进程的waitKey()发送信号就行。直接终止子进程会导致它在完成预期操作前退出。

我的首次尝试(预计会失败)代码如下:

path_to_python_env = "/home/user1/virtual-env/bin/python3"
path_to_script = "/home/user1/scripts/myScript.py"

while True:
    inputValue = input("enter value: ")

    if inputValue == "start":
        p = subprocess.Popen([path_to_python_env, path_to_script])
    elif inputValue == "function-y":
        p.send_signal('y')
# 假设用户会先输入"start"再输入"function-y"

子进程脚本代码:

import cv2
while True:
    img = cv2.imread("image1.png")
    cv2.imshow("picture", img)
    if cv2.waitKey(10) == ord('y'):
        break
print("some string")
cv2.destroyAllWindows()

解决方案

方法1:模拟键盘按键发送到OpenCV窗口

cv2.waitKey()监听的是窗口的键盘事件而非标准输入,因此可以通过模拟向目标OpenCV窗口发送键盘事件实现触发。

Linux环境(X11)

借助xdotool工具定位窗口并发送按键:

  1. 先安装xdotool:sudo apt install xdotool
  2. 修改父脚本:
import subprocess
import time

path_to_python_env = "/home/user1/virtual-env/bin/python3"
path_to_script = "/home/user1/scripts/myScript.py"
p = None

while True:
    inputValue = input("enter value: ")

    if inputValue == "start":
        p = subprocess.Popen([path_to_python_env, path_to_script])
        # 给窗口启动留缓冲时间
        time.sleep(1)
    elif inputValue == "function-y":
        # 找到标题为"picture"的OpenCV窗口并发送'y'按键
        subprocess.run(["xdotool", "search", "--name", "picture", "key", "y"])

Windows环境

使用pyautogui库模拟按键,需先激活目标窗口:

import subprocess
import time
import pyautogui

path_to_python_env = "C:/path/to/python.exe"
path_to_script = "C:/path/to/myScript.py"
p = None

while True:
    inputValue = input("enter value: ")

    if inputValue == "start":
        p = subprocess.Popen([path_to_python_env, path_to_script])
        time.sleep(1)
        # 激活标题为"picture"的OpenCV窗口
        pyautogui.getWindowsWithTitle("picture")[0].activate()
    elif inputValue == "function-y":
        pyautogui.press('y')

方法2:修改子进程逻辑,用文件作为触发信号

如果不想依赖窗口模拟,可以让子进程同时监听waitKey()和一个临时文件的存在状态:

子进程修改后代码:

import cv2
import os

# 定义信号文件路径
signal_file = "/tmp/opencv_trigger.txt"

# 启动前清理残留的信号文件
if os.path.exists(signal_file):
    os.remove(signal_file)

while True:
    img = cv2.imread("image1.png")
    cv2.imshow("picture", img)
    
    # 原有的waitKey检测
    if cv2.waitKey(10) == ord('y'):
        break
    
    # 检测信号文件是否存在
    if os.path.exists(signal_file):
        print("收到外部触发信号,退出循环")
        os.remove(signal_file)
        break

print("some string")
cv2.destroyAllWindows()

父脚本修改为通过创建信号文件触发:

import subprocess
import time
import os

path_to_python_env = "/home/user1/virtual-env/bin/python3"
path_to_script = "/home/user1/scripts/myScript.py"
signal_file = "/tmp/opencv_trigger.txt"
p = None

while True:
    inputValue = input("enter value: ")

    if inputValue == "start":
        # 清理残留信号文件
        if os.path.exists(signal_file):
            os.remove(signal_file)
        p = subprocess.Popen([path_to_python_env, path_to_script])
        time.sleep(1)
    elif inputValue == "function-y":
        # 创建信号文件触发子进程
        with open(signal_file, 'w') as f:
            f.write("trigger")

方法3:使用进程间通信管道

父进程与子进程建立标准输入管道,子进程定期检查管道内容:

父脚本:

import subprocess
import time

path_to_python_env = "/home/user1/virtual-env/bin/python3"
path_to_script = "/home/user1/scripts/myScript.py"
p = None

while True:
    inputValue = input("enter value: ")

    if inputValue == "start":
        # 创建带管道的子进程
        p = subprocess.Popen(
            [path_to_python_env, path_to_script],
            stdin=subprocess.PIPE,
            text=True
        )
        time.sleep(1)
    elif inputValue == "function-y":
        # 向管道写入触发字符
        p.stdin.write('y\n')
        p.stdin.flush()

子进程修改后:

import cv2
import sys

while True:
    img = cv2.imread("image1.png")
    cv2.imshow("picture", img)
    
    # 原有的waitKey检测
    if cv2.waitKey(10) == ord('y'):
        break
    
    # 检查父进程通过管道发送的内容
    line = sys.stdin.readline()
    if line.strip() == 'y':
        print("收到父进程信号,退出循环")
        break

print("some string")
cv2.destroyAllWindows()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 10:17:51