6.4. Dtype#
Il tipo degli elementi di un ndarray è il suo dtype. Il dtype stabilisce tre cose in una sola volta: quanti byte occupa ogni elemento, come vengono interpretati i byte e quale intervallo di valori l’array può memorizzare. Scegliere il dtype giusto è la singola decisione che più influisce sull’uso della RAM sulla camera.
6.4.1. I dtype supportati#
numpy sulla camera supporta un piccolo insieme di dtype:
dtype | byte | intervallo |
|---|---|---|
| 1 | da 0 a 255 |
| 1 | da -128 a 127 |
| 2 | da 0 a 65.535 |
| 2 | da -32.768 a 32.767 |
| 4 | IEEE 754 a precisione singola |
| 1 |
|
Non esistono int32 o int64 e la build di ulab di OpenMV non abilita il dtype opzionale complex.
Scegli il tipo che corrisponde all’hardware che ha prodotto i dati. Un campione da un ADC a 8 bit vuole uint8; un campione da un ADC a 12 bit entra in uint16; un pixel di luminanza da una camera in scala di grigi entra in uint8 – risparmiando quattro volte la RAM che costerebbe il float predefinito.
6.4.2. Il dtype predefinito#
Il dtype predefinito di ogni costruttore in Creare array è float. Raramente è ciò che l’applicazione desidera quando gestisce dati provenienti da sensori. Passa dtype= esplicitamente ogni volta che la larghezza naturale è inferiore:
sensor = np.array(samples, dtype=np.uint16)
Riavvolgere un array di interi senza un argomento dtype= copia e converte in float, il che costa sia tempo sia RAM. Quando le prestazioni contano, indica il dtype.
6.4.3. Il dtype di un array esistente#
dtype restituisce il dtype dell’array come il codice di tipo intero che l’array porta internamente:
a = np.array([1, 2, 3], dtype=np.uint8)
print(a.dtype) # 66 (the integer value of ``'B'``)
Gli interi del codice di tipo corrispondono alle costanti esposte nel modulo numpy – numpy.uint8, numpy.int8, numpy.uint16, numpy.int16, numpy.float, numpy.bool – quindi confrontare il dtype con la costante del modulo è il modo in cui uno script si dirama in base a ciò che un array contiene:
if a.dtype == np.uint8:
... # uint8 branch
6.4.4. Regole di promozione (upcasting)#
Due array di dtype diversi possono essere operandi dello stesso operatore. numpy sceglie il tipo del risultato in base a una breve tabella:
sinistra | destra | risultato |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
qualsiasi |
|
|
La riga uint16 / int16 viene promossa direttamente a float perché numpy sulla camera non ha un dtype intero a 32 bit.
Quando un operatore binario ha uno scalare Python su un lato, lo scalare viene convertito in un array a elemento singolo del dtype adatto più piccolo: 123 diventa un array uint8, -1000 diventa int16, un float Python diventa float.
6.4.5. L’overflow degli interi avvolge#
Le operazioni su due array dello stesso dtype intero mantengono quel dtype, anche quando il risultato va in overflow. Il riporto viene scartato silenziosamente:
a = np.array([200, 200], dtype=np.uint8)
b = np.array([100, 100], dtype=np.uint8)
print(a + b)
Output:
array([44, 44], dtype=uint8)
Il risultato è 300 mod 256 == 44. Quando un valore intermedio necessita di un intervallo maggiore di quello consentito dal dtype di input, esegui prima il cast:
c = np.array(a, dtype=np.uint16) + b
# array([300, 300], dtype=uint16)
Questa regola si applica a ogni operatore intero – +, -, *, //, %, &, |, ^. Gli array float non vanno mai in overflow (vengono invece promossi a infinito), quindi il trucco del cast serve solo nel caso degli interi.