[PATCH v4 3/4] libcamera: software_isp: Add support for contrast control

Laurent Pinchart laurent.pinchart at ideasonboard.com
Wed Nov 27 08:15:38 CET 2024


Hi Milan,

Thank you for the patch.

On Tue, Nov 26, 2024 at 10:15:04AM +0100, Milan Zamazal wrote:
> Software ISP is currently fully automatic and doesn't allow image
> modifications by explicitly set control values.  The user has no means
> to make the image looking better.
> 
> This patch introduces support for contrast control, which can improve
> e.g. a flat looking image.  Based on the provided contrast value with a
> range 0..infinity and 1.0 being the normal value, it applies a simple
> S-curve modification to the image.  The contrast algorithm just handles
> the provided values, while the S-curve is applied in the gamma algorithm
> on the computed gamma curve whenever the contrast value changes.  Since
> the algorithm is applied only on the lookup table already present, its
> overhead is negligible.

Isn't contrast defined as a multiplier ? Applying a different luminance
transformation and calling it contrast will make different cameras
behave in different ways.

> This is a preparation patch without actually providing the control
> itself, which is done in the following patch.
> 
> Signed-off-by: Milan Zamazal <mzamazal at redhat.com>
> ---
>  src/ipa/simple/algorithms/lut.cpp | 38 +++++++++++++++++++++++++++----
>  src/ipa/simple/algorithms/lut.h   |  5 ++++
>  src/ipa/simple/ipa_context.h      |  7 ++++++
>  3 files changed, 45 insertions(+), 5 deletions(-)
> 
> diff --git a/src/ipa/simple/algorithms/lut.cpp b/src/ipa/simple/algorithms/lut.cpp
> index 9744e773a..ffded0594 100644
> --- a/src/ipa/simple/algorithms/lut.cpp
> +++ b/src/ipa/simple/algorithms/lut.cpp
> @@ -9,14 +9,19 @@
>  
>  #include <algorithm>
>  #include <cmath>
> +#include <optional>
>  #include <stdint.h>
>  
>  #include <libcamera/base/log.h>
>  
>  #include "simple/ipa_context.h"
>  
> +#include "control_ids.h"
> +
>  namespace libcamera {
>  
> +LOG_DEFINE_CATEGORY(IPASoftLut)
> +
>  namespace ipa::soft::algorithms {
>  
>  int Lut::configure(IPAContext &context,
> @@ -24,24 +29,46 @@ int Lut::configure(IPAContext &context,
>  {
>  	/* Gamma value is fixed */
>  	context.configuration.gamma = 0.5;
> +	context.activeState.knobs.contrast = std::optional<double>();
>  	updateGammaTable(context);
>  
>  	return 0;
>  }
>  
> +void Lut::queueRequest(typename Module::Context &context,
> +		       [[maybe_unused]] const uint32_t frame,
> +		       [[maybe_unused]] typename Module::FrameContext &frameContext,
> +		       const ControlList &controls)
> +{
> +	const auto &contrast = controls.get(controls::Contrast);
> +	if (contrast.has_value()) {
> +		context.activeState.knobs.contrast = contrast;
> +		LOG(IPASoftLut, Debug) << "Setting contrast to " << contrast.value();
> +	}
> +}
> +
>  void Lut::updateGammaTable(IPAContext &context)
>  {
>  	auto &gammaTable = context.activeState.gamma.gammaTable;
> -	auto blackLevel = context.activeState.blc.level;
> +	const auto blackLevel = context.activeState.blc.level;
>  	const unsigned int blackIndex = blackLevel * gammaTable.size() / 256;
> +	const auto contrast = context.activeState.knobs.contrast.value_or(1.0);
>  
>  	std::fill(gammaTable.begin(), gammaTable.begin() + blackIndex, 0);
>  	const float divisor = gammaTable.size() - blackIndex - 1.0;
> -	for (unsigned int i = blackIndex; i < gammaTable.size(); i++)
> -		gammaTable[i] = UINT8_MAX * std::pow((i - blackIndex) / divisor,
> -						     context.configuration.gamma);
> +	for (unsigned int i = blackIndex; i < gammaTable.size(); i++) {
> +		double normalized = (i - blackIndex) / divisor;
> +		/* Apply simple S-curve */
> +		if (normalized < 0.5)
> +			normalized = 0.5 * std::pow(normalized / 0.5, contrast);
> +		else
> +			normalized = 1.0 - 0.5 * std::pow((1.0 - normalized) / 0.5, contrast);
> +		gammaTable[i] = UINT8_MAX *
> +				std::pow(normalized, context.configuration.gamma);
> +	}
>  
>  	context.activeState.gamma.blackLevel = blackLevel;
> +	context.activeState.gamma.contrast = contrast;
>  }
>  
>  void Lut::prepare(IPAContext &context,
> @@ -55,7 +82,8 @@ void Lut::prepare(IPAContext &context,
>  	 * observed, it's not permanently prone to minor fluctuations or
>  	 * rounding errors.
>  	 */
> -	if (context.activeState.gamma.blackLevel != context.activeState.blc.level)
> +	if (context.activeState.gamma.blackLevel != context.activeState.blc.level ||
> +	    context.activeState.gamma.contrast != context.activeState.knobs.contrast)
>  		updateGammaTable(context);
>  
>  	auto &gains = context.activeState.gains;
> diff --git a/src/ipa/simple/algorithms/lut.h b/src/ipa/simple/algorithms/lut.h
> index b635987d0..ef2df147c 100644
> --- a/src/ipa/simple/algorithms/lut.h
> +++ b/src/ipa/simple/algorithms/lut.h
> @@ -20,6 +20,11 @@ public:
>  	~Lut() = default;
>  
>  	int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;
> +	void queueRequest(typename Module::Context &context,
> +			  const uint32_t frame,
> +			  typename Module::FrameContext &frameContext,
> +			  const ControlList &controls)
> +		override;
>  	void prepare(IPAContext &context,
>  		     const uint32_t frame,
>  		     IPAFrameContext &frameContext,
> diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h
> index fd7343e91..148052207 100644
> --- a/src/ipa/simple/ipa_context.h
> +++ b/src/ipa/simple/ipa_context.h
> @@ -11,6 +11,8 @@
>  #include <optional>
>  #include <stdint.h>
>  
> +#include <libcamera/controls.h>
> +
>  #include <libipa/fc_queue.h>
>  
>  namespace libcamera {
> @@ -48,7 +50,12 @@ struct IPAActiveState {
>  	struct {
>  		std::array<double, kGammaLookupSize> gammaTable;
>  		uint8_t blackLevel;
> +		double contrast;
>  	} gamma;
> +	struct {
> +		/* 0..inf range, 1.0 = normal */
> +		std::optional<double> contrast;
> +	} knobs;
>  };
>  
>  struct IPAFrameContext : public FrameContext {

-- 
Regards,

Laurent Pinchart


More information about the libcamera-devel mailing list