diff options
Diffstat (limited to 'src/ipa/rpi/controller')
-rw-r--r-- | src/ipa/rpi/controller/histogram.cpp | 6 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/af.cpp | 4 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/agc_channel.cpp | 16 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/alsc.cpp | 24 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/awb.cpp | 41 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/awb.h | 4 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/black_level.cpp | 1 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/ccm.cpp | 12 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/contrast.cpp | 8 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/geq.cpp | 6 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/hdr.cpp | 4 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/lux.cpp | 1 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/noise.cpp | 4 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/sharpen.cpp | 4 | ||||
-rw-r--r-- | src/ipa/rpi/controller/rpi/tonemap.cpp | 2 |
15 files changed, 91 insertions, 46 deletions
diff --git a/src/ipa/rpi/controller/histogram.cpp b/src/ipa/rpi/controller/histogram.cpp index ba5b25dd..13089839 100644 --- a/src/ipa/rpi/controller/histogram.cpp +++ b/src/ipa/rpi/controller/histogram.cpp @@ -4,7 +4,7 @@ * * histogram calculations */ -#include <math.h> +#include <cmath> #include <stdio.h> #include "histogram.h" @@ -49,9 +49,9 @@ double Histogram::interBinMean(double binLo, double binHi) const { assert(binHi >= binLo); double sumBinFreq = 0, cumulFreq = 0; - for (double binNext = floor(binLo) + 1.0; binNext <= ceil(binHi); + for (double binNext = std::floor(binLo) + 1.0; binNext <= std::ceil(binHi); binLo = binNext, binNext += 1.0) { - int bin = floor(binLo); + int bin = std::floor(binLo); double freq = (cumulative_[bin + 1] - cumulative_[bin]) * (std::min(binNext, binHi) - binLo); sumBinFreq += bin * freq; diff --git a/src/ipa/rpi/controller/rpi/af.cpp b/src/ipa/rpi/controller/rpi/af.cpp index 304629d6..2157eb94 100644 --- a/src/ipa/rpi/controller/rpi/af.cpp +++ b/src/ipa/rpi/controller/rpi/af.cpp @@ -7,8 +7,8 @@ #include "af.h" +#include <cmath> #include <iomanip> -#include <math.h> #include <stdlib.h> #include <libcamera/base/log.h> @@ -139,7 +139,7 @@ int Af::CfgParams::read(const libcamera::YamlObject ¶ms) readNumber<uint32_t>(skipFrames, params, "skip_frames"); if (params.contains("map")) - map.readYaml(params["map"]); + map = params["map"].get<ipa::Pwl>(ipa::Pwl{}); else LOG(RPiAf, Warning) << "No map defined"; diff --git a/src/ipa/rpi/controller/rpi/agc_channel.cpp b/src/ipa/rpi/controller/rpi/agc_channel.cpp index a381dd97..c9df9b5b 100644 --- a/src/ipa/rpi/controller/rpi/agc_channel.cpp +++ b/src/ipa/rpi/controller/rpi/agc_channel.cpp @@ -130,7 +130,8 @@ int AgcConstraint::read(const libcamera::YamlObject ¶ms) return -EINVAL; qHi = *value; - return yTarget.readYaml(params["y_target"]); + yTarget = params["y_target"].get<ipa::Pwl>(ipa::Pwl{}); + return yTarget.empty() ? -EINVAL : 0; } static std::tuple<int, AgcConstraintMode> @@ -237,9 +238,9 @@ int AgcConfig::read(const libcamera::YamlObject ¶ms) return ret; } - ret = yTarget.readYaml(params["y_target"]); - if (ret) - return ret; + yTarget = params["y_target"].get<ipa::Pwl>(ipa::Pwl{}); + if (yTarget.empty()) + return -EINVAL; speed = params["speed"].get<double>(0.2); startupFrames = params["startup_frames"].get<uint16_t>(10); @@ -882,11 +883,14 @@ void AgcChannel::filterExposure() /* * AGC adapts instantly if both shutter and gain are directly specified - * or we're in the startup phase. + * or we're in the startup phase. Also disable the stable region, because we want + * to reflect any user exposure/gain updates, however small. */ if ((status_.fixedShutter && status_.fixedAnalogueGain) || - frameCount_ <= config_.startupFrames) + frameCount_ <= config_.startupFrames) { speed = 1.0; + stableRegion = 0.0; + } if (!filtered_.totalExposure) { filtered_.totalExposure = target_.totalExposure; } else if (filtered_.totalExposure * (1.0 - stableRegion) < target_.totalExposure && diff --git a/src/ipa/rpi/controller/rpi/alsc.cpp b/src/ipa/rpi/controller/rpi/alsc.cpp index 67029fc3..21edb819 100644 --- a/src/ipa/rpi/controller/rpi/alsc.cpp +++ b/src/ipa/rpi/controller/rpi/alsc.cpp @@ -6,9 +6,10 @@ */ #include <algorithm> +#include <cmath> #include <functional> -#include <math.h> #include <numeric> +#include <vector> #include <libcamera/base/log.h> #include <libcamera/base/span.h> @@ -251,12 +252,12 @@ static bool compareModes(CameraMode const &cm0, CameraMode const &cm1) */ if (cm0.transform != cm1.transform) return true; - int leftDiff = abs(cm0.cropX - cm1.cropX); - int topDiff = abs(cm0.cropY - cm1.cropY); - int rightDiff = fabs(cm0.cropX + cm0.scaleX * cm0.width - - cm1.cropX - cm1.scaleX * cm1.width); - int bottomDiff = fabs(cm0.cropY + cm0.scaleY * cm0.height - - cm1.cropY - cm1.scaleY * cm1.height); + int leftDiff = std::abs(cm0.cropX - cm1.cropX); + int topDiff = std::abs(cm0.cropY - cm1.cropY); + int rightDiff = std::abs(cm0.cropX + cm0.scaleX * cm0.width - + cm1.cropX - cm1.scaleX * cm1.width); + int bottomDiff = std::abs(cm0.cropY + cm0.scaleY * cm0.height - + cm1.cropY - cm1.scaleY * cm1.height); /* * These thresholds are a rather arbitrary amount chosen to trigger * when carrying on with the previously calculated tables might be @@ -496,8 +497,9 @@ void resampleCalTable(const Array2D<double> &calTableIn, * Precalculate and cache the x sampling locations and phases to save * recomputing them on every row. */ - int xLo[X], xHi[X]; - double xf[X]; + std::vector<int> xLo(X); + std::vector<int> xHi(X); + std::vector<double> xf(X); double scaleX = cameraMode.sensorWidth / (cameraMode.width * cameraMode.scaleX); double xOff = cameraMode.cropX / (double)cameraMode.sensorWidth; @@ -730,7 +732,7 @@ static double gaussSeidel2Sor(const SparseArray<double> &M, double omega, double maxDiff = 0; for (i = 0; i < XY; i++) { lambda[i] = oldLambda[i] + (lambda[i] - oldLambda[i]) * omega; - if (fabs(lambda[i] - oldLambda[i]) > fabs(maxDiff)) + if (std::abs(lambda[i] - oldLambda[i]) > std::abs(maxDiff)) maxDiff = lambda[i] - oldLambda[i]; } return maxDiff; @@ -762,7 +764,7 @@ static void runMatrixIterations(const Array2D<double> &C, constructM(C, W, M); double lastMaxDiff = std::numeric_limits<double>::max(); for (unsigned int i = 0; i < nIter; i++) { - double maxDiff = fabs(gaussSeidel2Sor(M, omega, lambda, lambdaBound)); + double maxDiff = std::abs(gaussSeidel2Sor(M, omega, lambda, lambdaBound)); if (maxDiff < threshold) { LOG(RPiAlsc, Debug) << "Stop after " << i + 1 << " iterations"; diff --git a/src/ipa/rpi/controller/rpi/awb.cpp b/src/ipa/rpi/controller/rpi/awb.cpp index 603953d7..9d8e170d 100644 --- a/src/ipa/rpi/controller/rpi/awb.cpp +++ b/src/ipa/rpi/controller/rpi/awb.cpp @@ -6,6 +6,7 @@ */ #include <assert.h> +#include <cmath> #include <functional> #include <libcamera/base/log.h> @@ -20,6 +21,8 @@ using namespace libcamera; LOG_DEFINE_CATEGORY(RPiAwb) +constexpr double kDefaultCT = 4500.0; + #define NAME "rpi.awb" /* @@ -49,7 +52,8 @@ int AwbPrior::read(const libcamera::YamlObject ¶ms) return -EINVAL; lux = *value; - return prior.readYaml(params["prior"]); + prior = params["prior"].get<ipa::Pwl>(ipa::Pwl{}); + return prior.empty() ? -EINVAL : 0; } static int readCtCurve(ipa::Pwl &ctR, ipa::Pwl &ctB, const libcamera::YamlObject ¶ms) @@ -121,7 +125,7 @@ int AwbConfig::read(const libcamera::YamlObject ¶ms) } if (priors.empty()) { LOG(RPiAwb, Error) << "AwbConfig: no AWB priors configured"; - return ret; + return -EINVAL; } } if (params.contains("modes")) { @@ -166,6 +170,14 @@ int AwbConfig::read(const libcamera::YamlObject ¶ms) whitepointB = params["whitepoint_b"].get<double>(0.0); if (bayes == false) sensitivityR = sensitivityB = 1.0; /* nor do sensitivities make any sense */ + /* + * The biasProportion parameter adds a small proportion of the counted + * pixles to a region biased to the biasCT colour temperature. + * + * A typical value for biasProportion would be between 0.05 to 0.1. + */ + biasProportion = params["bias_proportion"].get<double>(0.0); + biasCT = params["bias_ct"].get<double>(kDefaultCT); return 0; } @@ -213,7 +225,7 @@ void Awb::initialise() syncResults_.gainB = 1.0 / config_.ctB.eval(syncResults_.temperatureK); } else { /* random values just to stop the world blowing up */ - syncResults_.temperatureK = 4500; + syncResults_.temperatureK = kDefaultCT; syncResults_.gainR = syncResults_.gainG = syncResults_.gainB = 1.0; } prevSyncResults_ = syncResults_; @@ -406,7 +418,8 @@ void Awb::asyncFunc() static void generateStats(std::vector<Awb::RGB> &zones, StatisticsPtr &stats, double minPixels, - double minG, Metadata &globalMetadata) + double minG, Metadata &globalMetadata, + double biasProportion, double biasCtR, double biasCtB) { std::scoped_lock<RPiController::Metadata> l(globalMetadata); @@ -419,6 +432,14 @@ static void generateStats(std::vector<Awb::RGB> &zones, continue; zone.R = region.val.rSum / region.counted; zone.B = region.val.bSum / region.counted; + /* + * Add some bias samples to allow the search to tend to a + * bias CT in failure cases. + */ + const unsigned int proportion = biasProportion * region.counted; + zone.R += proportion * biasCtR; + zone.B += proportion * biasCtB; + zone.G += proportion * 1.0; /* Factor in the ALSC applied colour shading correction if required. */ const AlscStatus *alscStatus = globalMetadata.getLocked<AlscStatus>("alsc.status"); if (stats->colourStatsPos == Statistics::ColourStatsPos::PreLsc && alscStatus) { @@ -439,7 +460,9 @@ void Awb::prepareStats() * any LSC compensation. We also ignore config_.fast in this version. */ generateStats(zones_, statistics_, config_.minPixels, - config_.minG, getGlobalMetadata()); + config_.minG, getGlobalMetadata(), + config_.biasProportion, config_.ctR.eval(config_.biasCT), + config_.ctB.eval(config_.biasCT)); /* * apply sensitivities, so values appear to come from our "canonical" * sensor. @@ -504,7 +527,7 @@ static double interpolateQuadatric(ipa::Pwl::Point const &a, ipa::Pwl::Point con const double eps = 1e-3; ipa::Pwl::Point ca = c - a, ba = b - a; double denominator = 2 * (ba.y() * ca.x() - ca.y() * ba.x()); - if (abs(denominator) > eps) { + if (std::abs(denominator) > eps) { double numerator = ba.y() * ca.x() * ca.x() - ca.y() * ba.x() * ba.x(); double result = numerator / denominator + a.x(); return std::max(a.x(), std::min(c.x(), result)); @@ -715,7 +738,11 @@ void Awb::awbGrey() sumR += *ri, sumB += *bi; double gainR = sumR.G / (sumR.R + 1), gainB = sumB.G / (sumB.B + 1); - asyncResults_.temperatureK = 4500; /* don't know what it is */ + /* + * The grey world model can't estimate the colour temperature, use a + * default value. + */ + asyncResults_.temperatureK = kDefaultCT; asyncResults_.gainR = gainR; asyncResults_.gainG = 1.0; asyncResults_.gainB = gainB; diff --git a/src/ipa/rpi/controller/rpi/awb.h b/src/ipa/rpi/controller/rpi/awb.h index ab30f4fa..5d628b47 100644 --- a/src/ipa/rpi/controller/rpi/awb.h +++ b/src/ipa/rpi/controller/rpi/awb.h @@ -87,6 +87,10 @@ struct AwbConfig { double whitepointR; double whitepointB; bool bayes; /* use Bayesian algorithm */ + /* proportion of counted samples to add for the search bias */ + double biasProportion; + /* CT target for the search bias */ + double biasCT; }; class Awb : public AwbAlgorithm diff --git a/src/ipa/rpi/controller/rpi/black_level.cpp b/src/ipa/rpi/controller/rpi/black_level.cpp index ea991df9..4c968f14 100644 --- a/src/ipa/rpi/controller/rpi/black_level.cpp +++ b/src/ipa/rpi/controller/rpi/black_level.cpp @@ -5,7 +5,6 @@ * black level control algorithm */ -#include <math.h> #include <stdint.h> #include <libcamera/base/log.h> diff --git a/src/ipa/rpi/controller/rpi/ccm.cpp b/src/ipa/rpi/controller/rpi/ccm.cpp index 3272a141..aefa580c 100644 --- a/src/ipa/rpi/controller/rpi/ccm.cpp +++ b/src/ipa/rpi/controller/rpi/ccm.cpp @@ -71,9 +71,9 @@ int Ccm::read(const libcamera::YamlObject ¶ms) int ret; if (params.contains("saturation")) { - ret = config_.saturation.readYaml(params["saturation"]); - if (ret) - return ret; + config_.saturation = params["saturation"].get<ipa::Pwl>(ipa::Pwl{}); + if (config_.saturation.empty()) + return -EINVAL; } for (auto &p : params["ccms"].asList()) { @@ -113,8 +113,10 @@ void Ccm::initialise() { } +namespace { + template<typename T> -static bool getLocked(Metadata *metadata, std::string const &tag, T &value) +bool getLocked(Metadata *metadata, std::string const &tag, T &value) { T *ptr = metadata->getLocked<T>(tag); if (ptr == nullptr) @@ -149,6 +151,8 @@ Matrix applySaturation(Matrix const &ccm, double saturation) return Y2RGB * S * RGB2Y * ccm; } +} /* namespace */ + void Ccm::prepare(Metadata *imageMetadata) { bool awbOk = false, luxOk = false; diff --git a/src/ipa/rpi/controller/rpi/contrast.cpp b/src/ipa/rpi/controller/rpi/contrast.cpp index 66871a61..fe866a54 100644 --- a/src/ipa/rpi/controller/rpi/contrast.cpp +++ b/src/ipa/rpi/controller/rpi/contrast.cpp @@ -53,7 +53,9 @@ int Contrast::read(const libcamera::YamlObject ¶ms) config_.hiHistogram = params["hi_histogram"].get<double>(0.95); config_.hiLevel = params["hi_level"].get<double>(0.95); config_.hiMax = params["hi_max"].get<double>(2000); - return config_.gammaCurve.readYaml(params["gamma_curve"]); + + config_.gammaCurve = params["gamma_curve"].get<ipa::Pwl>(ipa::Pwl{}); + return config_.gammaCurve.empty() ? -EINVAL : 0; } void Contrast::setBrightness(double brightness) @@ -92,6 +94,8 @@ void Contrast::prepare(Metadata *imageMetadata) imageMetadata->set("contrast.status", status_); } +namespace { + ipa::Pwl computeStretchCurve(Histogram const &histogram, ContrastConfig const &config) { @@ -151,6 +155,8 @@ ipa::Pwl applyManualContrast(ipa::Pwl const &gammaCurve, double brightness, return newGammaCurve; } +} /* namespace */ + void Contrast::process(StatisticsPtr &stats, [[maybe_unused]] Metadata *imageMetadata) { diff --git a/src/ipa/rpi/controller/rpi/geq.cpp b/src/ipa/rpi/controller/rpi/geq.cpp index c9c38ebf..40e7191b 100644 --- a/src/ipa/rpi/controller/rpi/geq.cpp +++ b/src/ipa/rpi/controller/rpi/geq.cpp @@ -44,9 +44,9 @@ int Geq::read(const libcamera::YamlObject ¶ms) } if (params.contains("strength")) { - int ret = config_.strength.readYaml(params["strength"]); - if (ret) - return ret; + config_.strength = params["strength"].get<ipa::Pwl>(ipa::Pwl{}); + if (config_.strength.empty()) + return -EINVAL; } return 0; diff --git a/src/ipa/rpi/controller/rpi/hdr.cpp b/src/ipa/rpi/controller/rpi/hdr.cpp index d533a4ea..f3da8291 100644 --- a/src/ipa/rpi/controller/rpi/hdr.cpp +++ b/src/ipa/rpi/controller/rpi/hdr.cpp @@ -42,7 +42,7 @@ void HdrConfig::read(const libcamera::YamlObject ¶ms, const std::string &mod /* Lens shading related parameters. */ if (params.contains("spatial_gain_curve")) { - spatialGainCurve.readYaml(params["spatial_gain_curve"]); + spatialGainCurve = params["spatial_gain_curve"].get<ipa::Pwl>(ipa::Pwl{}); } else if (params.contains("spatial_gain")) { double spatialGain = params["spatial_gain"].get<double>(2.0); spatialGainCurve.append(0.0, spatialGain); @@ -66,7 +66,7 @@ void HdrConfig::read(const libcamera::YamlObject ¶ms, const std::string &mod iirStrength = params["iir_strength"].get<double>(8.0); strength = params["strength"].get<double>(1.5); if (tonemapEnable) - tonemap.readYaml(params["tonemap"]); + tonemap = params["tonemap"].get<ipa::Pwl>(ipa::Pwl{}); speed = params["speed"].get<double>(1.0); if (params.contains("hi_quantile_targets")) { hiQuantileTargets = params["hi_quantile_targets"].getList<double>().value(); diff --git a/src/ipa/rpi/controller/rpi/lux.cpp b/src/ipa/rpi/controller/rpi/lux.cpp index 7b31faab..652d85d7 100644 --- a/src/ipa/rpi/controller/rpi/lux.cpp +++ b/src/ipa/rpi/controller/rpi/lux.cpp @@ -4,7 +4,6 @@ * * Lux control algorithm */ -#include <math.h> #include <libcamera/base/log.h> diff --git a/src/ipa/rpi/controller/rpi/noise.cpp b/src/ipa/rpi/controller/rpi/noise.cpp index 3f1c62cf..145175fb 100644 --- a/src/ipa/rpi/controller/rpi/noise.cpp +++ b/src/ipa/rpi/controller/rpi/noise.cpp @@ -5,7 +5,7 @@ * Noise control algorithm */ -#include <math.h> +#include <cmath> #include <libcamera/base/log.h> @@ -69,7 +69,7 @@ void Noise::prepare(Metadata *imageMetadata) * make some adjustments based on the camera mode (such as * binning), if we knew how to discover it... */ - double factor = sqrt(deviceStatus.analogueGain) / modeFactor_; + double factor = std::sqrt(deviceStatus.analogueGain) / modeFactor_; struct NoiseStatus status; status.noiseConstant = referenceConstant_ * factor; status.noiseSlope = referenceSlope_ * factor; diff --git a/src/ipa/rpi/controller/rpi/sharpen.cpp b/src/ipa/rpi/controller/rpi/sharpen.cpp index 39537f4a..1d143ff5 100644 --- a/src/ipa/rpi/controller/rpi/sharpen.cpp +++ b/src/ipa/rpi/controller/rpi/sharpen.cpp @@ -5,7 +5,7 @@ * sharpening control algorithm */ -#include <math.h> +#include <cmath> #include <libcamera/base/log.h> @@ -68,7 +68,7 @@ void Sharpen::prepare(Metadata *imageMetadata) * we adjust the limit and threshold less aggressively. Using a sqrt * function is an arbitrary but gentle way of accomplishing this. */ - double userStrengthSqrt = sqrt(userStrength_); + double userStrengthSqrt = std::sqrt(userStrength_); struct SharpenStatus status; /* * Binned modes seem to need the sharpening toned down with this diff --git a/src/ipa/rpi/controller/rpi/tonemap.cpp b/src/ipa/rpi/controller/rpi/tonemap.cpp index 2dc50dfc..3422adfe 100644 --- a/src/ipa/rpi/controller/rpi/tonemap.cpp +++ b/src/ipa/rpi/controller/rpi/tonemap.cpp @@ -33,7 +33,7 @@ int Tonemap::read(const libcamera::YamlObject ¶ms) config_.detailSlope = params["detail_slope"].get<double>(0.1); config_.iirStrength = params["iir_strength"].get<double>(1.0); config_.strength = params["strength"].get<double>(1.0); - config_.tonemap.readYaml(params["tone_curve"]); + config_.tonemap = params["tone_curve"].get<ipa::Pwl>(ipa::Pwl{}); return 0; } |