6.18. Kuvat ja ndarrayt¶
Image-luokka on nopea rajapinta kameran natiiviin pikselikäsittelyyn: jokainen sen metodi toimii suoraan kehyspuskuriin kameran natiivissa pikseliformaatissa. numpy on yleiskäyttöinen numeerinen rajapinta kaikkeen muuhun. Kaksi metodia yhdistävät ne:
image.Image.to_ndarray()– kopioi kuvan pikselitndarray-olioon.image.Image-konstruktori – rakentaa uuden kuvanndarray-oliosta.
Yhdessä ne antavat sovelluksen ottaa kehyksen, luovuttaa sen numpy:lle mukautettua muunnosta varten ja sijoittaa tuloksen sitten takaisin kuvaan näytettäväksi, tallennettavaksi tai syötettäväksi muulle kuvakirjastolle.
6.18.1. Kuvasta ndarrayksi¶
to_ndarray() varaa uuden ndarray-olion ja kopioi siihen kuvan pikselidatan (alla olevan dtype-kuvauksen mukaisesti). Se ei koskaan ole näkymä kuvan kehyspuskuriin – numpy-taulukko omistaa aina omat tavunsa. Allekirjoitus on to_ndarray(dtype, *, buffer=None), ja tuloksen muoto riippuu kuvaformaatista:
GRAYSCALE – 2-ulotteinen taulukko, muoto
(height, width).RGB565 – 3-ulotteinen taulukko, muoto
(height, width, 3), tasot järjestyksessä R/G/B.
dtype-argumentti hallitsee, miten kukin 8-bittinen pikseliarvo v kuvataan:
|
alkio |
kuvaus 8-bittiselle pikseliarvolle |
|---|---|---|
|
|
|
|
|
|
|
|
|
Esimerkki – tarkastele harmaasävykehystä uint8-matriisina:
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=-avainsana antaa sovelluksen käyttää uudelleen jo varaamaansa bytearray-oliota, joten kameran ei tarvitse varata uutta jokaista kehystä varten:
buf = bytearray(320 * 240)
while True:
img = csi0.snapshot()
a = img.to_ndarray('B', buffer=buf)
# ... process a ...
6.18.2. ndarraysta kuvaksi¶
Toiseen suuntaan: välitä ndarray ensimmäisenä argumenttina image.Image:lle. Konstruktori varaa uuden kuvapuskurin ja kopioi taulukon arvot siihen, rajattuna ja pyöristettynä välille 0..255
image.Image(arr, *, buffer=None, copy_to_fb=False)
Konstruktori päättelee geometrian ja pikseliformaatin taulukon muodosta:
muoto
(h, w)–GRAYSCALE-kuva.muoto
(h, w, 3)–RGB565-kuva.
ndarray:n dtypen on oltava float; konstruktori tukee tällä hetkellä vain tätä tapausta. Arvot pyöristetään ja rajataan välille 0..255.
buffer= antaa sovelluksen tarjota bytearray-olion, jonka se on jo varannut tulokseksi tulevaa kuvaa varten. copy_to_fb=True kirjoittaa tuloksen kameran kehyspuskuriin, mikä on oikea valinta silloin, kun tuloksen tulee näkyä IDE:n esikatselussa.
6.18.3. Edestakainen muunnos¶
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. Milloin yhdistää¶
Tämä silta on oikea ratkaisu silloin, kun sovellus tarvitsee yleiskäyttöisen numeerisen operaation, jota sisäänrakennetut image-metodit eivät tarjoa – mukautettuja suodattimia, mukautettuja sekoituksia, epätavallisia epälineaarisuuksia – tai kun pikselidata on yhdistettävä ei-kuvadataan (IMU-akselit, äänitteet) yhdessä laskennassa.
Se ei ole oikea ratkaisu korkean läpäisykyvyn pikselikäsittelyyn, jonka Image-luokka jo kattaa. Sisäänrakennetut metodit toimivat suoraan kehyspuskuriin kameran natiivissa pikseliformaatissa ja ovat paljon nopeampia kuin vastaava numpy-lauseke. Käytä siltaa operaatioihin, joita kuvakirjasto ei jo tarjoa.