Ambil gambar dalam waktu singkat menggunakan modul kamera Raspberry Pi

13

Saya sedang mengerjakan sebuah proyek di mana saya perlu mengambil sekitar 30 gambar per detik (tidak ada film) menggunakan modul kamera Raspberry Pi.

Saya menggunakan perpustakaan Picamera ( http://picamera.readthedocs.org/en/latest/api.html ) untuk itu tetapi masalahnya adalah, bahwa mengambil gambar membutuhkan waktu sekitar 0,2 - 0,4 detik yang merupakan cara lama. Saya sudah mengatur use_video_portproperti True, yang sedikit membantu, tetapi waktunya masih lama.

Apakah ada di antara Anda yang tahu cara mengambil gambar dalam waktu singkat (sekitar 0,025 detik) menggunakan modul kamera Python dan Raspberry Pi?

Timo Denk
sumber

Jawaban:

18

Untuk mengambil gambar dalam jarak 0,025 detik dengan kamera digital, Anda memerlukan kecepatan bingkai lebih dari atau sama dengan 80fps. Alasan untuk membutuhkan 80 lebih dari 40fps (mengingat bahwa 1 / 0,025 = 40) adalah bahwa saat ini ada beberapa masalah yang menyebabkan setiap bingkai lainnya dilewati dalam multi-image encoder sehingga tingkat pengambilan gambar yang efektif berakhir sebagai setengah dari framerate kamera.

Modul kamera Pi mampu menghasilkan 80fps di firmware berikutnya (lihat mode kamera dalam dokumentasi kamera), tetapi hanya pada resolusi VGA (permintaan untuk resolusi yang lebih tinggi dengan framerate> 30fps akan menghasilkan peningkatan dari VGA ke resolusi yang diminta, jadi ini adalah batasan yang akan Anda hadapi bahkan pada 40fps). Masalah lain yang mungkin Anda temui adalah keterbatasan kecepatan kartu SD. Dengan kata lain, Anda mungkin perlu menangkap sesuatu yang lebih cepat seperti port jaringan atau aliran dalam memori (dengan asumsi semua gambar yang Anda perlu ambil akan sesuai dengan RAM).

Script berikut memberi saya tingkat penangkapan ~ 38fps (yaitu tepat di atas 0,025s per pic) pada Pi dengan overclocking yang diatur ke 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)))

Jika Anda ingin melakukan sesuatu di antara setiap frame, ini dimungkinkan bahkan dengan capture_sequencemenyediakan fungsi generator alih-alih daftar 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)))

Ingatlah bahwa dalam contoh di atas, pemrosesan terjadi secara serial sebelum penangkapan berikutnya (yaitu pemrosesan yang Anda lakukan tentu akan menunda penangkapan berikutnya). Dimungkinkan untuk mengurangi latensi ini dengan trik threading tetapi melakukan itu melibatkan sejumlah kompleksitas.

Anda mungkin juga ingin melihat ke dalam tangkapan yang tidak disandikan untuk diproses (yang menghapus overhead pengkodean dan kemudian mendekode JPEG). Namun, perlu diingat bahwa CPU Pi kecil (terutama dibandingkan dengan GPU VideoCore). Meskipun Anda mungkin dapat menangkap di 40fps, tidak ada cara Anda akan dapat melakukan pemrosesan serius dari frame tersebut di 40fps bahkan dengan semua trik yang disebutkan di atas. Satu-satunya cara realistis untuk melakukan pemrosesan frame pada tingkat itu adalah mengirimkan frame melalui jaringan ke mesin yang lebih cepat, atau melakukan pemrosesan pada GPU.

Dave Jones
sumber
Terima kasih atas balasan cepat Anda! Tetapi dalam program Anda, saya tidak akan dapat memproses gambar individu saat .capture_afterence berjalan, kan? Apakah ada cara untuk melakukan ini? Karena saya perlu bekerja dengan setiap gambar individu sebelum yang berikutnya adalah token.
Timo Denk
1
Mengubah jawaban untuk memasukkan metode melakukan pemrosesan antara frame dengan fungsi generator.
Dave Jones
.capture_ berikutnyaence tampaknya mengabaikan KeyboardInterrupts. Apakah Anda tahu cara mengatasi ini?
Cerin
@ Cerin apa yang akan konsumsi daya pada sesuatu seperti ini?
Ted Taylor dari Life
Fps cepat untuk solusi ini tetapi bagaimana cara menyimpan gambar ke file dari aliran?
akanolo
4

Menurut jawaban StackOverflow ini Anda dapat menggunakan gstreamer dan perintah berikut untuk mencapai apa yang Anda inginkan:

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

Perintah ini tampaknya mengambil output video raspivid untuk menghasilkan aliran video dengan 25 frame per detik dan kemudian menggunakan gstreamer untuk mengkonversi video ke gambar jpeg individu.

Artikel ini memberikan instruksi tentang cara menginstal gstreamer1.0 dari repositori alternatif.

HeatfanJohn
sumber