Skip to content

Commit 3523393

Browse files
committed
ipa: rkisp1: agc: Read histogram weights from tuning file
Add support to the rkisp1 AGC to read histogram weights from the tuning file. As controls for selecting the metering mode are not yet supported, for now hardcode the matrix metering mode, which is the same as what the AGC previously hardcoded. Signed-off-by: Paul Elder <paul.elder@ideasonboard.com> Reviewed-by: Stefan Klug <stefan.klug@ideasonboard.com> Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
1 parent 1b91725 commit 3523393

File tree

2 files changed

+103
-3
lines changed

2 files changed

+103
-3
lines changed

src/ipa/rkisp1/algorithms/agc.cpp

Lines changed: 97 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
#include <libcamera/control_ids.h>
1818
#include <libcamera/ipa/core_ipa_interface.h>
1919

20+
#include "libcamera/internal/yaml_parser.h"
21+
2022
#include "libipa/histogram.h"
2123

2224
/**
@@ -36,6 +38,85 @@ namespace ipa::rkisp1::algorithms {
3638

3739
LOG_DEFINE_CATEGORY(RkISP1Agc)
3840

41+
int Agc::parseMeteringModes(IPAContext &context, const YamlObject &tuningData)
42+
{
43+
if (!tuningData.isDictionary()) {
44+
LOG(RkISP1Agc, Error)
45+
<< "'AeMeteringMode' parameter not found in tuning file";
46+
return -EINVAL;
47+
}
48+
49+
for (const auto &[key, value] : tuningData.asDict()) {
50+
if (controls::AeMeteringModeNameValueMap.find(key) ==
51+
controls::AeMeteringModeNameValueMap.end()) {
52+
LOG(RkISP1Agc, Warning)
53+
<< "Skipping unknown metering mode '" << key << "'";
54+
continue;
55+
}
56+
57+
std::vector<uint8_t> weights =
58+
value.getList<uint8_t>().value_or(std::vector<uint8_t>{});
59+
if (weights.size() != context.hw->numHistogramWeights) {
60+
LOG(RkISP1Agc, Warning)
61+
<< "Failed to read metering mode'" << key << "'";
62+
continue;
63+
}
64+
65+
meteringModes_[controls::AeMeteringModeNameValueMap.at(key)] = weights;
66+
}
67+
68+
if (meteringModes_.empty()) {
69+
LOG(RkISP1Agc, Warning)
70+
<< "No metering modes read from tuning file; defaulting to matrix";
71+
int32_t meteringModeId = controls::AeMeteringModeNameValueMap.at("MeteringMatrix");
72+
std::vector<uint8_t> weights(context.hw->numHistogramWeights, 1);
73+
74+
meteringModes_[meteringModeId] = weights;
75+
}
76+
77+
return 0;
78+
}
79+
80+
uint8_t Agc::computeHistogramPredivider(Size &size, enum rkisp1_cif_isp_histogram_mode mode)
81+
{
82+
/*
83+
* The maximum number of pixels that could potentially be in one bin is
84+
* if all the pixels of the image are in it, multiplied by 3 for the
85+
* three color channels. The counter for each bin is 16 bits wide, so
86+
* `factor` thus contains the number of times we'd wrap around. This is
87+
* obviously the number of pixels that we need to skip to make sure
88+
* that we don't wrap around, but we compute the square root of it
89+
* instead, as the skip that we need to program is for both the x and y
90+
* directions.
91+
*
92+
* Even though it looks like dividing into a counter of 65536 would
93+
* overflow by 1, this is apparently fine according to the hardware
94+
* documentation, and this successfully gets the expected documented
95+
* predivider size for cases where:
96+
* (width / predivider) * (height / predivider) * 3 == 65536.
97+
*
98+
* There's a bit of extra rounding math to make sure the rounding goes
99+
* the correct direction so that the square of the step is big enough
100+
* to encompass the `factor` number of pixels that we need to skip.
101+
*
102+
* \todo Take into account weights. That is, if the weights are low
103+
* enough we can potentially reduce the predivider to increase
104+
* precision. This needs some investigation however, as this hardware
105+
* behavior is undocumented and is only an educated guess.
106+
*/
107+
int count = mode == RKISP1_CIF_ISP_HISTOGRAM_MODE_RGB_COMBINED ? 3 : 1;
108+
double factor = size.width * size.height * count / 65536.0;
109+
double root = std::sqrt(factor);
110+
uint8_t predivider;
111+
112+
if (std::pow(std::floor(root), 2) < factor)
113+
predivider = static_cast<uint8_t>(std::ceil(root));
114+
else
115+
predivider = static_cast<uint8_t>(std::floor(root));
116+
117+
return std::clamp<uint8_t>(predivider, 3, 127);
118+
}
119+
39120
Agc::Agc()
40121
{
41122
supportsRaw_ = true;
@@ -59,6 +140,11 @@ int Agc::init(IPAContext &context, const YamlObject &tuningData)
59140
if (ret)
60141
return ret;
61142

143+
const YamlObject &yamlMeteringModes = tuningData["AeMeteringMode"];
144+
ret = parseMeteringModes(context, yamlMeteringModes);
145+
if (ret)
146+
return ret;
147+
62148
context.ctrlMap.merge(controls());
63149

64150
return 0;
@@ -160,6 +246,7 @@ void Agc::prepare(IPAContext &context, const uint32_t frame,
160246
frameContext.agc.gain = context.activeState.agc.automatic.gain;
161247
}
162248

249+
/* \todo Remove this when we can set the below with controls */
163250
if (frame > 0)
164251
return;
165252

@@ -178,14 +265,21 @@ void Agc::prepare(IPAContext &context, const uint32_t frame,
178265
params->meas.hst_config.meas_window = context.configuration.agc.measureWindow;
179266
/* Produce the luminance histogram. */
180267
params->meas.hst_config.mode = RKISP1_CIF_ISP_HISTOGRAM_MODE_Y_HISTOGRAM;
268+
181269
/* Set an average weighted histogram. */
182270
Span<uint8_t> weights{
183271
params->meas.hst_config.hist_weight,
184272
context.hw->numHistogramWeights
185273
};
186-
std::fill(weights.begin(), weights.end(), 1);
187-
/* Step size can't be less than 3. */
188-
params->meas.hst_config.histogram_predivider = 4;
274+
/* \todo Get this from control */
275+
std::vector<uint8_t> &modeWeights = meteringModes_.at(controls::MeteringMatrix);
276+
std::copy(modeWeights.begin(), modeWeights.end(), weights.begin());
277+
278+
struct rkisp1_cif_isp_window window = params->meas.hst_config.meas_window;
279+
Size windowSize = { window.h_size, window.v_size };
280+
params->meas.hst_config.histogram_predivider =
281+
computeHistogramPredivider(windowSize,
282+
static_cast<rkisp1_cif_isp_histogram_mode>(params->meas.hst_config.mode));
189283

190284
/* Update the configuration for histogram. */
191285
params->module_cfg_update |= RKISP1_CIF_ISP_MODULE_HST;

src/ipa/rkisp1/algorithms/agc.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,17 @@ class Agc : public Algorithm, public AgcMeanLuminance
4444
ControlList &metadata) override;
4545

4646
private:
47+
int parseMeteringModes(IPAContext &context, const YamlObject &tuningData);
48+
uint8_t computeHistogramPredivider(Size &size,
49+
enum rkisp1_cif_isp_histogram_mode mode);
50+
4751
void fillMetadata(IPAContext &context, IPAFrameContext &frameContext,
4852
ControlList &metadata);
4953
double estimateLuminance(double gain) const override;
5054

5155
Span<const uint8_t> expMeans_;
56+
57+
std::map<int32_t, std::vector<uint8_t>> meteringModes_;
5258
};
5359

5460
} /* namespace ipa::rkisp1::algorithms */

0 commit comments

Comments
 (0)