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:
image.Image.to_ndarray()– zkopíruje pixely obrazu dondarray.Konstruktor třídy
image.Image– vytvoří nový obraz zndarray.
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:
|
prvek |
mapování 8bitové hodnoty pixelu |
|---|---|---|
|
|
|
|
|
|
|
|
|
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)– obrazGRAYSCALE.tvar
(h, w, 3)– obrazRGB565.
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.