[PATCH v2 1/1] libcamera: software_isp: Add saturation control

Bryan O'Donoghue bryan.odonoghue at linaro.org
Sat May 10 18:29:57 CEST 2025


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.

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