跳至內容
測試伺服器
開發伺服器

處理影像#

本主題說明圖像資料如何在 pypylon 中表示、如何安全地存取它,以及如何為進一步處理(例如使用 NumPy、OpenCV 或 AI 框架)做好準備。

圖像表示#

在 pypylon 中,圖像會以例如 NumPy arrays 的形式公開,這意味著它們可以直接用於科學和機器視覺工作流程中。

這是一個典型的工作流程:

Camera → GrabResult → Buffer → NumPy Array

存取圖像資料#

必須清楚了解何時該複製擷取結果中的資料,何時不該複製。複製過多會浪費時間,而複製過少則可能導致系統當機或像素資料錯誤。

程式碼 描述 是否需要複製?
.Array 傳回 NumPy 複本 否(已經是複本)
.GetMemoryView() 傳回緩衝區檢視 是
.GetArrayZeroCopy() 傳回零複製陣列 是
  • grab_result.Array 是內部緩衝區的複本。
  • grab_result.GetMemoryView() 是一個 檢視內部緩衝區 (像素類型除外,其中 pylon.IsPacked(grab_result.PixelType) 為 True)。
  • grab_result.GetArrayZeroCopy() 是一個 檢視內部緩衝區 提供無需複製的 NumPy 陣列(以下像素類型除外: pylon.IsPacked(grab_result.PixelType) 為 True)。
  • 抓取結果緩衝區會在離開 with 區塊或 grab_result.Release() 為止。
  • 在緩衝區釋放後存取 Memory 檢視或 zero-copy 陣列可能會導致無效的 Memory 存取。

正確用法:

with camera.RetrieveResult(5000) as grab_result:
    if grab_result.GrabSucceeded():
        image = grab_result.Array

圖像形狀與格式#

陣列的形狀取決於 Pixel Format:

Pixel Format 形狀範例
Mono8 (高度、寬度)
RGB8/BGR8 (高度、寬度、3)

您可以直接檢查形狀:

print(image.shape)

Pixel Format Conversion#

根據相機組態,原始影像格式可能不適用,且可能需要進行轉換。

範例:轉換為 BGR(相容於 OpenCV)

converter = pylon.ImageFormatConverter()
converter.OutputPixelFormat = pylon.PixelType_BGR8packed

image = converter.Convert(grab_result).GetArray()

資訊

在 ImageFormatConverter, OutputPixelFormat 是用於保存像素類型值的簡單屬性,而非 Property 節點。請直接指派(converter.OutputPixelFormat = pylon.PixelType_BGR8packed)。它沒有 .Value 存取子。

直接轉換為 NumPy 陣列(ConvertToArray)#

converter.Convert(src) 會傳回 PylonImage。使用 .Array (或針對 32 位元應用程式的 .GetArray()讀取其像素)會對已轉換的緩衝區進行 額外的複製 。如果您只需要將結果作為 NumPy 陣列,請改用 converter.ConvertToArray(src) 。這會預先配置一個具有正確形狀和資料類型的 NumPy 陣列,並讓轉換器將轉換後的像素 直接寫入該陣列中。,從而避免了額外複製。

converter = pylon.ImageFormatConverter()
converter.OutputPixelFormat = pylon.PixelType_BGR8packed

# Equivalent result to converter.Convert(grab_result).Array, but without the extra copy.
image = converter.ConvertToArray(grab_result)

ConvertToArray 接受與以下相同的來源類型: Convert (一個抓取結果、一個 PylonImage、一個資料元件,或任何 IImage),且產生的陣列形狀與資料類型反映了 OutputPixelFormat:

  • PixelType_Mono8 → (height, width), uint8
  • PixelType_Mono16 → (height, width), uint16
  • PixelType_RGB8packed / PixelType_BGR8packed → (height, width, 3), uint8

