raspberrypi / picamera2

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

use auto exposure from night time to day time #1060

Open LeifSec opened 1 week ago

LeifSec commented 1 week ago

I have set auto exposure mode (exposure time = 0`) and

ae_enable: true
ae_exposure_mode: Normal

Starting the camera in the late morning all picture are going including in late evening when it is already dark long after sunset. In this time pictures has been take with in interval of a few minutes.

But then keep the camera running until the next morning after sunup and taking no further pictures the picture are much too bright. But than after talking several picture (~15 -- 20) they get darker and darker until they are OK again.

How does the auto exposure work? Do I have to take picture in short intervals to have always the next one adapted to environment brightness?

davidplowman commented 1 week ago

Hi, thanks for the question.

Perhaps you could start by confirming what kind of Pi you have and what type of camera you are using. We also recommend ensuring your software is up to date (normally sudo apt update followed by sudo apt full-upgrade if you have an official Raspberry Pi camera).

Because you're posting here, I assume you're using Picamera2 and not rpicam-apps. Might you be able to post a very short version of your script that shows the problem? In particular, I'd like to understand how you are configuring the camera, whether you leave it running, or whether you're starting and stopping it between captures, how frequent these captures are, and so on. Thanks.

LeifSec commented 1 week ago

Sorry for missing information. I just wanted to understand how auto exposure is working because neither from picamera2 nor from libcamera documentation I found it / understand it. As I am using unattended updates I did not take care about versions and I assumed it is always the up to date one from stable branch.

rpicam-apps build: 6202c09b2bfa 16-02-2024 (17:44:15)
libcamera build: v0.2.0+46-075b54d5

(Raspberian 12

camera Model: ix708 (official Raspberry Pi camera) pi: Pi3B 1 GB

Yes, the question is of curse about picamera2 even if the question maybe better be answered by the libcamera team. (?)

Code for configuration (relevant values) - only run at startup:

self.__camera.set_controls({"ExposureTime": 0})
self.__camera.set_controls({"AeExposureMode": 0})  # normal
self.__camera.set_controls({("AeEnable", True})

Code taking picture

     def __store_current_config(self):
        started = self.__camera.started
        started = copy.deepcopy(started)
        request = None
        if started:
            request = self.__camera.capture_request()
        return (started, request, self.__camera.camera_config)

    def __make_picture_settings(self) :
        self.__camera.stop()
        self.__camera.configure(self.__settings.still_configuration)
        self.__camera.start()

    def take_picture(self) :
        self.__led_lightning.switch_on()
        started, request, config = self.__store_current_config()
        self.__make_picture_settings()
        img = self.__camera.capture_image("main")
        self.__reset_previous_settings(request, config, started)
        img.save(IMAGE_NAME)

    def __reset_previous_settings(self, request, config: dict, started: bool):
        self.__camera.stop()
        self.__camera.configure(config)
        if request is not None:
            request.release()
        if started:
            self.__camera.start()

There has been no other access to camera by other function (like video mode) than the above one during the whole run time.

The frequency is not fixed because it is external triggered but it is > 10 / h.

davidplowman commented 1 week ago

Thanks for the update. I'm not entirely sure I understand exactly when you're start/stopping the camera, but here is some guidance that may help.

  1. The camera must be started for the AGC/AEC to run.
  2. You need to leave it running freely for a few frames for it to have any effect.
  3. AGC/AEC settings are preserved when you stop, reconfigure the camera, and restart it, but not if you close and re-open it.

I can't really see how the AGC/AEC would stop adapting unless you're not running the camera between captures. Obviously looking at the exposure/ISO in the captures might tell you something, but the following debug might also be useful:

def callback(request):
    metadata = request.get_metadata()
    print("Exposure", metadata['ExposureTime'], "gain", metadata['AnalogueGain'])

and just after you start the camera add

    self.__camera.pre_callback = callback

This will show you every frame that the camera system is producing (and which the AGC/AEC gets to look at), and what exposure/gain values it has.

LeifSec commented 1 week ago

Thanks for the update. I'm not entirely sure I understand exactly when you're start/stopping the camera, but here is some guidance that may help.

The application has been designed to provide a video live stream for configuration and monitoring and than during this take some external triggered pictures (with e.g. higher resolution) with minimal delay . Thus, if there is a trigger:

  1. store current (video) configuration
  2. stop camera (to be able to change configuration)
  3. apply picture configuration
  4. start camera
  5. take picture
  6. stop camera (to be able to change configuration)
  7. restore previous configuration
  8. start camera if it has been running before

Because of #930 video capture is not used at the moment but the code above is still the code for that. I tried to remove all not relevant code but I forgot to remove self.__led_lightning.switch_on() which is switching on an infrared LED.

1. The camera must be started for the AGC/AEC to run.

2. You need to leave it running freely for a few frames for it to have any effect.

OK, I understand. Because I start the camera only direly before picture capture and the camera is not doing AGC/AEC during picture capture I might has at least one frame between start and capture / capture and stop for AGC/AEC.

3. AGC/AEC settings are preserved when you stop, reconfigure the camera, and restart it, but not if you close and re-open it.

I am not closing it.

I can't really see how the AGC/AEC would stop adapting unless you're not running the camera between captures.

Unfortunate this is what I am doing. For a first test with minimal code change I will just place a small sleep between start and capture.

Obviously looking at the exposure/ISO in the captures might tell you something, but the following debug might also be > useful:

def callback(request):
    metadata = request.get_metadata()
    print("Exposure", metadata['ExposureTime'], "gain", metadata['AnalogueGain'])

and just after you start the camera add

    self.__camera.pre_callback = callback

This will show you every frame that the camera system is producing (and which the AGC/AEC gets to look at), and what exposure/gain values it has.

Thanks a lot, I will do a test (unfortunately this is a productive live system) with the debug output.

davidplowman commented 1 week ago

It certainly seems a bit mysterious, but perhaps you can experiment if you have a non-live system somewhere.

On an unrelated note, I was wondering if switch_mode_and_capture_image() might simplify your code a bit. It feels like you've coded up something fairly similar?