libcamera: ipa: simple: Remove Lut algorithm
The Lut algorithm is not really an algorithm. Moreover, algorithms may be enabled or disabled but with Lut disabled, nothing will work. Let's move the construction of lookup tables to CPU debayering, where it is used. The implied and related changes are: - DebayerParams is changed to contain the real params rather than lookup tables. - contrastExp parameter introduced by GPU ISP is used for CPU ISP too. - The params must be initialised so that debayering gets meaningful parameter values even when some algorithms are disabled. - combinedMatrix must be put to params everywhere where it is modified. - Matrix changes needn't be tracked in the algorithms any more. - CPU debayering must watch for changes of the corresponding parameters to update the lookup tables when and only when needed. - Swapping red and blue is integrated into lookup table constructions. - gpuIspEnabled flags are removed as they are not needed any more. Reviewed-by: Robert Mader <robert.mader@collabora.com> Signed-off-by: Milan Zamazal <mzamazal@redhat.com> Acked-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
This commit is contained in:
committed by
Kieran Bingham
parent
c43aeaade0
commit
3ffaa4c0e2
@@ -95,23 +95,20 @@ void Adjust::applySaturation(Matrix<float, 3, 3> &matrix, float saturation)
|
||||
void Adjust::prepare(IPAContext &context,
|
||||
[[maybe_unused]] const uint32_t frame,
|
||||
IPAFrameContext &frameContext,
|
||||
[[maybe_unused]] DebayerParams *params)
|
||||
DebayerParams *params)
|
||||
{
|
||||
frameContext.gamma = context.activeState.knobs.gamma;
|
||||
frameContext.contrast = context.activeState.knobs.contrast;
|
||||
|
||||
if (!context.ccmEnabled)
|
||||
return;
|
||||
|
||||
auto &saturation = context.activeState.knobs.saturation;
|
||||
frameContext.saturation = saturation;
|
||||
if (saturation)
|
||||
if (context.ccmEnabled && saturation) {
|
||||
applySaturation(context.activeState.combinedMatrix, saturation.value());
|
||||
|
||||
if (saturation != lastSaturation_) {
|
||||
context.activeState.matrixChanged = true;
|
||||
lastSaturation_ = saturation;
|
||||
frameContext.saturation = saturation;
|
||||
}
|
||||
|
||||
params->gamma = 1.0 / context.activeState.knobs.gamma;
|
||||
const float contrast = context.activeState.knobs.contrast.value_or(kDefaultContrast);
|
||||
params->contrastExp = tan(std::clamp(contrast * M_PI_4, 0.0, M_PI_2 - 0.00001));
|
||||
}
|
||||
|
||||
void Adjust::process([[maybe_unused]] IPAContext &context,
|
||||
|
||||
@@ -7,8 +7,6 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <optional>
|
||||
|
||||
#include "libcamera/internal/matrix.h"
|
||||
|
||||
#include <libipa/interpolator.h>
|
||||
@@ -45,8 +43,6 @@ public:
|
||||
|
||||
private:
|
||||
void applySaturation(Matrix<float, 3, 3> &ccm, float saturation);
|
||||
|
||||
std::optional<float> lastSaturation_;
|
||||
};
|
||||
|
||||
} /* namespace ipa::soft::algorithms */
|
||||
|
||||
@@ -37,7 +37,7 @@ int Awb::configure(IPAContext &context,
|
||||
void Awb::prepare(IPAContext &context,
|
||||
[[maybe_unused]] const uint32_t frame,
|
||||
IPAFrameContext &frameContext,
|
||||
[[maybe_unused]] DebayerParams *params)
|
||||
DebayerParams *params)
|
||||
{
|
||||
auto &gains = context.activeState.awb.gains;
|
||||
Matrix<float, 3, 3> gainMatrix = { { gains.r(), 0, 0,
|
||||
@@ -45,9 +45,11 @@ void Awb::prepare(IPAContext &context,
|
||||
0, 0, gains.b() } };
|
||||
context.activeState.combinedMatrix =
|
||||
context.activeState.combinedMatrix * gainMatrix;
|
||||
/* Just report, the gains are applied in LUT algorithm. */
|
||||
|
||||
frameContext.gains.red = gains.r();
|
||||
frameContext.gains.blue = gains.b();
|
||||
|
||||
params->gains = gains;
|
||||
}
|
||||
|
||||
void Awb::process(IPAContext &context,
|
||||
|
||||
@@ -51,7 +51,6 @@ void Ccm::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame,
|
||||
utils::abs_diff(ct, lastCt_) >= kTemperatureThreshold) {
|
||||
currentCcm_ = ccm_.getInterpolated(ct);
|
||||
lastCt_ = ct;
|
||||
context.activeState.matrixChanged = true;
|
||||
}
|
||||
|
||||
context.activeState.combinedMatrix =
|
||||
|
||||
@@ -1,140 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
* Copyright (C) 2024-2026, Red Hat Inc.
|
||||
*
|
||||
* Color lookup tables construction
|
||||
*/
|
||||
|
||||
#include "lut.h"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cmath>
|
||||
#include <optional>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <libcamera/base/log.h>
|
||||
|
||||
#include <libcamera/control_ids.h>
|
||||
|
||||
#include "simple/ipa_context.h"
|
||||
|
||||
#include "adjust.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
LOG_DEFINE_CATEGORY(IPASoftLut)
|
||||
|
||||
namespace ipa::soft::algorithms {
|
||||
|
||||
int Lut::configure(IPAContext &context,
|
||||
[[maybe_unused]] const IPAConfigInfo &configInfo)
|
||||
{
|
||||
updateGammaTable(context);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void Lut::updateGammaTable(IPAContext &context)
|
||||
{
|
||||
const auto blackLevel = context.activeState.blc.level;
|
||||
const auto gamma = 1.0 / context.activeState.knobs.gamma;
|
||||
const auto contrast = context.activeState.knobs.contrast.value_or(1.0);
|
||||
/* Convert 0..2 to 0..infinity; avoid actual inifinity at tan(pi/2) */
|
||||
float contrastExp = tan(std::clamp(contrast * M_PI_4, 0.0, M_PI_2 - 0.00001));
|
||||
|
||||
if (!context.gpuIspEnabled) {
|
||||
auto &gammaTable = context.activeState.gamma.gammaTable;
|
||||
const unsigned int blackIndex = blackLevel * gammaTable.size() / 256;
|
||||
const float divisor = gammaTable.size() - blackIndex - 1.0;
|
||||
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, contrastExp);
|
||||
else
|
||||
normalized = 1.0 - 0.5 * std::pow((1.0 - normalized) / 0.5, contrastExp);
|
||||
gammaTable[i] = UINT8_MAX * std::pow(normalized, gamma);
|
||||
}
|
||||
/*
|
||||
* Due to CCM operations, the table lookup may reach indices below the black
|
||||
* level. Let's set the table values below black level to the minimum
|
||||
* non-black value to prevent problems when the minimum value is
|
||||
* significantly non-zero (for example, when the image should be all grey).
|
||||
*/
|
||||
std::fill(gammaTable.begin(), gammaTable.begin() + blackIndex,
|
||||
gammaTable[blackIndex]);
|
||||
}
|
||||
|
||||
context.activeState.gamma.gamma = gamma;
|
||||
context.activeState.gamma.blackLevel = blackLevel;
|
||||
context.activeState.gamma.contrastExp = contrastExp;
|
||||
}
|
||||
|
||||
int16_t Lut::matrixValue(unsigned int i, float ccm) const
|
||||
{
|
||||
return std::round(i * ccm);
|
||||
}
|
||||
|
||||
void Lut::prepare(IPAContext &context,
|
||||
[[maybe_unused]] const uint32_t frame,
|
||||
[[maybe_unused]] IPAFrameContext &frameContext,
|
||||
DebayerParams *params)
|
||||
{
|
||||
/*
|
||||
* Update the gamma table if needed. This means if black level changes
|
||||
* and since the black level gets updated only if a lower value is
|
||||
* observed, it's not permanently prone to minor fluctuations or
|
||||
* rounding errors.
|
||||
*/
|
||||
const bool gammaUpdateNeeded =
|
||||
context.activeState.gamma.blackLevel != context.activeState.blc.level ||
|
||||
context.activeState.gamma.contrast != context.activeState.knobs.contrast;
|
||||
if (gammaUpdateNeeded)
|
||||
updateGammaTable(context);
|
||||
|
||||
auto &gains = context.activeState.awb.gains;
|
||||
auto &gammaTable = context.activeState.gamma.gammaTable;
|
||||
const unsigned int gammaTableSize = gammaTable.size();
|
||||
const double div = static_cast<double>(DebayerParams::kRGBLookupSize) /
|
||||
gammaTableSize;
|
||||
|
||||
if (!context.ccmEnabled) {
|
||||
for (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) {
|
||||
/* Apply gamma after gain! */
|
||||
const RGB<float> lutGains = (gains * i / div).min(gammaTableSize - 1);
|
||||
params->red[i] = gammaTable[static_cast<unsigned int>(lutGains.r())];
|
||||
params->green[i] = gammaTable[static_cast<unsigned int>(lutGains.g())];
|
||||
params->blue[i] = gammaTable[static_cast<unsigned int>(lutGains.b())];
|
||||
}
|
||||
} else if (context.activeState.matrixChanged || gammaUpdateNeeded) {
|
||||
auto &matrix = context.activeState.combinedMatrix;
|
||||
auto &red = params->redCcm;
|
||||
auto &green = params->greenCcm;
|
||||
auto &blue = params->blueCcm;
|
||||
params->ccm = matrix;
|
||||
if (!context.gpuIspEnabled) {
|
||||
for (unsigned int i = 0; i < DebayerParams::kRGBLookupSize; i++) {
|
||||
red[i].r = matrixValue(i, matrix[0][0]);
|
||||
red[i].g = matrixValue(i, matrix[1][0]);
|
||||
red[i].b = matrixValue(i, matrix[2][0]);
|
||||
green[i].r = matrixValue(i, matrix[0][1]);
|
||||
green[i].g = matrixValue(i, matrix[1][1]);
|
||||
green[i].b = matrixValue(i, matrix[2][1]);
|
||||
blue[i].r = matrixValue(i, matrix[0][2]);
|
||||
blue[i].g = matrixValue(i, matrix[1][2]);
|
||||
blue[i].b = matrixValue(i, matrix[2][2]);
|
||||
params->gammaLut[i] = gammaTable[i / div];
|
||||
}
|
||||
}
|
||||
context.activeState.matrixChanged = false;
|
||||
}
|
||||
|
||||
params->gamma = context.activeState.gamma.gamma;
|
||||
params->contrastExp = context.activeState.gamma.contrastExp;
|
||||
}
|
||||
|
||||
REGISTER_IPA_ALGORITHM(Lut, "Lut")
|
||||
|
||||
} /* namespace ipa::soft::algorithms */
|
||||
|
||||
} /* namespace libcamera */
|
||||
@@ -1,35 +0,0 @@
|
||||
/* SPDX-License-Identifier: LGPL-2.1-or-later */
|
||||
/*
|
||||
* Copyright (C) 2024, Red Hat Inc.
|
||||
*
|
||||
* Color lookup tables construction
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "algorithm.h"
|
||||
|
||||
namespace libcamera {
|
||||
|
||||
namespace ipa::soft::algorithms {
|
||||
|
||||
class Lut : public Algorithm
|
||||
{
|
||||
public:
|
||||
Lut() = default;
|
||||
~Lut() = default;
|
||||
|
||||
int configure(IPAContext &context, const IPAConfigInfo &configInfo) override;
|
||||
void prepare(IPAContext &context,
|
||||
const uint32_t frame,
|
||||
IPAFrameContext &frameContext,
|
||||
DebayerParams *params) override;
|
||||
|
||||
private:
|
||||
void updateGammaTable(IPAContext &context);
|
||||
int16_t matrixValue(unsigned int i, float ccm) const;
|
||||
};
|
||||
|
||||
} /* namespace ipa::soft::algorithms */
|
||||
|
||||
} /* namespace libcamera */
|
||||
@@ -6,5 +6,4 @@ soft_simple_ipa_algorithms = files([
|
||||
'agc.cpp',
|
||||
'blc.cpp',
|
||||
'ccm.cpp',
|
||||
'lut.cpp',
|
||||
])
|
||||
|
||||
Reference in New Issue
Block a user