@@ -178,18 +178,16 @@ Histogram Agc::parseStatistics(const ipu3_uapi_stats_3a *stats,
*/
double Agc::estimateLuminance(double gain) const
{
- double redSum = 0, greenSum = 0, blueSum = 0;
+ RGB<double> sum{ 0.0 };
for (unsigned int i = 0; i < rgbTriples_.size(); i++) {
- redSum += std::min(std::get<0>(rgbTriples_[i]) * gain, 255.0);
- greenSum += std::min(std::get<1>(rgbTriples_[i]) * gain, 255.0);
- blueSum += std::min(std::get<2>(rgbTriples_[i]) * gain, 255.0);
+ sum.r() += std::min(std::get<0>(rgbTriples_[i]) * gain, 255.0);
+ sum.g() += std::min(std::get<1>(rgbTriples_[i]) * gain, 255.0);
+ sum.b() += std::min(std::get<2>(rgbTriples_[i]) * gain, 255.0);
}
- double ySum = rec601LuminanceFromRGB(redSum * rGain_,
- greenSum * gGain_,
- blueSum * bGain_);
-
+ RGB<double> gains{{ rGain_, gGain_, bGain_ }};
+ double ySum = rec601LuminanceFromRGB(sum * gains);
return ySum / (bdsGrid_.height * bdsGrid_.width) / 255;
}
@@ -412,7 +412,7 @@ void Awb::awbGreyWorld()
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_.temperatureK = estimateCCT({{ sumRed.r(), sumRed.g(), sumBlue.b() }});
/*
* Gain values are unsigned integer value ranging [0, 8) with 13 bit
@@ -21,9 +21,7 @@ namespace ipa {
/**
* \brief Estimate luminance from RGB values following ITU-R BT.601
- * \param[in] r The red value
- * \param[in] g The green value
- * \param[in] b The blue value
+ * \param[in] rgb The RGB value
*
* This function estimates a luminance value from a triplet of Red, Green and
* Blue values, following the formula defined by ITU-R Recommendation BT.601-7
@@ -31,21 +29,19 @@ namespace ipa {
*
* \return The estimated luminance value
*/
-double rec601LuminanceFromRGB(double r, double g, double b)
+double rec601LuminanceFromRGB(const RGB<double> &rgb)
{
- return (r * .299) + (g * .587) + (b * .114);
+ return (rgb.r() * .299) + (rgb.g() * .587) + (rgb.b() * .114);
}
/**
* \brief Estimate correlated colour temperature from RGB color space input
- * \param[in] red The input red value
- * \param[in] green The input green value
- * \param[in] blue The input blue value
+ * \param[in] rgb The RGB value
*
* This function estimates the correlated color temperature 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.
+ * in a particular chromaticity space as the black body temperature changes.
*
* If a narrow range of color temperatures is considered (those encapsulating
* daylight being the most practical case) one can approximate the Planckian
@@ -56,12 +52,12 @@ double rec601LuminanceFromRGB(double r, double g, double b)
*
* \return The estimated color temperature
*/
-uint32_t estimateCCT(double red, double green, double blue)
+uint32_t estimateCCT(const RGB<double> &rgb)
{
/* 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);
+ double X = (-0.14282) * rgb.r() + (1.54924) * rgb.g() + (-0.95641) * rgb.b();
+ double Y = (-0.32466) * rgb.r() + (1.57837) * rgb.g() + (-0.73191) * rgb.b();
+ double Z = (-0.68202) * rgb.r() + (0.77073) * rgb.g() + (0.56332) * rgb.b();
/* Calculate the normalized chromaticity values */
double x = X / (X + Y + Z);
@@ -9,12 +9,14 @@
#include <stdint.h>
+#include "vector.h"
+
namespace libcamera {
namespace ipa {
-double rec601LuminanceFromRGB(double r, double g, double b);
-uint32_t estimateCCT(double red, double green, double blue);
+double rec601LuminanceFromRGB(const RGB<double> &rgb);
+uint32_t estimateCCT(const RGB<double> &rgb);
} /* namespace ipa */
@@ -192,9 +192,7 @@ void Awb::process(IPAContext &context,
const rkisp1_cif_isp_stat *params = &stats->params;
const rkisp1_cif_isp_awb_stat *awb = ¶ms->awb;
IPAActiveState &activeState = context.activeState;
- double greenMean;
- double redMean;
- double blueMean;
+ RGB<double> rgbMeans;
metadata.set(controls::AwbEnable, frameContext.awb.autoEnabled);
metadata.set(controls::ColourGains, {
@@ -209,9 +207,11 @@ void Awb::process(IPAContext &context,
}
if (rgbMode_) {
- greenMean = awb->awb_mean[0].mean_y_or_g;
- redMean = awb->awb_mean[0].mean_cr_or_r;
- blueMean = awb->awb_mean[0].mean_cb_or_b;
+ rgbMeans = {{
+ static_cast<double>(awb->awb_mean[0].mean_y_or_g),
+ static_cast<double>(awb->awb_mean[0].mean_cr_or_r),
+ static_cast<double>(awb->awb_mean[0].mean_cb_or_b)
+ }};
} else {
/* Get the YCbCr mean values */
double yMean = awb->awb_mean[0].mean_y_or_g;
@@ -233,9 +233,11 @@ void Awb::process(IPAContext &context,
yMean -= 16;
cbMean -= 128;
crMean -= 128;
- redMean = 1.1636 * yMean - 0.0623 * cbMean + 1.6008 * crMean;
- greenMean = 1.1636 * yMean - 0.4045 * cbMean - 0.7949 * crMean;
- blueMean = 1.1636 * yMean + 1.9912 * cbMean - 0.0250 * crMean;
+ rgbMeans = {{
+ 1.1636 * yMean - 0.0623 * cbMean + 1.6008 * crMean,
+ 1.1636 * yMean - 0.4045 * cbMean - 0.7949 * crMean,
+ 1.1636 * yMean + 1.9912 * cbMean - 0.0250 * crMean
+ }};
/*
* Due to hardware rounding errors in the YCbCr means, the
@@ -243,9 +245,7 @@ void Awb::process(IPAContext &context,
* negative gains, messing up calculation. Prevent this by
* clamping the means to positive values.
*/
- redMean = std::max(redMean, 0.0);
- greenMean = std::max(greenMean, 0.0);
- blueMean = std::max(blueMean, 0.0);
+ rgbMeans = rgbMeans.max(0.0);
}
/*
@@ -253,19 +253,22 @@ void Awb::process(IPAContext &context,
* divide by the gains that were used to get the raw means from the
* sensor.
*/
- redMean /= frameContext.awb.gains.red;
- greenMean /= frameContext.awb.gains.green;
- blueMean /= frameContext.awb.gains.blue;
+ RGB<double> gains{{
+ frameContext.awb.gains.red,
+ frameContext.awb.gains.green,
+ frameContext.awb.gains.blue
+ }};
+ rgbMeans /= gains;
/*
* If the means are too small we don't have enough information to
* meaningfully calculate gains. Freeze the algorithm in that case.
*/
- if (redMean < kMeanMinThreshold && greenMean < kMeanMinThreshold &&
- blueMean < kMeanMinThreshold)
+ if (rgbMeans.r() < kMeanMinThreshold && rgbMeans.g() < kMeanMinThreshold &&
+ rgbMeans.b() < kMeanMinThreshold)
return;
- activeState.awb.temperatureK = estimateCCT(redMean, greenMean, blueMean);
+ activeState.awb.temperatureK = estimateCCT(rgbMeans);
/* Metadata shall contain the up to date measurement */
metadata.set(controls::ColourTemperature, activeState.awb.temperatureK);
@@ -275,8 +278,8 @@ void Awb::process(IPAContext &context,
* gain is hardcoded to 1.0. Avoid divisions by zero by clamping the
* divisor to a minimum value of 1.0.
*/
- double redGain = greenMean / std::max(redMean, 1.0);
- double blueGain = greenMean / std::max(blueMean, 1.0);
+ double redGain = rgbMeans.g() / std::max(rgbMeans.r(), 1.0);
+ double blueGain = rgbMeans.g() / std::max(rgbMeans.b(), 1.0);
/*
* Clamp the gain values to the hardware, which expresses gains as Q2.8
@@ -298,8 +301,8 @@ void Awb::process(IPAContext &context,
LOG(RkISP1Awb, Debug)
<< std::showpoint
- << "Means [" << redMean << ", " << greenMean << ", " << blueMean
- << "], gains [" << activeState.awb.gains.automatic.red << ", "
+ << "Means " << rgbMeans
+ << ", gains [" << activeState.awb.gains.automatic.red << ", "
<< activeState.awb.gains.automatic.green << ", "
<< activeState.awb.gains.automatic.blue << "], temp "
<< activeState.awb.temperatureK << "K";
@@ -13,6 +13,7 @@
#include <libcamera/base/log.h>
#include "libipa/colours.h"
+#include "libipa/vector.h"
#include "../awb_status.h"
#include "../device_status.h"
@@ -680,12 +681,13 @@ static double computeInitialY(StatisticsPtr &stats, AwbStatus const &awb,
* Note that the weights are applied by the IPA to the statistics directly,
* before they are given to us here.
*/
- double rSum = 0, gSum = 0, bSum = 0, pixelSum = 0;
+ ipa::RGB<double> sum{ 0.0 };
+ double pixelSum = 0;
for (unsigned int i = 0; i < stats->agcRegions.numRegions(); i++) {
auto ®ion = stats->agcRegions.get(i);
- rSum += std::min<double>(region.val.rSum * gain, (maxVal - 1) * region.counted);
- gSum += std::min<double>(region.val.gSum * gain, (maxVal - 1) * region.counted);
- bSum += std::min<double>(region.val.bSum * gain, (maxVal - 1) * region.counted);
+ sum.r() += std::min<double>(region.val.rSum * gain, (maxVal - 1) * region.counted);
+ sum.g() += std::min<double>(region.val.gSum * gain, (maxVal - 1) * region.counted);
+ sum.b() += std::min<double>(region.val.bSum * gain, (maxVal - 1) * region.counted);
pixelSum += region.counted;
}
if (pixelSum == 0.0) {
@@ -693,14 +695,11 @@ static double computeInitialY(StatisticsPtr &stats, AwbStatus const &awb,
return 0;
}
- double ySum;
/* Factor in the AWB correction if needed. */
- if (stats->agcStatsPos == Statistics::AgcStatsPos::PreWb) {
- ySum = ipa::rec601LuminanceFromRGB(rSum * awb.gainR,
- gSum * awb.gainG,
- bSum * awb.gainB);
- } else
- ySum = ipa::rec601LuminanceFromRGB(rSum, gSum, bSum);
+ if (stats->agcStatsPos == Statistics::AgcStatsPos::PreWb)
+ sum *= ipa::RGB<double>{{ awb.gainR, awb.gainR, awb.gainB }};
+
+ double ySum = ipa::rec601LuminanceFromRGB(sum);
return ySum / pixelSum / (1 << 16);
}