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.