6.18. Obrazy a ndarray

Třída Image je rychlé rozhraní pro práci s pixely v nativním formátu kamery: každá její metoda pracuje přímo se snímkovým bufferem (frame buffer) v nativním pixelovém formátu kamery. numpy je obecné numerické rozhraní pro vše ostatní. Propojují je dvě metody:

Společně umožňují aplikaci pořídit snímek, předat jej modulu numpy pro vlastní transformaci a poté výsledek vložit zpět do obrazu pro zobrazení, uložení nebo zpětné předání do zbytku obrazové knihovny.

6.18.1. Z obrazu na ndarray

to_ndarray() alokuje nový ndarray a zkopíruje do něj pixelová data obrazu (s mapováním dtype uvedeným níže). Nikdy se nejedná o pohled (view) na snímkový buffer (frame buffer) obrazu – pole numpy vždy vlastní své vlastní bajty. Signatura je to_ndarray(dtype, *, buffer=None) a tvar výstupu závisí na formátu obrazu:

  • GRAYSCALE – 2D pole, tvar (height, width).

  • RGB565 – 3D pole, tvar (height, width, 3), roviny v pořadí R/G/B.

Argument dtype řídí, jak je mapována každá 8bitová hodnota pixelu v:

dtype

prvek

mapování 8bitové hodnoty pixelu v

'B'

uint8

v (surová hodnota)

'b'

int8

v - 128 (znovu vystředěno kolem nuly)

'f'

float32

float(v) (0.0 … 255.0)

Příklad – zobrazení snímku ve stupních šedi jako matice 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))

Klíčové slovo buffer= umožňuje aplikaci znovu použít bytearray, který už alokovala, takže kamera nemusí alokovat nový pro každý snímek:

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

6.18.2. Z ndarray na obraz

Opačným směrem předejte ndarray jako první argument třídě image.Image. Konstruktor alokuje nový obrazový buffer a zkopíruje do něj hodnoty pole, oříznuté a zaokrouhlené do rozsahu 0..255

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

Konstruktor odvodí geometrii a pixelový formát z tvaru pole:

  • tvar (h, w) – obraz GRAYSCALE.

  • tvar (h, w, 3) – obraz RGB565.

ndarray musí mít dtype float; konstruktor dnes podporuje pouze tento případ. Hodnoty jsou zaokrouhleny a oříznuty do rozsahu 0..255.

buffer= umožňuje aplikaci dodat bytearray, který už alokovala pro výsledný obraz. copy_to_fb=True zapíše výsledek do snímkového bufferu (frame buffer) kamery, což je správná volba, když se má výsledek objevit v náhledu IDE.

6.18.3. Cesta tam a zpět

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. Kdy propojovat

Toto propojení je správná odpověď, když aplikace potřebuje obecnou numerickou operaci, kterou vestavěné metody image neposkytují – vlastní filtry, vlastní směšování, neobvyklé nelinearity – nebo když je nutné v jediném výpočtu zkombinovat pixelová data s daty mimo obraz (osy IMU, audio vzorky).

Není to správná odpověď pro vysoce propustné zpracování pixelů, které už třída Image pokrývá. Vestavěné metody pracují přímo se snímkovým bufferem (frame buffer) v nativním pixelovém formátu kamery a jsou mnohem rychlejší než ekvivalentní výraz numpy. Po propojení sáhněte pro operace, které obrazová knihovna ještě neposkytuje.