6.4. Dtypy

Typ prvků v ndarray je jeho dtype. Dtype rozhoduje o třech věcech najednou: kolik bajtů zabírá každý prvek, jak jsou bajty interpretovány a jaký rozsah hodnot může pole uchovávat. Volba správného dtype je jediným nejdůležitějším rozhodnutím, které ovlivňuje využití RAM na kameře.

6.4.1. Podporované dtypy

numpy na kameře podporuje malou sadu dtypů:

dtype

bajty

rozsah

uint8

1

0 až 255

int8

1

-128 až 127

uint16

2

0 až 65 535

int16

2

-32 768 až 32 767

float

4

IEEE 754 jednoduchá přesnost

bool

1

True / False

Neexistuje int32 ani int64 a sestavení ulab od OpenMV nemá povolen volitelný dtype complex.

Vyberte typ, který odpovídá hardwaru, jenž data vyprodukoval. 8bitový vzorek z ADC chce uint8; 12bitový vzorek z ADC se vejde do uint16; jasový pixel z kamery ve stupních šedi se vejde do uint8 – což ušetří čtyřnásobek RAM oproti výchozímu float.

6.4.2. Výchozí dtype

Výchozím dtype každého konstruktoru na stránce Vytváření polí je float. To je málokdy to, co aplikace chce při práci s daty ze senzorů. Pokud je přirozená šířka menší, předávejte dtype= explicitně:

sensor = np.array(samples, dtype=np.uint16)

Opětovné zabalení celočíselného pole bez argumentu dtype= data zkopíruje a převede na float, což stojí čas i RAM. Když na výkonu záleží, dtype pojmenujte.

6.4.3. Dtype existujícího pole

dtype načte zpět dtype pole jako celočíselný kód typu, který si pole interně nese:

a = np.array([1, 2, 3], dtype=np.uint8)
print(a.dtype)            # 66 (the integer value of ``'B'``)

Celá čísla kódů typů odpovídají konstantám vystaveným v modulu numpynumpy.uint8, numpy.int8, numpy.uint16, numpy.int16, numpy.float, numpy.bool – takže porovnání dtype proti konstantě modulu je způsob, jak se skript větví podle toho, co pole obsahuje:

if a.dtype == np.uint8:
    ...  # uint8 branch

6.4.4. Pravidla rozšiřování typů (upcasting)

Dvě pole různých dtypů mohou být operandy téhož operátoru. numpy vybírá výsledný typ podle krátké tabulky:

levý

pravý

výsledek

uint8

int8

int16

uint8

int16

int16

uint8

uint16

uint16

int8

int16

int16

int8

uint16

uint16

uint16

int16

float

libovolný

float

float

Řádek uint16 / int16 se rovnou povýší na float, protože numpy na kameře nemá 32bitový celočíselný dtype.

Když má binární operátor na jedné straně Python skalár, skalár se převede na jednoprvkové pole nejmenšího vhodného dtype: 123 se stane polem uint8, -1000 se stane int16, Python float se stane float.

6.4.5. Celočíselné přetečení přetéká (wrap)

Operace nad dvěma poli stejného celočíselného dtype tento dtype zachovají, i když výsledek přeteče. Přenos se tiše zahodí:

a = np.array([200, 200], dtype=np.uint8)
b = np.array([100, 100], dtype=np.uint8)
print(a + b)

Výstup:

array([44, 44], dtype=uint8)

Výsledkem je 300 mod 256 == 44. Když mezivýsledek potřebuje větší rozsah, než vstupní dtype dovoluje, nejprve proveďte přetypování:

c = np.array(a, dtype=np.uint16) + b
# array([300, 300], dtype=uint16)

Toto pravidlo platí pro každý celočíselný operátor – +, -, *, //, %, &, |, ^. Pole typu float nikdy nepřetečou (místo toho se povýší na nekonečno), takže trik s přetypováním je potřeba jen v celočíselném případě.