| Message ID | 20260407-kbingham-awb-split-v1-7-a39af3f4dc20@ideasonboard.com |
|---|---|
| State | New |
| Headers | show |
| Series |
|
| Related | show |
Hi Kieran, Kieran Bingham <kieran.bingham@ideasonboard.com> writes: > Utilise the lux component of libipa to map in the lux estimate > process using the yHistgram of the Soft ISP statistics. s/yHistgram/yHistogram/ I suppose the algorithm is supposed to be enabled manually, in case the corresponding tuning data is available? It would be worth to explain its purpose and use here. > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > --- > src/ipa/simple/algorithms/lux.cpp | 93 +++++++++++++++++++++++++++++++++++ > src/ipa/simple/algorithms/lux.h | 39 +++++++++++++++ > src/ipa/simple/algorithms/meson.build | 1 + > src/ipa/simple/ipa_context.h | 5 ++ > 4 files changed, 138 insertions(+) > > diff --git a/src/ipa/simple/algorithms/lux.cpp b/src/ipa/simple/algorithms/lux.cpp > new file mode 100644 > index 0000000000000000000000000000000000000000..03b44ac584ae141509e79954159272504cdba17d > --- /dev/null > +++ b/src/ipa/simple/algorithms/lux.cpp > @@ -0,0 +1,93 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2024, Ideas On Board > + * > + * Simple Lux control > + */ > + > +#include "lux.h" > + > +#include <libcamera/base/log.h> > + > +#include <libcamera/control_ids.h> > + > +#include "libipa/histogram.h" > +#include "libipa/lux.h" > + > +/** > + * \file lux.h > + */ > + > +namespace libcamera { > + > +namespace ipa::soft::algorithms { > + > +/** > + * \class Lux > + * \brief SoftISP Lux control > + * > + * The Lux algorithm is responsible for estimating the lux level of the image. > + * It doesn't take or generate any controls, but it provides a lux level for > + * other algorithms (such as AGC) to use. > + */ > + > +/** > + * \brief Construct a SoftISP Lux algo module > + */ > +Lux::Lux() > +{ > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::init > + */ > +int Lux::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) > +{ > + return lux_.parseTuningData(tuningData); > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::prepare > + */ > +void Lux::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, > + IPAFrameContext &frameContext, > + [[maybe_unused]] DebayerParams *params) > +{ > + frameContext.lux.lux = context.activeState.lux.lux; > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::process > + */ > +void Lux::process(IPAContext &context, > + [[maybe_unused]] const uint32_t frame, > + IPAFrameContext &frameContext, > + const SwIspStats *stats, > + ControlList &metadata) > +{ > + /* > + * Report the lux level used by algorithms to prepare this frame > + * not the lux level *of* this frame. > + */ > + metadata.set(controls::Lux, frameContext.lux.lux); Should this be reported before the lux value is determined for the first time? > + if (!stats) > + return; > + > + /* Todo: Sensor configuration should move out of AGC */ Todo: -> \todo The comment is a bit confusing here, it might be better to attach it to the sensor configuration in AGC. > + utils::Duration exposureTime = context.configuration.agc.lineDuration * > + frameContext.sensor.exposure; > + double gain = frameContext.sensor.gain; > + double digitalGain = 1.0; > + > + Histogram yHist(stats->yHistogram); > + > + context.activeState.lux.lux = > + lux_.estimateLux(exposureTime, gain, digitalGain, yHist); > +} > + > +REGISTER_IPA_ALGORITHM(Lux, "Lux") > + > +} /* namespace ipa::soft::algorithms */ > + > +} /* namespace libcamera */ > diff --git a/src/ipa/simple/algorithms/lux.h b/src/ipa/simple/algorithms/lux.h > new file mode 100644 > index 0000000000000000000000000000000000000000..04ec4c163ede422369977017cca70d12a8d361fb > --- /dev/null > +++ b/src/ipa/simple/algorithms/lux.h > @@ -0,0 +1,39 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2024, Ideas On Board > + * > + * Simple Lux control > + */ > + > +#pragma once > + > +#include <sys/types.h> > + > +#include "libipa/lux.h" > + > +#include "algorithm.h" > + > +namespace libcamera { > + > +namespace ipa::soft::algorithms { > + > +class Lux : public Algorithm > +{ > +public: > + Lux(); > + > + int init(IPAContext &context, const YamlObject &tuningData) override; > + void prepare(IPAContext &context, const uint32_t frame, > + IPAFrameContext &frameContext, > + DebayerParams *params) override; > + void process(IPAContext &context, const uint32_t frame, > + IPAFrameContext &frameContext, > + const SwIspStats *stats, > + ControlList &metadata) override; > + > +private: > + ipa::Lux lux_; > +}; > + > +} /* namespace ipa::soft::algorithms */ > +} /* namespace libcamera */ > diff --git a/src/ipa/simple/algorithms/meson.build b/src/ipa/simple/algorithms/meson.build > index 73c63722083ff92147253c6b10440ce50743988d..27e73c9a0eea2241cc4a4cefd1594c976fb59318 100644 > --- a/src/ipa/simple/algorithms/meson.build > +++ b/src/ipa/simple/algorithms/meson.build > @@ -6,4 +6,5 @@ soft_simple_ipa_algorithms = files([ > 'agc.cpp', > 'blc.cpp', > 'ccm.cpp', > + 'lux.cpp', > ]) > diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h > index 8ccfacb46a59cedb5a0ad051d67f7c1f40af4b52..2bd7c4642b118d7bb94b1b16cdf4ede5fb2554b5 100644 > --- a/src/ipa/simple/ipa_context.h > +++ b/src/ipa/simple/ipa_context.h > @@ -17,6 +17,7 @@ > #include "libcamera/internal/vector.h" > > #include <libipa/fc_queue.h> > +#include <libipa/lux.h> > > #include "core_ipa_interface.h" > > @@ -36,6 +37,8 @@ struct IPASessionConfiguration { > }; > > struct IPAActiveState { > + ipa::lux::ActiveState lux; Does this need setting an initial value some way? > + > struct { > int32_t exposure; > double again; > @@ -64,6 +67,8 @@ struct IPAActiveState { > }; > > struct IPAFrameContext : public FrameContext { > + ipa::lux::FrameContext lux; > + > Matrix<float, 3, 3> ccm; > > struct {
Quoting Milan Zamazal (2026-04-08 15:12:26) > Hi Kieran, > > Kieran Bingham <kieran.bingham@ideasonboard.com> writes: > > > Utilise the lux component of libipa to map in the lux estimate > > process using the yHistgram of the Soft ISP statistics. > > s/yHistgram/yHistogram/ > > I suppose the algorithm is supposed to be enabled manually, in case the > corresponding tuning data is available? It would be worth to explain > its purpose and use here. Not manually, I think it's just used when there is available tuning data. It helps for AWB ultimately. > > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > > --- > > src/ipa/simple/algorithms/lux.cpp | 93 +++++++++++++++++++++++++++++++++++ > > src/ipa/simple/algorithms/lux.h | 39 +++++++++++++++ > > src/ipa/simple/algorithms/meson.build | 1 + > > src/ipa/simple/ipa_context.h | 5 ++ > > 4 files changed, 138 insertions(+) > > > > diff --git a/src/ipa/simple/algorithms/lux.cpp b/src/ipa/simple/algorithms/lux.cpp > > new file mode 100644 > > index 0000000000000000000000000000000000000000..03b44ac584ae141509e79954159272504cdba17d > > --- /dev/null > > +++ b/src/ipa/simple/algorithms/lux.cpp > > @@ -0,0 +1,93 @@ > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > > +/* > > + * Copyright (C) 2024, Ideas On Board > > + * > > + * Simple Lux control > > + */ > > + > > +#include "lux.h" > > + > > +#include <libcamera/base/log.h> > > + > > +#include <libcamera/control_ids.h> > > + > > +#include "libipa/histogram.h" > > +#include "libipa/lux.h" > > + > > +/** > > + * \file lux.h > > + */ > > + > > +namespace libcamera { > > + > > +namespace ipa::soft::algorithms { > > + > > +/** > > + * \class Lux > > + * \brief SoftISP Lux control > > + * > > + * The Lux algorithm is responsible for estimating the lux level of the image. > > + * It doesn't take or generate any controls, but it provides a lux level for > > + * other algorithms (such as AGC) to use. > > + */ > > + > > +/** > > + * \brief Construct a SoftISP Lux algo module > > + */ > > +Lux::Lux() > > +{ > > +} I don't think that's needed when it's empty ;-) > > + > > +/** > > + * \copydoc libcamera::ipa::Algorithm::init > > + */ > > +int Lux::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) > > +{ > > + return lux_.parseTuningData(tuningData); > > +} > > + > > +/** > > + * \copydoc libcamera::ipa::Algorithm::prepare > > + */ > > +void Lux::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, > > + IPAFrameContext &frameContext, > > + [[maybe_unused]] DebayerParams *params) > > +{ > > + frameContext.lux.lux = context.activeState.lux.lux; > > +} > > + > > +/** > > + * \copydoc libcamera::ipa::Algorithm::process > > + */ > > +void Lux::process(IPAContext &context, > > + [[maybe_unused]] const uint32_t frame, > > + IPAFrameContext &frameContext, > > + const SwIspStats *stats, > > + ControlList &metadata) > > +{ > > + /* > > + * Report the lux level used by algorithms to prepare this frame > > + * not the lux level *of* this frame. > > + */ > > + metadata.set(controls::Lux, frameContext.lux.lux); > > Should this be reported before the lux value is determined for the first > time? Ohh no good spot, there's some startup ordering errors here... > > > + if (!stats) > > + return; > > + > > + /* Todo: Sensor configuration should move out of AGC */ > > Todo: -> \todo > > The comment is a bit confusing here, it might be better to attach it to > the sensor configuration in AGC. Maybe, but this is me explicitly telling myself yet another place that needs to refactor the AEGC into libipa, and split out sensor controls from the AGC, and have a dedicated sensor context. Because even if AEGC isn't "running" if we know the stats, and the exposure and gain we can know the lux - so the sensor properties shouldn't be tied directly into the AGC like they are. It's one of the many rabbit holes that have made it harder for me to split out AgcMeanLuminance and use it for soft-ipa. I've hoped starting with Lux/AWB will make it easier to progress and then do the same for AGC./ > > > + utils::Duration exposureTime = context.configuration.agc.lineDuration * > > + frameContext.sensor.exposure; > > + double gain = frameContext.sensor.gain; > > + double digitalGain = 1.0; > > + > > + Histogram yHist(stats->yHistogram); > > + > > + context.activeState.lux.lux = > > + lux_.estimateLux(exposureTime, gain, digitalGain, yHist); > > +} > > + > > +REGISTER_IPA_ALGORITHM(Lux, "Lux") > > + > > +} /* namespace ipa::soft::algorithms */ > > + > > +} /* namespace libcamera */ > > diff --git a/src/ipa/simple/algorithms/lux.h b/src/ipa/simple/algorithms/lux.h > > new file mode 100644 > > index 0000000000000000000000000000000000000000..04ec4c163ede422369977017cca70d12a8d361fb > > --- /dev/null > > +++ b/src/ipa/simple/algorithms/lux.h > > @@ -0,0 +1,39 @@ > > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > > +/* > > + * Copyright (C) 2024, Ideas On Board > > + * > > + * Simple Lux control > > + */ > > + > > +#pragma once > > + > > +#include <sys/types.h> > > + > > +#include "libipa/lux.h" > > + > > +#include "algorithm.h" > > + > > +namespace libcamera { > > + > > +namespace ipa::soft::algorithms { > > + > > +class Lux : public Algorithm > > +{ > > +public: > > + Lux(); > > + > > + int init(IPAContext &context, const YamlObject &tuningData) override; > > + void prepare(IPAContext &context, const uint32_t frame, > > + IPAFrameContext &frameContext, > > + DebayerParams *params) override; > > + void process(IPAContext &context, const uint32_t frame, > > + IPAFrameContext &frameContext, > > + const SwIspStats *stats, > > + ControlList &metadata) override; > > + > > +private: > > + ipa::Lux lux_; > > +}; > > + > > +} /* namespace ipa::soft::algorithms */ > > +} /* namespace libcamera */ > > diff --git a/src/ipa/simple/algorithms/meson.build b/src/ipa/simple/algorithms/meson.build > > index 73c63722083ff92147253c6b10440ce50743988d..27e73c9a0eea2241cc4a4cefd1594c976fb59318 100644 > > --- a/src/ipa/simple/algorithms/meson.build > > +++ b/src/ipa/simple/algorithms/meson.build > > @@ -6,4 +6,5 @@ soft_simple_ipa_algorithms = files([ > > 'agc.cpp', > > 'blc.cpp', > > 'ccm.cpp', > > + 'lux.cpp', > > ]) > > diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h > > index 8ccfacb46a59cedb5a0ad051d67f7c1f40af4b52..2bd7c4642b118d7bb94b1b16cdf4ede5fb2554b5 100644 > > --- a/src/ipa/simple/ipa_context.h > > +++ b/src/ipa/simple/ipa_context.h > > @@ -17,6 +17,7 @@ > > #include "libcamera/internal/vector.h" > > > > #include <libipa/fc_queue.h> > > +#include <libipa/lux.h> > > > > #include "core_ipa_interface.h" > > > > @@ -36,6 +37,8 @@ struct IPASessionConfiguration { > > }; > > > > struct IPAActiveState { > > + ipa::lux::ActiveState lux; > > Does this need setting an initial value some way? It at least needs to be not reported before we calculate it perhaps... I'll think about it when I refresh this series. Thanks Kieran > > > + > > struct { > > int32_t exposure; > > double again; > > @@ -64,6 +67,8 @@ struct IPAActiveState { > > }; > > > > struct IPAFrameContext : public FrameContext { > > + ipa::lux::FrameContext lux; > > + > > Matrix<float, 3, 3> ccm; > > > > struct { >
Kieran Bingham <kieran.bingham@ideasonboard.com> writes: > Quoting Milan Zamazal (2026-04-08 15:12:26) >> Hi Kieran, >> > >> Kieran Bingham <kieran.bingham@ideasonboard.com> writes: >> >> > Utilise the lux component of libipa to map in the lux estimate >> > process using the yHistgram of the Soft ISP statistics. >> >> s/yHistgram/yHistogram/ >> >> I suppose the algorithm is supposed to be enabled manually, in case the >> corresponding tuning data is available? It would be worth to explain >> its purpose and use here. > > Not manually, I think it's just used when there is available tuning > data. It helps for AWB ultimately. OK. >> >> > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> >> > --- >> > src/ipa/simple/algorithms/lux.cpp | 93 +++++++++++++++++++++++++++++++++++ >> > src/ipa/simple/algorithms/lux.h | 39 +++++++++++++++ >> > src/ipa/simple/algorithms/meson.build | 1 + >> > src/ipa/simple/ipa_context.h | 5 ++ >> > 4 files changed, 138 insertions(+) >> > >> > diff --git a/src/ipa/simple/algorithms/lux.cpp b/src/ipa/simple/algorithms/lux.cpp >> > new file mode 100644 >> > index 0000000000000000000000000000000000000000..03b44ac584ae141509e79954159272504cdba17d >> > --- /dev/null >> > +++ b/src/ipa/simple/algorithms/lux.cpp >> > @@ -0,0 +1,93 @@ >> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ >> > +/* >> > + * Copyright (C) 2024, Ideas On Board >> > + * >> > + * Simple Lux control >> > + */ >> > + >> > +#include "lux.h" >> > + >> > +#include <libcamera/base/log.h> >> > + >> > +#include <libcamera/control_ids.h> >> > + >> > +#include "libipa/histogram.h" >> > +#include "libipa/lux.h" >> > + >> > +/** >> > + * \file lux.h >> > + */ >> > + >> > +namespace libcamera { >> > + >> > +namespace ipa::soft::algorithms { >> > + >> > +/** >> > + * \class Lux >> > + * \brief SoftISP Lux control >> > + * >> > + * The Lux algorithm is responsible for estimating the lux level of the image. >> > + * It doesn't take or generate any controls, but it provides a lux level for >> > + * other algorithms (such as AGC) to use. >> > + */ >> > + >> > +/** >> > + * \brief Construct a SoftISP Lux algo module >> > + */ >> > +Lux::Lux() >> > +{ >> > +} > > I don't think that's needed when it's empty ;-) Then the declaration in lux.h should be removed too. >> > + >> > +/** >> > + * \copydoc libcamera::ipa::Algorithm::init >> > + */ >> > +int Lux::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) >> > +{ >> > + return lux_.parseTuningData(tuningData); >> > +} >> > + >> > +/** >> > + * \copydoc libcamera::ipa::Algorithm::prepare >> > + */ >> > +void Lux::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, >> > + IPAFrameContext &frameContext, >> > + [[maybe_unused]] DebayerParams *params) >> > +{ >> > + frameContext.lux.lux = context.activeState.lux.lux; >> > +} >> > + >> > +/** >> > + * \copydoc libcamera::ipa::Algorithm::process >> > + */ >> > +void Lux::process(IPAContext &context, >> > + [[maybe_unused]] const uint32_t frame, >> > + IPAFrameContext &frameContext, >> > + const SwIspStats *stats, >> > + ControlList &metadata) >> > +{ >> > + /* >> > + * Report the lux level used by algorithms to prepare this frame >> > + * not the lux level *of* this frame. >> > + */ >> > + metadata.set(controls::Lux, frameContext.lux.lux); >> >> Should this be reported before the lux value is determined for the first >> time? > > Ohh no good spot, there's some startup ordering errors here... > >> >> > + if (!stats) >> > + return; >> > + >> > + /* Todo: Sensor configuration should move out of AGC */ >> >> Todo: -> \todo >> >> The comment is a bit confusing here, it might be better to attach it to >> the sensor configuration in AGC. > > Maybe, but this is me explicitly telling myself yet another place that > needs to refactor the AEGC into libipa, and split out sensor controls > from the AGC, and have a dedicated sensor context. > > Because even if AEGC isn't "running" if we know the stats, and the > exposure and gain we can know the lux - so the sensor properties > shouldn't be tied directly into the AGC like they are. > > It's one of the many rabbit holes that have made it harder for me to split out > AgcMeanLuminance and use it for soft-ipa. I've hoped starting with > Lux/AWB will make it easier to progress and then do the same for AGC./ Makes sense but then I'd suggest to make the comment clearer; well, many TODO comments survive much longer than initially expected. >> >> > + utils::Duration exposureTime = context.configuration.agc.lineDuration * >> > + frameContext.sensor.exposure; >> > + double gain = frameContext.sensor.gain; >> > + double digitalGain = 1.0; >> > + >> > + Histogram yHist(stats->yHistogram); >> > + >> > + context.activeState.lux.lux = >> > + lux_.estimateLux(exposureTime, gain, digitalGain, yHist); >> > +} >> > + >> > +REGISTER_IPA_ALGORITHM(Lux, "Lux") >> > + >> > +} /* namespace ipa::soft::algorithms */ >> > + >> > +} /* namespace libcamera */ >> > diff --git a/src/ipa/simple/algorithms/lux.h b/src/ipa/simple/algorithms/lux.h >> > new file mode 100644 >> > index 0000000000000000000000000000000000000000..04ec4c163ede422369977017cca70d12a8d361fb >> > --- /dev/null >> > +++ b/src/ipa/simple/algorithms/lux.h >> > @@ -0,0 +1,39 @@ >> > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ >> > +/* >> > + * Copyright (C) 2024, Ideas On Board >> > + * >> > + * Simple Lux control >> > + */ >> > + >> > +#pragma once >> > + >> > +#include <sys/types.h> >> > + >> > +#include "libipa/lux.h" >> > + >> > +#include "algorithm.h" >> > + >> > +namespace libcamera { >> > + >> > +namespace ipa::soft::algorithms { >> > + >> > +class Lux : public Algorithm >> > +{ >> > +public: >> > + Lux(); >> > + >> > + int init(IPAContext &context, const YamlObject &tuningData) override; >> > + void prepare(IPAContext &context, const uint32_t frame, >> > + IPAFrameContext &frameContext, >> > + DebayerParams *params) override; >> > + void process(IPAContext &context, const uint32_t frame, >> > + IPAFrameContext &frameContext, >> > + const SwIspStats *stats, >> > + ControlList &metadata) override; >> > + >> > +private: >> > + ipa::Lux lux_; >> > +}; >> > + >> > +} /* namespace ipa::soft::algorithms */ >> > +} /* namespace libcamera */ >> > diff --git a/src/ipa/simple/algorithms/meson.build b/src/ipa/simple/algorithms/meson.build >> > index 73c63722083ff92147253c6b10440ce50743988d..27e73c9a0eea2241cc4a4cefd1594c976fb59318 100644 >> > --- a/src/ipa/simple/algorithms/meson.build >> > +++ b/src/ipa/simple/algorithms/meson.build >> > @@ -6,4 +6,5 @@ soft_simple_ipa_algorithms = files([ >> > 'agc.cpp', >> > 'blc.cpp', >> > 'ccm.cpp', >> > + 'lux.cpp', >> > ]) >> > diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h >> > index 8ccfacb46a59cedb5a0ad051d67f7c1f40af4b52..2bd7c4642b118d7bb94b1b16cdf4ede5fb2554b5 100644 >> > --- a/src/ipa/simple/ipa_context.h >> > +++ b/src/ipa/simple/ipa_context.h >> > @@ -17,6 +17,7 @@ >> > #include "libcamera/internal/vector.h" >> > >> > #include <libipa/fc_queue.h> >> > +#include <libipa/lux.h> >> > >> > #include "core_ipa_interface.h" >> > >> > @@ -36,6 +37,8 @@ struct IPASessionConfiguration { >> > }; >> > >> > struct IPAActiveState { >> > + ipa::lux::ActiveState lux; >> >> Does this need setting an initial value some way? > > It at least needs to be not reported before we calculate it perhaps... > I'll think about it when I refresh this series. > > Thanks > > Kieran > > >> >> > + >> > struct { >> > int32_t exposure; >> > double again; >> > @@ -64,6 +67,8 @@ struct IPAActiveState { >> > }; >> > >> > struct IPAFrameContext : public FrameContext { >> > + ipa::lux::FrameContext lux; >> > + >> > Matrix<float, 3, 3> ccm; >> > >> > struct { >>
On Tue, Apr 07, 2026 at 11:01:10PM +0100, Kieran Bingham wrote: > Utilise the lux component of libipa to map in the lux estimate > process using the yHistgram of the Soft ISP statistics. > > Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> > --- > src/ipa/simple/algorithms/lux.cpp | 93 +++++++++++++++++++++++++++++++++++ > src/ipa/simple/algorithms/lux.h | 39 +++++++++++++++ > src/ipa/simple/algorithms/meson.build | 1 + > src/ipa/simple/ipa_context.h | 5 ++ > 4 files changed, 138 insertions(+) > > diff --git a/src/ipa/simple/algorithms/lux.cpp b/src/ipa/simple/algorithms/lux.cpp > new file mode 100644 > index 0000000000000000000000000000000000000000..03b44ac584ae141509e79954159272504cdba17d > --- /dev/null > +++ b/src/ipa/simple/algorithms/lux.cpp > @@ -0,0 +1,93 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2024, Ideas On Board > + * > + * Simple Lux control > + */ > + > +#include "lux.h" > + > +#include <libcamera/base/log.h> > + > +#include <libcamera/control_ids.h> > + > +#include "libipa/histogram.h" > +#include "libipa/lux.h" > + > +/** > + * \file lux.h > + */ > + > +namespace libcamera { > + > +namespace ipa::soft::algorithms { > + > +/** > + * \class Lux > + * \brief SoftISP Lux control > + * > + * The Lux algorithm is responsible for estimating the lux level of the image. > + * It doesn't take or generate any controls, but it provides a lux level for > + * other algorithms (such as AGC) to use. > + */ > + > +/** > + * \brief Construct a SoftISP Lux algo module > + */ > +Lux::Lux() > +{ > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::init > + */ > +int Lux::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) > +{ > + return lux_.parseTuningData(tuningData); > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::prepare > + */ > +void Lux::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, > + IPAFrameContext &frameContext, > + [[maybe_unused]] DebayerParams *params) > +{ > + frameContext.lux.lux = context.activeState.lux.lux; > +} > + > +/** > + * \copydoc libcamera::ipa::Algorithm::process > + */ > +void Lux::process(IPAContext &context, > + [[maybe_unused]] const uint32_t frame, > + IPAFrameContext &frameContext, > + const SwIspStats *stats, > + ControlList &metadata) > +{ > + /* > + * Report the lux level used by algorithms to prepare this frame > + * not the lux level *of* this frame. > + */ > + metadata.set(controls::Lux, frameContext.lux.lux); > + > + if (!stats) > + return; > + > + /* Todo: Sensor configuration should move out of AGC */ > + utils::Duration exposureTime = context.configuration.agc.lineDuration * > + frameContext.sensor.exposure; > + double gain = frameContext.sensor.gain; > + double digitalGain = 1.0; > + > + Histogram yHist(stats->yHistogram); > + > + context.activeState.lux.lux = > + lux_.estimateLux(exposureTime, gain, digitalGain, yHist); > +} > + > +REGISTER_IPA_ALGORITHM(Lux, "Lux") > + > +} /* namespace ipa::soft::algorithms */ > + > +} /* namespace libcamera */ > diff --git a/src/ipa/simple/algorithms/lux.h b/src/ipa/simple/algorithms/lux.h > new file mode 100644 > index 0000000000000000000000000000000000000000..04ec4c163ede422369977017cca70d12a8d361fb > --- /dev/null > +++ b/src/ipa/simple/algorithms/lux.h > @@ -0,0 +1,39 @@ > +/* SPDX-License-Identifier: LGPL-2.1-or-later */ > +/* > + * Copyright (C) 2024, Ideas On Board > + * > + * Simple Lux control > + */ > + > +#pragma once > + > +#include <sys/types.h> > + > +#include "libipa/lux.h" > + > +#include "algorithm.h" > + > +namespace libcamera { > + > +namespace ipa::soft::algorithms { > + > +class Lux : public Algorithm > +{ > +public: > + Lux(); > + > + int init(IPAContext &context, const YamlObject &tuningData) override; > + void prepare(IPAContext &context, const uint32_t frame, > + IPAFrameContext &frameContext, > + DebayerParams *params) override; > + void process(IPAContext &context, const uint32_t frame, > + IPAFrameContext &frameContext, > + const SwIspStats *stats, > + ControlList &metadata) override; > + > +private: > + ipa::Lux lux_; Would it make sense to inherit from ipa::Lux instead, the same way Agc in rkisp1 inherits from AgcMeanLuminance ? > +}; > + > +} /* namespace ipa::soft::algorithms */ > +} /* namespace libcamera */ > diff --git a/src/ipa/simple/algorithms/meson.build b/src/ipa/simple/algorithms/meson.build > index 73c63722083ff92147253c6b10440ce50743988d..27e73c9a0eea2241cc4a4cefd1594c976fb59318 100644 > --- a/src/ipa/simple/algorithms/meson.build > +++ b/src/ipa/simple/algorithms/meson.build > @@ -6,4 +6,5 @@ soft_simple_ipa_algorithms = files([ > 'agc.cpp', > 'blc.cpp', > 'ccm.cpp', > + 'lux.cpp', > ]) > diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h > index 8ccfacb46a59cedb5a0ad051d67f7c1f40af4b52..2bd7c4642b118d7bb94b1b16cdf4ede5fb2554b5 100644 > --- a/src/ipa/simple/ipa_context.h > +++ b/src/ipa/simple/ipa_context.h > @@ -17,6 +17,7 @@ > #include "libcamera/internal/vector.h" > > #include <libipa/fc_queue.h> > +#include <libipa/lux.h> > > #include "core_ipa_interface.h" > > @@ -36,6 +37,8 @@ struct IPASessionConfiguration { > }; > > struct IPAActiveState { > + ipa::lux::ActiveState lux; > + > struct { > int32_t exposure; > double again; > @@ -64,6 +67,8 @@ struct IPAActiveState { > }; > > struct IPAFrameContext : public FrameContext { > + ipa::lux::FrameContext lux; > + > Matrix<float, 3, 3> ccm; > > struct { >
diff --git a/src/ipa/simple/algorithms/lux.cpp b/src/ipa/simple/algorithms/lux.cpp new file mode 100644 index 0000000000000000000000000000000000000000..03b44ac584ae141509e79954159272504cdba17d --- /dev/null +++ b/src/ipa/simple/algorithms/lux.cpp @@ -0,0 +1,93 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Ideas On Board + * + * Simple Lux control + */ + +#include "lux.h" + +#include <libcamera/base/log.h> + +#include <libcamera/control_ids.h> + +#include "libipa/histogram.h" +#include "libipa/lux.h" + +/** + * \file lux.h + */ + +namespace libcamera { + +namespace ipa::soft::algorithms { + +/** + * \class Lux + * \brief SoftISP Lux control + * + * The Lux algorithm is responsible for estimating the lux level of the image. + * It doesn't take or generate any controls, but it provides a lux level for + * other algorithms (such as AGC) to use. + */ + +/** + * \brief Construct a SoftISP Lux algo module + */ +Lux::Lux() +{ +} + +/** + * \copydoc libcamera::ipa::Algorithm::init + */ +int Lux::init([[maybe_unused]] IPAContext &context, const YamlObject &tuningData) +{ + return lux_.parseTuningData(tuningData); +} + +/** + * \copydoc libcamera::ipa::Algorithm::prepare + */ +void Lux::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, + IPAFrameContext &frameContext, + [[maybe_unused]] DebayerParams *params) +{ + frameContext.lux.lux = context.activeState.lux.lux; +} + +/** + * \copydoc libcamera::ipa::Algorithm::process + */ +void Lux::process(IPAContext &context, + [[maybe_unused]] const uint32_t frame, + IPAFrameContext &frameContext, + const SwIspStats *stats, + ControlList &metadata) +{ + /* + * Report the lux level used by algorithms to prepare this frame + * not the lux level *of* this frame. + */ + metadata.set(controls::Lux, frameContext.lux.lux); + + if (!stats) + return; + + /* Todo: Sensor configuration should move out of AGC */ + utils::Duration exposureTime = context.configuration.agc.lineDuration * + frameContext.sensor.exposure; + double gain = frameContext.sensor.gain; + double digitalGain = 1.0; + + Histogram yHist(stats->yHistogram); + + context.activeState.lux.lux = + lux_.estimateLux(exposureTime, gain, digitalGain, yHist); +} + +REGISTER_IPA_ALGORITHM(Lux, "Lux") + +} /* namespace ipa::soft::algorithms */ + +} /* namespace libcamera */ diff --git a/src/ipa/simple/algorithms/lux.h b/src/ipa/simple/algorithms/lux.h new file mode 100644 index 0000000000000000000000000000000000000000..04ec4c163ede422369977017cca70d12a8d361fb --- /dev/null +++ b/src/ipa/simple/algorithms/lux.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2024, Ideas On Board + * + * Simple Lux control + */ + +#pragma once + +#include <sys/types.h> + +#include "libipa/lux.h" + +#include "algorithm.h" + +namespace libcamera { + +namespace ipa::soft::algorithms { + +class Lux : public Algorithm +{ +public: + Lux(); + + int init(IPAContext &context, const YamlObject &tuningData) override; + void prepare(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + DebayerParams *params) override; + void process(IPAContext &context, const uint32_t frame, + IPAFrameContext &frameContext, + const SwIspStats *stats, + ControlList &metadata) override; + +private: + ipa::Lux lux_; +}; + +} /* namespace ipa::soft::algorithms */ +} /* namespace libcamera */ diff --git a/src/ipa/simple/algorithms/meson.build b/src/ipa/simple/algorithms/meson.build index 73c63722083ff92147253c6b10440ce50743988d..27e73c9a0eea2241cc4a4cefd1594c976fb59318 100644 --- a/src/ipa/simple/algorithms/meson.build +++ b/src/ipa/simple/algorithms/meson.build @@ -6,4 +6,5 @@ soft_simple_ipa_algorithms = files([ 'agc.cpp', 'blc.cpp', 'ccm.cpp', + 'lux.cpp', ]) diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h index 8ccfacb46a59cedb5a0ad051d67f7c1f40af4b52..2bd7c4642b118d7bb94b1b16cdf4ede5fb2554b5 100644 --- a/src/ipa/simple/ipa_context.h +++ b/src/ipa/simple/ipa_context.h @@ -17,6 +17,7 @@ #include "libcamera/internal/vector.h" #include <libipa/fc_queue.h> +#include <libipa/lux.h> #include "core_ipa_interface.h" @@ -36,6 +37,8 @@ struct IPASessionConfiguration { }; struct IPAActiveState { + ipa::lux::ActiveState lux; + struct { int32_t exposure; double again; @@ -64,6 +67,8 @@ struct IPAActiveState { }; struct IPAFrameContext : public FrameContext { + ipa::lux::FrameContext lux; + Matrix<float, 3, 3> ccm; struct {
Utilise the lux component of libipa to map in the lux estimate process using the yHistgram of the Soft ISP statistics. Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com> --- src/ipa/simple/algorithms/lux.cpp | 93 +++++++++++++++++++++++++++++++++++ src/ipa/simple/algorithms/lux.h | 39 +++++++++++++++ src/ipa/simple/algorithms/meson.build | 1 + src/ipa/simple/ipa_context.h | 5 ++ 4 files changed, 138 insertions(+)