ถ่ายภาพในเวลาอันสั้นโดยใช้โมดูลกล้อง Raspberry Pi


13

ฉันกำลังทำงานในโครงการที่ฉันต้องใช้ประมาณ 30 ภาพต่อวินาที (ไม่มีภาพยนตร์) โดยใช้โมดูลกล้อง Raspberry Pi

ฉันใช้ห้องสมุด Picamera ( http://picamera.readthedocs.org/en/latest/api.html ) สำหรับเรื่องนี้ แต่ปัญหาคือการถ่ายภาพใช้เวลาประมาณ 0.2 - 0.4 วินาทีซึ่งเป็นระยะเวลานาน ฉันได้ตั้งค่าuse_video_portคุณสมบัติเป็นTrueแล้วซึ่งช่วยได้เล็กน้อย แต่เวลาก็ยังคงยาวนาน

มีใครบ้างที่รู้วิธีถ่ายภาพในเวลาอันรวดเร็ว (ประมาณ 0.025 วินาที) โดยใช้ Python และโมดูลกล้อง Raspberry Pi?

คำตอบ:


18

ในการถ่ายภาพด้วย Picamera 0.025s คุณจะต้องมีอัตราเฟรมมากกว่าหรือเท่ากับ 80fps เหตุผลที่ต้องใช้ 80 ค่อนข้าง 40fps (ระบุว่า 1 / 0.025 = 40) คือในปัจจุบันมีปัญหาบางอย่างที่ทำให้เฟรมอื่น ๆ ข้ามไปในตัวเข้ารหัสหลายภาพเพื่อให้อัตราการจับภาพมีประสิทธิภาพขึ้นครึ่งเฟรมของกล้อง

โมดูลกล้องของ Pi มีความสามารถ 80fps ในเฟิร์มแวร์ในภายหลัง (ดูโหมดกล้องใน picamera docs) แต่เฉพาะที่ความละเอียด VGA (การร้องขอความละเอียดสูงกว่าด้วย framerates> 30fps จะทำให้การลดอัตราการสุ่มจาก VGA เป็นความละเอียดที่ร้องขอ ข้อ จำกัด ที่คุณต้องเผชิญคือ 40fps) ปัญหาอื่น ๆ ที่คุณอาจพบคือข้อ จำกัด ความเร็วของการ์ด SD กล่าวอีกนัยหนึ่งคุณอาจต้องจับภาพไปยังสิ่งที่เร็วกว่าเช่นพอร์ตเครือข่ายหรือสตรีมในหน่วยความจำ (สมมติว่าภาพทั้งหมดที่คุณต้องการถ่ายจะพอดีใน RAM)

สคริปต์ต่อไปนี้ทำให้ฉันมีอัตราการจับ ~ 38fps (เช่นสูงกว่า 0.025s ต่อรูป) บน Pi ที่มีการโอเวอร์คล็อกตั้งค่าเป็น 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)))

หากคุณต้องการทำบางสิ่งบางอย่างระหว่างแต่ละเฟรมสิ่งนี้อาจเกิดขึ้นได้แม้จะมี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 มีขนาดเล็ก (โดยเฉพาะเมื่อเทียบกับ VideoCore GPU) แม้ว่าคุณจะสามารถจับภาพที่ 40fps ได้ แต่ก็ไม่มีทางที่คุณจะสามารถทำการประมวลผลที่จริงจังของเฟรมเหล่านั้นที่ 40fps ได้แม้จะมีเทคนิคทั้งหมดที่กล่าวมาข้างต้น วิธีเดียวที่เป็นจริงในการประมวลผลเฟรมในอัตรานั้นคือจัดส่งเฟรมผ่านเครือข่ายไปยังเครื่องที่เร็วขึ้นหรือทำการประมวลผลบน GPU


ขอบคุณสำหรับการตอบกลับที่รวดเร็วของคุณ! แต่ในโปรแกรมของคุณฉันจะไม่สามารถประมวลผลรูปภาพแต่ละภาพในขณะที่. captture_sequence ทำงานใช่ไหม มีวิธีทำเช่นนี้หรือไม่? เพราะฉันต้องทำงานกับภาพทุกภาพก่อนที่จะต่อไปคือโทเค็น
Timo Denk

1
แก้ไขคำตอบเพื่อรวมวิธีการประมวลผลระหว่างเฟรมด้วยฟังก์ชันตัวสร้าง
เดฟโจนส์

.capture_sequence ปรากฏขึ้นเพื่อละเว้น KeyboardInterrupts คุณรู้วิธีแก้ปัญหานี้หรือไม่?
Cerin

@Cerin การใช้พลังงานของสิ่งนี้จะเป็นอย่างไร
เทดเทย์เลอร์แห่งชีวิต

fps เร็วสำหรับโซลูชันนี้ แต่จะบันทึกรูปภาพไปยังไฟล์จากสตรีมได้อย่างไร
bakalolo

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.