mirror of
https://git.libcamera.org/libcamera/libcamera.git
synced 2025-07-12 23:09:45 +03:00
ipa: libipa: colour: Use the RGB class to model RGB values
The rec601LuminanceFromRGB() and estimateCCT() functions take RGB triplets as three variables. Replace them with instances of the RGB class and adapt the users accordingly. Only variables passed directly to these functions are converted to RGB instances, further conversion of IPA modules to the RGB class will be performed separately. While at it, fix a typo in the documentation of the estimateCCT() function. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Milan Zamazal <mzamazal@redhat.com>
This commit is contained in:
parent
cb3e3095d6
commit
29892f1c56
6 changed files with 55 additions and 57 deletions
|
@ -178,18 +178,16 @@ Histogram Agc::parseStatistics(const ipu3_uapi_stats_3a *stats,
|
||||||
*/
|
*/
|
||||||
double Agc::estimateLuminance(double gain) const
|
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++) {
|
for (unsigned int i = 0; i < rgbTriples_.size(); i++) {
|
||||||
redSum += std::min(std::get<0>(rgbTriples_[i]) * gain, 255.0);
|
sum.r() += std::min(std::get<0>(rgbTriples_[i]) * gain, 255.0);
|
||||||
greenSum += std::min(std::get<1>(rgbTriples_[i]) * gain, 255.0);
|
sum.g() += std::min(std::get<1>(rgbTriples_[i]) * gain, 255.0);
|
||||||
blueSum += std::min(std::get<2>(rgbTriples_[i]) * gain, 255.0);
|
sum.b() += std::min(std::get<2>(rgbTriples_[i]) * gain, 255.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
double ySum = rec601LuminanceFromRGB(redSum * rGain_,
|
RGB<double> gains{{ rGain_, gGain_, bGain_ }};
|
||||||
greenSum * gGain_,
|
double ySum = rec601LuminanceFromRGB(sum * gains);
|
||||||
blueSum * bGain_);
|
|
||||||
|
|
||||||
return ySum / (bdsGrid_.height * bdsGrid_.width) / 255;
|
return ySum / (bdsGrid_.height * bdsGrid_.width) / 255;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -412,7 +412,7 @@ void Awb::awbGreyWorld()
|
||||||
blueGain = sumBlue.g() / (sumBlue.b() + 1);
|
blueGain = sumBlue.g() / (sumBlue.b() + 1);
|
||||||
|
|
||||||
/* Color temperature is not relevant in Grey world but still useful to estimate it :-) */
|
/* 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
|
* 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
|
* \brief Estimate luminance from RGB values following ITU-R BT.601
|
||||||
* \param[in] r The red value
|
* \param[in] rgb The RGB value
|
||||||
* \param[in] g The green value
|
|
||||||
* \param[in] b The blue value
|
|
||||||
*
|
*
|
||||||
* This function estimates a luminance value from a triplet of Red, Green and
|
* 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
|
* Blue values, following the formula defined by ITU-R Recommendation BT.601-7
|
||||||
|
@ -31,21 +29,19 @@ namespace ipa {
|
||||||
*
|
*
|
||||||
* \return The estimated luminance value
|
* \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
|
* \brief Estimate correlated colour temperature from RGB color space input
|
||||||
* \param[in] red The input red value
|
* \param[in] rgb The RGB value
|
||||||
* \param[in] green The input green value
|
|
||||||
* \param[in] blue The input blue value
|
|
||||||
*
|
*
|
||||||
* This function estimates the correlated color temperature RGB color space
|
* This function estimates the correlated color temperature RGB color space
|
||||||
* input. In physics and color science, the Planckian locus or black body locus
|
* 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
|
* 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
|
* If a narrow range of color temperatures is considered (those encapsulating
|
||||||
* daylight being the most practical case) one can approximate the Planckian
|
* 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
|
* \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) */
|
/* Convert the RGB values to CIE tristimulus values (XYZ) */
|
||||||
double X = (-0.14282) * (red) + (1.54924) * (green) + (-0.95641) * (blue);
|
double X = (-0.14282) * rgb.r() + (1.54924) * rgb.g() + (-0.95641) * rgb.b();
|
||||||
double Y = (-0.32466) * (red) + (1.57837) * (green) + (-0.73191) * (blue);
|
double Y = (-0.32466) * rgb.r() + (1.57837) * rgb.g() + (-0.73191) * rgb.b();
|
||||||
double Z = (-0.68202) * (red) + (0.77073) * (green) + (0.56332) * (blue);
|
double Z = (-0.68202) * rgb.r() + (0.77073) * rgb.g() + (0.56332) * rgb.b();
|
||||||
|
|
||||||
/* Calculate the normalized chromaticity values */
|
/* Calculate the normalized chromaticity values */
|
||||||
double x = X / (X + Y + Z);
|
double x = X / (X + Y + Z);
|
||||||
|
|
|
@ -9,12 +9,14 @@
|
||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "vector.h"
|
||||||
|
|
||||||
namespace libcamera {
|
namespace libcamera {
|
||||||
|
|
||||||
namespace ipa {
|
namespace ipa {
|
||||||
|
|
||||||
double rec601LuminanceFromRGB(double r, double g, double b);
|
double rec601LuminanceFromRGB(const RGB<double> &rgb);
|
||||||
uint32_t estimateCCT(double red, double green, double blue);
|
uint32_t estimateCCT(const RGB<double> &rgb);
|
||||||
|
|
||||||
} /* namespace ipa */
|
} /* namespace ipa */
|
||||||
|
|
||||||
|
|
|
@ -192,9 +192,7 @@ void Awb::process(IPAContext &context,
|
||||||
const rkisp1_cif_isp_stat *params = &stats->params;
|
const rkisp1_cif_isp_stat *params = &stats->params;
|
||||||
const rkisp1_cif_isp_awb_stat *awb = ¶ms->awb;
|
const rkisp1_cif_isp_awb_stat *awb = ¶ms->awb;
|
||||||
IPAActiveState &activeState = context.activeState;
|
IPAActiveState &activeState = context.activeState;
|
||||||
double greenMean;
|
RGB<double> rgbMeans;
|
||||||
double redMean;
|
|
||||||
double blueMean;
|
|
||||||
|
|
||||||
metadata.set(controls::AwbEnable, frameContext.awb.autoEnabled);
|
metadata.set(controls::AwbEnable, frameContext.awb.autoEnabled);
|
||||||
metadata.set(controls::ColourGains, {
|
metadata.set(controls::ColourGains, {
|
||||||
|
@ -209,9 +207,11 @@ void Awb::process(IPAContext &context,
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rgbMode_) {
|
if (rgbMode_) {
|
||||||
greenMean = awb->awb_mean[0].mean_y_or_g;
|
rgbMeans = {{
|
||||||
redMean = awb->awb_mean[0].mean_cr_or_r;
|
static_cast<double>(awb->awb_mean[0].mean_y_or_g),
|
||||||
blueMean = awb->awb_mean[0].mean_cb_or_b;
|
static_cast<double>(awb->awb_mean[0].mean_cr_or_r),
|
||||||
|
static_cast<double>(awb->awb_mean[0].mean_cb_or_b)
|
||||||
|
}};
|
||||||
} else {
|
} else {
|
||||||
/* Get the YCbCr mean values */
|
/* Get the YCbCr mean values */
|
||||||
double yMean = awb->awb_mean[0].mean_y_or_g;
|
double yMean = awb->awb_mean[0].mean_y_or_g;
|
||||||
|
@ -233,9 +233,11 @@ void Awb::process(IPAContext &context,
|
||||||
yMean -= 16;
|
yMean -= 16;
|
||||||
cbMean -= 128;
|
cbMean -= 128;
|
||||||
crMean -= 128;
|
crMean -= 128;
|
||||||
redMean = 1.1636 * yMean - 0.0623 * cbMean + 1.6008 * crMean;
|
rgbMeans = {{
|
||||||
greenMean = 1.1636 * yMean - 0.4045 * cbMean - 0.7949 * crMean;
|
1.1636 * yMean - 0.0623 * cbMean + 1.6008 * crMean,
|
||||||
blueMean = 1.1636 * yMean + 1.9912 * cbMean - 0.0250 * 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
|
* 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
|
* negative gains, messing up calculation. Prevent this by
|
||||||
* clamping the means to positive values.
|
* clamping the means to positive values.
|
||||||
*/
|
*/
|
||||||
redMean = std::max(redMean, 0.0);
|
rgbMeans = rgbMeans.max(0.0);
|
||||||
greenMean = std::max(greenMean, 0.0);
|
|
||||||
blueMean = std::max(blueMean, 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
|
* divide by the gains that were used to get the raw means from the
|
||||||
* sensor.
|
* sensor.
|
||||||
*/
|
*/
|
||||||
redMean /= frameContext.awb.gains.red;
|
RGB<double> gains{{
|
||||||
greenMean /= frameContext.awb.gains.green;
|
frameContext.awb.gains.red,
|
||||||
blueMean /= frameContext.awb.gains.blue;
|
frameContext.awb.gains.green,
|
||||||
|
frameContext.awb.gains.blue
|
||||||
|
}};
|
||||||
|
rgbMeans /= gains;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* If the means are too small we don't have enough information to
|
* If the means are too small we don't have enough information to
|
||||||
* meaningfully calculate gains. Freeze the algorithm in that case.
|
* meaningfully calculate gains. Freeze the algorithm in that case.
|
||||||
*/
|
*/
|
||||||
if (redMean < kMeanMinThreshold && greenMean < kMeanMinThreshold &&
|
if (rgbMeans.r() < kMeanMinThreshold && rgbMeans.g() < kMeanMinThreshold &&
|
||||||
blueMean < kMeanMinThreshold)
|
rgbMeans.b() < kMeanMinThreshold)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
activeState.awb.temperatureK = estimateCCT(redMean, greenMean, blueMean);
|
activeState.awb.temperatureK = estimateCCT(rgbMeans);
|
||||||
|
|
||||||
/* Metadata shall contain the up to date measurement */
|
/* Metadata shall contain the up to date measurement */
|
||||||
metadata.set(controls::ColourTemperature, activeState.awb.temperatureK);
|
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
|
* gain is hardcoded to 1.0. Avoid divisions by zero by clamping the
|
||||||
* divisor to a minimum value of 1.0.
|
* divisor to a minimum value of 1.0.
|
||||||
*/
|
*/
|
||||||
double redGain = greenMean / std::max(redMean, 1.0);
|
double redGain = rgbMeans.g() / std::max(rgbMeans.r(), 1.0);
|
||||||
double blueGain = greenMean / std::max(blueMean, 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
|
* 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)
|
LOG(RkISP1Awb, Debug)
|
||||||
<< std::showpoint
|
<< std::showpoint
|
||||||
<< "Means [" << redMean << ", " << greenMean << ", " << blueMean
|
<< "Means " << rgbMeans
|
||||||
<< "], gains [" << activeState.awb.gains.automatic.red << ", "
|
<< ", gains [" << activeState.awb.gains.automatic.red << ", "
|
||||||
<< activeState.awb.gains.automatic.green << ", "
|
<< activeState.awb.gains.automatic.green << ", "
|
||||||
<< activeState.awb.gains.automatic.blue << "], temp "
|
<< activeState.awb.gains.automatic.blue << "], temp "
|
||||||
<< activeState.awb.temperatureK << "K";
|
<< activeState.awb.temperatureK << "K";
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include <libcamera/base/log.h>
|
#include <libcamera/base/log.h>
|
||||||
|
|
||||||
#include "libipa/colours.h"
|
#include "libipa/colours.h"
|
||||||
|
#include "libipa/vector.h"
|
||||||
|
|
||||||
#include "../awb_status.h"
|
#include "../awb_status.h"
|
||||||
#include "../device_status.h"
|
#include "../device_status.h"
|
||||||
|
@ -681,12 +682,13 @@ static double computeInitialY(StatisticsPtr &stats, AwbStatus const &awb,
|
||||||
* Note that the weights are applied by the IPA to the statistics directly,
|
* Note that the weights are applied by the IPA to the statistics directly,
|
||||||
* before they are given to us here.
|
* 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++) {
|
for (unsigned int i = 0; i < stats->agcRegions.numRegions(); i++) {
|
||||||
auto ®ion = stats->agcRegions.get(i);
|
auto ®ion = stats->agcRegions.get(i);
|
||||||
rSum += std::min<double>(region.val.rSum * gain, (maxVal - 1) * region.counted);
|
sum.r() += std::min<double>(region.val.rSum * gain, (maxVal - 1) * region.counted);
|
||||||
gSum += std::min<double>(region.val.gSum * gain, (maxVal - 1) * region.counted);
|
sum.g() += std::min<double>(region.val.gSum * gain, (maxVal - 1) * region.counted);
|
||||||
bSum += std::min<double>(region.val.bSum * gain, (maxVal - 1) * region.counted);
|
sum.b() += std::min<double>(region.val.bSum * gain, (maxVal - 1) * region.counted);
|
||||||
pixelSum += region.counted;
|
pixelSum += region.counted;
|
||||||
}
|
}
|
||||||
if (pixelSum == 0.0) {
|
if (pixelSum == 0.0) {
|
||||||
|
@ -694,14 +696,11 @@ static double computeInitialY(StatisticsPtr &stats, AwbStatus const &awb,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
double ySum;
|
|
||||||
/* Factor in the AWB correction if needed. */
|
/* Factor in the AWB correction if needed. */
|
||||||
if (stats->agcStatsPos == Statistics::AgcStatsPos::PreWb) {
|
if (stats->agcStatsPos == Statistics::AgcStatsPos::PreWb)
|
||||||
ySum = ipa::rec601LuminanceFromRGB(rSum * awb.gainR,
|
sum *= ipa::RGB<double>{{ awb.gainR, awb.gainR, awb.gainB }};
|
||||||
gSum * awb.gainG,
|
|
||||||
bSum * awb.gainB);
|
double ySum = ipa::rec601LuminanceFromRGB(sum);
|
||||||
} else
|
|
||||||
ySum = ipa::rec601LuminanceFromRGB(rSum, gSum, bSum);
|
|
||||||
|
|
||||||
return ySum / pixelSum / (1 << 16);
|
return ySum / pixelSum / (1 << 16);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue