[v4,40/49] ipa: simple: agc: Adjust histogram for black level
diff mbox series

Message ID 20260810103846.1075936-41-barnabas.pocze@ideasonboard.com
State New
Headers show
Series
  • ipa: libipa: agc rework
Related show

Commit Message

Barnabás Pőcze Aug. 10, 2026, 10:38 a.m. UTC
Instead of providing the black separately, adjust the luminance histogram
according to the current black level. Everything under the black level is
summed into the bin corresponding to the current black level, and the MSV
calculation is carried out on the partial histogram that starts at the
bin of the black level.

This changes the behaviour slightly as previously everything under the
black level was ignored, and only the remaining part was split into the
5 bins, but now the ignored bins are instead summed into the "first" bin
of the "new" histogram.

This can result in the same image with the same statistics being perceived
as darker by the algorithm.

Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>
---
 src/ipa/simple/algorithms/agc.cpp | 23 +++++++++++++----------
 1 file changed, 13 insertions(+), 10 deletions(-)

Comments

Milan Zamazal Aug. 10, 2026, 3:19 p.m. UTC | #1
Barnabás Pőcze <barnabas.pocze@ideasonboard.com> writes:

> Instead of providing the black separately, adjust the luminance histogram
> according to the current black level. Everything under the black level is
> summed into the bin corresponding to the current black level, and the MSV
> calculation is carried out on the partial histogram that starts at the
> bin of the black level.
>
> This changes the behaviour slightly as previously everything under the
> black level was ignored, and only the remaining part was split into the
> 5 bins, but now the ignored bins are instead summed into the "first" bin
> of the "new" histogram.
>
> This can result in the same image with the same statistics being perceived
> as darker by the algorithm.
>
> Signed-off-by: Barnabás Pőcze <barnabas.pocze@ideasonboard.com>

Reviewed-by: Milan Zamazal <mzamazal@redhat.com>

