6.4. Dtypes

ชนิดข้อมูลขององค์ประกอบใน ndarray เรียกว่า dtype ซึ่งกำหนดสามสิ่งในคราวเดียวกัน ได้แก่ จำนวนไบต์ที่แต่ละองค์ประกอบใช้ วิธีตีความไบต์เหล่านั้น และช่วงของค่าที่อาร์เรย์เก็บได้ การเลือก dtype ที่เหมาะสมเป็นการตัดสินใจสำคัญที่สุดที่ส่งผลต่อการใช้ RAM บนกล้อง

6.4.1. ชนิด dtype ที่รองรับ

numpy บนกล้องรองรับ dtype เพียงชุดเล็กๆ:

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 เริ่มต้นของทุก constructor บน การสร้างอาร์เรย์ คือ float ซึ่งแทบไม่ตรงกับความต้องการของแอปพลิเคชันเมื่อจัดการข้อมูลจาก sensor ควรระบุ 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'``)

รหัสจำนวนเต็มของชนิดข้อมูลตรงกับค่าคงที่ที่เปิดเผยไว้ในโมดูล numpy ได้แก่ numpy.uint8, numpy.int8, numpy.uint16, numpy.int16, numpy.float, numpy.bool ดังนั้นการเปรียบเทียบ dtype กับค่าคงที่ของโมดูลคือวิธีที่สคริปต์แยกสาขาตามประเภทข้อมูลที่อาร์เรย์เก็บ:

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

6.4.4. กฎการยกระดับชนิดข้อมูล

อาร์เรย์สองตัวที่มี dtype ต่างกันสามารถเป็นตัวดำเนินการของโอเปอเรเตอร์เดียวกันได้ 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 scalar อยู่ด้านหนึ่ง scalar นั้นจะถูกแปลงเป็นอาร์เรย์ที่มีองค์ประกอบเดียวในชนิด dtype ที่เล็กที่สุดที่เหมาะสม: 123 กลายเป็นอาร์เรย์ uint8, -1000 กลายเป็น int16, Python float กลายเป็น 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 ไม่เคยล้นค่า (แต่จะยกระดับเป็น infinity แทน) ดังนั้นเทคนิคการแปลงชนิดจึงจำเป็นเฉพาะในกรณีจำนวนเต็มเท่านั้น