picamera2 icon indicating copy to clipboard operation
picamera2 copied to clipboard

[HOW-TO] Get current AeMeteringMode value

Open azsde opened this issue 5 months ago • 5 comments

Hi,

I'm trying to determine which AeMeteringMode is currently used but printing the controls doesn't return anything:

picam2 = Picamera2()
picam2.set_controls({"AeMeteringMode": controls.AeMeteringModeEnum.Spot})
print("Current controls:", picam2.controls)

Returns: Current controls: <Controls: {}>

I've tried several approaches and I can't manage to get controls to display the current values

Am I doing something wrong ?

azsde avatar Jul 25 '25 09:07 azsde

Sorry for the closing and re-opening, I thought I had found how to do it but no.

azsde avatar Jul 25 '25 09:07 azsde

So when you set a control, it obviously takes some time before it's applied to a frame. I'm assuming you're wanting to know what the metering mode was set to for a particular frame or set of frames?

Clearly if you just wanted to know what the last metering mode was that you set - you probably just need to remember that for yourself in the code. Maybe:

def my_set_controls(picam2, new_controls):
    global current_controls
    current_controls |= new_controls
    picam2.set_controls(new_controls)    

You get the idea!

To find out whether a specific frame has this value set, we have to look in the metadata. Now, there's always been a bit of a debate in libcamera circles about whether every possible metadata item comes out with every frame or not. The Pi doesn't do this generally, so the AeMeteringMode metadata will come out only once, on the first frame where it changed. When there is no metadata for it, you can assume it's the same as before.

There is a slight gotcha in that, if you set these values immediately as you start the camera, then you may not see them. That's because the metadata signal will appear on a frame where the system is still "sorting itself out" and a few frames are not delivered to the application. I'd probably be tempted to try something like this:

from picamera2 import Picamera2
from libcamera import controls

picam2 = Picamera2()
current_controls = {"AeMeteringMode": controls.AeMeteringModeEnum.Normal})  # your defaults here
picam2.configure(your_config, controls=current_controls)
picam2.start()

while True:
    current_controls |= picam2.capture_metadata()  # current_controls should reflect the frame correctly

Be aware though that a few controls behave a bit differently. For example FrameRate is a "fake" control for user convenience, so it will never appear in the frame metadata. Instead, you get FrameDuration which is the duration of that frame. Also, setting FrameDurationLimits (which is what FrameRate translates into) will not appear. There may be one or two other corner cases, but I can't think of them right now!

To be honest, we've always wondered a bit whether we should report everything on every frame, but as I've said, it's not the case today.

davidplowman avatar Jul 25 '25 10:07 davidplowman

My usecase is more tricky.

As you may recall I'm working on a web interface that allow to view a livestream, record, and also to tinker with the settings.

When the user load the web page, I need to populate the UI with currently effective values:

  • The user launch the web interface, and changes AeMeteringMode to: Spot
  • The change is made
  • The user reload the web interface, the dropdown menu should be on previously selected value (spot in that case).

Storing the latest requested value could be done on my side, but dynamically retrieving the actual value would be way more elegant, but I am not sure it is possible ?

azsde avatar Jul 25 '25 10:07 azsde

Hmm, I'm not really sure what the best option is. Do you want the webpage to reflect the last control values the user requested (just a case of remembering the last things you sent), or the values currently being applied to the frames coming out? Indeed, is there even a meaningful difference from the user's point of view?

The first of those two, as discussed above, is trivial, I think.

The second (displaying what the camera system has actually applied to the current frame) is, also as discussed, more difficult. I don't believe there's any completely trivial way to get every setting for current frame, though I thought my suggestion was fairly reasonable. We have and indeed still are wondering about reporting everything on every frame, but I'm not even sure if that's what you need?

davidplowman avatar Jul 25 '25 11:07 davidplowman

In theory, those value (user sent vs effective in picamera2/libcamera) should be the same so there is not significant impact for the end user.

Defining whether the user last request should be stored and used as a "truth" source versus fetching the actual values from libcamera is more of a software architecture issue.

In my opinion, storing the request values is not the right approach, and we should be able to query any "parameter" / "settings" at any point from picamera2 / libcamera, those should be used rather than storing whatever the user sent.

This approach should limit the side effects / bugs that can be encountered.

I don't think this need is exclusive to my usecase, but I may be wrong and I'm up for discussing this further if you wish to do so ! :)

That being said, AeMeteringMode is not available in the metadata returned by capture_metadata

azsde avatar Jul 25 '25 11:07 azsde