4.14. พื้นฐาน CSI¶
โมดูล csi คือวิธีที่โค้ด Python ควบคุมเซนเซอร์กล้อง สคริปต์ทุกตัวที่จับเฟรมจะมีรูปแบบสามส่วนเหมือนกัน: การนำเข้าที่ด้านบน การกำหนดค่าครั้งเดียวตรงกลาง และลูป while True ที่ด้านล่างที่ดึงเฟรมจากกล้องทีละหนึ่ง
4.14.1. ลูปทั่วไป¶
import csi, image, time
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
clock = time.clock()
while True:
clock.tick()
img = csi0.snapshot()
# process img here
print(clock.fps())
4.14.2. สิ่งที่แต่ละการเรียกทำ¶
import csi, image, timeนำเข้าสามโมดูล
csiควบคุมเซนเซอร์imageกำหนดคลาสImageที่snapshot()คืนค่า และtimeให้ตัวช่วยtime.clock()ที่ใช้วัดเฟรมต่อวินาทีcsi.CSI()สร้างอินสแตนซ์
CSIที่ครอบเซนเซอร์กล้องทางกายภาพหนึ่งตัว ตัวสร้างจะอ้างสิทธิ์อุปกรณ์ต่อพ่วงกล้องและบันทึกการกำหนดค่าต่อเซนเซอร์ กล้องที่มีเซนเซอร์เดียวมีอินสแตนซ์CSIหนึ่งตัว กล้องที่มีสองเซนเซอร์ (สีบวกความร้อน สีบวกเหตุการณ์) มีสองตัว โดยแต่ละตัวเลือกด้วยอาร์กิวเมนต์cidให้กับตัวสร้างcsi0.reset()จ่ายไฟและกำหนดค่าเซนเซอร์ โดยค่าเริ่มต้นจะกระตุกพินรีเซ็ตของเซนเซอร์ จากนั้นเขียนรีจิสเตอร์ I2C ของเซนเซอร์ไปยังสถานะเริ่มต้นที่รู้จัก การเรียกกำหนดค่าที่ตามมา --
pixformat,framesize, ปุ่มควบคุมอัตโนมัติ -- จะส่งการเขียนรีจิสเตอร์เพิ่มเติมผ่านบัส I2C ควบคุมเดียวกันcsi0.pixformat(csi.RGB565)เขียนรีจิสเตอร์เซนเซอร์ที่เลือกรูปแบบพิกเซลเอาต์พุต ตัวเลือกที่มีคือรูปแบบที่หน้า pixel formats แนะนำไว้:
RGB565,GRAYSCALE,BAYER,YUV422, และJPEGบนเซนเซอร์ที่รองรับcsi0.framesize(csi.QVGA)เขียนรีจิสเตอร์ที่เลือกความละเอียดเอาต์พุต
QVGAคือ 320 × 240 ขนาดที่ตั้งชื่อไว้สูงสุดถึงWQXGA2(2592 × 1944 ประมาณ 5 MP) บนเซนเซอร์ที่รองรับ ทูเปิล(width, height)แบบกำหนดเองก็ใช้ได้เช่นกัน ตราบใดที่สอดคล้องกับความสามารถเอาต์พุตของเซนเซอร์clock = time.clock()สร้างตัวช่วยนาฬิกา การเรียก
clock.tick()แต่ละครั้งภายในลูปจะบันทึกเวลาเริ่มต้นของการวนซ้ำtime.clock.fps()รายงานอัตราลูปล่าสุดเป็นเฟรมต่อวินาทีimg = csi0.snapshot()จับหนึ่งเฟรมจากเซนเซอร์และคืนค่าเป็น
Imageกลไกที่เฟรมนั้นลงเอยในหน่วยความจำนั้นคุ้มค่าที่จะพิจารณาอย่างละเอียดมากขึ้น
4.14.3. วิธีที่ snapshot เติมหน่วยความจำ¶
เซนเซอร์ส่งพิกเซลบนบัสข้อมูลพิกเซลที่อธิบายใน sensor buses ด้วยอัตราหลายร้อยเมกะไบต์ต่อวินาที -- เร็วเกินไปมากสำหรับ CPU ที่จะคัดลอกพิกเซลต่อพิกเซลในซอฟต์แวร์
แทนที่ MCU จะโอนภาระการถ่ายโอนไปยัง Direct Memory Access (DMA) -- เอ็นจินฮาร์ดแวร์ที่แยกจาก CPU ที่คัดลอกไบต์จากที่หนึ่งไปยังอีกที่หนึ่งภายใน MCU โดยไม่เกี่ยวข้องกับ CPU เลย อุปกรณ์ต่อพ่วงอินพุตกล้องจะรับไบต์พิกเซลขาเข้าแต่ละตัวลงใน FIFO บนชิปขนาดเล็ก ขั้นตอน ISP ที่ทำงานบน MCU จะประมวลผลข้อมูลระหว่างทาง และเอ็นจิน DMA จะเขียนพิกเซลที่เสร็จสมบูรณ์ลงในบัฟเฟอร์เฟรมใน RAM ที่ออฟเซ็ตพิกเซลที่สอดคล้องกัน ไม่มีสิ่งใดในห่วงโซ่นั้นต้องการ CPU เมื่อช่อง DMA ได้รับการตั้งโปรแกรมแล้ว
เมื่อเรียก snapshot():
ไดรเวอร์ CSI ตั้งโปรแกรมเอ็นจิน DMA ด้วยที่อยู่ของบัฟเฟอร์เฟรม ความยาวการถ่ายโอน (พิกเซลหนึ่งเฟรม) และคอลแบ็กสำหรับอินเทอร์รัปต์ DMA เสร็จสิ้น
ไดรเวอร์เปิดใช้งานอุปกรณ์ต่อพ่วงอินพุตกล้องและรอให้เซนเซอร์ส่งสัญญาณเริ่มต้นของเฟรมถัดไป
ขณะที่เซนเซอร์สตรีมเฟรมออกมา อุปกรณ์ต่อพ่วงจะส่งไบต์พิกเซลแต่ละตัวผ่าน ISP และไปยังเอ็นจิน DMA ซึ่งเขียนผลลัพธ์ลงใน RAM ที่ออฟเซ็ตบัฟเฟอร์เฟรมถัดไป CPU สามารถทำงานโค้ดอื่นได้ระหว่างการถ่ายโอน
เมื่อพิกเซลสุดท้ายของเฟรมมาถึง DMA จะยิงอินเทอร์รัปต์เสร็จสิ้น ไดรเวอร์ครอบบัฟเฟอร์เฟรมใน
Imageและsnapshot()คืนค่าให้กับโค้ดผู้ใช้
Image ที่คืนค่ามาไม่ได้เป็นเจ้าของสำเนาของข้อมูลพิกเซล -- มันชี้ไปที่บัฟเฟอร์เฟรมของกล้องตัวใดตัวหนึ่งใน RAM จำนวนบัฟเฟอร์เฟรมที่กล้องเก็บ และวิธีที่ส่งต่อระหว่าง DMA และโค้ดผู้ใช้ในการเรียก snapshot() แต่ละครั้ง ขึ้นอยู่กับโหมดการบัฟเฟอร์ที่แอปพลิเคชันเลือกผ่าน framebuffers()