6.4. Dtypes¶
Der Elementtyp eines ndarray ist sein dtype. Der dtype legt drei Dinge auf einmal fest: wie viele Bytes jedes Element belegt, wie die Bytes interpretiert werden und welchen Wertebereich das Array speichern kann. Die Wahl des richtigen dtype ist die einzelne wichtigste Entscheidung, die den RAM-Verbrauch auf der Kamera beeinflusst.
6.4.1. Die unterstützten dtypes¶
numpy auf der Kamera unterstützt eine kleine Menge von dtypes:
dtype |
Bytes |
Bereich |
|---|---|---|
|
1 |
0 bis 255 |
|
1 |
-128 bis 127 |
|
2 |
0 bis 65.535 |
|
2 |
-32.768 bis 32.767 |
|
4 |
IEEE 754 einfache Genauigkeit |
|
1 |
|
Es gibt kein int32 oder int64, und der ulab-Build von OpenMV aktiviert den optionalen complex-dtype nicht.
Wähle den Typ, der zur Hardware passt, die die Daten erzeugt hat. Ein 8-Bit-ADC-Sample möchte uint8; ein 12-Bit-ADC-Sample passt in uint16; ein Luminanzpixel von einer Graustufenkamera passt in uint8 – und spart das Vierfache des RAM, das der voreingestellte float kosten würde.
6.4.2. Der voreingestellte dtype¶
Der voreingestellte dtype jedes Konstruktors auf Arrays erstellen ist float. Das ist selten das, was die Anwendung beim Umgang mit Sensordaten möchte. Übergib dtype= explizit, wann immer die natürliche Breite kleiner ist:
sensor = np.array(samples, dtype=np.uint16)
Das erneute Verpacken eines Integer-Arrays ohne ein dtype=-Argument kopiert und konvertiert nach float, was sowohl Zeit als auch RAM kostet. Wenn die Performance wichtig ist, benenne den dtype.
6.4.3. Der dtype eines vorhandenen Arrays¶
dtype liest den dtype des Arrays als den Integer-Typcode zurück, den das Array intern trägt:
a = np.array([1, 2, 3], dtype=np.uint8)
print(a.dtype) # 66 (the integer value of ``'B'``)
Die Typcode-Integer entsprechen den Konstanten, die auf dem numpy-Modul bereitgestellt werden – numpy.uint8, numpy.int8, numpy.uint16, numpy.int16, numpy.float, numpy.bool – daher ist der Vergleich des dtype mit der Modulkonstante die Art, wie ein Skript je nach Inhalt eines Arrays verzweigt:
if a.dtype == np.uint8:
... # uint8 branch
6.4.4. Upcasting-Regeln¶
Zwei Arrays unterschiedlicher dtypes können Operanden desselben Operators sein. numpy wählt den Ergebnistyp anhand einer kurzen Tabelle:
links |
rechts |
Ergebnis |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
beliebig |
|
|
Die Zeile uint16 / int16 wird direkt zu float heraufgestuft, weil numpy auf der Kamera keinen 32-Bit-Integer-dtype hat.
Wenn ein binärer Operator auf einer Seite einen Python-Skalar hat, wird der Skalar in ein einelementiges Array des kleinsten geeigneten dtype konvertiert: 123 wird zu einem uint8-Array, -1000 wird zu int16, ein Python-float wird zu float.
6.4.5. Integer-Überlauf läuft um¶
Operationen auf zwei Arrays desselben Integer-dtype behalten diesen dtype, selbst wenn das Ergebnis überläuft. Der Übertrag wird stillschweigend verworfen:
a = np.array([200, 200], dtype=np.uint8)
b = np.array([100, 100], dtype=np.uint8)
print(a + b)
Ausgabe:
array([44, 44], dtype=uint8)
Das Ergebnis ist 300 mod 256 == 44. Wenn ein Zwischenwert mehr Bereich benötigt, als der Eingabe-dtype zulässt, caste zuerst:
c = np.array(a, dtype=np.uint16) + b
# array([300, 300], dtype=uint16)
Diese Regel gilt für jeden Integer-Operator – +, -, *, //, %, &, |, ^. Float-Arrays laufen nie über (sie stufen sich stattdessen zu unendlich hoch), daher wird der Cast-Trick nur im Integer-Fall benötigt.