6.4. Dtypes

Le type d’élément d’un ndarray est son dtype. Le dtype détermine trois choses à la fois : combien d’octets chaque élément occupe, comment les octets sont interprétés et quelle plage de valeurs le tableau peut stocker. Choisir le bon dtype est la décision la plus importante qui affecte l’utilisation de la RAM sur la caméra.

6.4.1. Les dtypes pris en charge

numpy sur la caméra prend en charge un petit ensemble de dtypes :

dtype

octets

plage

uint8

1

0 à 255

int8

1

-128 à 127

uint16

2

0 à 65 535

int16

2

-32 768 à 32 767

float

4

IEEE 754 simple précision

bool

1

True / False

Il n’y a pas de int32 ni de int64, et la version ulab d’OpenMV n’active pas le dtype optionnel complex.

Choisissez le type qui correspond au matériel qui a produit les données. Un échantillon ADC 8 bits demande uint8 ; un échantillon ADC 12 bits tient dans uint16 ; un pixel de luminance issu d’une caméra en niveaux de gris tient dans uint8 – ce qui économise quatre fois la RAM que coûterait le float par défaut.

6.4.2. Le dtype par défaut

Le dtype par défaut de chaque constructeur sur Créer des tableaux est float. Ce n’est que rarement ce que l’application souhaite lorsqu’elle manipule des données de capteur. Passez dtype= explicitement chaque fois que la largeur naturelle est plus petite

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

Réenvelopper un tableau d’entiers sans argument dtype= copie et convertit en float, ce qui coûte à la fois du temps et de la RAM. Lorsque la performance compte, nommez le dtype.

6.4.3. Le dtype d’un tableau existant

dtype relit le dtype du tableau sous la forme du code de type entier que le tableau porte en interne

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

Les entiers de code de type correspondent aux constantes exposées sur le module numpynumpy.uint8, numpy.int8, numpy.uint16, numpy.int16, numpy.float, numpy.bool – de sorte que comparer le dtype à la constante du module est la façon dont un script se ramifie selon ce qu’un tableau contient

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

6.4.4. Règles de promotion (upcasting)

Deux tableaux de dtypes différents peuvent être opérandes du même opérateur. numpy choisit le type du résultat selon une courte table :

gauche

droite

résultat

uint8

int8

int16

uint8

int16

int16

uint8

uint16

uint16

int8

int16

int16

int8

uint16

uint16

uint16

int16

float

tous

float

float

La ligne uint16 / int16 est directement promue en float car numpy sur la caméra n’a pas de dtype entier 32 bits.

Lorsqu’un opérateur binaire a un scalaire Python d’un côté, le scalaire est converti en un tableau à un seul élément du plus petit dtype adapté : 123 devient un tableau uint8, -1000 devient int16, un float Python devient float.

6.4.5. Le débordement entier reboucle

Les opérations sur deux tableaux du même dtype entier conservent ce dtype, même lorsque le résultat déborde. La retenue est silencieusement abandonnée

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

Sortie

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

Le résultat est 300 mod 256 == 44. Lorsqu’un résultat intermédiaire a besoin de plus de plage que le dtype d’entrée ne le permet, effectuez d’abord une conversion

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

Cette règle s’applique à chaque opérateur entier – +, -, *, //, %, &, |, ^. Les tableaux de flottants ne débordent jamais (ils sont promus vers l’infini à la place), donc l’astuce de conversion n’est nécessaire que dans le cas entier.