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 |
|---|---|---|
|
1 |
0 tot 255 |
|
1 |
-128 tot 127 |
|
2 |
0 tot 65.535 |
|
2 |
-32.768 tot 32.767 |
|
4 |
IEEE 754 single precision |
|
1 |
|
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 |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
elke |
|
|
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.