6.18. Slike i ndarray-evi

Klasa Image brza je površina za rad s pikselima u izvornom formatu kamere: svaka njezina metoda izravno operira na međuspremniku slike u izvornom formatu piksela kamere. numpy je generička numerička površina za sve ostalo. Dvije metode ih premošćuju:

Zajedno omogućuju aplikaciji da snimi sličicu, preda je modulu numpy za prilagođenu transformaciju, a zatim rezultat vrati natrag u sliku radi prikaza, spremanja ili povratnog prosljeđivanja ostatku biblioteke za rad sa slikama.

6.18.1. Slika u ndarray

to_ndarray() alocira novi ndarray i kopira podatke piksela slike u njega (s mapiranjem dtype-a u nastavku). Nikada nije prikaz (view) na međuspremnik slike – numpy polje uvijek posjeduje vlastite bajtove. Potpis je to_ndarray(dtype, *, buffer=None), a izlazni oblik ovisi o formatu slike:

  • GRAYSCALE – 2-D polje, oblik (height, width).

  • RGB565 – 3-D polje, oblik (height, width, 3), ravnine u redoslijedu R/G/B.

Argument dtype upravlja time kako se svaka 8-bitna vrijednost piksela v mapira:

dtype

element

mapiranje za 8-bitnu vrijednost piksela v

'B'

uint8

v (sirovo)

'b'

int8

v - 128 (ponovno centrirano oko nule)

'f'

float32

float(v) (0.0 … 255.0)

Primjer – prikaz sličice u sivim tonovima kao uint8 matrice:

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

Ključna riječ buffer= omogućuje aplikaciji da ponovno upotrijebi bytearray koji je već alocirala, pa kamera ne mora alocirati novi za svaku sličicu:

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

6.18.2. ndarray u sliku

U suprotnom smjeru, proslijedite ndarray kao prvi argument klasi image.Image. Konstruktor alocira novi međuspremnik slike i kopira vrijednosti polja u njega, ograničene i zaokružene na 0..255

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

Konstruktor zaključuje geometriju i format piksela iz oblika polja:

  • oblik (h, w) – slika GRAYSCALE.

  • oblik (h, w, 3) – slika RGB565.

ndarray mora imati dtype float; konstruktor danas podržava samo taj slučaj. Vrijednosti se zaokružuju i ograničavaju na raspon 0..255.

buffer= omogućuje aplikaciji da dostavi bytearray koji je već alocirala za rezultantnu sliku. copy_to_fb=True zapisuje rezultat u međuspremnik slike kamere, što je ispravan izbor kada se rezultat treba pojaviti u pretpregledu OpenMV IDE-a.

6.18.3. Povratni put

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. Kada premostiti

Ovaj most ispravan je odgovor kada aplikaciji treba generička numerička operacija koju ugrađene metode modula image ne pružaju – prilagođeni filtri, prilagođena miješanja, neuobičajene nelinearnosti – ili kada se podaci piksela moraju kombinirati s ne-slikovnim podacima (osi IMU-a, audio uzorci) u jednom izračunu.

Nije ispravan odgovor za obradu piksela visoke propusnosti koju klasa Image već pokriva. Ugrađene metode operiraju izravno na međuspremniku slike u izvornom formatu piksela kamere i znatno su brže od ekvivalentnog numpy izraza. Posegnite za mostom za one operacije koje biblioteka za rad sa slikama već ne pruža.