6.18. 影像與 ndarray

Image 類別是處理相機原生像素的高速介面:它的每個方法都直接在影格緩衝區上以相機原生像素格式運作。numpy 則是處理其他所有工作的通用數值介面。有兩個方法在兩者之間搭起橋樑:

兩者搭配使用,可讓應用程式擷取一張影格、交給 numpy 進行自訂轉換,再將結果放回影像中以顯示、儲存,或回饋給影像函式庫的其餘部分。

6.18.1. 影像轉 ndarray

to_ndarray() 會配置一個新的 ndarray,並將影像的像素資料複製進去(依照下方的 dtype 對應方式)。它絕不會是影像影格緩衝區的檢視(view)-- numpy 陣列永遠擁有自己的位元組。其函式簽章為 to_ndarray(dtype, *, buffer=None),輸出的形狀取決於影像格式:

  • GRAYSCALE -- 二維陣列,形狀為 (height, width)

  • RGB565 -- 三維陣列,形狀為 (height, width, 3),平面依 R/G/B 順序排列。

dtype 引數控制每個 8 位元像素值 v 的對應方式:

dtype

元素

8 位元像素值 v 的對應

'B'

uint8

v(原始值)

'b'

int8

v - 128(以零為中心重新置中)

'f'

float32

float(v)(0.0 ... 255.0)

範例 -- 將灰階影格檢視為 uint8 矩陣:

import csi
from ulab import numpy as np

csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize(csi.QVGA)

img = csi0.snapshot()
a   = img.to_ndarray('B')        # shape (240, 320), dtype=uint8

print(a.shape, a.dtype)
print("mean brightness:", np.mean(a))

buffer= 關鍵字可讓應用程式重複使用已配置的 bytearray,這樣相機就不必每張影格都配置一個新的:

buf = bytearray(320 * 240)
while True:
    img = csi0.snapshot()
    a   = img.to_ndarray('B', buffer=buf)
    # ... process a ...

6.18.2. ndarray 轉影像

反向操作時,將 ndarray 作為第一個引數傳給 image.Image。建構式會配置一個新的影像緩衝區,並將陣列的值複製進去,截斷並四捨五入至 0..255:

image.Image(arr, *, buffer=None, copy_to_fb=False)

建構式會從陣列的形狀推斷幾何尺寸與像素格式:

  • 形狀 (h, w) -- GRAYSCALE 影像。

  • 形狀 (h, w, 3) -- RGB565 影像。

ndarray 的 dtype 必須為 float;目前建構式僅支援此情況。值會被四捨五入並截斷至 0..255 範圍。

buffer= 可讓應用程式為產生的影像提供已配置的 bytearraycopy_to_fb=True 會將結果寫入相機的影格緩衝區,當結果需要顯示在 IDE 預覽中時,這是正確的選擇。

6.18.3. 往返轉換

import csi
import image
from ulab import numpy as np

csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize(csi.QVGA)

img = csi0.snapshot()
a   = img.to_ndarray('f')                  # work in float space

a = 255.0 * (a / 255.0) ** 0.5             # gamma correction

out = image.Image(a, copy_to_fb=True)      # back to an image

6.18.4. 何時該使用橋接

當應用程式需要內建 image 方法未提供的通用數值運算時 -- 自訂濾鏡、自訂混合、不尋常的非線性運算 -- 或者當像素資料必須與非影像資料(IMU 軸向、音訊取樣)在單一計算中結合時,這個橋接方式就是正確的答案。

對於 Image 類別已涵蓋的高吞吐量像素處理,它並不是正確的選擇。內建方法直接在影格緩衝區上以相機原生像素格式運作,比起對等的 numpy 運算式要快得多。請只在影像函式庫尚未提供的運算上使用此橋接方式。