[PATCH 4/5] libipa: histogram: Fix interQuantileMean() for small ranges

Kieran Bingham kieran.bingham at ideasonboard.com
Mon Mar 31 20:12:27 CEST 2025


Quoting Stefan Klug (2025-03-24 17:07:39)
> The interQuantileMean() is supposed to return a weighted mean value
> between two quantiles. This works for reasonably fine histograms, but

reasonably 'for' fine histograms ...

> fails for coarse histograms and small quantile ranges because the weight
> is always taken from the lower border of the bin.
> 
> Fix that by rewriting the algorithm to calculate a lower and upper bound
> for every (partial) bin that goes into the mean calculation and weight
> the bins by the middle of these bounds.
> 
> Signed-off-by: Stefan Klug <stefan.klug at ideasonboard.com>

I haven't given this the attention and checks through all paths here
that it would deserve for a full RB tag, but because you've added tests
that validate it, which I'll put my faith in ...

Acked-by: Kieran Bingham <kieran.bingham at ideasonboard.com>

> ---
>  src/ipa/libipa/histogram.cpp | 20 +++++++++++---------
>  1 file changed, 11 insertions(+), 9 deletions(-)
> 
> diff --git a/src/ipa/libipa/histogram.cpp b/src/ipa/libipa/histogram.cpp
> index c19a4cbbf3cd..31f017af3458 100644
> --- a/src/ipa/libipa/histogram.cpp
> +++ b/src/ipa/libipa/histogram.cpp
> @@ -153,22 +153,24 @@ double Histogram::interQuantileMean(double lowQuantile, double highQuantile) con
>         double lowPoint = quantile(lowQuantile);
>         /* Proportion of pixels which lies below highQuantile */
>         double highPoint = quantile(highQuantile, static_cast<uint32_t>(lowPoint));
> -       double sumBinFreq = 0, cumulFreq = 0;
> +       double sumBinFreq = 0;
> +       double cumulFreq = 0;
> +
> +       for (int bin = std::floor(lowPoint); bin < std::ceil(highPoint); bin++) {
> +               double lowBound = std::max(static_cast<double>(bin), lowPoint);
> +               double highBound = std::min(static_cast<double>(bin + 1), highPoint);
>  
> -       for (double p_next = floor(lowPoint) + 1.0;
> -            p_next <= ceil(highPoint);
> -            lowPoint = p_next, p_next += 1.0) {
> -               int bin = floor(lowPoint);
>                 double freq = (cumulative_[bin + 1] - cumulative_[bin])
> -                       * (std::min(p_next, highPoint) - lowPoint);
> +                       * (highBound - lowBound);
>  
>                 /* Accumulate weighted bin */
> -               sumBinFreq += bin * freq;
> +               sumBinFreq += 0.5 * (highBound + lowBound) * freq;
> +
>                 /* Accumulate weights */
>                 cumulFreq += freq;
>         }
> -       /* add 0.5 to give an average for bin mid-points */
> -       return sumBinFreq / cumulFreq + 0.5;
> +
> +       return sumBinFreq / cumulFreq;
>  }
>  
>  } /* namespace ipa */
> -- 
> 2.43.0
>


More information about the libcamera-devel mailing list