使用mss库结合多线程时出现AttributeError问题求助
多线程图像检测中MSS库的AttributeError问题修复
错误信息
Traceback (most recent call last): File "AppData\Local\Programs\Python\Python311\Lib\threading.py", line 1038, in _bootstrap_inner self.run() File "AppData\Local\Programs\Python\Python311\Lib\threading.py", line 975, in run self._target(*self._args, **self._kwargs) File "e:\Dev\CV3\vision.py", line 19, in image_tracker img = np.asarray(self.stc.grab(coordinates)) ^^^^^^^^^^^^^^^^^^^^^^^^^^ File "E:\Dev\CV3\venv\Lib\site-packages\mss\base.py", line 90, in grab screenshot = self._grab_impl(monitor) ^^^^^^^^^^^^^^^^^^^^^^^^ File "E:\Dev\CV3\venv\Lib\site-packages\mss\windows.py", line 235, in _grab_impl srcdc, memdc = self._handles.srcdc, self._handles.memdc ^^^^^^^^^^^^^^^^^^^ AttributeError: '_thread._local' object has no attribute 'srcdc'
原始代码
vision.py
import cv2 import mss import numpy as np class Vision: stc = mss.mss() def __init__(self, mon,): self.mon = self.stc.monitors[mon] def image_tracker(self, top, left, width, height, window_name): coordinates = {'top': self.mon['top'] + top, 'left': self.mon['left'] + left, 'width': width, 'height': height} while True: img = np.asarray(self.stc.grab(coordinates)) cv2.imshow(f'{window_name}', img) if cv2.waitKey(25) & 0xFF == ord('q'): cv2.destroyAllWindows() break
main.py
from vision import Vision from threading import Thread vision = Vision(2) tensinon_line = Thread(target=vision.image_tracker, args=(1340, 870, 300, 25, 'Tension',)) counter = Thread(target=vision.image_tracker, args=(1300, 1385, 27, 20, 'Counter',)) tensinon_line.start() counter.start()
问题原因
MSS的mss()实例不是线程安全的,你将它作为类的静态成员,导致多个线程共享同一个实例。MSS内部用_thread._local存储线程相关的句柄(如srcdc),新线程中没有初始化这些句柄,因此抛出属性不存在的错误。
修复方案
让每个线程使用独立的MSS实例,避免多线程共享同一个对象。修改vision.py如下:
import cv2 import mss import numpy as np class Vision: def __init__(self, mon): # 仅在初始化时获取监视器信息,不保留全局MSS实例 with mss.mss() as stc: self.mon = stc.monitors[mon] def image_tracker(self, top, left, width, height, window_name): # 每个线程创建独立的MSS实例,用上下文管理器自动管理资源 with mss.mss() as stc: coordinates = { 'top': self.mon['top'] + top, 'left': self.mon['left'] + left, 'width': width, 'height': height } while True: img = np.asarray(stc.grab(coordinates)) cv2.imshow(window_name, img) if cv2.waitKey(25) & 0xFF == ord('q'): cv2.destroyAllWindows() break
说明
- 初始化方法中临时创建MSS实例仅用于获取监视器参数,之后立即释放
- 每个线程运行
image_tracker时,都会创建专属的MSS实例,该实例会在当前线程中初始化所需的句柄资源,彻底避免多线程冲突
内容的提问来源于stack exchange,提问作者PythonNooob
相关产品推荐
相关产品推荐

