[PATCH v3 3/4] libcamera: software_isp: Add support for contrast control
Milan Zamazal
mzamazal at redhat.com
Fri Oct 11 20:27:58 CEST 2024
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.
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 | 8 +++++++
3 files changed, 46 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 491448ece..3a8d2d59c 100644
--- a/src/ipa/simple/ipa_context.h
+++ b/src/ipa/simple/ipa_context.h
@@ -8,8 +8,11 @@
#pragma once
#include <array>
+#include <optional>
#include <stdint.h>
+#include <libcamera/controls.h>
+
#include <libipa/fc_queue.h>
namespace libcamera {
@@ -44,7 +47,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 {
--
2.44.1
More information about the libcamera-devel
mailing list