6.4. Dtypes

סוג האיברים של ndarray הוא ה-dtype שלו. ה-dtype מכריע שלושה דברים בבת אחת: כמה בתים תופס כל איבר, כיצד מפרשים את הבתים, ואיזה טווח ערכים יכול המערך לאחסן. בחירת ה-dtype הנכון היא ההחלטה היחידה הגדולה ביותר המשפיעה על השימוש ב-RAM של המצלמה.

6.4.1. ה-dtypes הנתמכים

numpy על המצלמה תומך בקבוצה קטנה של dtypes:

dtype

בתים

טווח

uint8

1

0 עד 255

int8

1

-128 עד 127

uint16

2

0 עד 65,535

int16

2

-32,768 עד 32,767

float

4

IEEE 754 דיוק יחיד

bool

1

True / False

אין int32 או int64, ובניית ulab של OpenMV אינה מפעילה את ה-dtype האופציונלי complex.

בחר את הסוג התואם לחומרה שהפיקה את הנתונים. דגימת ADC של 8 סיביות זקוקה ל-uint8; דגימת ADC של 12 סיביות נכנסת ב-uint16; פיקסל בהירות ממצלמת גווני אפור נכנס ב-uint8 – וחוסך פי ארבעה מה-RAM שברירת המחדל float הייתה עולה.

6.4.2. ברירת המחדל של dtype

ברירת המחדל של dtype בכל בנאי שב-יצירת מערכים היא float. לעיתים רחוקות זה מה שהיישום רוצה כאשר מטפלים בנתוני חיישן. העבר dtype= במפורש בכל פעם שהרוחב הטבעי קטן יותר:

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

עטיפה מחדש של מערך שלמים ללא ארגומנט dtype= מעתיקה וגם ממירה ל-float, מה שעולה גם בזמן וגם ב-RAM. כשהביצועים חשובים, ציין את ה-dtype בשמו.

6.4.3. ה-dtype של מערך קיים

dtype מחזיר את ה-dtype של המערך בתור קוד הסוג השלם שהמערך נושא בתוכו:

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

השלמים של קוד הסוג תואמים לקבועים הנחשפים במודול numpynumpy.uint8, numpy.int8, numpy.uint16, numpy.int16, numpy.float, numpy.bool – כך שהשוואת ה-dtype אל קבוע המודול היא הדרך שבה סקריפט מתפצל לפי מה שמערך מכיל:

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

6.4.4. כללי העלאת סוג

שני מערכים בעלי dtypes שונים יכולים להיות אופרנדים של אותו אופרטור. numpy בוחר את סוג התוצאה לפי טבלה קצרה:

שמאל

ימין

תוצאה

uint8

int8

int16

uint8

int16

int16

uint8

uint16

uint16

int8

int16

int16

int8

uint16

uint16

uint16

int16

float

כל

float

float

השורה של uint16 / int16 מקודמת ישירות ל-float משום של-numpy על המצלמה אין dtype שלם בן 32 סיביות.

כאשר לאופרטור בינארי יש סקלר של Python בצד אחד, הסקלר מומר למערך בן איבר יחיד מה-dtype המתאים ה-קטן ביותר: 123 הופך למערך uint8, -1000 הופך ל-int16, ו-float של Python הופך ל-float.

6.4.5. גלישת שלמים מתגלגלת

פעולות על שני מערכים מאותו dtype שלם שומרות על אותו dtype, גם כאשר התוצאה גולשת. הנשא מושמט בשקט:

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. כאשר ביניים זקוק לטווח גדול יותר מזה ש-dtype הקלט מאפשר, בצע המרה תחילה:

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

כלל זה חל על כל אופרטור שלמים – +, -, *, //, %, &, |, ^. מערכי float לעולם אינם גולשים (הם מתקדמים לאינסוף במקום), ולכן טריק ההמרה נחוץ רק במקרה השלם.