如何从父进程向子进程的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工具定位窗口并发送按键:
- 先安装
xdotool:sudo apt install xdotool - 修改父脚本:
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
相关产品推荐
相关产品推荐

