[PATCH v3 1/2] ipa: libipa: Add Lux helper
Isaac Scott
isaac.scott at ideasonboard.com
Fri Dec 20 17:11:50 CET 2024
On Wed, 2024-12-18 at 16:46 +0900, Paul Elder wrote:
> Add a Lux helper to libipa that does the estimation of the lux level
> given gain, exposure, and luminance histogram. The helper also
> handles reading the reference values from the tuning file. These are
> expected to be common operations of lux algorithm modules in IPAs,
> and
> is modeled/copied from Raspberry Pi.
>
> Signed-off-by: Paul Elder <paul.elder at ideasonboard.com>
> Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
>
> ---
> Changes in v3:
> - improve documentation
> - minor docs formatting fixes
> - replace setBinSize() with constructor parameter
> - s/readYaml/parseTuningData/
> - remove unnecessary includes
>
> Changes in v2:
> - improve documentation
> - add binSize member variable and corresponding setter
> - remove aperture
> - split gain into analogue and digital
> - change tuning file names into camel case
> ---
> src/ipa/libipa/lux.cpp | 181
> +++++++++++++++++++++++++++++++++++++
> src/ipa/libipa/lux.h | 42 +++++++++
> src/ipa/libipa/meson.build | 2 +
> 3 files changed, 225 insertions(+)
> create mode 100644 src/ipa/libipa/lux.cpp
> create mode 100644 src/ipa/libipa/lux.h
>
> diff --git a/src/ipa/libipa/lux.cpp b/src/ipa/libipa/lux.cpp
> new file mode 100644
> index 000000000000..b60060e21803
> --- /dev/null
> +++ b/src/ipa/libipa/lux.cpp
> @@ -0,0 +1,181 @@
> +/* SPDX-License-Identifier: BSD-2-Clause */
> +/*
> + * Copyright (C) 2019, Raspberry Pi Ltd
> + * Copyright (C) 2024, Paul Elder <paul.elder at ideasonboard.com>
> + *
> + * Helper class that implements lux estimation
> + */
> +#include "lux.h"
> +
> +#include <algorithm>
> +#include <chrono>
> +
> +#include <libcamera/base/log.h>
> +
> +#include "libcamera/internal/yaml_parser.h"
> +
> +#include "histogram.h"
> +
> +/**
> + * \file lux.h
> + * \brief Helper class that implements lux estimation
> + *
> + * Estimating the lux level of an image is a common operation that
> can for
> + * instance be used to adjust the target Y value in AGC or for
> Bayesian AWB
> + * estimation.
> + */
> +
> +namespace libcamera {
> +
> +using namespace std::literals::chrono_literals;
> +
> +LOG_DEFINE_CATEGORY(Lux)
> +
> +namespace ipa {
> +
> +/**
> + * \class Lux
> + * \brief Class that implements lux estimation
> + *
> + * IPAs that wish to use lux esimation should create a Lux algorithm
> module
s/esimation/estimation
Very nitpicky... but otherwise
Reviewed-by: Isaac Scott <isaac.scott at ideasonboard.com>
> + * that lightly wraps this module by providing the platform-specific
> luminance
> + * histogram. The Lux entry in the tuning file must then precede the
> algorithms
> + * that depend on the estimated lux value.
> + */
> +
> +/**
> + * \var Lux::binSize_
> + * \brief The maximum count of each bin
> + */
> +
> +/**
> + * \var Lux::referenceExposureTime_
> + * \brief The exposure time of the reference image, in microseconds
> + */
> +
> +/**
> + * \var Lux::referenceAnalogueGain_
> + * \brief The analogue gain of the reference image
> + */
> +
> +/**
> + * \var Lux::referenceDigitalGain_
> + * \brief The analogue gain of the reference image
> + */
> +
> +/**
> + * \var Lux::referenceY_
> + * \brief The measured luminance of the reference image, out of the
> bin size
> + *
> + * \sa binSize_
> + */
> +
> +/**
> + * \var Lux::referenceLux_
> + * \brief The estimated lux level of the reference image
> + */
> +
> +/**
> + * \brief Construct the Lux helper module
> + * \param[in] binSize The maximum count of each bin
> + */
> +Lux::Lux(unsigned int binSize)
> + : binSize_(binSize)
> +{
> +}
> +
> +/**
> + * \brief Parse tuning data
> + * \param[in] tuningData The YamlObject representing the tuning data
> + *
> + * This function parses yaml tuning data for the common Lux module.
> It requires
> + * reference exposure time, analogue gain, digital gain, and lux
> values.
> + *
> + * \code{.unparsed}
> + * algorithms:
> + * - Lux:
> + * referenceExposureTime: 10000
> + * referenceAnalogueGain: 4.0
> + * referenceDigitalGain: 1.0
> + * referenceY: 12000
> + * referenceLux: 1000
> + * \endcode
> + *
> + * \return 0 on success or a negative error code
> + */
> +int Lux::parseTuningData(const YamlObject &tuningData)
> +{
> + auto value =
> tuningData["referenceExposureTime"].get<double>();
> + if (!value) {
> + LOG(Lux, Error) << "Missing tuning parameter: "
> + << "'referenceExposureTime'";
> + return -EINVAL;
> + }
> + referenceExposureTime_ = *value * 1.0us;
> +
> + value = tuningData["referenceAnalogueGain"].get<double>();
> + if (!value) {
> + LOG(Lux, Error) << "Missing tuning parameter: "
> + << "'referenceAnalogueGain'";
> + return -EINVAL;
> + }
> + referenceAnalogueGain_ = *value;
> +
> + value = tuningData["referenceDigitalGain"].get<double>();
> + if (!value) {
> + LOG(Lux, Error) << "Missing tuning parameter: "
> + << "'referenceDigitalGain'";
> + return -EINVAL;
> + }
> + referenceDigitalGain_ = *value;
> +
> + value = tuningData["referenceY"].get<double>();
> + if (!value) {
> + LOG(Lux, Error) << "Missing tuning parameter: "
> + << "'referenceY'";
> + return -EINVAL;
> + }
> + referenceY_ = *value;
> +
> + value = tuningData["referenceLux"].get<double>();
> + if (!value) {
> + LOG(Lux, Error) << "Missing tuning parameter: "
> + << "'referenceLux'";
> + return -EINVAL;
> + }
> + referenceLux_ = *value;
> +
> + return 0;
> +}
> +
> +/**
> + * \brief Estimate lux given runtime values
> + * \param[in] exposureTime Exposure time applied to the frame
> + * \param[in] aGain Analogue gain applied to the frame
> + * \param[in] dGain Digital gain applied to the frame
> + * \param[in] yHist Histogram from the ISP statistics
> + *
> + * Estimate the lux given the exposure time, gain, and histogram.
> + *
> + * \return Estimated lux value
> + */
> +double Lux::estimateLux(utils::Duration exposureTime,
> + double aGain, double dGain,
> + const Histogram &yHist) const
> +{
> + double currentY = yHist.interQuantileMean(0, 1);
> + double exposureTimeRatio = referenceExposureTime_ /
> exposureTime;
> + double aGainRatio = referenceAnalogueGain_ / aGain;
> + double dGainRatio = referenceDigitalGain_ / dGain;
> + double yRatio = currentY * (binSize_ / yHist.bins()) /
> referenceY_;
> +
> + double estimatedLux = exposureTimeRatio * aGainRatio *
> dGainRatio *
> + yRatio * referenceLux_;
> +
> + LOG(Lux, Debug) << "Estimated lux " << estimatedLux;
> + return estimatedLux;
> +}
> +
> +} /* namespace ipa */
> +
> +} /* namespace libcamera */
> diff --git a/src/ipa/libipa/lux.h b/src/ipa/libipa/lux.h
> new file mode 100644
> index 000000000000..93ca64795803
> --- /dev/null
> +++ b/src/ipa/libipa/lux.h
> @@ -0,0 +1,42 @@
> +/* SPDX-License-Identifier: BSD-2-Clause */
> +/*
> + * Copyright (C) 2019, Raspberry Pi Ltd
> + * Copyright (C) 2024, Paul Elder <paul.elder at ideasonboard.com>
> + *
> + * Helper class that implements lux estimation
> + */
> +
> +#pragma once
> +
> +#include <libcamera/base/utils.h>
> +
> +namespace libcamera {
> +
> +class YamlObject;
> +
> +namespace ipa {
> +
> +class Histogram;
> +
> +class Lux
> +{
> +public:
> + Lux(unsigned int binSize);
> +
> + int parseTuningData(const YamlObject &tuningData);
> + double estimateLux(utils::Duration exposureTime,
> + double aGain, double dGain,
> + const Histogram &yHist) const;
> +
> +private:
> + unsigned int binSize_;
> + utils::Duration referenceExposureTime_;
> + double referenceAnalogueGain_;
> + double referenceDigitalGain_;
> + double referenceY_;
> + double referenceLux_;
> +};
> +
> +} /* namespace ipa */
> +
> +} /* namespace libcamera */
> diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build
> index a7f16ff63079..f2b2f4be50db 100644
> --- a/src/ipa/libipa/meson.build
> +++ b/src/ipa/libipa/meson.build
> @@ -11,6 +11,7 @@ libipa_headers = files([
> 'histogram.h',
> 'interpolator.h',
> 'lsc_polynomial.h',
> + 'lux.h',
> 'module.h',
> 'pwl.h',
> 'vector.h',
> @@ -27,6 +28,7 @@ libipa_sources = files([
> 'histogram.cpp',
> 'interpolator.cpp',
> 'lsc_polynomial.cpp',
> + 'lux.cpp',
> 'module.cpp',
> 'pwl.cpp',
> 'vector.cpp',
More information about the libcamera-devel
mailing list