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.