| Message ID | 20260703153819.1088752-18-barnabas.pocze@ideasonboard.com |
|---|---|
| State | Superseded |
| Headers | show |
| Series |
|
| Related | show |
2026. 07. 03. 17:38 keltezéssel, Barnabás Pőcze írta: > Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> > --- > src/ipa/simple/algorithms/agc.cpp | 153 +++++++++++++++++++++++++----- > src/ipa/simple/algorithms/agc.h | 9 +- > src/ipa/simple/ipa_context.h | 4 + > 3 files changed, 143 insertions(+), 23 deletions(-) > > diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp > index db4f63eba5..7d035618e8 100644 > --- a/src/ipa/simple/algorithms/agc.cpp > +++ b/src/ipa/simple/algorithms/agc.cpp > @@ -7,7 +7,12 @@ > > #include "agc.h" > > +#include <variant> > + > #include <libcamera/base/log.h> > +#include <libcamera/base/utils.h> > + > +#include <libipa/histogram.h> > > namespace libcamera { > > @@ -15,38 +20,119 @@ LOG_DEFINE_CATEGORY(IPASoftExposure) > > namespace ipa::soft::algorithms { > > -int Agc::init(IPAContext &context, [[maybe_unused]] const ValueNode &tuningData) > +namespace { > + > +class AgcTraits : public AgcMeanLuminance::Traits > { > - return agc_.configure(context.configuration.agc.simple, context.activeState.agc.simple, { > +public: > + AgcTraits(const SwIspStats &stats) > + : stats_(stats) > + { > + } > + > + double estimateLuminance(double gain) const override > + { > + double sum = 0; > + double count = 0; > + > + for (const auto &[i, cnt] : utils::enumerate(stats_.yHistogram)) { > + sum += std::min(1.0, gain * i / stats_.yHistogram.size()) * cnt; > + count += cnt; > + } > + > + return sum / count; > + } > + > +private: > + const SwIspStats &stats_; > +}; > + > +} > + > +int Agc::init(IPAContext &context, const ValueNode &tuningData) > +{ > + const AgcAlgorithm::ConfigurationParams config = { > .sensor = context.camHelper.get(), > .sensorInfo = context.sensorInfo, > .sensorControls = context.sensorControls, > .ctrlMap = context.ctrlMap, > .autoAllowed = true, > - }); > + }; > + > + if (config.sensor) > + agc_.emplace<AgcMeanLuminanceAlgorithm>(); > + else > + agc_.emplace<AgcSimpleAlgorithm>(); > + > + return std::visit(utils::overloaded { > + [&](AgcSimpleAlgorithm &impl) { > + return impl.configure(context.configuration.agc.simple, > + context.activeState.agc.simple, > + config); > + }, > + [&](AgcMeanLuminanceAlgorithm &impl) { > + int ret = impl.init(tuningData); > + if (ret) > + return ret; > + > + return impl.configure(context.configuration.agc.ml, > + context.activeState.agc.ml, > + config); > + }, > + }, agc_); > } > > int Agc::configure(IPAContext &context, [[maybe_unused]] const IPAConfigInfo &configInfo) > { > - return agc_.configure(context.configuration.agc.simple, context.activeState.agc.simple, { > + const AgcAlgorithm::ConfigurationParams config = { > .sensor = context.camHelper.get(), > .sensorInfo = context.sensorInfo, > .sensorControls = context.sensorControls, > .ctrlMap = context.ctrlMap, > - .autoAllowed = true, // \todo not if raw? > - }); > + .autoAllowed = true, // \todo if not raw? > + }; > + > + return std::visit(utils::overloaded { > + [&](AgcSimpleAlgorithm &impl) { > + return impl.configure(context.configuration.agc.simple, > + context.activeState.agc.simple, > + config); > + }, > + [&](AgcMeanLuminanceAlgorithm &impl) { > + return impl.configure(context.configuration.agc.ml, > + context.activeState.agc.ml, > + config); > + }, > + }, agc_); > } > > void Agc::queueRequest(IPAContext &context, [[maybe_unused]] const uint32_t frame, IPAFrameContext &frameContext, const ControlList &controls) > { > - agc_.queueRequest(context.configuration.agc.simple, context.activeState.agc.simple, > - frameContext.agc.simple, controls); > + std::visit(utils::overloaded { > + [&](AgcSimpleAlgorithm &impl) { > + impl.queueRequest(context.configuration.agc.simple, > + context.activeState.agc.simple, > + frameContext.agc.simple, controls); > + }, > + [&](AgcMeanLuminanceAlgorithm &impl) { > + impl.queueRequest(context.configuration.agc.ml, > + context.activeState.agc.ml, > + frameContext.agc.ml, controls); > + }, > + }, agc_); > } > > void Agc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, > IPAFrameContext &frameContext, [[maybe_unused]] DebayerParams *params) > { > - agc_.prepare(context.activeState.agc.simple, frameContext.agc.simple); > + std::visit(utils::overloaded { > + [&](AgcSimpleAlgorithm &impl) { > + impl.prepare(context.activeState.agc.simple, frameContext.agc.simple); > + }, > + [&](AgcMeanLuminanceAlgorithm &impl) { > + impl.prepare(context.activeState.agc.ml, frameContext.agc.ml); > + }, > + }, agc_); > } > > void Agc::process(IPAContext &context, > @@ -55,20 +141,43 @@ void Agc::process(IPAContext &context, > const SwIspStats *stats, > ControlList &metadata) > { > - if (stats->valid) { > - agc_.process(context.configuration.agc.simple, context.activeState.agc.simple, frameContext.agc.simple, {{ > - .exposure = frameContext.sensor.exposure, > - .gain = frameContext.sensor.gain, > - .stats = *stats, > - .blackLevel = context.activeState.blc.level, > - }}, metadata); > - } else { > - agc_.process(context.configuration.agc.simple, context.activeState.agc.simple, > - frameContext.agc.simple, {}, metadata); > - } > + std::visit(utils::overloaded { > + [&](AgcSimpleAlgorithm &impl) { > + if (stats->valid) { > + impl.process(context.configuration.agc.simple, context.activeState.agc.simple, frameContext.agc.simple, {{ > + .exposure = frameContext.sensor.exposure, > + .gain = frameContext.sensor.gain, > + .stats = *stats, > + .blackLevel = context.activeState.blc.level, > + }}, metadata); > + } else { > + impl.process(context.configuration.agc.simple, context.activeState.agc.simple, > + frameContext.agc.simple, {}, metadata); > + } > + > + frameContext.agc.exposure = frameContext.agc.simple.exposure; > + frameContext.agc.gain = frameContext.agc.simple.gain; > + }, > + [&](AgcMeanLuminanceAlgorithm &impl) { > + if (stats->valid) { > + Histogram hist(stats->yHistogram); > + > + impl.process(context.configuration.agc.ml, context.activeState.agc.ml, frameContext.agc.ml, {{ > + .traits = AgcTraits(*stats), > + .hist = hist, > + .exposure = uint32_t(frameContext.sensor.exposure), > + .gain = frameContext.sensor.gain, > + }}, metadata); > + > + } else { > + impl.process(context.configuration.agc.ml, context.activeState.agc.ml, > + frameContext.agc.ml, {}, metadata); > + } > > - frameContext.agc.exposure = frameContext.agc.simple.exposure; > - frameContext.agc.gain = frameContext.agc.simple.gain; > + frameContext.agc.exposure = frameContext.agc.ml.exposure; > + frameContext.agc.gain = frameContext.agc.ml.gain; > + }, > + }, agc_); > } > > REGISTER_IPA_ALGORITHM(Agc, "Agc") > diff --git a/src/ipa/simple/algorithms/agc.h b/src/ipa/simple/algorithms/agc.h > index 869817fc95..5dac17ab1d 100644 > --- a/src/ipa/simple/algorithms/agc.h > +++ b/src/ipa/simple/algorithms/agc.h > @@ -7,6 +7,10 @@ > > #pragma once > > +#include <variant> > + > +#include <libipa/agc_mean_luminance.h> > + > #include "algorithm.h" > #include "agc_simple.h" > > @@ -30,7 +34,10 @@ public: > ControlList &metadata) override; > > private: > - AgcSimpleAlgorithm agc_; > + std::variant< > + AgcSimpleAlgorithm, > + AgcMeanLuminanceAlgorithm > + > agc_; > }; > > } /* namespace ipa::soft::algorithms */ > diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h > index 36e1d8bba8..b4a11b04cd 100644 > --- a/src/ipa/simple/ipa_context.h > +++ b/src/ipa/simple/ipa_context.h > @@ -15,6 +15,7 @@ > #include "libcamera/internal/matrix.h" > #include "libcamera/internal/vector.h" > > +#include <libipa/agc_mean_luminance.h> > #include <libipa/camera_sensor_helper.h> > #include <libipa/fc_queue.h> > > @@ -29,6 +30,7 @@ namespace ipa::soft { > struct IPASessionConfiguration { > struct { > AgcSimpleAlgorithm::Session simple; > + AgcMeanLuminanceAlgorithm::Session ml; This is of course greatly suboptimal, this should really be a `union` or something similar. > double again10, againMinStep; > } agc; > struct { > @@ -39,6 +41,7 @@ struct IPASessionConfiguration { > struct IPAActiveState { > struct { > AgcSimpleAlgorithm::ActiveState simple; > + AgcMeanLuminanceAlgorithm::ActiveState ml; > } agc; > > struct { > @@ -67,6 +70,7 @@ struct IPAFrameContext : public FrameContext { > > struct { > AgcSimpleAlgorithm::FrameContext simple; > + AgcMeanLuminanceAlgorithm::FrameContext ml; > int32_t exposure; > double gain; > } agc; > -- > 2.54.0 >
diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp index db4f63eba5..7d035618e8 100644 --- a/src/ipa/simple/algorithms/agc.cpp +++ b/src/ipa/simple/algorithms/agc.cpp @@ -7,7 +7,12 @@ #include "agc.h" +#include <variant> + #include <libcamera/base/log.h> +#include <libcamera/base/utils.h> + +#include <libipa/histogram.h> namespace libcamera { @@ -15,38 +20,119 @@ LOG_DEFINE_CATEGORY(IPASoftExposure) namespace ipa::soft::algorithms { -int Agc::init(IPAContext &context, [[maybe_unused]] const ValueNode &tuningData) +namespace { + +class AgcTraits : public AgcMeanLuminance::Traits { - return agc_.configure(context.configuration.agc.simple, context.activeState.agc.simple, { +public: + AgcTraits(const SwIspStats &stats) + : stats_(stats) + { + } + + double estimateLuminance(double gain) const override + { + double sum = 0; + double count = 0; + + for (const auto &[i, cnt] : utils::enumerate(stats_.yHistogram)) { + sum += std::min(1.0, gain * i / stats_.yHistogram.size()) * cnt; + count += cnt; + } + + return sum / count; + } + +private: + const SwIspStats &stats_; +}; + +} + +int Agc::init(IPAContext &context, const ValueNode &tuningData) +{ + const AgcAlgorithm::ConfigurationParams config = { .sensor = context.camHelper.get(), .sensorInfo = context.sensorInfo, .sensorControls = context.sensorControls, .ctrlMap = context.ctrlMap, .autoAllowed = true, - }); + }; + + if (config.sensor) + agc_.emplace<AgcMeanLuminanceAlgorithm>(); + else + agc_.emplace<AgcSimpleAlgorithm>(); + + return std::visit(utils::overloaded { + [&](AgcSimpleAlgorithm &impl) { + return impl.configure(context.configuration.agc.simple, + context.activeState.agc.simple, + config); + }, + [&](AgcMeanLuminanceAlgorithm &impl) { + int ret = impl.init(tuningData); + if (ret) + return ret; + + return impl.configure(context.configuration.agc.ml, + context.activeState.agc.ml, + config); + }, + }, agc_); } int Agc::configure(IPAContext &context, [[maybe_unused]] const IPAConfigInfo &configInfo) { - return agc_.configure(context.configuration.agc.simple, context.activeState.agc.simple, { + const AgcAlgorithm::ConfigurationParams config = { .sensor = context.camHelper.get(), .sensorInfo = context.sensorInfo, .sensorControls = context.sensorControls, .ctrlMap = context.ctrlMap, - .autoAllowed = true, // \todo not if raw? - }); + .autoAllowed = true, // \todo if not raw? + }; + + return std::visit(utils::overloaded { + [&](AgcSimpleAlgorithm &impl) { + return impl.configure(context.configuration.agc.simple, + context.activeState.agc.simple, + config); + }, + [&](AgcMeanLuminanceAlgorithm &impl) { + return impl.configure(context.configuration.agc.ml, + context.activeState.agc.ml, + config); + }, + }, agc_); } void Agc::queueRequest(IPAContext &context, [[maybe_unused]] const uint32_t frame, IPAFrameContext &frameContext, const ControlList &controls) { - agc_.queueRequest(context.configuration.agc.simple, context.activeState.agc.simple, - frameContext.agc.simple, controls); + std::visit(utils::overloaded { + [&](AgcSimpleAlgorithm &impl) { + impl.queueRequest(context.configuration.agc.simple, + context.activeState.agc.simple, + frameContext.agc.simple, controls); + }, + [&](AgcMeanLuminanceAlgorithm &impl) { + impl.queueRequest(context.configuration.agc.ml, + context.activeState.agc.ml, + frameContext.agc.ml, controls); + }, + }, agc_); } void Agc::prepare(IPAContext &context, [[maybe_unused]] const uint32_t frame, IPAFrameContext &frameContext, [[maybe_unused]] DebayerParams *params) { - agc_.prepare(context.activeState.agc.simple, frameContext.agc.simple); + std::visit(utils::overloaded { + [&](AgcSimpleAlgorithm &impl) { + impl.prepare(context.activeState.agc.simple, frameContext.agc.simple); + }, + [&](AgcMeanLuminanceAlgorithm &impl) { + impl.prepare(context.activeState.agc.ml, frameContext.agc.ml); + }, + }, agc_); } void Agc::process(IPAContext &context, @@ -55,20 +141,43 @@ void Agc::process(IPAContext &context, const SwIspStats *stats, ControlList &metadata) { - if (stats->valid) { - agc_.process(context.configuration.agc.simple, context.activeState.agc.simple, frameContext.agc.simple, {{ - .exposure = frameContext.sensor.exposure, - .gain = frameContext.sensor.gain, - .stats = *stats, - .blackLevel = context.activeState.blc.level, - }}, metadata); - } else { - agc_.process(context.configuration.agc.simple, context.activeState.agc.simple, - frameContext.agc.simple, {}, metadata); - } + std::visit(utils::overloaded { + [&](AgcSimpleAlgorithm &impl) { + if (stats->valid) { + impl.process(context.configuration.agc.simple, context.activeState.agc.simple, frameContext.agc.simple, {{ + .exposure = frameContext.sensor.exposure, + .gain = frameContext.sensor.gain, + .stats = *stats, + .blackLevel = context.activeState.blc.level, + }}, metadata); + } else { + impl.process(context.configuration.agc.simple, context.activeState.agc.simple, + frameContext.agc.simple, {}, metadata); + } + + frameContext.agc.exposure = frameContext.agc.simple.exposure; + frameContext.agc.gain = frameContext.agc.simple.gain; + }, + [&](AgcMeanLuminanceAlgorithm &impl) { + if (stats->valid) { + Histogram hist(stats->yHistogram); + + impl.process(context.configuration.agc.ml, context.activeState.agc.ml, frameContext.agc.ml, {{ + .traits = AgcTraits(*stats), + .hist = hist, + .exposure = uint32_t(frameContext.sensor.exposure), + .gain = frameContext.sensor.gain, + }}, metadata); + + } else { + impl.process(context.configuration.agc.ml, context.activeState.agc.ml, + frameContext.agc.ml, {}, metadata); + } - frameContext.agc.exposure = frameContext.agc.simple.exposure; - frameContext.agc.gain = frameContext.agc.simple.gain; + frameContext.agc.exposure = frameContext.agc.ml.exposure; + frameContext.agc.gain = frameContext.agc.ml.gain; + }, + }, agc_); } REGISTER_IPA_ALGORITHM(Agc, "Agc") diff --git a/src/ipa/simple/algorithms/agc.h b/src/ipa/simple/algorithms/agc.h index 869817fc95..5dac17ab1d 100644 --- a/src/ipa/simple/algorithms/agc.h +++ b/src/ipa/simple/algorithms/agc.h @@ -7,6 +7,10 @@ #pragma once +#include <variant> + +#include <libipa/agc_mean_luminance.h> + #include "algorithm.h" #include "agc_simple.h" @@ -30,7 +34,10 @@ public: ControlList &metadata) override; private: - AgcSimpleAlgorithm agc_; + std::variant< + AgcSimpleAlgorithm, + AgcMeanLuminanceAlgorithm + > agc_; }; } /* namespace ipa::soft::algorithms */ diff --git a/src/ipa/simple/ipa_context.h b/src/ipa/simple/ipa_context.h index 36e1d8bba8..b4a11b04cd 100644 --- a/src/ipa/simple/ipa_context.h +++ b/src/ipa/simple/ipa_context.h @@ -15,6 +15,7 @@ #include "libcamera/internal/matrix.h" #include "libcamera/internal/vector.h" +#include <libipa/agc_mean_luminance.h> #include <libipa/camera_sensor_helper.h> #include <libipa/fc_queue.h> @@ -29,6 +30,7 @@ namespace ipa::soft { struct IPASessionConfiguration { struct { AgcSimpleAlgorithm::Session simple; + AgcMeanLuminanceAlgorithm::Session ml; double again10, againMinStep; } agc; struct { @@ -39,6 +41,7 @@ struct IPASessionConfiguration { struct IPAActiveState { struct { AgcSimpleAlgorithm::ActiveState simple; + AgcMeanLuminanceAlgorithm::ActiveState ml; } agc; struct { @@ -67,6 +70,7 @@ struct IPAFrameContext : public FrameContext { struct { AgcSimpleAlgorithm::FrameContext simple; + AgcMeanLuminanceAlgorithm::FrameContext ml; int32_t exposure; double gain; } agc;
Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com> --- src/ipa/simple/algorithms/agc.cpp | 153 +++++++++++++++++++++++++----- src/ipa/simple/algorithms/agc.h | 9 +- src/ipa/simple/ipa_context.h | 4 + 3 files changed, 143 insertions(+), 23 deletions(-)