[PATCH v2 1/1] libcamera: software_isp: Add saturation control
Milan Zamazal
mzamazal at redhat.com
Mon May 12 19:04:52 CEST 2025
Bryan O'Donoghue <bryan.odonoghue at linaro.org> writes:
> On 30/04/2025 12:20, Milan Zamazal wrote:
>> Saturation control is added on top of the colour correction matrix. A
>> way of saturation adjustment that can be fully integrated into the
>
>> colour correction matrix is used. The control is available only if Ccm
>> algorithm is enabled.
>> The control uses 0.0-2.0 value range, with 1.0 being unmodified
>> saturation, 0.0 full desaturation and 2.0 quite saturated.
>> The saturation is adjusted by converting to Y'CbCr colour space,
>> applying the saturation value on the colour axes, and converting back to
>> RGB. ITU-R BT.601 conversion is used to convert between the colour
>> spaces, for no particular reason.
>> The colour correction matrix is applied before gamma and the given
>> matrix is suitable for such a case. Alternatively, the transformation
>> used in libcamera rpi ccm.cpp could be used.
>> Signed-off-by: Milan Zamazal <mzamazal at redhat.com>
>> ---
>> src/ipa/simple/algorithms/ccm.cpp | 60 +++++++++++++++++++++++++++++--
>> src/ipa/simple/algorithms/ccm.h | 11 ++++++
>> src/ipa/simple/ipa_context.h | 4 +++
>> 3 files changed, 72 insertions(+), 3 deletions(-)
>> diff --git a/src/ipa/simple/algorithms/ccm.cpp b/src/ipa/simple/algorithms/ccm.cpp
>> index d5ba928d..021aefc9 100644
>> --- a/src/ipa/simple/algorithms/ccm.cpp
>> +++ b/src/ipa/simple/algorithms/ccm.cpp
>> @@ -3,7 +3,7 @@
>> * Copyright (C) 2024, Ideas On Board
>> * Copyright (C) 2024-2025, Red Hat Inc.
>> *
>> - * Color correction matrix
>> + * Color correction matrix + saturation
>> */
>> #include "ccm.h"
>> @@ -13,6 +13,8 @@
>> #include <libcamera/control_ids.h>
>> +#include "libcamera/internal/matrix.h"
>> +
>> namespace {
>> constexpr unsigned int kTemperatureThreshold = 100;
>> @@ -35,28 +37,77 @@ int Ccm::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData
>> }
>> context.ccmEnabled = true;
>> + context.ctrlMap[&controls::Saturation] = ControlInfo(0.0f, 2.0f, 1.0f);
>> +
>> + return 0;
>> +}
>> +
>> +int Ccm::configure(IPAContext &context,
>> + [[maybe_unused]] const IPAConfigInfo &configInfo)
>> +{
>> + context.activeState.knobs.saturation = std::optional<double>();
>> return 0;
>> }
>> +void Ccm::queueRequest(typename Module::Context &context,
>> + [[maybe_unused]] const uint32_t frame,
>> + [[maybe_unused]] typename Module::FrameContext &frameContext,
>> + const ControlList &controls)
>> +{
>> + const auto &saturation = controls.get(controls::Saturation);
>> + if (saturation.has_value()) {
>> + context.activeState.knobs.saturation = saturation;
>> + LOG(IPASoftCcm, Debug) << "Setting saturation to " << saturation.value();
>> + }
>> +}
>> +
>> +void Ccm::updateSaturation(Matrix<float, 3, 3> &ccm, float saturation)
>> +{
>> + /* https://en.wikipedia.org/wiki/YCbCr#ITU-R_BT.601_conversion */
>> + const Matrix<float, 3, 3> rgb2ycbcr{
>> + { 0.256788235294, 0.504129411765, 0.0979058823529,
>> + -0.148223529412, -0.290992156863, 0.439215686275,
>> + 0.439215686275, -0.367788235294, -0.0714274509804 }
>> + };
>> + const Matrix<float, 3, 3> ycbcr2rgb{
>> + { 1.16438356164, 0, 1.59602678571,
>> + 1.16438356164, -0.391762290094, -0.812967647235,
>> + 1.16438356164, 2.01723214285, 0 }
>> + };
>> + const Matrix<float, 3, 3> saturationMatrix{
>> + { 1, 0, 0,
>> + 0, saturation, 0,
>> + 0, 0, saturation }
>> + };
>> + ccm = ycbcr2rgb * saturationMatrix * rgb2ycbcr * ccm;
>> +}
>
>> +I applied this to the GPUISP branch but it occurs to me I don't really
> know how to test it.
If CCM is already working, you can run it with camshark and play with
the saturation control there: 0.0 = fully desaturated, 1.0 = normal
saturation, 2.0 = quite saturated.
> https://gitlab.freedesktop.org/camera/libcamera-softisp/-/tree/origin-master+whole-frame-swtats-v2-gpuisp-v1?ref_type=heads
>
> ---
> bod
More information about the libcamera-devel
mailing list