[PATCH v3 1/1] libcamera: software_isp: Get black level from the camera helper

Milan Zamazal mzamazal at redhat.com
Mon Oct 14 13:07:34 CEST 2024


Hi Robert,

thank you for testing and review.

Robert Mader <robert.mader at collabora.com> writes:

> Turns out I have to ask for/suggest some more changes:
>
> On 12.10.24 21:49, Robert Mader wrote:
>> I gave this a try on a Pixel 3a (IMX 355 and IMX 363). In both cases using 4096 made
>> the resulting image fully black when covering the sensor, which IIUC is the desired
>> effect. 

Yes.

>> Not putting any values or using lower ones such as 3200 results in a
>> greenish image - so there's definitely an improvement here. Thus fell
>> free to add a Tested-by: Robert Mader <robert.mader at collabora.com>
>>
>> At least in the case of the IMX355 the output overall becomes much darker - too dark
>> IMO. Is that expected - and can/will it be compensated by improvements of the AWB
>> algorithm?

No.  Blacks and shadows should be darker but overall the image should
have about the same brightness.  This is handled by auto-exposure, which
is applied after subtracting the black level.

>> P.S.: I guess I can submit a follow-up adding the black level for the IMX355 - the
>> IMX363 driver hasn't been submitted to upstream yet.
>>
>> On 11.10.24 17:39, Milan Zamazal wrote:
>>> The black level in software ISP is unconditionally guessed from the
>>> obtained frames.  CameraSensorHelper optionally provides the black level
>>> from camera specifications now.  Let's use the value if available.
>>>
>>> If the black level is not available from the given CameraSensorHelper
>>> instance, it's still determined on the fly.
>>>
>>> Signed-off-by: Milan Zamazal <mzamazal at redhat.com>
>>> Reviewed-by: Kieran Bingham <kieran.bingham at ideasonboard.com>
>>> ---
>>>   src/ipa/simple/algorithms/blc.cpp | 6 +++++-
>>>   src/ipa/simple/ipa_context.h      | 4 ++++
>>>   src/ipa/simple/soft_simple.cpp    | 9 +++++++++
>>>   3 files changed, 18 insertions(+), 1 deletion(-)
>>>
>>> diff --git a/src/ipa/simple/algorithms/blc.cpp b/src/ipa/simple/algorithms/blc.cpp
>>> index b9f2aaa6d..a7af2e12c 100644
>>> --- a/src/ipa/simple/algorithms/blc.cpp
>>> +++ b/src/ipa/simple/algorithms/blc.cpp
>>> @@ -24,7 +24,8 @@ BlackLevel::BlackLevel()
>>>   int BlackLevel::configure(IPAContext &context,
>>>                 [[maybe_unused]] const IPAConfigInfo &configInfo)
>>>   {
>>> -    context.activeState.blc.level = 255;
>>> +    context.activeState.blc.level =
>>> +        context.configuration.black.level.value_or(255);
>>>       return 0;
>>>   }
>>>   @@ -34,6 +35,9 @@ void BlackLevel::process(IPAContext &context,
>>>                const SwIspStats *stats,
>>>                [[maybe_unused]] ControlList &metadata)
>>>   {
>>> +    if (context.configuration.black.level.has_value())
>>> +        return;
>>> +
>>>       if (frameContext.sensor.exposure == exposure_ &&
>>>           frameContext.sensor.gain == gain_) {
>>>           return;
>>> diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h
>>> index 3519f20f6..fd121eebe 100644
>>> --- a/src/ipa/simple/ipa_context.h
>>> +++ b/src/ipa/simple/ipa_context.h
>>> @@ -8,6 +8,7 @@
>>>   #pragma once
>>>     #include <array>
>>> +#include <optional>
>>>   #include <stdint.h>
>>>     #include <libipa/fc_queue.h>
>>> @@ -22,6 +23,9 @@ struct IPASessionConfiguration {
>>>           int32_t exposureMin, exposureMax;
>>>           double againMin, againMax, againMinStep;
>>>       } agc;
>>> +    struct {
>>> +        std::optional<uint8_t> level;
>>> +    } black;
>>>   };
>>>     struct IPAActiveState {
>>> diff --git a/src/ipa/simple/soft_simple.cpp b/src/ipa/simple/soft_simple.cpp
>>> index b28c7039f..079409f6d 100644
>>> --- a/src/ipa/simple/soft_simple.cpp
>>> +++ b/src/ipa/simple/soft_simple.cpp
>>> @@ -201,6 +201,15 @@ int IPASoftSimple::configure(const IPAConfigInfo &configInfo)
>>>               (context_.configuration.agc.againMax -
>>>                context_.configuration.agc.againMin) /
>>>               100.0;
>>> +        if (camHelper_->blackLevel().has_value())
>>> +            /*
>>> +             * The black level from camHelper_ is a 16 bit value, software ISP
>>> +             * works with 8 bit pixel values, both regardless of the actual
>>> +             * sensor pixel width. Hence we obtain the pixel-based black value
>>> +             * by dividing the value from the helper by 256.
>>> +             */
>>> +            context_.configuration.black.level =
>>> +                camHelper_->blackLevel().value() / 256;
>
> Style nit: braces around this block would be good now that there's the comment.

OK.

> More importantly though: Assuming setting a value for blackLevel_ without providing
> values for gain makes sense, then it would be great to adapt the code above to not
> assume so. It currently only works in builds with asserts disabled - which I used
> yesterday when trying it. There are two more similar places in processStats()
> (camHelper_ ? ...).
>
> Forcing the non-cam-helper code for gain seems to fix the regression I mentioned in the
> previous mail.

I'm not sure I understand what you mean exactly.  What the patch does is
that if a camera sensor helper is available for the given sensor and it
provides black level then that black level is used; otherwise black
level auto-detection is used (as before).  If there is no helper for the
given sensor, nothing changes.  Do you mean there is some trouble in the
current code in such a case (it seems to work fine for me)?  Or do you
talk about a situation when the helper provides black level but not
the corresponding gains?  And what assertion fails?

>>>       } else {
>>>           /*
>>>            * The camera sensor gain (g) is usually not equal to the value written
>>



More information about the libcamera-devel mailing list