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

uint8

1

da 0 a 255

int8

1

da -128 a 127

uint16

2

da 0 a 65.535

int16

2

da -32.768 a 32.767

float

4

IEEE 754 a precisione singola

bool

1

True / False

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 numpynumpy.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

uint8

int8

int16

uint8

int16

int16

uint8

uint16

uint16

int8

int16

int16

int8

uint16

uint16

uint16

int16

float

qualsiasi

float

float

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.