6.18. Bilder och ndarrays

Klassen Image är det snabba gränssnittet för kameranativt pixelarbete: varje metod på den arbetar direkt på bildbufferten i kamerans nativa pixelformat. numpy är det generiska numeriska gränssnittet för allt annat. Två metoder överbryggar dem:

Tillsammans låter de en applikation ta en bildruta, lämna den till numpy för en anpassad transformering och sedan lägga tillbaka resultatet i en bild för att visa, spara eller mata tillbaka det till resten av bildbiblioteket.

6.18.1. Bild till ndarray

to_ndarray() allokerar en ny ndarray och kopierar bildens pixeldata till den (med dtype-mappningen nedan). Den är aldrig en vy mot bildens bildbuffert – numpy-arrayen äger alltid sina egna byte. Signaturen är to_ndarray(dtype, *, buffer=None), och utdataformen beror på bildformatet:

  • GRAYSCALE – 2D-array, form (height, width).

  • RGB565 – 3D-array, form (height, width, 3), plan i R/G/B-ordning.

Argumentet dtype styr hur varje 8-bitars pixelvärde v mappas:

dtype

element

mappning för ett 8-bitars pixelvärde v

'B'

uint8

v (rått)

'b'

int8

v - 128 (omcentrerat kring noll)

'f'

float32

float(v) (0.0 … 255.0)

Exempel – visa en gråskalebildruta som en uint8-matris:

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))

Nyckelordet buffer= låter applikationen återanvända en bytearray som den redan har allokerat, så att kameran inte behöver allokera en ny för varje bildruta:

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

6.18.2. ndarray till bild

För att gå åt andra hållet skickar du ndarray som första argument till image.Image. Konstruktorn allokerar en ny bildbuffert och kopierar arrayens värden till den, begränsade och avrundade till 0..255

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

Konstruktorn härleder geometrin och pixelformatet från arrayens form:

  • form (h, w)GRAYSCALE-bild.

  • form (h, w, 3)RGB565-bild.

ndarray måste ha dtype float; konstruktorn stöder endast det fallet idag. Värden avrundas och begränsas till intervallet 0..255.

buffer= låter applikationen tillhandahålla en bytearray som den redan har allokerat för den resulterande bilden. copy_to_fb=True skriver resultatet till kamerans bildbuffert, vilket är rätt val när resultatet ska visas i IDE-förhandsvisningen.

6.18.3. Rundtur

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. När man ska överbrygga

Denna brygga är rätt svar när applikationen behöver en generisk numerisk operation som de inbyggda image-metoderna inte tillhandahåller – anpassade filter, anpassade blandningar, ovanliga icke-lineariteter – eller när pixeldata måste kombineras med icke-bilddata (IMU-axlar, ljudsampel) i en enda beräkning.

Det är inte rätt svar för pixelbehandling med hög genomströmning som klassen Image redan täcker. De inbyggda metoderna arbetar direkt på bildbufferten i kamerans nativa pixelformat och är mycket snabbare än motsvarande numpy-uttryck. Ta till bryggan för de operationer som bildbiblioteket inte redan tillhandahåller.