Python OpenCV: многопоточность с потоковым видео opecv

#python #python-3.x #multithreadin& #opencv #opencv-python

#python #python-3.x #многопоточность #opencv #opencv-python

Вопрос:

Я хотел запустить один многопоточный вместе с видеопотоком opencv. Я хочу активировать GPIO, если объект обнаруживается в течение 3 секунд, пока видео транслируется постоянно. Я пробовал использовать многопоточность (метод объединения), но видео приостанавливается во время вызова потока, потому что у него есть time.sleep(). Есть ли какой-либо способ, которым я могу постоянно транслировать видео и параллельно запускать поток? Ниже приведен код, который ведет себя таким же образом. Если я удалю соединение, то time.sleep вообще не окажет никакого эффекта.

 import threadin& 
import time
import numpy as np
import cv2

def print_hello():
    print("Hello")
    time.sleep(3)
    print ("World")

t1 = threadin&.Thread(tar&et=print_hello)  

cap = cv2.VideoCapture(0)

while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()

    # Our operations on the frame come here
    &ray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Display the resultin& frame
    cv2.imshow('frame',&ray)

    t1.start()
    t1.join()

    if cv2.waitKey(1) amp; 0xFF == ord('q'):
        break

# When everythin& done, release the capture
cap.release()
cv2.destroyAllWindows()
  

Комментарии:

1. вы должны использовать цикл .join() after, потому что .join() ожидает окончания потока и блокирует другой код. Но в вашем примере проблема в том, что while цикл может выполняться очень, очень много раз за одну секунду, поэтому он создаст очень, очень много потоков, если вам нужен только один поток, тогда запустите его перед циклом и используйте некоторую внутреннюю функцию цикла, чтобы запускать его снова и снова.

Ответ №1:

.join() ожидает окончания потока и блокирует код — поэтому он не отправляет его для запуска внутри цикла, но вы должны запустить его после цикла или в конце программы

Другая проблема заключается в .start() цикле, потому что .start() can запускает поток только один раз, поэтому многократное использование его в цикле приведет к возникновению ошибки.

Вы можете запустить поток перед циклом и запустить некоторый цикл внутри потока, чтобы запускать его постоянно.

 import threadin& 
import time
import numpy as np
import cv2

# --- functions ---

runnin& = True

def print_hello():
    while runnin&:
        print("Hello World")
        time.sleep(3)

# --- main ---

t1 = threadin&.Thread(tar&et=print_hello)  
t1.start()

# --- loop ---

cap = cv2.VideoCapture(0)

while True:
    # Capture frame-by-frame
    ret, frame = cap.read()

    # Our operations on the frame come here
    &ray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Display the resultin& frame
    cv2.imshow('frame',&ray)

    if cv2.waitKey(1) amp; 0xFF == ord('q'):
        break

# --- after loop ---

runnin& = False # to stop loop in thread
t1.join()

cap.release()
cv2.destroyAllWindows()
  

Если вам нужно запустить поток в цикле, вам также придется создать новый поток внутри цикла.

В этом примере я использую key t для запуска нового потока — без этого он создавал бы новый поток в каждом цикле, поэтому создавал бы сотни потоков за короткое время, так что это не имеет смысла.

 import threadin& 
import time
import numpy as np
import cv2

# --- functions ---

def print_hello():
    print("Hello")
    time.sleep(3)
    print("World")

# --- main ---

all_threads = []

# --- loop ---

cap = cv2.VideoCapture(0)

while True:
    # Capture frame-by-frame
    ret, frame = cap.read()

    # Our operations on the frame come here
    &ray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Display the resultin& frame
    cv2.imshow('frame',&ray)

    key = cv2.waitKey(1) amp; 0xFF
    if key == ord('q'):
        break
    if key == ord('t'):
        t = threadin&.Thread(tar&et=print_hello)  
        t.start()
        all_threads.append(t)

# --- after loop ---

for t in all_threads:
    t.join()

cap.release()
cv2.destroyAllWindows()
  

Но даже при многократном нажатии t вы можете создать множество потоков одновременно, и они будут работать вместе. Если вам это не нужно, то вам придется контролировать, работает ли threat все еще, и создавать новую только тогда, когда она больше не работает — используйте is_alive() — так это может усложнить задачу.

 import threadin& 
import time
import numpy as np
import cv2

# --- functions ---

def print_hello():
    print("Hello")
    time.sleep(3)
    print("World")

# --- main ---

t = None

# --- loop ---

cap = cv2.VideoCapture(0)

while True:
    # Capture frame-by-frame
    ret, frame = cap.read()

    # Our operations on the frame come here
    &ray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Display the resultin& frame
    cv2.imshow('frame',&ray)

    key = cv2.waitKey(1) amp; 0xFF
    if key == ord('q'):
        break

    if key == ord('t'):
        if t is None or not t.is_alive():
            t = threadin&.Thread(tar&et=print_hello)  
            t.start()
        else:
            print('previous thread is still runnin&')
            
# --- after loop ---

if t is not None:
    t.join()

cap.release()
cv2.destroyAllWindows()
  

Комментарии:

1. Спасибо! @furas, последнее решение — это то, которое я искал!

Ответ №2:

Это почти никогда не бывает хорошей идеей:

 t1.start()
t1.join()
  

Проблема в том, что это противоречит единственной цели потоков, которая заключается в том, чтобы иметь возможность выполнять две разные задачи одновременно.

Это имеет больше смысла, потому что «… some_other_thin& …()» может происходить, пока t1 выполняет все, что делает t1.

 t1.start()
do_some_other_thin&_concurrently_with_t1()
t1.join()