[PATCH 1/3] ipa: libipa: Add Lux helper

Kieran Bingham kieran.bingham at ideasonboard.com
Fri Apr 12 12:53:54 CEST 2024


Hi Paul,

Quoting Paul Elder (2024-04-12 10:16:58)
> Add a Lux helper to libipa that does the estimation of the lux level
> given gain, exposure, aperture, 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>
> ---
>  src/ipa/libipa/lux.cpp     | 119 +++++++++++++++++++++++++++++++++++++
>  src/ipa/libipa/lux.h       |  45 ++++++++++++++
>  src/ipa/libipa/meson.build |   2 +
>  3 files changed, 166 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 00000000..756cd3c4
> --- /dev/null
> +++ b/src/ipa/libipa/lux.cpp
> @@ -0,0 +1,119 @@
> +/* SPDX-License-Identifier: BSD-2-Clause */
> +/*
> + * Copyright (C) 2019, Raspberry Pi Ltd
> + * Copyright (C) 2024, Paul Elder <paul.elder at ideasonboard.com>
> + *
> + * lux.h - 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
> + *
> + * As estimating the lux level of an image is expected to be a common
> + * operation, it is implemented in a helper in libipa.

I think the brief should explain what it is and how to use it (or in
this case what it uses?) - not where it lives.

> + */
> +
> +namespace libcamera {
> +
> +using namespace std::literals::chrono_literals;
> +
> +LOG_DEFINE_CATEGORY(Lux)
> +
> +namespace ipa {
> +
> +/**
> + * \class Lux
> + * \brief Class that implements lux estimation
> + */
> +
> +/**
> + * \var Lux::referenceExposureTime_
> + * \brief The exposure time of the reference image, in microseconds.
> + */
> +
> +/**
> + * \var Lux::referenceGain_
> + * \brief The analogue gain of the reference image.
> + */
> +
> +/**
> + * \var Lux::referenceAperture_
> + * \brief The aperture of the reference image in units of 1/f.
> + */
> +
> +/**
> + * \var Lux::referenceY_
> + * \brief The measured luminance of the reference image, out of 65536.

Why 65536? Would it be better/more explicit to say that it's a 16 bit
value? Except of course that is BIT(16) so it's a 16-bit-value plus one?
Is 65536 a permitted value?

> + */
> +
> +/**
> + * \var Lux::referenceLux_
> + * \brief The estimated lux level of the reference image.
> + */
> +
> +int Lux::readYaml(const YamlObject &tuningData)
> +{
> +       auto value = tuningData["reference_exposure_time"].get<double>();
> +       if (!value) {
> +               LOG(Lux, Error) << "Missing tuning parameter: 'reference_exposure_time'";
> +               return -EINVAL;
> +       }
> +       referenceExposureTime_ = *value * 1.0us;
> +
> +       value = tuningData["reference_gain"].get<double>();
> +       if (!value) {
> +               LOG(Lux, Error) << "Missing tuning parameter: 'reference_gain'";
> +               return -EINVAL;
> +       }
> +       referenceGain_ = *value;
> +
> +       referenceAperture_ = tuningData["reference_aperture"].get<double>(1.0);
> +
> +       value = tuningData["reference_Y"].get<double>();
> +       if (!value) {
> +               LOG(Lux, Error) << "Missing tuning parameter: 'reference_Y'";
> +               return -EINVAL;
> +       }
> +       referenceY_ = *value;
> +
> +       value = tuningData["reference_lux"].get<double>();
> +       if (!value) {
> +               LOG(Lux, Error) << "Missing tuning parameter: 'reference_lux'";
> +               return -EINVAL;
> +       }
> +       referenceLux_ = *value;
> +
> +       return 0;
> +}
> +
> +double Lux::process(double gain, utils::Duration exposureTime, double aperture,
> +                   const Histogram &yHist) const

As this isn't an algorithm itself, it's a helper I wonder if this
function should be named to match what it /does/. I.e.
  double Lux::estimate() ?

> +{
> +       double currentY = yHist.interQuantileMean(0, 1);
> +       double gainRatio = referenceGain_ / gain;
> +       double exposureTimeRatio = referenceExposureTime_ / exposureTime;
> +       double apertureRatio = referenceAperture_ / aperture;
> +       double yRatio = currentY * (65536 / yHist.bins()) / referenceY_;
> +
> +       double estimatedLux = exposureTimeRatio * gainRatio *
> +                             apertureRatio * apertureRatio *
> +                             yRatio * referenceLux_;

Does the tuning process only generate a single reference point? I guess
it's expected to be closely linear here? Or maybe it's close enough as
an estimate anyway.



> +
> +       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 00000000..6bc9cf9f
> --- /dev/null
> +++ b/src/ipa/libipa/lux.h
> @@ -0,0 +1,45 @@
> +/* SPDX-License-Identifier: BSD-2-Clause */
> +/*
> + * Copyright (C) 2019, Raspberry Pi Ltd
> + * Copyright (C) 2024, Paul Elder <paul.elder at ideasonboard.com>
> + *
> + * lux.h - Helper class that implements lux estimation
> + */
> +
> +#pragma once
> +
> +#include <algorithm>
> +#include <tuple>
> +#include <vector>
> +
> +#include <libcamera/base/utils.h>
> +
> +#include "libcamera/internal/yaml_parser.h"
> +
> +#include "histogram.h"
> +
> +namespace libcamera {
> +
> +namespace ipa {
> +
> +class Lux
> +{
> +public:
> +       Lux() = default;
> +       ~Lux() = default;
> +
> +       int readYaml(const YamlObject &tuningData);
> +       double process(double gain, utils::Duration exposureTime,
> +                      double aperture, const Histogram &yHist) const;
> +
> +private:
> +       utils::Duration referenceExposureTime_;
> +       double referenceGain_;
> +       double referenceAperture_;
> +       double referenceY_;
> +       double referenceLux_;
> +};
> +
> +} /* namespace ipa */
> +
> +} /* namespace libcamera */
> diff --git a/src/ipa/libipa/meson.build b/src/ipa/libipa/meson.build
> index 0796982e..b6d58900 100644
> --- a/src/ipa/libipa/meson.build
> +++ b/src/ipa/libipa/meson.build
> @@ -8,6 +8,7 @@ libipa_headers = files([
>      'exposure_mode_helper.h',
>      'fc_queue.h',
>      'histogram.h',
> +    'lux.h',
>      'matrix.h',
>      'module.h',
>      'pwl.h',
> @@ -21,6 +22,7 @@ libipa_sources = files([
>      'exposure_mode_helper.cpp',
>      'fc_queue.cpp',
>      'histogram.cpp',
> +    'lux.cpp',
>      'matrix.cpp',
>      'module.cpp',
>      'pwl.cpp'
> -- 
> 2.39.2
>


More information about the libcamera-devel mailing list