> ---
>  src/ipa/simple/algorithms/agc.cpp | 23 +++++++++++++----------
>  1 file changed, 13 insertions(+), 10 deletions(-)
>
> diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp
> index e24eacde72..a3e0ebbc3d 100644
> --- a/src/ipa/simple/algorithms/agc.cpp
> +++ b/src/ipa/simple/algorithms/agc.cpp
> @@ -66,19 +66,15 @@ static constexpr float kExpMaxStep = 0.15;
>  
>  namespace {
>  
> -std::optional<float> calculateMSV(const Histogram &histogram, uint8_t blackLevel)
> +std::optional<float> calculateMSV(const Histogram &histogram)
>  {
>  	/*
>  	 * Calculate Mean Sample Value (MSV) according to formula from:
>  	 * https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf
>  	 */
> -	const unsigned int blackLevelHistIdx =
> -		blackLevel * histogram.bins() / 256;
> -	const unsigned int histogramSize =
> -		histogram.bins() - blackLevelHistIdx;
> -	const unsigned int yHistValsPerBin = histogramSize / kExposureBinsCount;
> +	const unsigned int yHistValsPerBin = histogram.bins() / kExposureBinsCount;
>  	const unsigned int yHistValsPerBinMod =
> -		histogramSize / (histogramSize % kExposureBinsCount + 1);
> +		histogram.bins() / (histogram.bins() % kExposureBinsCount + 1);
>  	int exposureBins[kExposureBinsCount] = {};
>  	unsigned int denom = 0;
>  	unsigned int num = 0;
> @@ -86,9 +82,9 @@ std::optional<float> calculateMSV(const Histogram &histogram, uint8_t blackLevel
>  	if (yHistValsPerBin == 0)
>  		return {};
>  
> -	for (unsigned int i = 0; i < histogramSize; i++) {
> +	for (unsigned int i = 0; i < histogram.bins(); i++) {
>  		unsigned int idx = (i - (i / yHistValsPerBinMod)) / yHistValsPerBin;
> -		exposureBins[idx] += histogram[blackLevelHistIdx + i];
> +		exposureBins[idx] += histogram[i];
>  	}
>  
>  	for (unsigned int i = 0; i < kExposureBinsCount; i++) {
> @@ -193,7 +189,14 @@ void Agc::process(IPAContext &context,
>  		return;
>  	}
>  
> -	auto exposureMSV = calculateMSV({ stats->yHistogram }, context.activeState.blc.level);
> +	auto histogram = stats->yHistogram;
> +	const unsigned int blackLevelHistIdx =
> +		context.activeState.blc.level * std::size(histogram) / 256;
> +
> +	for (unsigned int i = 0; i < blackLevelHistIdx; i++)
> +		histogram[blackLevelHistIdx] += histogram[i];
> +
> +	auto exposureMSV = calculateMSV({ { histogram.begin() + blackLevelHistIdx, histogram.end() } });
>  	if (!exposureMSV) {
>  		LOG(IPASoftExposure, Debug)
>  			<< "Not adjusting exposure due to insufficient histogram data";

Patch
diff mbox series

diff --git a/src/ipa/simple/algorithms/agc.cpp b/src/ipa/simple/algorithms/agc.cpp
index e24eacde72..a3e0ebbc3d 100644
--- a/src/ipa/simple/algorithms/agc.cpp
+++ b/src/ipa/simple/algorithms/agc.cpp
@@ -66,19 +66,15 @@  static constexpr float kExpMaxStep = 0.15;
 
 namespace {
 
-std::optional<float> calculateMSV(const Histogram &histogram, uint8_t blackLevel)
+std::optional<float> calculateMSV(const Histogram &histogram)
 {
 	/*
 	 * Calculate Mean Sample Value (MSV) according to formula from:
 	 * https://www.araa.asn.au/acra/acra2007/papers/paper84final.pdf
 	 */
-	const unsigned int blackLevelHistIdx =
-		blackLevel * histogram.bins() / 256;
-	const unsigned int histogramSize =
-		histogram.bins() - blackLevelHistIdx;
-	const unsigned int yHistValsPerBin = histogramSize / kExposureBinsCount;
+	const unsigned int yHistValsPerBin = histogram.bins() / kExposureBinsCount;
 	const unsigned int yHistValsPerBinMod =
-		histogramSize / (histogramSize % kExposureBinsCount + 1);
+		histogram.bins() / (histogram.bins() % kExposureBinsCount + 1);
 	int exposureBins[kExposureBinsCount] = {};
 	unsigned int denom = 0;
 	unsigned int num = 0;
@@ -86,9 +82,9 @@  std::optional<float> calculateMSV(const Histogram &histogram, uint8_t blackLevel
 	if (yHistValsPerBin == 0)
 		return {};
 
-	for (unsigned int i = 0; i < histogramSize; i++) {
+	for (unsigned int i = 0; i < histogram.bins(); i++) {
 		unsigned int idx = (i - (i / yHistValsPerBinMod)) / yHistValsPerBin;
-		exposureBins[idx] += histogram[blackLevelHistIdx + i];
+		exposureBins[idx] += histogram[i];
 	}
 
 	for (unsigned int i = 0; i < kExposureBinsCount; i++) {
@@ -193,7 +189,14 @@  void Agc::process(IPAContext &context,
 		return;
 	}
 
-	auto exposureMSV = calculateMSV({ stats->yHistogram }, context.activeState.blc.level);
+	auto histogram = stats->yHistogram;
+	const unsigned int blackLevelHistIdx =
+		context.activeState.blc.level * std::size(histogram) / 256;
+
+	for (unsigned int i = 0; i < blackLevelHistIdx; i++)
+		histogram[blackLevelHistIdx] += histogram[i];
+
+	auto exposureMSV = calculateMSV({ { histogram.begin() + blackLevelHistIdx, histogram.end() } });
 	if (!exposureMSV) {
 		LOG(IPASoftExposure, Debug)
 			<< "Not adjusting exposure due to insufficient histogram data";