Files
external_libcamera/src/ipa/libipa/awb.cpp
T
Stefan Klug c699d26573 libipa: awb: Make result of gainsFromColourTemp optional
In the grey world AWB case, if no colour gains are contained in the
tuning file, the colour gains get reset to 1 when the colour temperature
is set manually. This is unexpected and undesirable. Allow the
gainsFromColourTemp() function to return a std::nullopt to handle that
case.

While at it, remove an unnecessary import from rkisp1/algorithms/awb.h.

Signed-off-by: Stefan Klug <stefan.klug@ideasonboard.com>
Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
Reviewed-by: Paul Elder <paul.elder@ideasonboard.com>
2025-05-20 11:20:08 +02:00

266 lines
6.8 KiB
C++

/* SPDX-License-Identifier: LGPL-2.1-or-later */
/*
* Copyright (C) 2024 Ideas on Board Oy
*
* Generic AWB algorithms
*/
#include "awb.h"
#include <libcamera/base/log.h>
#include <libcamera/control_ids.h>
/**
* \file awb.h
* \brief Base classes for AWB algorithms
*/
namespace libcamera {
LOG_DEFINE_CATEGORY(Awb)
namespace ipa {
/**
* \class AwbResult
* \brief The result of an AWB calculation
*
* This class holds the result of an auto white balance calculation.
*/
/**
* \var AwbResult::gains
* \brief The calculated white balance gains
*/
/**
* \var AwbResult::colourTemperature
* \brief The calculated colour temperature in Kelvin
*/
/**
* \class AwbStats
* \brief An abstraction class wrapping hardware-specific AWB statistics
*
* IPA modules using an AWB algorithm based on the AwbAlgorithm class need to
* implement this class to give the algorithm access to the hardware-specific
* statistics data.
*/
/**
* \fn AwbStats::computeColourError()
* \brief Compute an error value for when the given gains would be applied
* \param[in] gains The gains to apply
*
* Compute an error value (non-greyness) assuming the given \a gains would be
* applied. To keep the actual implementations computationally inexpensive,
* the squared colour error shall be returned.
*
* If the AWB statistics provide multiple zones, the average of the individual
* squared errors shall be returned. Averaging/normalizing is necessary so that
* the numeric dimensions are the same on all hardware platforms.
*
* \return The computed error value
*/
/**
* \fn AwbStats::rgbMeans()
* \brief Get RGB means of the statistics
*
* Fetch the RGB means from the statistics. The values of each channel are
* dimensionless and only the ratios are used for further calculations. This is
* used by the simple grey world model to calculate the gains to apply.
*
* \return The RGB means
*/
/**
* \class AwbAlgorithm
* \brief A base class for auto white balance algorithms
*
* This class is a base class for auto white balance algorithms. It defines an
* interface for the algorithms to implement, and is used by the IPAs to
* interact with the concrete implementation.
*/
/**
* \fn AwbAlgorithm::init()
* \brief Initialize the algorithm with the given tuning data
* \param[in] tuningData The tuning data to use for the algorithm
*
* \return 0 on success, a negative error code otherwise
*/
/**
* \fn AwbAlgorithm::calculateAwb()
* \brief Calculate AWB data from the given statistics
* \param[in] stats The statistics to use for the calculation
* \param[in] lux The lux value of the scene
*
* Calculate an AwbResult object from the given statistics and lux value. A \a
* lux value of 0 means it is unknown or invalid and the algorithm shall ignore
* it.
*
* \return The AWB result
*/
/**
* \fn AwbAlgorithm::gainsFromColourTemperature()
* \brief Compute white balance gains from a colour temperature
* \param[in] colourTemperature The colour temperature in Kelvin
*
* Compute the white balance gains from a \a colourTemperature. This function
* does not take any statistics into account. It is used to compute the colour
* gains when the user manually specifies a colour temperature.
*
* \return The colour gains or std::nullopt if the conversion is not possible
*/
/**
* \fn AwbAlgorithm::controls()
* \brief Get the controls info map for this algorithm
*
* \return The controls info map
*/
/**
* \fn AwbAlgorithm::handleControls()
* \param[in] controls The controls to handle
* \brief Handle the controls supplied in a request
*/
/**
* \brief Parse the mode configurations from the tuning data
* \param[in] tuningData the YamlObject representing the tuning data
* \param[in] def The default value for the AwbMode control
*
* Utility function to parse the tuning data for an AwbMode entry and read all
* provided modes. It adds controls::AwbMode to AwbAlgorithm::controls_ and
* populates AwbAlgorithm::modes_. For a list of possible modes see \ref
* controls::AwbModeEnum.
*
* Each mode entry must contain a "lo" and "hi" key to specify the lower and
* upper colour temperature of that mode. For example:
*
* \code{.unparsed}
* algorithms:
* - Awb:
* AwbMode:
* AwbAuto:
* lo: 2500
* hi: 8000
* AwbIncandescent:
* lo: 2500
* hi: 3000
* ...
* \endcode
*
* If \a def is supplied but not contained in the the \a tuningData, -EINVAL is
* returned.
*
* \sa controls::AwbModeEnum
* \return Zero on success, negative error code otherwise
*/
int AwbAlgorithm::parseModeConfigs(const YamlObject &tuningData,
const ControlValue &def)
{
std::vector<ControlValue> availableModes;
const YamlObject &yamlModes = tuningData[controls::AwbMode.name()];
if (!yamlModes.isDictionary()) {
LOG(Awb, Error)
<< "AwbModes must be a dictionary.";
return -EINVAL;
}
for (const auto &[modeName, modeDict] : yamlModes.asDict()) {
if (controls::AwbModeNameValueMap.find(modeName) ==
controls::AwbModeNameValueMap.end()) {
LOG(Awb, Warning)
<< "Skipping unknown AWB mode '"
<< modeName << "'";
continue;
}
if (!modeDict.isDictionary()) {
LOG(Awb, Error)
<< "Invalid AWB mode '" << modeName << "'";
return -EINVAL;
}
const auto &modeValue = static_cast<controls::AwbModeEnum>(
controls::AwbModeNameValueMap.at(modeName));
ModeConfig &config = modes_[modeValue];
auto hi = modeDict["hi"].get<double>();
if (!hi) {
LOG(Awb, Error) << "Failed to read hi param of mode "
<< modeName;
return -EINVAL;
}
config.ctHi = *hi;
auto lo = modeDict["lo"].get<double>();
if (!lo) {
LOG(Awb, Error) << "Failed to read low param of mode "
<< modeName;
return -EINVAL;
}
config.ctLo = *lo;
availableModes.push_back(modeValue);
}
if (modes_.empty()) {
LOG(Awb, Error) << "No AWB modes configured";
return -EINVAL;
}
if (!def.isNone() &&
modes_.find(def.get<controls::AwbModeEnum>()) == modes_.end()) {
const auto &names = controls::AwbMode.enumerators();
LOG(Awb, Error) << names.at(def.get<controls::AwbModeEnum>())
<< " mode is missing in the configuration.";
return -EINVAL;
}
controls_[&controls::AwbMode] = ControlInfo(availableModes, def);
return 0;
}
/**
* \class AwbAlgorithm::ModeConfig
* \brief Holds the configuration of a single AWB mode
*
* AWB modes limit the regulation of the AWB algorithm to a specific range of
* colour temperatures.
*/
/**
* \var AwbAlgorithm::ModeConfig::ctLo
* \brief The lowest valid colour temperature of that mode
*/
/**
* \var AwbAlgorithm::ModeConfig::ctHi
* \brief The highest valid colour temperature of that mode
*/
/**
* \var AwbAlgorithm::controls_
* \brief Controls info map for the controls provided by the algorithm
*/
/**
* \var AwbAlgorithm::modes_
* \brief Map of all configured modes
* \sa AwbAlgorithm::parseModeConfigs
*/
} /* namespace ipa */
} /* namespace libcamera */