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.