6.4. Типи даних (dtype)¶
Тип елементів ndarray — це його dtype. Тип визначає три речі одночасно: скільки байтів займає кожен елемент, як інтерпретуються ці байти та який діапазон значень може зберігати масив. Вибір правильного типу — найважливіше рішення, що впливає на використання RAM на камері.
6.4.1. Підтримувані типи¶
numpy на камері підтримує невеликий набір типів:
dtype |
байти |
діапазон |
|---|---|---|
|
1 |
0 до 255 |
|
1 |
-128 до 127 |
|
2 |
0 до 65,535 |
|
2 |
-32,768 до 32,767 |
|
4 |
IEEE 754 одинарна точність |
|
1 |
|
Немає типів int32 або int64, і збірка OpenMV ulab не підтримує необов’язковий тип complex.
Вибирайте тип, що відповідає апаратному забезпеченню, яке виробило дані. Зразок 8-бітного ADC потребує uint8; зразок 12-бітного ADC вміщується у uint16; піксель яскравості з камери у відтінках сірого вміщується у uint8 — що заощаджує в чотири рази більше RAM порівняно з типом float за замовчуванням.
6.4.2. Тип за замовчуванням¶
Тип за замовчуванням для кожного конструктора у Створення масивів — float. Це рідко те, чого потребує застосунок при обробці даних датчиків. Завжди явно передавайте dtype=, коли природна ширина менша:
sensor = np.array(samples, dtype=np.uint16)
Повторне обгортання цілочисельного масиву без аргументу dtype= копіює і конвертує у float, що коштує і часу, і RAM. Коли продуктивність важлива — вказуйте тип явно.
6.4.3. Тип існуючого масиву¶
dtype повертає тип масиву як ціле число — код типу, який масив зберігає внутрішньо:
a = np.array([1, 2, 3], dtype=np.uint8)
print(a.dtype) # 66 (the integer value of ``'B'``)
Цілочисельні коди типів збігаються з константами, що визначені в модулі numpy — numpy.uint8, numpy.int8, numpy.uint16, numpy.int16, numpy.float, numpy.bool — тому порівняння типу з константою модуля — це спосіб, яким скрипт розгалужується залежно від вмісту масиву:
if a.dtype == np.uint8:
... # uint8 branch
6.4.4. Правила підвищення типу¶
Два масиви з різними типами можуть бути операндами одного оператора. numpy визначає тип результату відповідно до короткої таблиці:
ліворуч |
праворуч |
результат |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
будь-який |
|
|
Рядок uint16 / int16 одразу підвищується до float, оскільки numpy на камері не має 32-бітного цілочисельного типу.
Коли бінарний оператор має скалярне значення Python з одного боку, воно перетворюється на масив з одного елемента найменшого підходящого типу: 123 стає масивом uint8, -1000 стає int16, Python float стає float.
6.4.5. Переповнення цілих чисел циклічне¶
Операції над двома масивами одного цілочисельного типу зберігають цей тип, навіть якщо результат переповнюється. Перенесення мовчки відкидається:
a = np.array([200, 200], dtype=np.uint8)
b = np.array([100, 100], dtype=np.uint8)
print(a + b)
Вивід:
array([44, 44], dtype=uint8)
Результат — 300 mod 256 == 44. Якщо проміжне значення потребує більшого діапазону, ніж дозволяє тип, спочатку виконайте приведення типу:
c = np.array(a, dtype=np.uint16) + b
# array([300, 300], dtype=uint16)
Це правило застосовується до кожного цілочисельного оператора — +, -, *, //, %, &, |, ^. Масиви float ніколи не переповнюються (натомість вони стають нескінченністю), тому прийом з приведенням типу потрібен лише для цілочисельного випадку.