6.4. Dtypes¶
O tipo de elemento de um ndarray é o seu dtype. O dtype define simultaneamente três coisas: quantos bytes cada elemento ocupa, como os bytes são interpretados, e o intervalo de valores que o array pode armazenar. Escolher o dtype correto é a decisão mais importante no que respeita ao uso de RAM na câmara.
6.4.1. Os dtypes suportados¶
O numpy na câmara suporta um conjunto reduzido de dtypes:
dtype |
bytes |
intervalo |
|---|---|---|
|
1 |
0 a 255 |
|
1 |
-128 a 127 |
|
2 |
0 a 65 535 |
|
2 |
-32 768 a 32 767 |
|
4 |
Precisão simples IEEE 754 |
|
1 |
|
Não existe int32 nem int64, e a compilação ulab do OpenMV não ativa o dtype opcional complex.
Escolha o tipo que corresponde ao hardware que produziu os dados. Uma amostra de ADC de 8 bits usa uint8; uma amostra de ADC de 12 bits cabe em uint16; um pixel de luminância de uma câmara em escala de cinzentos cabe em uint8 – poupando quatro vezes a RAM que o float predefinido consumiria.
6.4.2. O dtype predefinido¶
O dtype predefinido de todos os construtores em Criação de arrays é float. Isso raramente corresponde ao que a aplicação necessita ao tratar dados de sensor. Passe dtype= explicitamente sempre que a largura natural for menor:
sensor = np.array(samples, dtype=np.uint16)
Reembrulhar um array de inteiros sem o argumento dtype= copia e converte para float, o que aumenta o tempo e consome RAM. Quando o desempenho importa, indique o dtype.
6.4.3. O dtype de um array existente¶
dtype devolve o dtype do array como o código de tipo inteiro que o array guarda internamente:
a = np.array([1, 2, 3], dtype=np.uint8)
print(a.dtype) # 66 (the integer value of ``'B'``)
Os inteiros de código de tipo correspondem às constantes expostas no módulo numpy – numpy.uint8, numpy.int8, numpy.uint16, numpy.int16, numpy.float, numpy.bool – por isso comparar o dtype com a constante do módulo é a forma de um script ramificar consoante o que um array contém:
if a.dtype == np.uint8:
... # uint8 branch
6.4.4. Regras de promoção de tipo¶
Dois arrays de dtypes diferentes podem ser operandos do mesmo operador. O numpy escolhe o tipo do resultado de acordo com uma tabela resumida:
esquerda |
direita |
resultado |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
qualquer |
|
|
A linha uint16 / int16 promove diretamente para float porque o numpy na câmara não possui dtype de inteiro de 32 bits.
Quando um operador binário tem um escalar Python de um lado, o escalar é convertido num array de elemento único do dtype menor adequado: 123 torna-se um array uint8, -1000 torna-se int16, um float Python torna-se float.
6.4.5. Overflow em inteiros causa wrapping¶
Operações sobre dois arrays do mesmo dtype inteiro mantêm esse dtype, mesmo quando o resultado faz overflow. O transporte é descartado silenciosamente:
a = np.array([200, 200], dtype=np.uint8)
b = np.array([100, 100], dtype=np.uint8)
print(a + b)
Saída:
array([44, 44], dtype=uint8)
O resultado é 300 mod 256 == 44. Quando um valor intermédio necessita de um intervalo maior do que o dtype de entrada permite, converta primeiro:
c = np.array(a, dtype=np.uint16) + b
# array([300, 300], dtype=uint16)
Esta regra aplica-se a todos os operadores inteiros – +, -, *, //, %, &, |, ^. Os arrays float nunca fazem overflow (promovem para infinito em vez disso), pelo que o truque de conversão é necessário apenas no caso de inteiros.