[libcamera-devel] [RFC PATCH 5/5] ipa: ipu3: Move IPU3 agc into algorithms
Jean-Michel Hautbois
jeanmichel.hautbois at ideasonboard.com
Mon Aug 9 11:20:07 CEST 2021
Use the Context class and algorithm interface to properly call the AGC
algorithm from IPAIPU3.
We need to pass shutter speed and analogue gain through Context. Add a
dedicated AGC structure for that.
Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois at ideasonboard.com>
---
.../ipu3/{ipu3_agc.cpp => algorithms/agc.cpp} | 56 ++++++++++---------
src/ipa/ipu3/{ipu3_agc.h => algorithms/agc.h} | 31 +++++-----
src/ipa/ipu3/algorithms/meson.build | 1 +
src/ipa/ipu3/ipa_context.h | 11 ++++
src/ipa/ipu3/ipu3.cpp | 25 +++++----
src/ipa/ipu3/meson.build | 1 -
6 files changed, 70 insertions(+), 55 deletions(-)
rename src/ipa/ipu3/{ipu3_agc.cpp => algorithms/agc.cpp} (81%)
rename src/ipa/ipu3/{ipu3_agc.h => algorithms/agc.h} (61%)
diff --git a/src/ipa/ipu3/ipu3_agc.cpp b/src/ipa/ipu3/algorithms/agc.cpp
similarity index 81%
rename from src/ipa/ipu3/ipu3_agc.cpp
rename to src/ipa/ipu3/algorithms/agc.cpp
index 733814dd..1146a34a 100644
--- a/src/ipa/ipu3/ipu3_agc.cpp
+++ b/src/ipa/ipu3/algorithms/agc.cpp
@@ -2,26 +2,25 @@
/*
* Copyright (C) 2021, Ideas On Board
*
- * ipu3_agc.cpp - AGC/AEC control algorithm
+ * agc.cpp - AGC/AEC control algorithm
*/
-#include "ipu3_agc.h"
+#include "agc.h"
-#include <algorithm>
#include <cmath>
+
+#include <algorithm>
#include <numeric>
#include <libcamera/base/log.h>
-#include <libcamera/ipa/core_ipa_interface.h>
-
#include "libipa/histogram.h"
namespace libcamera {
using namespace std::literals::chrono_literals;
-namespace ipa::ipu3 {
+namespace ipa::ipu3::algorithms {
LOG_DEFINE_CATEGORY(IPU3Agc)
@@ -36,8 +35,8 @@ static constexpr uint32_t kMaxISO = 1500;
/* Maximum analogue gain value
* \todo grab it from a camera helper */
-static constexpr uint32_t kMinGain = kMinISO / 100;
-static constexpr uint32_t kMaxGain = kMaxISO / 100;
+static constexpr double kMinGain = kMinISO / 100;
+static constexpr double kMaxGain = kMaxISO / 100;
/* \todo use calculated value based on sensor */
static constexpr uint32_t kMinExposure = 1;
@@ -50,24 +49,24 @@ static constexpr double kEvGainTarget = 0.5;
/* A cell is 8 bytes and contains averages for RGB values and saturation ratio */
static constexpr uint8_t kCellSize = 8;
-IPU3Agc::IPU3Agc()
+Agc::Agc()
: frameCount_(0), lastFrame_(0), converged_(false),
- updateControls_(false), iqMean_(0.0),
- lineDuration_(0s), maxExposureTime_(0s),
+ updateControls_(false), iqMean_(0.0), maxExposureTime_(0s),
prevExposure_(0s), prevExposureNoDg_(0s),
currentExposure_(0s), currentExposureNoDg_(0s)
{
}
-void IPU3Agc::initialise(struct ipu3_uapi_grid_config &bdsGrid, const IPACameraSensorInfo &sensorInfo)
+int Agc::configure(IPAContext &context)
{
- aeGrid_ = bdsGrid;
+ /* The AGC algorithm uses the AWB statistics */
+ aeGrid_ = context.awb.grid.bdsGrid;
+ maxExposureTime_ = kMaxExposure * context.agc.lineDuration;
- lineDuration_ = sensorInfo.lineLength * 1.0s / sensorInfo.pixelRate;
- maxExposureTime_ = kMaxExposure * lineDuration_;
+ return 0;
}
-void IPU3Agc::processBrightness(const ipu3_uapi_stats_3a *stats)
+void Agc::processBrightness(const ipu3_uapi_stats_3a *stats)
{
const struct ipu3_uapi_grid_config statsAeGrid = stats->stats_4a_config.awb_config.grid;
Rectangle aeRegion = { statsAeGrid.x_start,
@@ -108,7 +107,7 @@ void IPU3Agc::processBrightness(const ipu3_uapi_stats_3a *stats)
iqMean_ = Histogram(Span<uint32_t>(hist)).interQuantileMean(0.98, 1.0);
}
-void IPU3Agc::filterExposure()
+void Agc::filterExposure()
{
double speed = 0.2;
if (prevExposure_ == 0s) {
@@ -128,7 +127,7 @@ void IPU3Agc::filterExposure()
prevExposure_ = speed * currentExposure_ +
prevExposure_ * (1.0 - speed);
prevExposureNoDg_ = speed * currentExposureNoDg_ +
- prevExposureNoDg_ * (1.0 - speed);
+ prevExposureNoDg_ * (1.0 - speed);
}
/*
* We can't let the no_dg exposure deviate too far below the
@@ -142,7 +141,7 @@ void IPU3Agc::filterExposure()
LOG(IPU3Agc, Debug) << "After filtering, total_exposure " << prevExposure_;
}
-void IPU3Agc::lockExposureGain(uint32_t &exposure, double &gain)
+void Agc::lockExposureGain(IPAContext &context)
{
updateControls_ = false;
@@ -160,7 +159,9 @@ void IPU3Agc::lockExposureGain(uint32_t &exposure, double &gain)
double newGain = kEvGainTarget * knumHistogramBins / iqMean_;
/* extracted from Rpi::Agc::computeTargetExposure */
- libcamera::utils::Duration currentShutter = exposure * lineDuration_;
+ libcamera::utils::Duration currentShutter = context.agc.shutterTime;
+ uint32_t exposure = currentShutter / context.agc.lineDuration;
+ double &gain = context.agc.analogueGain;
currentExposureNoDg_ = currentShutter * gain;
LOG(IPU3Agc, Debug) << "Actual total exposure " << currentExposureNoDg_
<< " Shutter speed " << currentShutter
@@ -177,26 +178,27 @@ void IPU3Agc::lockExposureGain(uint32_t &exposure, double &gain)
if (currentShutter < maxExposureTime_) {
exposure = std::clamp(static_cast<uint32_t>(exposure * currentExposure_ / currentExposureNoDg_), kMinExposure, kMaxExposure);
newExposure = currentExposure_ / exposure;
- gain = std::clamp(static_cast<uint32_t>(gain * currentExposure_ / newExposure), kMinGain, kMaxGain);
+ gain = std::clamp(static_cast<double>(gain * currentExposure_ / newExposure), kMinGain, kMaxGain);
updateControls_ = true;
} else if (currentShutter >= maxExposureTime_) {
- gain = std::clamp(static_cast<uint32_t>(gain * currentExposure_ / currentExposureNoDg_), kMinGain, kMaxGain);
+ gain = std::clamp(static_cast<double>(gain * currentExposure_ / currentExposureNoDg_), kMinGain, kMaxGain);
newExposure = currentExposure_ / gain;
exposure = std::clamp(static_cast<uint32_t>(exposure * currentExposure_ / newExposure), kMinExposure, kMaxExposure);
updateControls_ = true;
}
- LOG(IPU3Agc, Debug) << "Adjust exposure " << exposure * lineDuration_ << " and gain " << gain;
+ context.agc.shutterTime = exposure * context.agc.lineDuration;
+ LOG(IPU3Agc, Debug) << "Adjust exposure " << exposure * context.agc.lineDuration << " and gain " << gain;
}
lastFrame_ = frameCount_;
}
-void IPU3Agc::process(const ipu3_uapi_stats_3a *stats, uint32_t &exposure, double &gain)
+void Agc::process(IPAContext &context)
{
- processBrightness(stats);
- lockExposureGain(exposure, gain);
+ processBrightness(context.stats);
+ lockExposureGain(context);
frameCount_++;
}
-} /* namespace ipa::ipu3 */
+} /* namespace ipa::ipu3::algorithms */
} /* namespace libcamera */
diff --git a/src/ipa/ipu3/ipu3_agc.h b/src/ipa/ipu3/algorithms/agc.h
similarity index 61%
rename from src/ipa/ipu3/ipu3_agc.h
rename to src/ipa/ipu3/algorithms/agc.h
index 3b7f781e..e87a06f3 100644
--- a/src/ipa/ipu3/ipu3_agc.h
+++ b/src/ipa/ipu3/algorithms/agc.h
@@ -4,44 +4,44 @@
*
* ipu3_agc.h - IPU3 AGC/AEC control algorithm
*/
-#ifndef __LIBCAMERA_IPU3_AGC_H__
-#define __LIBCAMERA_IPU3_AGC_H__
+#ifndef __LIBCAMERA_IPU3_ALGORITHMS_AGC_H__
+#define __LIBCAMERA_IPU3_ALGORITHMS_AGC_H__
+
+#include <linux/intel-ipu3.h>
#include <array>
#include <unordered_map>
-#include <linux/intel-ipu3.h>
-
#include <libcamera/base/utils.h>
#include <libcamera/geometry.h>
-#include "algorithms/algorithm.h"
-#include "libipa/algorithm.h"
+#include "algorithm.h"
namespace libcamera {
struct IPACameraSensorInfo;
-namespace ipa::ipu3 {
+namespace ipa::ipu3::algorithms {
using utils::Duration;
-class IPU3Agc : public ipa::Algorithm
+class Agc : public Algorithm
{
public:
- IPU3Agc();
- ~IPU3Agc() = default;
+ Agc();
+ ~Agc() = default;
+
+ int configure(IPAContext &context) override;
+ void process(IPAContext &context) override;
- void initialise(struct ipu3_uapi_grid_config &bdsGrid, const IPACameraSensorInfo &sensorInfo);
- void process(const ipu3_uapi_stats_3a *stats, uint32_t &exposure, double &gain);
bool converged() { return converged_; }
bool updateControls() { return updateControls_; }
private:
void processBrightness(const ipu3_uapi_stats_3a *stats);
void filterExposure();
- void lockExposureGain(uint32_t &exposure, double &gain);
+ void lockExposureGain(IPAContext &context);
struct ipu3_uapi_grid_config aeGrid_;
@@ -53,7 +53,6 @@ private:
double iqMean_;
- Duration lineDuration_;
Duration maxExposureTime_;
Duration prevExposure_;
@@ -62,8 +61,8 @@ private:
Duration currentExposureNoDg_;
};
-} /* namespace ipa::ipu3 */
+} /* namespace ipa::ipu3::algorithms */
} /* namespace libcamera */
-#endif /* __LIBCAMERA_IPU3_AGC_H__ */
+#endif /* __LIBCAMERA_IPU3_ALGORITHMS_AGC_H__ */
diff --git a/src/ipa/ipu3/algorithms/meson.build b/src/ipa/ipu3/algorithms/meson.build
index df36d719..3faf913e 100644
--- a/src/ipa/ipu3/algorithms/meson.build
+++ b/src/ipa/ipu3/algorithms/meson.build
@@ -1,6 +1,7 @@
# SPDX-License-Identifier: CC0-1.0
ipu3_ipa_algorithms = files([
+ 'agc.cpp',
'awb.cpp',
'contrast.cpp',
])
diff --git a/src/ipa/ipu3/ipa_context.h b/src/ipa/ipu3/ipa_context.h
index c43b275b..1d7a1984 100644
--- a/src/ipa/ipu3/ipa_context.h
+++ b/src/ipa/ipu3/ipa_context.h
@@ -11,10 +11,14 @@
#include <linux/intel-ipu3.h>
+#include <libcamera/base/utils.h>
+
#include <libcamera/geometry.h>
namespace libcamera {
+using libcamera::utils::Duration;
+
namespace ipa::ipu3 {
struct IPAContext {
@@ -33,6 +37,13 @@ struct IPAContext {
Size bdsOutputSize;
} grid;
} awb;
+
+ /* AGC specific parameters to share */
+ struct Agc {
+ Duration lineDuration;
+ Duration shutterTime;
+ double analogueGain;
+ } agc;
};
} /* namespace ipa::ipu3 */
diff --git a/src/ipa/ipu3/ipu3.cpp b/src/ipa/ipu3/ipu3.cpp
index 82506461..07b1d11c 100644
--- a/src/ipa/ipu3/ipu3.cpp
+++ b/src/ipa/ipu3/ipu3.cpp
@@ -22,12 +22,12 @@
#include "libcamera/internal/framebuffer.h"
+#include "algorithms/agc.h"
#include "algorithms/algorithm.h"
#include "algorithms/awb.h"
#include "algorithms/contrast.h"
#include "ipa_context.h"
-#include "ipu3_agc.h"
#include "libipa/camera_sensor_helper.h"
static constexpr uint32_t kMaxCellWidthPerSet = 160;
@@ -37,6 +37,8 @@ namespace libcamera {
LOG_DEFINE_CATEGORY(IPAIPU3)
+using namespace std::literals::chrono_literals;
+
namespace ipa::ipu3 {
class IPAIPU3 : public IPAIPU3Interface
@@ -81,8 +83,6 @@ private:
uint32_t minGain_;
uint32_t maxGain_;
- /* Interface to the AEC/AGC algorithm */
- std::unique_ptr<IPU3Agc> agcAlgo_;
/* Interface to the Camera Helper */
std::unique_ptr<CameraSensorHelper> camHelper_;
@@ -103,6 +103,7 @@ int IPAIPU3::init(const IPASettings &settings)
}
/* Construct our Algorithms */
+ algorithms_.emplace_back(new algorithms::Agc());
algorithms_.emplace_back(new algorithms::Awb());
algorithms_.emplace_back(new algorithms::Contrast());
@@ -214,11 +215,14 @@ int IPAIPU3::configure(const IPAConfigInfo &configInfo)
calculateBdsGrid(configInfo.bdsOutputSize);
context_.awb.grid.bdsOutputSize = configInfo.bdsOutputSize;
+ /* Prepare AGC parameters */
+ context_.agc.lineDuration = sensorInfo_.lineLength * 1.0s / sensorInfo_.pixelRate;
+ context_.agc.shutterTime = exposure_ * context_.agc.lineDuration;
+ context_.agc.analogueGain = camHelper_->gain(gain_);
+
configureAlgorithms();
bdsGrid_ = context_.awb.grid.bdsGrid;
- agcAlgo_ = std::make_unique<IPU3Agc>();
- agcAlgo_->initialise(bdsGrid_, sensorInfo_);
return 0;
}
@@ -341,12 +345,7 @@ void IPAIPU3::parseStatistics(unsigned int frame,
/* Run the process for each algorithm on the stats */
processAlgorithms(stats);
- double gain = camHelper_->gain(gain_);
- agcAlgo_->process(stats, exposure_, gain);
- gain_ = camHelper_->gainCode(gain);
-
- if (agcAlgo_->updateControls())
- setControls(frame);
+ setControls(frame);
/* \todo Use VBlank value calculated from each frame exposure. */
int64_t frameDuration = sensorInfo_.lineLength * (defVBlank_ + sensorInfo_.outputSize.height) /
@@ -365,6 +364,10 @@ void IPAIPU3::setControls(unsigned int frame)
IPU3Action op;
op.op = ActionSetSensorControls;
+ /* Convert gain and exposure */
+ gain_ = camHelper_->gainCode(context_.agc.analogueGain);
+ exposure_ = context_.agc.shutterTime / context_.agc.lineDuration;
+
ControlList ctrls(ctrls_);
ctrls.set(V4L2_CID_EXPOSURE, static_cast<int32_t>(exposure_));
ctrls.set(V4L2_CID_ANALOGUE_GAIN, static_cast<int32_t>(gain_));
diff --git a/src/ipa/ipu3/meson.build b/src/ipa/ipu3/meson.build
index d1126947..39320980 100644
--- a/src/ipa/ipu3/meson.build
+++ b/src/ipa/ipu3/meson.build
@@ -6,7 +6,6 @@ ipa_name = 'ipa_ipu3'
ipu3_ipa_sources = files([
'ipu3.cpp',
- 'ipu3_agc.cpp',
])
ipu3_ipa_sources += ipu3_ipa_algorithms
--
2.30.2
More information about the libcamera-devel
mailing list