4.18. หลาย sensor

OpenMV Cam บางรุ่นจับคู่ image sensor สองตัวบนบอร์ดเดียวกัน -- ที่พบบ่อยที่สุดคือกล้องสีควบคู่กับ sensor ความร้อน FLIR® Lepton® แต่รูปแบบเดียวกันนี้ใช้กับบอร์ด colour-plus-event และฮาร์ดแวร์ dual-sensor ในอนาคต sensor แต่ละตัวมีอาร์เรย์พิกเซลของตัวเอง บัสควบคุมของตัวเอง และรันไปป์ไลน์ของตัวเองที่อัตราเฟรมของตัวเอง CSI API ขยายเพื่อรองรับ sensor เหล่านี้โดยให้แอปพลิเคชันสร้างอินสแตนซ์ CSI หนึ่งตัวต่อ sensor ทางกายภาพหนึ่งตัว

4.18.1. การเลือก sensor

ตัวสร้าง CSI รับอาร์กิวเมนต์ cid ที่ระบุ sensor ที่เฉพาะเจาะจงบนบอร์ด cid=-1 (ค่าเริ่มต้น) จะเลือก sensor หลัก ค่าคงที่ cid ที่ระบุชื่อจะเลือก sensor รองด้วย chip ID:

import csi

csi_rgb     = csi.CSI()                    # primary colour sensor
csi_thermal = csi.CSI(cid=csi.LEPTON)      # FLIR® Lepton®

อินสแตนซ์แต่ละตัวมีการกำหนดค่าของตัวเอง -- รูปแบบพิกเซล ขนาดเฟรม ตัวปรับ exposure / gain พูลบัฟเฟอร์เฟรม -- และถูก reset กำหนดค่า และอ่านอิสระจากตัวอื่น ค่าคงที่สำหรับ sensor รองที่รองรับ (LEPTON, GENX320, และค่าอื่น ๆ ที่ระบุในเอกสาร CSI) ระบุชิปที่แอปพลิเคชันคาดหวังบนพอร์ตรอง ไดรเวอร์จะล้มเหลวในการสร้างหากชิปจริงไม่ตรงกัน

4.18.2. การจับภาพจากทั้งสอง sensor

sensor แต่ละตัวรันไปป์ไลน์การจับภาพของตัวเองโดยอิสระจากตัวอื่น -- sensor สีอาจส่งสามสิบเฟรมต่อวินาทีในขณะที่ Lepton® ส่งเก้าเฟรม วิธีที่ตรงไปตรงมาในการจัดการกับความไม่ตรงกันนั้นคือให้ sensor ที่เร็วกว่าขับเคลื่อน loop และอ่าน sensor ที่ช้ากว่าแบบ non-blocking โดยรับสิ่งที่พร้อมอยู่และข้ามการวนซ้ำเมื่อไม่มีอะไรพร้อม:

import csi

csi_rgb     = csi.CSI()
csi_thermal = csi.CSI(cid=csi.LEPTON)

csi_rgb.reset()                        # powers the rail, pulses RESET
csi_rgb.pixformat(csi.RGB565)
csi_rgb.framesize(csi.QVGA)

csi_thermal.reset(hard=False)          # I2C reconfigure only
csi_thermal.pixformat(csi.GRAYSCALE)
csi_thermal.framesize(csi.QQVGA)

while True:
    rgb_img     = csi_rgb.snapshot()                  # blocks for next colour frame
    thermal_img = csi_thermal.snapshot(blocking=False)  # returns None if not ready
    if thermal_img is not None:
        # process aligned colour + thermal pair
        pass
    else:
        # process colour only on this iteration
        pass

snapshot() แบบ blocking ควบคุมความเร็วของ loop ส่วนแบบ non-blocking จะคืนเฟรมความร้อนล่าสุดเมื่อมีเฟรมใหม่มาตั้งแต่การเรียกก่อนหน้า และคืน None ในกรณีอื่น แอปพลิเคชันยังคงทำงานที่อัตราเฟรมของ sensor สีและได้รับเฟรมความร้อนทุกครั้งที่ Lepton® ผลิตออกมา

รูปแบบตรงกันข้าม -- snapshot แบบ blocking สองครั้งต่อกัน -- ก็ใช้ได้เช่นกัน แต่ loop จะทำงานที่อัตราช้าที่สุดของสอง sensor โดยไปป์ไลน์ของ sensor ที่เร็วกว่าจะหยุดระหว่างการวนซ้ำ เลือกอัตราที่การประมวลผลต้นทางของแอปพลิเคชันต้องการจะขับเคลื่อนจริง ๆ

4.18.3. การ reset บน power rail ที่ใช้ร่วมกัน

บอร์ด dual-sensor บางรุ่นรันทั้งสองชิปบน power rail เดียวหรือใช้สาย reset ร่วมกัน บนบอร์ดเหล่านั้น reset() ครั้งแรกจะเปิด rail และส่งสัญญาณที่ใช้ร่วมกัน การ reset ถัดมาบนอินสแตนซ์ CSI อื่นควรส่ง hard=False เพื่อให้โปรแกรมชิปของตัวเองใหม่โดยไม่ดึง sensor เพื่อนบ้านผ่านการ reset:

csi_rgb.reset()                        # primary -- powers the rail, pulses RESET
csi_thermal.reset(hard=False)          # secondary -- I2C reconfigure only

hard=True บน sensor รองในรูปแบบนี้จะ reset sensor หลักอีกครั้งเป็นผลข้างเคียง ทำให้การตั้งค่าที่แอปพลิเคชันได้ push ไปแล้วเสียหาย หน้าอ้างอิงสำหรับบอร์ด dual-sensor แต่ละรุ่นจะระบุว่า rail เป็นทรัพยากรร่วมหรือไม่

4.18.4. การเลือกแหล่ง stream

กล้องที่มี sensor สองตัวมีอินสแตนซ์ CSI สองตัว แต่ยังคงมีบัฟเฟอร์เฟรม stream เพียงอันเดียวระหว่างกัน อาร์กิวเมนต์ตัวสร้างจะเลือกว่าเฟรมของ sensor ใดจะป้อนการพรีวิว:

csi_rgb     = csi.CSI()                    # primary
csi_thermal = csi.CSI(cid=csi.LEPTON,
                      stream=True)         # preview source

stream=True ทำให้อินสแตนซ์ที่ระบุเป็นแหล่งข้อมูล หากไม่มีอาร์กิวเมนต์ stream= sensor หลัก (cid=-1 ค่าเริ่มต้น) จะเป็นแหล่งข้อมูล อินสแตนซ์ที่สร้างด้วย cid= ของ sensor รองจะเงียบในการพรีวิวเว้นแต่จะส่ง stream=True อย่างชัดเจน การเรียก snapshot() บน sensor ที่ไม่ได้เลือกยังคงจับเฟรมลงใน framebuffer ของ sensor นั้นตามปกติ -- พวกมันแค่ไม่อัปเดตการพรีวิว