6.18. ภาพและ ndarrays

คลาส Image เป็นพื้นผิวที่รวดเร็วสำหรับการทำงานกับพิกเซลในรูปแบบดั้งเดิมของกล้อง: ทุกเมธอดบนนั้นทำงานโดยตรงบนบัฟเฟอร์เฟรมในรูปแบบพิกเซลดั้งเดิมของกล้อง numpy คือพื้นผิวตัวเลขทั่วไปสำหรับทุกอย่างอื่น มีสองเมธอดที่เชื่อมต่อกัน:

เมื่อใช้ร่วมกัน ทั้งสองทำให้แอปพลิเคชันสามารถถ่ายสแนปช็อตเฟรม ส่งต่อไปยัง numpy เพื่อแปลงแบบกำหนดเอง แล้วนำผลลัพธ์กลับมาเป็นภาพเพื่อแสดง บันทึก หรือส่งกลับไปยังไลบรารีภาพที่เหลือ

6.18.1. Image เป็น ndarray

to_ndarray() จัดสรร ndarray ใหม่และคัดลอกข้อมูลพิกเซลของภาพเข้าไป (ด้วยการแมป dtype ที่แสดงด้านล่าง) ไม่ใช่มุมมองของบัฟเฟอร์เฟรมของภาพ -- อาร์เรย์ numpy เป็นเจ้าของไบต์ของตัวเองเสมอ ลายเซ็นคือ to_ndarray(dtype, *, buffer=None) และรูปร่างของผลลัพธ์ขึ้นอยู่กับรูปแบบภาพ:

  • GRAYSCALE -- อาร์เรย์ 2 มิติ รูปร่าง (height, width)

  • RGB565 -- อาร์เรย์ 3 มิติ รูปร่าง (height, width, 3) ระนาบตามลำดับ R/G/B

อาร์กิวเมนต์ dtype ควบคุมการแมปของค่าพิกเซล 8 บิตแต่ละค่า v:

dtype

องค์ประกอบ

การแมปสำหรับค่าพิกเซล 8 บิต v

'B'

uint8

v (ดิบ)

'b'

int8

v - 128 (ปรับศูนย์กลางใหม่รอบศูนย์)

'f'

float32

float(v) (0.0 ... 255.0)

ตัวอย่าง -- ดูเฟรม grayscale เป็นเมทริกซ์ uint8

import csi
from ulab import numpy as np

csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize(csi.QVGA)

img = csi0.snapshot()
a   = img.to_ndarray('B')        # shape (240, 320), dtype=uint8

print(a.shape, a.dtype)
print("mean brightness:", np.mean(a))

คีย์เวิร์ด buffer= ช่วยให้แอปพลิเคชันนำ bytearray ที่จัดสรรไว้แล้วมาใช้ซ้ำ เพื่อให้กล้องไม่ต้องจัดสรรใหม่ทุกเฟรม:

buf = bytearray(320 * 240)
while True:
    img = csi0.snapshot()
    a   = img.to_ndarray('B', buffer=buf)
    # ... process a ...

6.18.2. ndarray เป็น image

ในทางตรงกันข้าม ส่ง ndarray เป็นอาร์กิวเมนต์แรกให้กับ image.Image ตัวสร้างจะจัดสรรบัฟเฟอร์ภาพใหม่และคัดลอกค่าของอาร์เรย์เข้าไป โดยตัดและปัดเศษให้อยู่ในช่วง 0..255

image.Image(arr, *, buffer=None, copy_to_fb=False)

ตัวสร้างจะอนุมานรูปทรงเรขาคณิตและรูปแบบพิกเซลจากรูปร่างของอาร์เรย์:

  • รูปร่าง (h, w) -- ภาพ GRAYSCALE

  • รูปร่าง (h, w, 3) -- ภาพ RGB565

ndarray ต้องมี dtype เป็น float ตัวสร้างรองรับเฉพาะกรณีนั้นในปัจจุบัน ค่าจะถูกปัดเศษและตัดให้อยู่ในช่วง 0..255

buffer= ช่วยให้แอปพลิเคชันระบุ bytearray ที่จัดสรรไว้แล้วสำหรับภาพผลลัพธ์ copy_to_fb=True เขียนผลลัพธ์ลงในบัฟเฟอร์เฟรมของกล้อง ซึ่งเป็นตัวเลือกที่ถูกต้องเมื่อผลลัพธ์ควรปรากฏในการแสดงตัวอย่างใน IDE

6.18.3. การส่งข้อมูลรอบทริป

import csi
import image
from ulab import numpy as np

csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.GRAYSCALE)
csi0.framesize(csi.QVGA)

img = csi0.snapshot()
a   = img.to_ndarray('f')                  # work in float space

a = 255.0 * (a / 255.0) ** 0.5             # gamma correction

out = image.Image(a, copy_to_fb=True)      # back to an image

6.18.4. เมื่อไหร่ควรใช้การเชื่อมต่อ

การเชื่อมต่อนี้คือคำตอบที่ถูกต้องเมื่อแอปพลิเคชันต้องการการดำเนินการตัวเลข ทั่วไป ที่เมธอด image ในตัวไม่มีให้ -- ฟิลเตอร์แบบกำหนดเอง การผสมแบบกำหนดเอง ความไม่เป็นเชิงเส้นที่ผิดปกติ -- หรือเมื่อข้อมูลพิกเซลต้องรวมกับข้อมูลที่ไม่ใช่ภาพ (แกน IMU ตัวอย่างเสียง) ในการคำนวณเดียว

มัน ไม่ใช่ คำตอบที่ถูกต้องสำหรับการประมวลผลพิกเซลปริมาณงานสูงที่คลาส Image ครอบคลุมอยู่แล้ว เมธอดในตัวทำงานโดยตรงบนบัฟเฟอร์เฟรมในรูปแบบพิกเซลดั้งเดิมของกล้องและเร็วกว่านิพจน์ numpy ที่เทียบเท่ามาก ใช้การเชื่อมต่อสำหรับการดำเนินการที่ไลบรารีภาพยังไม่มีอยู่