summaryrefslogtreecommitdiff
path: root/src/ipa/ipu3/ipu3_awb.cpp
diff options
context:
space:
mode:
authorJean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>2021-08-18 17:54:02 +0200
committerJean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com>2021-08-20 12:11:29 +0200
commitb145ae42428b9f21fff01d7353a655e07e818c33 (patch)
treec88399ecf4cd1d5f2725324f98f849a41ddfc689 /src/ipa/ipu3/ipu3_awb.cpp
parent16266def40cda947aaa1a50009e89f639c26e7cf (diff)
ipa: ipu3: Move IPU3 awb into algorithms
Now that the interface is properly used by the AWB class, move it into ipa::ipu3::algorithms and let the loops do the calls. Signed-off-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Diffstat (limited to 'src/ipa/ipu3/ipu3_awb.cpp')
-rw-r--r--src/ipa/ipu3/ipu3_awb.cpp341
1 files changed, 0 insertions, 341 deletions
diff --git a/src/ipa/ipu3/ipu3_awb.cpp b/src/ipa/ipu3/ipu3_awb.cpp
deleted file mode 100644
index 728162fe..00000000
--- a/src/ipa/ipu3/ipu3_awb.cpp
+++ /dev/null
@@ -1,341 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-/*
- * Copyright (C) 2021, Ideas On Board
- *
- * ipu3_awb.cpp - AWB control algorithm
- */
-#include "ipu3_awb.h"
-
-#include <algorithm>
-#include <cmath>
-
-#include <libcamera/base/log.h>
-
-namespace libcamera {
-
-namespace ipa::ipu3 {
-
-LOG_DEFINE_CATEGORY(IPU3Awb)
-
-static constexpr uint32_t kMinZonesCounted = 16;
-static constexpr uint32_t kMinGreenLevelInZone = 32;
-
-/**
- * \struct IspStatsRegion
- * \brief RGB statistics for a given region
- *
- * The IspStatsRegion structure is intended to abstract the ISP specific
- * statistics and use an agnostic algorithm to compute AWB.
- *
- * \var IspStatsRegion::counted
- * \brief Number of pixels used to calculate the sums
- *
- * \var IspStatsRegion::uncounted
- * \brief Remaining number of pixels in the region
- *
- * \var IspStatsRegion::rSum
- * \brief Sum of the red values in the region
- *
- * \var IspStatsRegion::gSum
- * \brief Sum of the green values in the region
- *
- * \var IspStatsRegion::bSum
- * \brief Sum of the blue values in the region
- */
-
-/**
- * \struct AwbStatus
- * \brief AWB parameters calculated
- *
- * The AwbStatus structure is intended to store the AWB
- * parameters calculated by the algorithm
- *
- * \var AwbStatus::temperatureK
- * \brief Color temperature calculated
- *
- * \var AwbStatus::redGain
- * \brief Gain calculated for the red channel
- *
- * \var AwbStatus::greenGain
- * \brief Gain calculated for the green channel
- *
- * \var AwbStatus::blueGain
- * \brief Gain calculated for the blue channel
- */
-
-/**
- * \struct Ipu3AwbCell
- * \brief Memory layout for each cell in AWB metadata
- *
- * The Ipu3AwbCell structure is used to get individual values
- * such as red average or saturation ratio in a particular cell.
- *
- * \var Ipu3AwbCell::greenRedAvg
- * \brief Green average for red lines in the cell
- *
- * \var Ipu3AwbCell::redAvg
- * \brief Red average in the cell
- *
- * \var Ipu3AwbCell::blueAvg
- * \brief blue average in the cell
- *
- * \var Ipu3AwbCell::greenBlueAvg
- * \brief Green average for blue lines
- *
- * \var Ipu3AwbCell::satRatio
- * \brief Saturation ratio in the cell
- *
- * \var Ipu3AwbCell::padding
- * \brief array of unused bytes for padding
- */
-
-/* Default settings for Bayer noise reduction replicated from the Kernel */
-static const struct ipu3_uapi_bnr_static_config imguCssBnrDefaults = {
- .wb_gains = { 16, 16, 16, 16 },
- .wb_gains_thr = { 255, 255, 255, 255 },
- .thr_coeffs = { 1700, 0, 31, 31, 0, 16 },
- .thr_ctrl_shd = { 26, 26, 26, 26 },
- .opt_center = { -648, 0, -366, 0 },
- .lut = {
- { 17, 23, 28, 32, 36, 39, 42, 45,
- 48, 51, 53, 55, 58, 60, 62, 64,
- 66, 68, 70, 72, 73, 75, 77, 78,
- 80, 82, 83, 85, 86, 88, 89, 90 } },
- .bp_ctrl = { 20, 0, 1, 40, 0, 6, 0, 6, 0 },
- .dn_detect_ctrl = { 9, 3, 4, 0, 8, 0, 1, 1, 1, 1, 0 },
- .column_size = 1296,
- .opt_center_sqr = { 419904, 133956 },
-};
-
-/* Default color correction matrix defined as an identity matrix */
-static const struct ipu3_uapi_ccm_mat_config imguCssCcmDefault = {
- 8191, 0, 0, 0,
- 0, 8191, 0, 0,
- 0, 0, 8191, 0
-};
-
-IPU3Awb::IPU3Awb()
- : Algorithm()
-{
- asyncResults_.blueGain = 1.0;
- asyncResults_.greenGain = 1.0;
- asyncResults_.redGain = 1.0;
- asyncResults_.temperatureK = 4500;
-
- zones_.reserve(kAwbStatsSizeX * kAwbStatsSizeY);
-}
-
-IPU3Awb::~IPU3Awb() = default;
-
-/**
- * The function estimates the correlated color temperature using
- * from RGB color space input.
- * In physics and color science, the Planckian locus or black body locus is
- * the path or locus that the color of an incandescent black body would take
- * in a particular chromaticity space as the blackbody temperature changes.
- *
- * If a narrow range of color temperatures is considered (those encapsulating
- * daylight being the most practical case) one can approximate the Planckian
- * locus in order to calculate the CCT in terms of chromaticity coordinates.
- *
- * More detailed information can be found in:
- * https://en.wikipedia.org/wiki/Color_temperature#Approximation
- */
-uint32_t IPU3Awb::estimateCCT(double red, double green, double blue)
-{
- /* Convert the RGB values to CIE tristimulus values (XYZ) */
- double X = (-0.14282) * (red) + (1.54924) * (green) + (-0.95641) * (blue);
- double Y = (-0.32466) * (red) + (1.57837) * (green) + (-0.73191) * (blue);
- double Z = (-0.68202) * (red) + (0.77073) * (green) + (0.56332) * (blue);
-
- /* Calculate the normalized chromaticity values */
- double x = X / (X + Y + Z);
- double y = Y / (X + Y + Z);
-
- /* Calculate CCT */
- double n = (x - 0.3320) / (0.1858 - y);
- return 449 * n * n * n + 3525 * n * n + 6823.3 * n + 5520.33;
-}
-
-/* Generate an RGB vector with the average values for each region */
-void IPU3Awb::generateZones(std::vector<RGB> &zones)
-{
- for (unsigned int i = 0; i < kAwbStatsSizeX * kAwbStatsSizeY; i++) {
- RGB zone;
- double counted = awbStats_[i].counted;
- if (counted >= kMinZonesCounted) {
- zone.G = awbStats_[i].gSum / counted;
- if (zone.G >= kMinGreenLevelInZone) {
- zone.R = awbStats_[i].rSum / counted;
- zone.B = awbStats_[i].bSum / counted;
- zones.push_back(zone);
- }
- }
- }
-}
-
-/* Translate the IPU3 statistics into the default statistics region array */
-void IPU3Awb::generateAwbStats(const ipu3_uapi_stats_3a *stats)
-{
- uint32_t regionWidth = round(awbGrid_.width / static_cast<double>(kAwbStatsSizeX));
- uint32_t regionHeight = round(awbGrid_.height / static_cast<double>(kAwbStatsSizeY));
-
- /*
- * Generate a (kAwbStatsSizeX x kAwbStatsSizeY) array from the IPU3 grid which is
- * (awbGrid_.width x awbGrid_.height).
- */
- for (unsigned int j = 0; j < kAwbStatsSizeY * regionHeight; j++) {
- for (unsigned int i = 0; i < kAwbStatsSizeX * regionWidth; i++) {
- uint32_t cellPosition = j * awbGrid_.width + i;
- uint32_t cellX = (cellPosition / regionWidth) % kAwbStatsSizeX;
- uint32_t cellY = ((cellPosition / awbGrid_.width) / regionHeight) % kAwbStatsSizeY;
-
- uint32_t awbRegionPosition = cellY * kAwbStatsSizeX + cellX;
- cellPosition *= 8;
-
- /* Cast the initial IPU3 structure to simplify the reading */
- Ipu3AwbCell *currentCell = reinterpret_cast<Ipu3AwbCell *>(const_cast<uint8_t *>(&stats->awb_raw_buffer.meta_data[cellPosition]));
- if (currentCell->satRatio == 0) {
- /* The cell is not saturated, use the current cell */
- awbStats_[awbRegionPosition].counted++;
- uint32_t greenValue = currentCell->greenRedAvg + currentCell->greenBlueAvg;
- awbStats_[awbRegionPosition].gSum += greenValue / 2;
- awbStats_[awbRegionPosition].rSum += currentCell->redAvg;
- awbStats_[awbRegionPosition].bSum += currentCell->blueAvg;
- }
- }
- }
-}
-
-void IPU3Awb::clearAwbStats()
-{
- for (unsigned int i = 0; i < kAwbStatsSizeX * kAwbStatsSizeY; i++) {
- awbStats_[i].bSum = 0;
- awbStats_[i].rSum = 0;
- awbStats_[i].gSum = 0;
- awbStats_[i].counted = 0;
- awbStats_[i].uncounted = 0;
- }
-}
-
-void IPU3Awb::awbGreyWorld()
-{
- LOG(IPU3Awb, Debug) << "Grey world AWB";
- /*
- * Make a separate list of the derivatives for each of red and blue, so
- * that we can sort them to exclude the extreme gains. We could
- * consider some variations, such as normalising all the zones first, or
- * doing an L2 average etc.
- */
- std::vector<RGB> &redDerivative(zones_);
- std::vector<RGB> blueDerivative(redDerivative);
- std::sort(redDerivative.begin(), redDerivative.end(),
- [](RGB const &a, RGB const &b) {
- return a.G * b.R < b.G * a.R;
- });
- std::sort(blueDerivative.begin(), blueDerivative.end(),
- [](RGB const &a, RGB const &b) {
- return a.G * b.B < b.G * a.B;
- });
-
- /* Average the middle half of the values. */
- int discard = redDerivative.size() / 4;
-
- RGB sumRed(0, 0, 0);
- RGB sumBlue(0, 0, 0);
- for (auto ri = redDerivative.begin() + discard,
- bi = blueDerivative.begin() + discard;
- ri != redDerivative.end() - discard; ri++, bi++)
- sumRed += *ri, sumBlue += *bi;
-
- double redGain = sumRed.G / (sumRed.R + 1),
- blueGain = sumBlue.G / (sumBlue.B + 1);
-
- /* Color temperature is not relevant in Grey world but still useful to estimate it :-) */
- asyncResults_.temperatureK = estimateCCT(sumRed.R, sumRed.G, sumBlue.B);
- asyncResults_.redGain = redGain;
- asyncResults_.greenGain = 1.0;
- asyncResults_.blueGain = blueGain;
-}
-
-void IPU3Awb::calculateWBGains(const ipu3_uapi_stats_3a *stats)
-{
- ASSERT(stats->stats_3a_status.awb_en);
- zones_.clear();
- clearAwbStats();
- generateAwbStats(stats);
- generateZones(zones_);
- LOG(IPU3Awb, Debug) << "Valid zones: " << zones_.size();
- if (zones_.size() > 10) {
- awbGreyWorld();
- LOG(IPU3Awb, Debug) << "Gain found for red: " << asyncResults_.redGain
- << " and for blue: " << asyncResults_.blueGain;
- }
-}
-
-void IPU3Awb::process(IPAContext &context, const ipu3_uapi_stats_3a *stats)
-{
- calculateWBGains(stats);
-
- /*
- * Gains are only recalculated if enough zones were detected.
- * The results are cached, so if no results were calculated, we set the
- * cached values from asyncResults_ here.
- */
- context.frameContext.awb.gains.blue = asyncResults_.blueGain;
- context.frameContext.awb.gains.green = asyncResults_.greenGain;
- context.frameContext.awb.gains.red = asyncResults_.redGain;
-}
-
-void IPU3Awb::prepare(IPAContext &context, ipu3_uapi_params *params)
-{
- params->acc_param.awb.config.rgbs_thr_gr = 8191;
- params->acc_param.awb.config.rgbs_thr_r = 8191;
- params->acc_param.awb.config.rgbs_thr_gb = 8191;
- params->acc_param.awb.config.rgbs_thr_b = IPU3_UAPI_AWB_RGBS_THR_B_INCL_SAT
- | IPU3_UAPI_AWB_RGBS_THR_B_EN
- | 8191;
-
- awbGrid_ = context.configuration.grid.bdsGrid;
-
- params->acc_param.awb.config.grid = context.configuration.grid.bdsGrid;
-
- /*
- * Optical center is column start (respectively row start) of the
- * region of interest minus its X center (respectively Y center).
- *
- * For the moment use BDS as a first approximation, but it should
- * be calculated based on Shading (SHD) parameters.
- */
- params->acc_param.bnr = imguCssBnrDefaults;
- Size &bdsOutputSize = context.configuration.grid.bdsOutputSize;
- params->acc_param.bnr.column_size = bdsOutputSize.width;
- params->acc_param.bnr.opt_center.x_reset = awbGrid_.x_start - (bdsOutputSize.width / 2);
- params->acc_param.bnr.opt_center.y_reset = awbGrid_.y_start - (bdsOutputSize.height / 2);
- params->acc_param.bnr.opt_center_sqr.x_sqr_reset = params->acc_param.bnr.opt_center.x_reset
- * params->acc_param.bnr.opt_center.x_reset;
- params->acc_param.bnr.opt_center_sqr.y_sqr_reset = params->acc_param.bnr.opt_center.y_reset
- * params->acc_param.bnr.opt_center.y_reset;
- /*
- * Green gains should not be touched and considered 1.
- * Default is 16, so do not change it at all.
- * 4096 is the value for a gain of 1.0
- */
- params->acc_param.bnr.wb_gains.gr = 16 * context.frameContext.awb.gains.green;
- params->acc_param.bnr.wb_gains.r = 4096 * context.frameContext.awb.gains.red;
- params->acc_param.bnr.wb_gains.b = 4096 * context.frameContext.awb.gains.blue;
- params->acc_param.bnr.wb_gains.gb = 16 * context.frameContext.awb.gains.green;
-
- LOG(IPU3Awb, Debug) << "Color temperature estimated: " << asyncResults_.temperatureK;
-
- /* The CCM matrix may change when color temperature will be used */
- params->acc_param.ccm = imguCssCcmDefault;
-
- params->use.acc_awb = 1;
- params->use.acc_bnr = 1;
- params->use.acc_ccm = 1;
-}
-
-} /* namespace ipa::ipu3 */
-
-} /* namespace libcamera */