0

I'm currently writing a python script which needs to capture an image. I'm currently using PiCamera.capture() to accomplish this, but it takes too long to capture images. The project requires as high of a resolution as possible, so I cannot reduce the resolution below the max of 2592x1944 (for my current camera module).

This script shows the issue with PiCamera.capture():

import time
from picamera import PiCamera
from io import BytesIO

cam = PiCamera()

start = time.time()
cam.start_preview()
print("preview start:", time.time() - start, "seconds")

# 2592x1944 test
cam.resolution = (2592, 1944)
time.sleep(2)   # give it time to change resolution
start = time.time()
cam.capture("test-2592x1944.png")
print("2592x1944 capture:", time.time() - start, "seconds")

# 640x480 test
cam.resolution = (640, 480)
time.sleep(2)   # give it time to change resolution
start = time.time()
cam.capture("test-640x480.png")
print("  640x480 capture:", time.time() - start, "seconds")

# 2592x1944 test with IO stream
cam.resolution = (2592, 1944)
time.sleep(2)   # give it time to change resolution
my_stream = BytesIO()
start = time.time()
cam.capture(my_stream, "png")
print("2592x1944 capture with stream:", time.time() - start, "seconds")

It gives the following output:

preview start: 0.017431259155273438 seconds
2592x1944 capture: 13.869317054748535 seconds
  640x480 capture: 1.24507474899292 seconds
2592x1944 capture with stream: 13.91780948638916 seconds

I don't mind a capture taking a few seconds, but over 13 seconds is too long. Capturing to a stream instead of a file doesn't help either, as you can see. How can I reduce the time of capturing without reducing the resolution, either within the PiCamera library or outside it?


Addressing why this shouldn't be closed as duplicate

I'm aware of two questions which ask similar questions. This question is not answered by them for the following reasons:

3
  • it really is a duplicate of the previous question ... the previous question was not answered though ... a suggestion was made how to isolate the area that is causing the slowness ... try researching in the Linux realm, not in RPi realm
    – jsotola
    Jun 10 at 0:21
  • @jsotola yeah, I guess you're right that it's a duplicate, but the previous question was unanswered so I feel like the way I'm approaching this is correct. If you've got a meta post or conduct rule suggesting otherwise though, feel free to provide it. And do you think this is an issue with Linux? I thought it would've been about the RPi since it's a PiCamera, but perhaps the question applies more generally to Linux OSs. I'd be ok with a migrate if so
    – Drake P
    Jun 10 at 4:17
  • 1
    i do not know what causes the slowness ... it's just that you may be limiting your success of resolution if you search only at Raspberry Pi websites
    – jsotola
    Jun 10 at 5:58
0

I still don't know why the PiCamera library's capture() function takes so long, but I found out that other formats run faster, which is sufficient for my needs. For reference, the PiCamera API says that it supports the formats jpeg, png, gif, bmp, yuv, rgb, rgba, bgr, and bgra.

Here's the script I used to test the capture times of each of these:

import time
from picamera import PiCamera
from io import BytesIO

cam = PiCamera()

def capture_time_test(img_format):
    cam.resolution = (2592, 1944)
    time.sleep(2)   # give it time to change resolution
    start = time.time()
    cam.capture("test-2592x1944." + img_format, format=img_format)
    print("2592x1944", img_format, "capture:", time.time() - start, "seconds")

start = time.time()
cam.start_preview()
print("preview start:", time.time() - start, "seconds")

print("\nLossy formats:")
capture_time_test('jpeg')
capture_time_test('gif')

print("\nLossless formats:")
capture_time_test('png')
capture_time_test('bmp')

print("\nRaw formats (also lossless):")
capture_time_test('yuv')
capture_time_test('rgb')
capture_time_test('rgba')
capture_time_test('bgr')
capture_time_test('bgra')

And here's the output:

preview start: 0.016833066940307617 seconds

Lossy formats:
2592x1944 jpeg capture: 0.6489131450653076 seconds
2592x1944 gif capture: 3.7407095432281494 seconds

Lossless formats:
2592x1944 png capture: 13.806164026260376 seconds
2592x1944 bmp capture: 3.9124062061309814 seconds

Raw formats (also lossless):
/usr/lib/python3/dist-packages/picamera/encoders.py:544: PiCameraResolutionRounded: frame size rounded up from 2592x1944 to 2592x1952
  width, height, fwidth, fheight)))
2592x1944 yuv capture: 0.5650444030761719 seconds
2592x1944 rgb capture: 0.6608328819274902 seconds
2592x1944 rgba capture: 0.7124671936035156 seconds
2592x1944 bgr capture: 0.7082788944244385 seconds
2592x1944 bgra capture: 0.7393949031829834 seconds

Raw formats work for my use-case and take only about half a second to capture at the given resolution, which is sufficient for me (and if I need other formats, I can process the raw into it in a separate thread).

If anyone has a solution for faster capturing in the other formats, please post it as an answer. :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.