執行緒與並行處理#
此視覺化示意圖說明了 Python 應用程式中影像擷取的運作方式。
- 影像擷取是在 pylon內的原生(C++)執行緒中執行的。
- 您的 Python 程式碼會從緩衝區佇列中擷取圖片。
- 這種分離使異步擷取成為可能。
在許多應用中,影像擷取的速度比處理速度更快:
若無並行處理:
- 緩衝區已滿。
- 發生掉幀。
- 延遲增加。
基本執行模型#
單執行緒方式是影像擷取流程中最簡單的形式。
範例:
while camera.IsGrabbing():
with camera.RetrieveResult(5000) as grab_result:
if grab_result.GrabSucceeded():
image = grab_result.Array
process(image)
這有以下缺點:
- 處理區塊的取得。
- CPU 使用率偏低
- 可擴充性有限
生產者–消費者模式(建議)#
這是一種更為精細的影像擷取流程。
- 製作人:擷取執行緒會擷取影像並將其推入佇列中。
- 使用者:工作執行緒會獨立處理影像。
使用自訂執行緒的實作範例#
資訊
您可以使用 InstantCamera 提供的抓取迴圈執行緒(請參閱grab_using_grab_loop_thread範例)。這是僅供示範用途的自訂實作。
import threading
import queue
from pypylon import pylon
def process(image):
print(image.shape)
image_queue = queue.Queue(maxsize=10)
# Producer thread
def grab_loop(camera):
while camera.IsGrabbing():
with camera.RetrieveResult(5000) as grab_result:
if grab_result.GrabSucceeded():
image = grab_result.Array
image_queue.put(image)
# Consumer thread
def process_loop():
while True:
image = image_queue.get()
process(image)
image_queue.task_done()
with pylon.InstantCamera(pylon.FirstFound) as camera:
camera.StartGrabbing()
grab_thread = threading.Thread(target=grab_loop, args=(camera,))
processing_thread = threading.Thread(target=process_loop)
grab_thread.start()
processing_thread.start()
grab_thread.join()
image_queue.join()
佇列行為與背壓#
策略:
- 增加佇列大小。
- 手動刪除幀。
- 使用
LatestImageOnly.
與 Grab 策略相結合#
LatestImageOnly: 減少積壓工作。OneByOne: 確保完整性。
最佳實踐:
關於執行緒安全性的考量#
- 請避免在未加鎖的情況下共用可變資料。
- 在將影像傳遞給其他執行緒之前,請先複製這些影像,例如透過使用
Array函數。 - 使用
queue.Queue以確保通訊安全。
CPU 使用率#
並行處理具有以下優點:
- 更佳的 CPU 使用率
- 關注點的分離
- 可擴展的架構
何時該使用多執行緒#
在以下情況下應使用多執行緒:
- 處理速度比擷取速度慢。
- 存在多個處理階段。
- 必須具備即時回應能力。
請避免在以下情況下進行線程操作:
- 處理過程可忽略不計。
- 系統的複雜度必須盡量降低。
進階模式(概述)#
多階段管線#
多階段管線將影像處理分割為獨立的步驟,這些步驟會並行執行,並透過佇列交換資料。
多使用者設定#
概念管道#
重點摘要#
- 資料擷取與處理應予以分離。
- 採用生產者-消費者模式以提升可擴展性。
- 佇列可提供線程安全的通訊機制。
- 多執行緒可提升效能,但會增加複雜性。