Rób zdjęcia w krótkim czasie za pomocą modułu kamery Raspberry Pi

13

Pracuję nad projektem, w którym muszę wykonać około 30 zdjęć na sekundę (bez filmu) przy użyciu modułu kamery Raspberry Pi.

Używam do tego biblioteki Picamera ( http://picamera.readthedocs.org/en/latest/api.html ), ale problem polega na tym, że zrobienie zdjęcia zajmuje około 0,2 - 0,4 sekundy, co jest bardzo długie. Ustawiłem już use_video_portwłaściwość na True, co trochę pomogło, ale czas jest jeszcze za długi.

Czy ktoś z was wie, jak robić zdjęcia w krótkim czasie (około 0,025 s) przy użyciu Pythona i modułu aparatu Raspberry Pi?

Timo Denk
źródło

Odpowiedzi:

18

Aby robić zdjęcia za pomocą aparatu fotograficznego w 0,025 s, potrzebujesz szybkości klatek większej lub równej 80 fps. Powodem, dla którego wymagane jest 80, a raczej 40 klatek na sekundę (biorąc pod uwagę, że 1 / 0,025 = 40) jest to, że obecnie istnieje problem, który powoduje, że każda inna klatka jest pomijana w koderze wielu obrazów, więc efektywna szybkość przechwytywania kończy się o połowę liczby klatek na sekundę w aparacie.

Moduł aparatu Pi jest zdolny do 80 klatek na sekundę w późniejszych wersjach oprogramowania układowego (patrz tryby aparatu w dokumentacji aparatu), ale tylko przy rozdzielczości VGA (prośby o wyższe rozdzielczości z liczbą klatek na sekundę> 30 klatek na sekundę spowodują zwiększenie rozdzielczości z VGA do żądanej rozdzielczości, więc jest to ograniczenie, z którym miałbyś do czynienia nawet przy 40 klatkach na sekundę). Innym problemem, który prawdopodobnie napotkasz, są ograniczenia prędkości karty SD. Innymi słowy, prawdopodobnie będziesz musiał przechwycić coś szybciej, jak port sieciowy lub strumienie w pamięci (zakładając, że wszystkie obrazy, które musisz przechwycić zmieści się w pamięci RAM).

Poniższy skrypt daje mi szybkość przechwytywania ~ 38 fps (tj. Nieco powyżej 0,025 s na zdjęcie) na Pi z podkręcaniem ustawionym na 900 MHz:

import io
import time
import picamera

with picamera.PiCamera() as camera:
    # Set the camera's resolution to VGA @40fps and give it a couple
    # of seconds to measure exposure etc.
    camera.resolution = (640, 480)
    camera.framerate = 80
    time.sleep(2)
    # Set up 40 in-memory streams
    outputs = [io.BytesIO() for i in range(40)]
    start = time.time()
    camera.capture_sequence(outputs, 'jpeg', use_video_port=True)
    finish = time.time()
    # How fast were we?
    print('Captured 40 images at %.2ffps' % (40 / (finish - start)))

Jeśli chcesz zrobić coś pomiędzy każdą ramką, jest to możliwe nawet capture_sequencepoprzez podanie funkcji generatora zamiast listy wyjść:

import io
import time
import picamera
#from PIL import Image

def outputs():
    stream = io.BytesIO()
    for i in range(40):
        # This returns the stream for the camera to capture to
        yield stream
        # Once the capture is complete, the loop continues here
        # (read up on generator functions in Python to understand
        # the yield statement). Here you could do some processing
        # on the image...
        #stream.seek(0)
        #img = Image.open(stream)
        # Finally, reset the stream for the next capture
        stream.seek(0)
        stream.truncate()

with picamera.PiCamera() as camera:
    camera.resolution = (640, 480)
    camera.framerate = 80
    time.sleep(2)
    start = time.time()
    camera.capture_sequence(outputs(), 'jpeg', use_video_port=True)
    finish = time.time()
    print('Captured 40 images at %.2ffps' % (40 / (finish - start)))

Należy pamiętać, że w powyższym przykładzie przetwarzanie odbywa się szeregowo przed następnym przechwytywaniem (tzn. Każde wykonane przetwarzanie koniecznie opóźnia następne przechwytywanie). Możliwe jest zmniejszenie tego opóźnienia dzięki sztuczkom wątkowym, ale powoduje to pewną złożoność.

Możesz także zajrzeć do niezakodowanych przechwytywania do przetwarzania (które usuwają narzut związany z kodowaniem, a następnie dekodowaniem plików JPEG). Należy jednak pamiętać, że procesor Pi jest niewielki (szczególnie w porównaniu do GPU VideoCore). Chociaż możesz być w stanie uchwycić przy 40 klatkach na sekundę, nie ma mowy, abyś był w stanie wykonać jakiekolwiek poważne przetwarzanie tych klatek przy 40 klatkach na sekundę, nawet przy wszystkich wymienionych wyżej sztuczkach. Jedynym realistycznym sposobem wykonywania przetwarzania ramek z tą prędkością jest wysyłanie ramek przez sieć na szybszą maszynę lub przetwarzanie na GPU.

Dave Jones
źródło
Dziękuję za szybką odpowiedź! Ale w twoim programie nie będę w stanie przetwarzać poszczególnych zdjęć podczas działania .capture_sequence, prawda? Czy jest na to sposób? Ponieważ muszę pracować z każdym pojedynczym obrazem, zanim następny będzie tokenem.
Timo Denk,
1
Zmieniono odpowiedź, aby uwzględnić metodę wykonywania przetwarzania między ramkami za pomocą funkcji generatora.
Dave Jones
Wygląda na to, że .capture_sequence ignoruje KeyboardInterrupts. Czy wiesz jak to obejść?
Cerin,
@Cerin, jaki byłby pobór mocy na czymś takim?
Ted Taylor of Life
Fps jest szybkie dla tego rozwiązania, ale jak zapisać obrazy do plików ze strumienia?
bakalolo
4

Zgodnie z odpowiedzią StackOverflow możesz użyć gstreamer i następującej komendy, aby osiągnąć to, co chcesz:

raspivid -n -t 1000000 -vf -b 2000000 -fps 25 -o - | gst-launch-1.0 fdsrc ! video/x-h264,framerate=25/1,stream-format=byte-stream ! decodebin ! videorate ! video/x-raw,framerate=10/1 ! videoconvert ! jpegenc ! multifilesink location=img_%04d.jpg

Wydaje się, że to polecenie pobiera wyjście wideo Raspivid w celu wygenerowania strumienia wideo z 25 klatkami na sekundę, a następnie użyj programu gstreamer do konwersji wideo na pojedyncze obrazy JPEG.

W tym artykule znajdują się instrukcje instalacji gstreamer1.0 z alternatywnego repozytorium.

Fan wentylatora John
źródło