6.4. Dtypes

El tipo de elemento de un ndarray es su dtype. El dtype decide tres cosas a la vez: cuántos bytes ocupa cada elemento, cómo se interpretan los bytes y qué rango de valores puede almacenar el array. Elegir el dtype correcto es la decisión más importante que afecta al uso de RAM en la cámara.

6.4.1. Los dtypes admitidos

numpy en la cámara admite un pequeño conjunto de dtypes:

dtype

bytes

rango

uint8

1

0 a 255

int8

1

-128 a 127

uint16

2

0 a 65.535

int16

2

-32.768 a 32.767

float

4

IEEE 754 de precisión simple

bool

1

True / False

No hay int32 ni int64, y la compilación de ulab de OpenMV no habilita el dtype opcional complex.

Elige el tipo que coincida con el hardware que produjo los datos. Una muestra de un ADC de 8 bits requiere uint8; una muestra de un ADC de 12 bits cabe en uint16; un píxel de luminancia de una cámara en escala de grises cabe en uint8, lo que ahorra cuatro veces la RAM que costaría el float predeterminado.

6.4.2. El dtype predeterminado

El dtype predeterminado de cada constructor en Creación de arrays es float. Eso rara vez es lo que la aplicación quiere al manejar datos de sensores. Pasa dtype= de forma explícita siempre que el ancho natural sea menor:

sensor = np.array(samples, dtype=np.uint16)

Volver a envolver un array de enteros sin un argumento dtype= copia y además convierte a float, lo que cuesta tanto tiempo como RAM. Cuando el rendimiento importa, indica el dtype.

6.4.3. El dtype de un array existente

dtype devuelve el dtype del array como el código de tipo entero que el array lleva internamente:

a = np.array([1, 2, 3], dtype=np.uint8)
print(a.dtype)            # 66 (the integer value of ``'B'``)

Los enteros de código de tipo coinciden con las constantes expuestas en el módulo numpynumpy.uint8, numpy.int8, numpy.uint16, numpy.int16, numpy.float, numpy.bool – por lo que comparar el dtype con la constante del módulo es la forma en que un script se ramifica según lo que contiene un array:

if a.dtype == np.uint8:
    ...  # uint8 branch

6.4.4. Reglas de promoción de tipos

Dos arrays de distintos dtypes pueden ser operandos del mismo operador. numpy elige el tipo del resultado según una tabla breve:

izquierda

derecha

resultado

uint8

int8

int16

uint8

int16

int16

uint8

uint16

uint16

int8

int16

int16

int8

uint16

uint16

uint16

int16

float

cualquiera

float

float

La fila uint16 / int16 promociona directamente a float porque numpy en la cámara no tiene un dtype entero de 32 bits.

Cuando un operador binario tiene un escalar de Python en un lado, el escalar se convierte en un array de un solo elemento del dtype adecuado más pequeño: 123 se convierte en un array uint8, -1000 se convierte en int16, y un float de Python se convierte en float.

6.4.5. El desbordamiento de enteros da la vuelta

Las operaciones sobre dos arrays del mismo dtype entero conservan ese dtype, incluso cuando el resultado se desborda. El acarreo se descarta de forma silenciosa:

a = np.array([200, 200], dtype=np.uint8)
b = np.array([100, 100], dtype=np.uint8)
print(a + b)

Salida:

array([44, 44], dtype=uint8)

El resultado es 300 mod 256 == 44. Cuando un valor intermedio necesita más rango del que permite el dtype de entrada, convierte primero:

c = np.array(a, dtype=np.uint16) + b
# array([300, 300], dtype=uint16)

Esta regla se aplica a todos los operadores de enteros – +, -, *, //, %, &, |, ^. Los arrays de float nunca se desbordan (en su lugar promocionan a infinito), por lo que el truco de la conversión solo es necesario en el caso de los enteros.