Nehmen Sie mit dem Raspberry Pi-Kameramodul in kurzer Zeit Bilder auf

13

Ich arbeite an einem Projekt, in dem ich mit dem Raspberry Pi-Kameramodul ungefähr 30 Bilder pro Sekunde (kein Film) aufnehmen muss.

Ich verwende dafür die Picamera-Bibliothek ( http://picamera.readthedocs.org/en/latest/api.html ), aber das Problem ist, dass das Aufnehmen eines Bildes etwa 0,2 - 0,4 Sekunden dauert, was viel zu lang ist. Ich habe die use_video_portEigenschaft bereits auf gesetzt True, was ein bisschen geholfen hat, aber die Zeit ist immer noch zu lang.

Weiß jemand von euch, wie man mit Python und dem Raspberry Pi-Kameramodul in kurzer Zeit (ca. 0,025 s) Bilder macht?

Timo Denk
quelle

Antworten:

18

Um mit Picamera Bilder in 0,025 s aufzunehmen, benötigen Sie eine Bildrate von mindestens 80 fps. Der Grund für die Anforderung von 80 statt 40 Bildern pro Sekunde (vorausgesetzt, 1 / 0.025 = 40) liegt darin, dass derzeit ein Problem vorliegt, bei dem jedes zweite Bild im Mehrbild-Encoder übersprungen wird, sodass sich die effektive Aufnahmerate auf die Hälfte der Bildrate der Kamera beläuft.

Das Pi-Kameramodul unterstützt in späteren Firmwares 80 Bilder pro Sekunde (siehe Kameramodi in den Picamera-Dokumenten), jedoch nur bei einer VGA-Auflösung (Anforderungen für höhere Auflösungen mit Bildraten> 30 Bilder pro Sekunde führen zu einer Hochskalierung von VGA auf die angeforderte Auflösung eine Einschränkung, der Sie sich auch bei 40 fps gegenübersehen würden). Das andere Problem, auf das Sie wahrscheinlich stoßen werden, sind Geschwindigkeitsbegrenzungen für SD-Karten. Mit anderen Worten, Sie müssen wahrscheinlich etwas Schnelleres wie einen Netzwerkanschluss oder In-Memory-Streams erfassen (vorausgesetzt, alle zu erfassenden Bilder passen in den Arbeitsspeicher).

Mit dem folgenden Skript erhalte ich eine Aufnahmerate von ~ 38 fps (dh knapp über 0,025 s pro Bild) auf einem Pi mit einer Übertaktung von 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)))

Wenn Sie zwischen den einzelnen Frames etwas tun möchten, ist dies auch möglich, capture_sequenceindem Sie anstelle einer Liste von Ausgängen eine Generatorfunktion bereitstellen:

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)))

Beachten Sie, dass im obigen Beispiel die Verarbeitung vor der nächsten Erfassung seriell erfolgt (dh, jede Verarbeitung, die Sie vornehmen, verzögert die nächste Erfassung zwangsläufig). Es ist möglich, diese Latenz mit Threading-Tricks zu reduzieren, dies ist jedoch mit einer gewissen Komplexität verbunden.

Möglicherweise möchten Sie auch nicht codierte Captures für die Verarbeitung untersuchen (wodurch der Aufwand für das Codieren und anschließende Decodieren von JPEGs entfällt). Beachten Sie jedoch, dass die CPU des Pi klein ist (insbesondere im Vergleich zur VideoCore-GPU). Während Sie in der Lage sein können Capture bei 40fps, gibt es keinen Weg wirst du in der Lage sein , bei 40fps jeder ernsthaften Verarbeitung dieses Rahmen durchzuführen , auch mit allen Tricks oben erwähnt. Die einzige realistische Möglichkeit, eine Frame-Verarbeitung mit dieser Rate durchzuführen, besteht darin, die Frames über ein Netzwerk an eine schnellere Maschine zu senden oder die Verarbeitung auf der GPU durchzuführen.

Dave Jones
quelle
Danke für Ihre schnelle Antwort! Aber in Ihrem Programm kann ich die einzelnen Bilder nicht verarbeiten, während .capture_sequence ausgeführt wird, oder? Gibt es eine Möglichkeit, dies zu tun? Weil ich mit jedem einzelnen Bild arbeiten muss, bevor das nächste ein Token ist.
Timo Denk
1
Die Antwort wurde dahingehend geändert, dass sie ein Verfahren zum Ausführen der Verarbeitung zwischen Frames mit einer Generatorfunktion enthält.
Dave Jones
.capture_sequence scheint KeyboardInterrupts zu ignorieren. Wissen Sie, wie Sie das umgehen können?
Cerin
@Cerin wie hoch wäre der stromverbrauch bei sowas?
Ted Taylor des Lebens
Das fps ist für diese Lösung schnell, aber wie kann man Bilder aus dem Stream in Dateien speichern?
Bakalolo
4

Entsprechend dieser StackOverflow-Antwort können Sie gstreamer und den folgenden Befehl verwenden, um die gewünschten Ergebnisse zu erzielen:

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

Dieser Befehl verwendet anscheinend die Videoausgabe von raspivid, um einen Videostream mit 25 Bildern pro Sekunde zu generieren, und konvertiert das Video dann mit gstreamer in einzelne JPEG-Bilder.

Dieser Artikel enthält Anweisungen zum Installieren von gstreamer1.0 aus einem alternativen Repository.

HeatfanJohn
quelle