Raspberry Piカメラモジュールを使用して短時間で画像を撮影する


13

Raspberry Piカメラモジュールを使用して、1秒あたり約30枚の画像(映画なし)を撮影する必要があるプロジェクトに取り組んでいます。

私はそのためにPicameraライブラリ(http://picamera.readthedocs.org/en/latest/api.html)を使用していますが、問題は、写真を撮るのに約0.2-0.4 秒かかることです。すでにuse_video_portプロパティをTrueに設定していますが、これは少し役立ちましたが、まだ時間がかかります。

PythonとRaspberry Piカメラモジュールを使用して、短時間(約0.025秒)で写真​​を撮る方法を知っている人はいますか?

回答:


18

picameraで0.025秒で写真を撮るには、80fps以上のフレームレートが必要です。40fpsではなく80fps(1 / 0.025 = 40と仮定)が必要な理由は、現在、マルチイメージエンコーダーで1つおきのフレームがスキップされ、有効なキャプチャレートがカメラのフレームレートの半分になるという問題があるためです。

Piのカメラモジュールは、後のファームウェアで8​​0fpsが可能です(picameraのドキュメントのカメラモードを参照)。ただし、VGA解像度でのみ(フレームレート> 30fpsでより高い解像度を要求すると、VGAから要求された解像度にアップスケーリングされます) 40fpsでも直面する制限)。発生する可能性のある他の問題は、SDカードの速度制限です。つまり、おそらくネットワークポートやメモリ内ストリームなど、より高速なものにキャプチャする必要があります(キャプチャする必要があるすべての画像がRAMに収まると仮定します)。

次のスクリプトは、オーバークロックが900Mhzに設定されているPiで〜38fps(つまり、1枚あたり0.025秒を少し上回る)のキャプチャレートを取得します。

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

各フレームの間に何かをしたい場合はcapture_sequence、出力のリストの代わりにジェネレーター関数を提供することでも可能です。

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

上記の例では、処理は次のキャプチャの前に連続して行われていることに注意してください(つまり、処理を行うと必ず次のキャプチャが遅延します)。スレッドトリックを使用してこのレイテンシを短縮することは可能ですが、そのためにはある程度の複雑さが伴います。

また、処理のためにエンコードされていないキャプチャを確認することもできます(これにより、JPEGのエンコードとデコードのオーバーヘッドが除去されます)。ただし、PiのCPUは小さいことに注意してください(特にVideoCore GPUと比較して)。40fpsでキャプチャできる場合もありますが、上記のすべてのトリックを使用しても、40fpsでこれらのフレームの深刻な処理を実行できる方法はありません。そのレートでフレーム処理を実行する唯一の現実的な方法は、ネットワークを介してより高速なマシンにフレームを送信するか、GPUで処理を実行することです。


迅速な返信ありがとうございます!しかし、あなたのプログラムでは、.capture_sequenceの実行中に個々の写真を処理することはできませんよね?これを行う方法はありますか?次のものがトークンになる前に、私はすべての個々の写真を扱う必要があるからです。
ティモデンク14

1
ジェネレーター関数を使用してフレーム間で処理を実行する方法を含めるように回答を修正しました。
デイブジョーンズ14

.capture_sequenceはKeyboardInterruptsを無視するようです。これを回避する方法を知っていますか?
セリン

@Cerinこのようなものの電力消費量はどうなりますか?
テッドテイラーオブライフ

fpsはこのソリューションでは高速ですが、ストリームからファイルに画像を保存する方法は?
バカロロ

4

このStackOverflowの回答によると、gstreamerと次のコマンドを使用して、目的を達成できます。

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

このコマンドは、raspividのビデオ出力を取得して25フレーム/秒のビデオストリームを生成し、gstreamerを使用してビデオを個々のjpegイメージに変換するようです。

この記事では、代替リポジトリからgstreamer1.0をインストールする方法について説明します。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.