Scatta immagini in breve tempo utilizzando il modulo fotocamera Raspberry Pi


13

Sto lavorando a un progetto in cui devo acquisire circa 30 immagini al secondo (senza filmato) utilizzando il modulo videocamera Raspberry Pi.

Sto usando la libreria Picamera ( http://picamera.readthedocs.org/en/latest/api.html ) per questo, ma il problema è che scattare una foto richiede circa 0,2 - 0,4 secondi, il che è troppo lungo. Ho già impostato la use_video_portproprietà su True, il che ha aiutato un po ', ma il tempo è ancora troppo lungo.

Qualcuno di voi sa come scattare foto in poco tempo (circa 0,025 secondi) usando Python e il modulo fotocamera Raspberry Pi?

Risposte:


18

Per scattare foto in 0,025 secondi con Picamera è necessario un frame rate maggiore o uguale a 80 fps. La ragione per richiedere 80 piuttosto 40 fps (dato che 1 / 0,025 = 40) è che attualmente c'è qualche problema che fa saltare ogni altro fotogramma nell'encoder multi-immagine in modo che la velocità di acquisizione effettiva finisca per metà del framerate della fotocamera.

Il modulo fotocamera del Pi è in grado di 80 fps nei firmware successivi (vedere le modalità della fotocamera nei documenti di Picamera), ma solo con una risoluzione VGA (richieste di risoluzioni più elevate con framerate> 30 fps comporteranno l'upscaling da VGA alla risoluzione richiesta, quindi questo è una limitazione che dovresti affrontare anche a 40 fps). L'altro problema che probabilmente incontrerai sono i limiti di velocità della scheda SD. In altre parole, probabilmente dovrai catturare qualcosa di più veloce come una porta di rete o flussi in memoria (supponendo che tutte le immagini che devi catturare si adattino alla RAM).

Il seguente script mi ​​dà una velocità di acquisizione di ~ 38fps (cioè appena sopra 0,025s per foto) su un Pi con overclock impostato su 900Mhz:

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

Se si desidera fare qualcosa tra un frame e l'altro, ciò è possibile anche capture_sequencefornendo una funzione del generatore anziché un elenco di output:

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

Tenere presente che nell'esempio sopra, l'elaborazione avviene in serie prima della successiva acquisizione (ovvero qualsiasi elaborazione effettuata ritarderà necessariamente la successiva acquisizione). È possibile ridurre questa latenza con trucchi di threading, ma ciò comporta una certa complessità.

Potresti anche voler esaminare le acquisizioni non codificate per l'elaborazione (che rimuovono il sovraccarico della codifica e quindi della decodifica dei JPEG). Tuttavia, tieni presente che la CPU del Pi è piccola (soprattutto rispetto alla GPU VideoCore). Mentre potresti essere in grado di catturare a 40fps, non puoi assolutamente eseguire alcuna elaborazione seria di quei frame a 40fps anche con tutti i trucchi sopra menzionati. L'unico modo realistico per eseguire l'elaborazione dei frame a tale velocità è spedire i frame su una rete a una macchina più veloce o eseguire l'elaborazione sulla GPU.


Grazie per la tua rapida risposta! Ma nel tuo programma non sarò in grado di elaborare le singole immagini mentre è in esecuzione .capture_sequence, giusto? C'è un modo per fare questo? Perché ho bisogno di lavorare con ogni singola immagine prima che sia il token successivo.
Timo Denk,

1
Modificata la risposta per includere un metodo per eseguire l'elaborazione tra i frame con una funzione generatore.
Dave Jones,

.capture_sequence sembra ignorare KeyboardInterrupts. Sai come aggirare questo?
Cerin,

@Cerin quale sarebbe il consumo di energia su qualcosa del genere?
Ted Taylor of Life,

L'FPS è veloce per questa soluzione ma come salvare le immagini in file dallo streaming?
Bakalolo,

4

Secondo questa risposta StackOverflow è possibile utilizzare gstreamer e il seguente comando per ottenere ciò che si desidera:

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

Questo comando sembra prendere l'uscita video di raspivid per generare un flusso video con 25 fotogrammi al secondo e quindi utilizzare gstreamer per convertire il video in singole immagini jpeg.

Questo articolo fornisce istruzioni su come installare gstreamer1.0 da un repository alternativo.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.