6.4. Dtypes

Het elementtype van een ndarray is zijn dtype. De dtype bepaalt drie dingen tegelijk: hoeveel bytes elk element inneemt, hoe de bytes worden geïnterpreteerd, en welk waardenbereik de array kan opslaan. De juiste dtype kiezen is veruit de belangrijkste beslissing die het RAM-gebruik op de camera beïnvloedt.

6.4.1. De ondersteunde dtypes

numpy op de camera ondersteunt een kleine set dtypes:

dtype

bytes

bereik

uint8

1

0 tot 255

int8

1

-128 tot 127

uint16

2

0 tot 65.535

int16

2

-32.768 tot 32.767

float

4

IEEE 754 single precision

bool

1

True / False

Er is geen int32 of int64, en de ulab-build van OpenMV schakelt de optionele complex-dtype niet in.

Kies het type dat past bij de hardware die de data produceerde. Een 8-bits ADC-sample wil uint8; een 12-bits ADC-sample past in uint16; een luminantie-pixel van een grijswaardencamera past in uint8 – waarmee viermaal het RAM wordt bespaard dat de standaard float zou kosten.

6.4.2. De standaard-dtype

De standaard-dtype van elke constructor op Arrays maken is float. Dat is zelden wat de applicatie wil bij het verwerken van sensordata. Geef dtype= expliciet op wanneer de natuurlijke breedte kleiner is:

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

Het opnieuw inpakken van een integer-array zonder een dtype=-argument kopieert en converteert naar float, wat zowel tijd als RAM kost. Wanneer prestaties van belang zijn, benoem dan de dtype.

6.4.3. De dtype van een bestaande array

dtype leest de dtype van de array terug als de integer-typecode die de array intern bijhoudt:

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

De typecode-integers komen overeen met de constanten die op de numpy-module worden blootgesteld – numpy.uint8, numpy.int8, numpy.uint16, numpy.int16, numpy.float, numpy.bool – dus de dtype vergelijken met de moduleconstante is hoe een script zich vertakt op basis van wat een array bevat:

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

6.4.4. Upcasting-regels

Twee arrays met verschillende dtypes kunnen operanden zijn van dezelfde operator. numpy kiest het resultaattype volgens een korte tabel:

links

rechts

resultaat

uint8

int8

int16

uint8

int16

int16

uint8

uint16

uint16

int8

int16

int16

int8

uint16

uint16

uint16

int16

float

elke

float

float

De rij uint16 / int16 promoveert rechtstreeks naar float omdat numpy op de camera geen 32-bits integer-dtype heeft.

Wanneer een binaire operator aan één kant een Python-scalar heeft, wordt de scalar geconverteerd naar een array met één element van de kleinste geschikte dtype: 123 wordt een uint8-array, -1000 wordt int16, een Python-float wordt float.

6.4.5. Integer-overflow loopt rond

Bewerkingen op twee arrays met dezelfde integer-dtype behouden die dtype, zelfs wanneer het resultaat overloopt. De carry wordt stilzwijgend weggegooid:

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

Uitvoer:

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

Het resultaat is 300 mod 256 == 44. Wanneer een tussenresultaat meer bereik nodig heeft dan de invoer-dtype toelaat, cast dan eerst:

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

Deze regel geldt voor elke integer-operator – +, -, *, //, %, &, |, ^. Float-arrays lopen nooit over (ze promoveren in plaats daarvan naar oneindig), dus de cast-truc is alleen nodig in het integer-geval.