位元封包輸出格式(其中 pylon.IsPacked(pixel_type) 為 True)沒有明確的 NumPy 形狀/資料類型,因此 ConvertToArray 預設會對其引發 ValueError 。請傳遞 raw=True 以改為取得轉換後的位元組作為一維 uint8 陣列:

# raw=True returns a flat uint8 array of the converted bytes,
# which is also how to handle bit-packed output formats.
raw_bytes = converter.ConvertToArray(grab_result, raw=True)
方法 結果 額外複製?
converter.Convert(src).Array 透過中介產生的 NumPy 陣列 PylonImage 是
converter.ConvertToArray(src) 就地寫入的 NumPy 陣列 否
converter.ConvertToArray(src, raw=True) 一維 uint8 陣列(也適用於封包格式) 否

為什麼需要轉換#

  • 相機通常會輸出原始格式或 Bayer 格式。
  • 應用程式通常預期:
    • BGR (OpenCV)
    • RGB (視覺化)

常見陷阱#

在釋放緩衝區後使用資料#

with camera.RetrieveResult(...) as grab_result:
    image = grab_result.Array # NumPy array
    memory_view = grab_result.GetMemoryView()
    with grab_result.GetArrayZeroCopy() as zero_copy_array:
        ... process zero_copy_array (NumPy array) ...

這是不安全的,因為 memory_view 現在可能會參照無效的 Memory。如果在區塊外部需要,請務必使用 result.Array ,或者保持 grab_result 處於啟用狀態。

忽略 Pixel Format#

請務必驗證或明確設定 Pixel Format。忽略此操作可能會導致以下後果:

  • 顏色解析錯誤
  • 處理結果不正確

效能開銷#

以下操作可能會降低效能:

  • 複製大型圖像需要花費時間
  • 轉換會增加 CPU 負載

避免此情況的策略:

在處理管線中使用圖像#

由於圖像為 NumPy 陣列,因此可以直接與 OpenCV、NumPy Operations 以及 AI/ML Frameworks 搭配使用。

這是圖像處理管線的通用圖解。

Camera → GrabResult → NumPy Array → Processing → Output

統計評估:

OpenCV#

import cv2

cv2.imshow("image", image)
cv2.waitKey(1)

NumPy 操作#

mean = image.mean()

AI/ML 框架#

  • PyTorch
  • TensorFlow

使用 NumPy 的範例圖像處理管線#

NumPy 能夠直接對擷取的圖像進行快速的向量化圖像處理。

以下範例是一個小型但切實可行的 NumPy 圖像處理管線。

範例程式碼#

import numpy as np
from pypylon import pylon

with pylon.InstantCamera(pylon.FirstFound) as camera:

    camera.StartGrabbingMax(100)

    while camera.IsGrabbing():
        with camera.RetrieveResult(5000) as grab_result:
            if grab_result.GrabSucceeded():
                image = grab_result.Array

                # Do something with the image data.

                if image.ndim == 3:
                    gray = image.mean(axis=2)
                else:
                    gray = image

                norm = gray / 255.0

                binary = norm > 0.5

                mean_intensity = norm.mean()
                bright_pixel_ratio = binary.mean()

                print(f"Mean intensity: {mean_intensity:.3f}")
                print(f"Bright pixels: {bright_pixel_ratio*100:.1f}%")

以下是各個步驟的說明:

  • 轉為灰階:

    gray = image.mean(axis=2)
    
  • 正規化:

    norm = gray / 255.0
    
  • 閾值處理:

    binary = norm > 0.5
    
  • 統計評估:

    mean_intensity = norm.mean()
    bright_pixel_ratio = binary.mean()
    

通用的 NumPy 圖像管線如下所示:

Raw Image → NumPy Array → Processing → Features → Decision

重點整理#

  • 圖像會以 NumPy 陣列的形式提供。
  • 需要在必要時複製緩衝區資料。
  • 確保您使用的是正確的 Pixel Format。
  • 後續處理可能需要進行轉換。