raspberrypi / picamera2

New libcamera based python library
BSD 2-Clause "Simplified" License
891 stars 188 forks source link

[SUGGESTION] Set timeout for autofocus #884

Open siranshen opened 11 months ago

siranshen commented 11 months ago

Is your feature request related to a problem? Please describe. If you call Picamera2#autofocus_cycle with Camera V3 in certain positions (facing down on a table or facing up to an empty ceiling), the autofocus process will take a really long time, about 25 seconds in my case.

Reproducible by the following code:

import time
from picamera2 import Picamera2

picam2 = Picamera2()
capture_config = picam2.create_still_configuration()
picam2.start(config=capture_config)
print('Started')

print('Starting autofocus')
start_time = time.time()
success = picam2.autofocus_cycle()
print(f'Autofocused: {success}, {time.time() - start_time}s')
print('Taking photo')
picam2.capture_file("test.jpg")
print('Photo taken')

Describe the solution you'd like Be able to set a timeout for autofocus.

Describe alternatives you've considered Check if the job has finished after a period of time and cancel the job by code if it is still not done. There currently seems no good way to check if job has finished or not, either.

davidplowman commented 11 months ago

Hi, thanks for the suggestion. I'm sure we could add some kind of a timeout so that you could tell if a job has finished, or discover if it hasn't finished after a certain amount of time.

In the meantime, I think you can probably cancel an AF cycle with

picam2.set_controls({'AfTrigger': libcamera.controls.AfTriggerEnum.Cancel})

(or just use the value 1 instead of that long enum).

Nonetheless, 25 seconds sounds like a rather long time for it be taking in cases where it is going to fail anyway. @njhollinghurst Do you think there might be anything we can do about that?

njhollinghurst commented 11 months ago

I'll investigate to check that it's actually taking that long and is not some kind of race condition (but then I'd expect it to take forever). But I suspect it's doing the AF sweep at full-frame size at 10fps, which will be slower than at 30fps.

davidplowman commented 11 months ago

That's true, full resolution is not the best choice for an AF cycle because of the slow framerate. Additionally, by default the still configuration uses only one buffer (to save memory), which probably means that every other frame gets dropped. But even so, 25 seconds is going to be over 100 frames which feels quite high.

@siranshen Could you maybe start the camera in preview mode and do the AF cycle, before switching to capture mode? It sounds like that should complete much more quickly. If you can't, try adding buffer_count=3 to your configuration as that should make it quicker too (so long as you have sufficient memory).

davidplowman commented 11 months ago

I've at a go at reproducing this. I can't actually make it take longer than about 10 seconds for the given script. Changing the buffer_count to 2 is enough to approximately halve this to 5s, and running in preview mode at 30fps reduces it to about 2.5s.

These numbers seem in line with what we might expect. Could you give us any extra guidance as to what we need to do to see numbers as high as 25s? Thanks.

siranshen commented 11 months ago

Hey guys, thanks for taking a look.

25s is reproducible on my Zero 2 W. It's probably less on other models.

Also, I tried modifying the script to use preview first, and yes, it did slash the time down from ~25s to ~8.5s:

picam2 = Picamera2()
preview_config = picam2.create_preview_configuration()
capture_config = picam2.create_still_configuration()
picam2.start(config=preview_config)  # Starting with preview instead
print('Started')

print('Starting autofocus')
start_time = time.time()
success = picam2.autofocus_cycle()
print(f'Autofocused: {success}, {time.time() - start_time}s')
print('Taking photo')
picam2.switch_mode_and_capture_file(capture_config, "test.jpg")  # Switch to still and shoot
print('Photo taken')
davidplowman commented 11 months ago

Ah, thanks for the info - maybe it's related to running on a Zero 2W. I wonder if we're experiencing more frame drops there. I'll have a look at that, though it'll have to wait just a bit as I don't have one available to me just at the moment.

davidplowman commented 11 months ago

I've had a go on a Pi 3 which is very similar to a Pi Zero 2. Here's what I found:

If you can use that preview mode at 30fps then I think you'll be OK. I am planning to add a timeout as well to all asynchronous camera commands because it's not difficult, but I'm hoping the above will work OK for you.

siranshen commented 11 months ago

Looks great to me. Thanks a lot!

On Tue, Dec 5, 2023 at 21:32 davidplowman @.***> wrote:

I've had a go on a Pi 3 which is very similar to a Pi Zero 2. Here's what I found:

  • Original script: I managed to get this to take as long as 17.5s
  • With buffer_count=2: down to 9.7s
  • With buffer_count=3 at 30fps (use create_still_configuration(controls={'FrameRate': 30}, buffer_count=3): 5.9s
  • Using preview (no framerate given): 6.2s
  • Using preview at 30fps (use create_preview_configuration(controls={'FrameRate': 30})): 2.6s

If you can use that preview mode at 30fps then I think you'll be OK. I am planning to add a timeout as well to all asynchronous camera commands because it's not difficult, but I'm hoping the above will work OK for you.

— Reply to this email directly, view it on GitHub https://github.com/raspberrypi/picamera2/issues/884#issuecomment-1840801349, or unsubscribe https://github.com/notifications/unsubscribe-auth/ACOGUSPSNAP63X4ZHDJLDP3YH4O5BAVCNFSM6AAAAABAEZLZGKVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMYTQNBQHAYDCMZUHE . You are receiving this because you were mentioned.Message ID: @.***>