<tbody id="86a2i"></tbody>


<dd id="86a2i"></dd>
<progress id="86a2i"><track id="86a2i"></track></progress>

<dd id="86a2i"></dd>
<em id="86a2i"><ruby id="86a2i"><u id="86a2i"></u></ruby></em>

    <dd id="86a2i"></dd>

    前言

    最近在功能性測試的過程中,需要在Python環境下用OpenCV讀取網絡攝像頭的視頻流,接著用目標檢測器進行視屏幀的后續處理。在測試過程中發現如果是單線程的情況,會出現比較嚴重的時延,如果目標檢測模型稍微大一點,像YOLOv4這類的,那么情況更加嚴重。

    后面考慮到演示效果,從單線程改為了多線程,即單獨用一個線程實時捕獲視頻幀,主線程在需要時從子線程拷貝最近的幀使用即可。通過這樣的修改,不僅時延基本消失,整個流程的實時性也有相對的提升,可以說是非常實用的技巧。

    Python多線程編程

    使用Python進行多線程編程是較為簡單的,Python的threading模塊封裝了相關的操作,通過編寫功能類繼承threading.Thread即可實現自己的邏輯。簡單的代碼示例如下所示:

    class myThread(threading.Thread):
        def __init__(self, name=None):
            super(myThread, self).__init__(name=name)
        def run(self):
            print('=> Thread %s is running ...' % self.name)
    thread = myThread()
    thread.start()
    thread.join()

    上面的代碼簡單展示了如何使用線程類:通過調用start()方法,線程實例開始在單獨的線程上下文中運行自己的run()函數處理任務,直到線程退出。在此期間,主線程可以繼續執行任務。當主線程任務執行結束時,主線程可通過設置全局狀態變量告知子線程退出,同時調用join()方法等待子線程運行結束。

    OpenCV視屏流的多線程處理

    在上面例子的基礎上,可對簡單的單線程處理流程進行優化,即將讀取視頻幀的部分單獨放在一個線程執行,同時提供線程間同步、數據交互的支持,在主線程中運行目標檢測模型和后續處理流程,在需要時從讀取視頻幀的子線程獲取最近的幀進行預處理、推理、后處理和可視化等操作。相關的示例代碼如下:

    import numpy as np
    import cv2
    import threading
    from copy import deepcopy
    thread_lock = threading.Lock()
    thread_exit = False
    class myThread(threading.Thread):
        def __init__(self, camera_id, img_height, img_width):
            super(myThread, self).__init__()
            self.camera_id = camera_id
            self.img_height = img_height
            self.img_width = img_width
            self.frame = np.zeros((img_height, img_width, 3), dtype=np.uint8)
        def get_frame(self):
            return deepcopy(self.frame)
        def run(self):
            global thread_exit
            cap = cv2.VideoCapture(self.camera_id)
            while not thread_exit:
                ret, frame = cap.read()
                if ret:
                    frame = cv2.resize(frame, (self.img_width, self.img_height))
                    thread_lock.acquire()
                    self.frame = frame
                    thread_lock.release()
                else:
                    thread_exit = True
            cap.release()
    def main():
        global thread_exit
        camera_id = 0
        img_height = 480
        img_width = 640
        thread = myThread(camera_id, img_height, img_width)
        thread.start()
        while not thread_exit:
            thread_lock.acquire()
            frame = thread.get_frame()
            thread_lock.release()
            cv2.imshow('Video', frame)
            if cv2.waitKey(1) & 0xFF == ord('q'):
                thread_exit = True
        thread.join()
    if __name__ == "__main__":
        main()

    在上面的代碼中,為確保資源訪問不受沖突,使用threading.Lock進行保護;主線程使用thread_exit全局狀態變量控制子線程的運行狀態。稍微特別一點的是,thread_exit實際上控制著兩個線程的運行狀態,因為在上述的處理流程中,兩個線程都擁有終止運行流程的話語權,故這樣的處理是合理的。

    結語

    實際上使用多線程并行處理任務,最大程度地利用資源早已是老生常談的技巧,例如在服務器端,會開辟有專門的線程池用于處理隨時可能到來的請求,而在嵌入式通信終端上,也通常采用線程池的方式來處理收到的消息包,以盡可能提升實時性。雖然多線程的處理方式相較單線程而言要稍微復雜一些,但帶來的性能提升確是實打實的,所以還是很值得一試。

    原文地址:https://blog.csdn.net/hlld__/article/details/110087110

    相關文章:

    免费一级a片在线播放视频|亚洲娇小性XXXX色|曰本无码毛片道毛片视频清|亚洲一级a片视频免费观看
    <tbody id="86a2i"></tbody>

    
    
    <dd id="86a2i"></dd>
    <progress id="86a2i"><track id="86a2i"></track></progress>

    <dd id="86a2i"></dd>
    <em id="86a2i"><ruby id="86a2i"><u id="86a2i"></u></ruby></em>

      <dd id="86a2i"></dd>