[英]Multithreaded cv2.imshow() in Python does not work
我有兩個攝像頭(使用 OpenNI,我每個攝像頭有兩個流,由驅動程序 API 的同一個實例處理)並且希望有兩個線程,每個線程獨立地從每個攝像頭捕獲數據,即驅動程序 API 的一個實例,說cam_handler
,我每個相機有兩個流depth
和rgb
,比如cam_handler.RGB1_stream
和cam_handler.DEPTH1_stream
這是相同的代碼:
import threading
def capture_and_save(cam_handle, cam_id, dir_to_write, log_writer, rgb_stream,
depth_stream, io):
t = threading.currentThread()
shot_idx = 0
rgb_window = 'RGB' + str(cam_id)
depth_window = 'DEPTH' + str(cam_id)
while getattr(t, "do_run", True):
if rgb_stream is not None:
rgb_array = cam_handle.get_rgb(rgb_stream)
rgb_array_disp = cv2.cvtColor(rgb_array, cv2.COLOR_BGR2RGB)
cv2.imshow(rgb_window, rgb_array_disp)
cam_handle.save_frame('rgb', rgb_array, shot_idx, dir_to_write + str(cam_id + 1))
io.write_log(log_writer[cam_id], shot_idx, None)
if depth_stream is not None:
depth_array = cam_handle.get_depth(depth_stream)
depth_array_disp = ((depth_array / 10000.) * 255).astype(np.uint8)
cv2.imshow(depth_window, np.uint8(depth_array_disp))
cam_handle.save_frame('depth', depth_array, shot_idx, dir_to_write + str(cam_id + 1))
shot_idx = shot_idx + 1
key = cv2.waitKey(1)
if key == 27: # exit on ESC
break
print "Stopping camera %d thread..." % (cam_id + 1)
return
def main():
''' Setup camera threads '''
cam_threads = []
dir_to_write = "some/save/path"
for cam in range(cam_count):
cam = (cam + 1) % cam_count
cv2.namedWindow('RGB' + str(cam))
cv2.namedWindow('DEPTH' + str(cam))
one_thread = threading.Thread(target=capture_and_save,
name="CamThread" + str(cam + 1),
args=(cam_cap, cam, dir_to_write,
log_writer,
rgb_stream[cam], depth_stream[cam], io,))
cam_threads.append(one_thread)
one_thread.daemon = True
one_thread.start()
try:
while True:
pass
# cv2.waitKey(1)
except KeyboardInterrupt:
''' Stop everything '''
for each_thread in cam_threads:
each_thread.do_run = False
each_thread.join(1)
cam_cap.stop_rgb(rgb_stream)
cam_cap.stop_depth(depth_stream)
''' Stop and quit '''
openni2.unload()
cv2.destroyAllWindows()
if __name__ == '__main__':
main()
所以,我的問題是,如果我從代碼中刪除cv2.imshow()
行,一切都會按預期運行,並且我會將兩個相機輸出保存到文件中。 但是,使用cv2.imshow()
,只創建了“空白” windows 並且線程似乎“卡住”了,根本沒有 output。
我嘗試了幾個建議,包括將namedWindow
創建移動到主線程以及capture_and_save
線程。 我也嘗試過在waitKey()
周圍移動,因為據說 OpenCV 只允許在主線程中使用waitKey()
。 然而,沒有區別。
我通過使用mutables,將字典cam_disp = {}
傳遞給線程並讀取主線程中的值來解決了這個問題。 cv2.imshow()
在主線程中保存效果最佳,因此效果很好。 我不確定這是否是“正確”的方式,所以歡迎所有建議。
嘗試在線程目標capture_and_save
移動cv2.namedWindow('RGB' + str(cam))
cv2.imshow
函數不是線程安全的。 只是移動cv2.namedWindow
到threading.Thread
的呼叫cv2.imshow
。
import cv2
import threading
def run():
cap = cv2.VideoCapture('test.mp4')
cv2.namedWindow("preview", cv2.WINDOW_NORMAL)
while True:
ret, frame = cap.read()
if frame is None:
print("Video is over")
break
cv2.imshow('preview', frame)
cv2.waitKey(1)
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
thread = threading.Thread(target=run)
thread.start()
thread.join()
print("Bye :)")
我認為,不知道:) 但這是我最好的解釋。
當您嘗試在視圖中打開圖像時,您會將圖像從相機線程傳遞到 GUI 線程。 這樣做時,您將不同步。 有時它會起作用。 我認為你會/可能會在某個時候遇到同樣的問題。 (我做過)運行超過 1 個線程時會更明顯。 您可以做的是使用線程安全的 memory(隊列)或線程鎖。
然后,您將線程鎖放在相機保存周圍,在線程中,並在 main 中讀取 imshow ,您將是安全的。 還有 GIL 令人毛骨悚然,您還需要了解更多信息。 但最簡單的是你的情況下的線程鎖,但這一切都取決於你需要多少控制數據流和“讀取相機”的優先級或“實時”在屏幕上顯示。 @DarkSidds 的回答也是正確的。 但是,如果您有超過 1 個攝像頭並且這些攝像頭是從線程中寫入的,那么您將崩潰。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.