4.18. Wiele sensorów#

Garstka kamer OpenMV Cam łączy dwa sensory obrazu na tej samej płytce – najczęściej kamerę kolorową obok termicznego sensora FLIR® Lepton®, ale ten sam schemat dotyczy płytek typu kolor plus zdarzenia oraz dowolnego przyszłego sprzętu z dwoma sensorami. Każdy sensor ma własną matrycę pikseli, własną magistralę sterującą i obsługuje własny potok z własną częstotliwością ramek. API CSI rozszerza się, aby je obsłużyć, pozwalając aplikacji utworzyć po jednym obiekcie CSI dla każdego fizycznego sensora.

4.18.1. Wybór sensora#

Konstruktor CSI przyjmuje argument cid, który nazywa konkretny sensor na płytce. cid=-1 (wartość domyślna) wybiera sensor podstawowy; nazwane stałe cid wybierają sensor dodatkowy według identyfikatora układu:

import csi

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

Każda instancja posiada własną konfigurację – format pikseli, rozmiar ramki, pokrętła ekspozycji / wzmocnienia, pulę bufora ramki – i jest resetowana, konfigurowana oraz odczytywana niezależnie od pozostałych. Stałe dla obsługiwanych sensorów dodatkowych (LEPTON, GENX320 oraz inne wymienione w dokumentacji CSI) nazywają układ, którego aplikacja oczekuje na porcie dodatkowym; sterownik przerywa konstrukcję, jeśli faktyczny układ się nie zgadza.

4.18.2. Przechwytywanie z obu sensorów#

Każdy sensor obsługuje swój potok przechwytywania niezależnie od drugiego – sensor kolorowy może dostarczać trzydzieści ramek na sekundę, podczas gdy Lepton® dostarcza dziewięć. Najprostszym sposobem obsługi tej rozbieżności jest pozwolenie, by pętlą sterował szybszy sensor, a wolniejszy sensor odczytywać w trybie nieblokującym, biorąc to, co jest gotowe, i pomijając iterację, gdy nic nie ma:

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

Blokujący snapshot() nadaje tempo pętli; wersja nieblokująca zwraca najnowszą ramkę termiczną, gdy świeża pojawiła się od czasu poprzedniego wywołania, a w przeciwnym razie None. Aplikacja działa nadal z częstotliwością ramek sensora kolorowego i otrzymuje ramkę termiczną zawsze, gdy Lepton® ją wyprodukuje.

Przeciwny wzorzec – dwa blokujące zrzuty obrazu jeden po drugim – również działa, ale pętla działa wtedy z wolniejszą z częstotliwości obu sensorów, a potok szybszego sensora zacina się pomiędzy iteracjami. Wybierz tę częstotliwość, którą faktycznie ma sterować dalsze przetwarzanie w aplikacji.

4.18.3. Reset na współdzielonych szynach zasilania#

Niektóre płytki z dwoma sensorami zasilają oba układy z jednej szyny zasilania lub współdzielą linię resetu. Na takich płytkach pierwszy reset() podnosi szynę i wysyła impuls na współdzielonym sygnale; kolejne resety na pozostałych instancjach CSI powinny przekazywać hard=False, aby przeprogramowały tylko własny układ, nie przeciągając sąsiada przez reset:

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

hard=True na instancji dodatkowej w tym układzie spowodowałoby ponowny reset instancji podstawowej jako efekt uboczny, niwecząc całą konfigurację, którą aplikacja już wprowadziła. Strona dokumentacji każdej płytki z dwoma sensorami wskazuje, czy szyny są współdzielone.

4.18.4. Wybór źródła strumienia#

Kamery z dwoma sensorami mają dwie instancje CSI, ale wciąż tylko jeden wspólny bufor ramki strumienia. Argument konstruktora wybiera, których ramek sensora używa podgląd:

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

stream=True ustawia nazwaną instancję jako źródło. Bez argumentu stream= źródłem jest sensor podstawowy (cid=-1, wartość domyślna); instancje zbudowane z cid= sensora dodatkowego pozostają milczące na podglądzie, chyba że stream=True zostanie przekazane jawnie. Wywołania snapshot() na niewybranym sensorze nadal przechwytują ramki do buforów ramki tego sensora w normalny sposób – po prostu nie aktualizują podglądu.