Prenez des images en peu de temps à l'aide du module de caméra Raspberry Pi


13

Je travaille sur un projet dans lequel je dois prendre environ 30 images par seconde (pas de film) en utilisant le module de caméra Raspberry Pi.

J'utilise la bibliothèque Picamera ( http://picamera.readthedocs.org/en/latest/api.html ) pour cela, mais le problème est que prendre une photo prend environ 0,2 à 0,4 seconde, ce qui est beaucoup trop long. J'ai déjà défini la use_video_portpropriété sur True, ce qui a un peu aidé, mais le temps est encore trop long.

Est-ce que quelqu'un d'entre vous sait comment prendre des photos en peu de temps (environ 0,025 s) en utilisant Python et le module de caméra Raspberry Pi?

Réponses:


18

Pour prendre des photos en 0,025 s avec picamera, vous aurez besoin d'une fréquence d'images supérieure ou égale à 80 ips. La raison pour laquelle il faut 80 à 40 images par seconde (étant donné que 1 / 0,025 = 40) est qu'actuellement, il y a un problème qui fait que toutes les autres images sont ignorées dans l'encodeur multi-images, de sorte que le taux de capture effectif se retrouve à la moitié de la fréquence d'images de l'appareil photo.

Le module de caméra du Pi est capable de 80 images par seconde dans les firmwares ultérieurs (voir les modes de caméra dans les documents picamera), mais uniquement à une résolution VGA (les demandes de résolutions plus élevées avec des cadences de trame > 30 images par seconde entraîneront une mise à l'échelle de VGA vers la résolution demandée, c'est donc une limitation que vous rencontriez même à 40 images par seconde). L'autre problème que vous rencontrerez probablement est la limitation de vitesse de la carte SD. En d'autres termes, vous devrez probablement capturer vers quelque chose de plus rapide comme un port réseau ou des flux en mémoire (en supposant que toutes les images que vous devez capturer tiendront dans la RAM).

Le script suivant me permet d'obtenir un taux de capture de ~ 38 ips (c'est-à-dire juste au-dessus de 0,025 s par image) sur un Pi avec un overclocking réglé à 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)))

Si vous souhaitez faire quelque chose entre chaque trame, cela est possible même capture_sequenceen fournissant une fonction de générateur au lieu d'une liste de sorties:

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

Gardez à l'esprit que dans l'exemple ci-dessus, le traitement se produit en série avant la prochaine capture (c'est-à-dire que tout traitement que vous effectuez retardera nécessairement la prochaine capture). Il est possible de réduire cette latence avec des astuces de threading mais cela implique une certaine complexité.

Vous pouvez également examiner les captures non encodées pour le traitement (ce qui supprime la surcharge d'encodage puis de décodage des JPEG). Cependant, gardez à l'esprit que le processeur du Pi est petit (surtout par rapport au GPU VideoCore). Bien que vous puissiez capturer à 40 images par seconde, il est impossible que vous puissiez effectuer un traitement sérieux de ces images à 40 images par seconde, même avec toutes les astuces mentionnées ci-dessus. La seule façon réaliste d'effectuer le traitement des trames à ce rythme est d'expédier les trames sur un réseau vers une machine plus rapide ou d'effectuer le traitement sur le GPU.


Merci pour votre réponse rapide! Mais dans votre programme, je ne pourrai pas traiter les images individuelles pendant l'exécution de .capture_sequence, n'est-ce pas? Y a-t-il un moyen de faire cela? Parce que je dois travailler avec chaque image individuelle avant que la prochaine ne soit symbolique.
Timo Denk

1
Modification de la réponse pour inclure une méthode d'exécution du traitement entre les trames avec une fonction de générateur.
Dave Jones

.capture_sequence semble ignorer KeyboardInterrupts. Savez-vous comment contourner cela?
Cerin

@Cerin quelle serait la consommation d'énergie sur quelque chose comme ça?
Ted Taylor of Life

Le fps est rapide pour cette solution, mais comment enregistrer des images dans des fichiers à partir d'un flux?
Bakalolo

4

Selon cette réponse StackOverflow, vous pouvez utiliser gstreamer et la commande suivante pour accomplir ce que vous voulez:

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

Cette commande semble prendre la sortie vidéo de raspivid pour générer un flux vidéo avec 25 images par seconde, puis utiliser gstreamer pour convertir la vidéo en images jpeg individuelles.

Cet article explique comment installer gstreamer1.0 à partir d'un autre référentiel.

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.