/* SPDX-License-Identifier: LGPL-2.1-or-later */ /* * Copyright (C) 2024, Ideas On Board * * Helper for radial polynomial used in lens shading correction. */ #pragma once #include #include #include #include #include #include #include "libcamera/internal/yaml_parser.h" namespace libcamera { LOG_DECLARE_CATEGORY(LscPolynomial) namespace ipa { class LscPolynomial { public: LscPolynomial(double cx = 0.0, double cy = 0.0, double k0 = 0.0, double k1 = 0.0, double k2 = 0.0, double k3 = 0.0, double k4 = 0.0) : cx_(cx), cy_(cy), cnx_(0), cny_(0), coefficients_({ k0, k1, k2, k3, k4 }) { } double sampleAtNormalizedPixelPos(double x, double y) const { double dx = x - cnx_; double dy = y - cny_; double r = sqrt(dx * dx + dy * dy); double res = 1.0; for (unsigned int i = 0; i < coefficients_.size(); i++) { res += coefficients_[i] * std::pow(r, (i + 1) * 2); } return res; } double getM() const { double cpx = imageSize_.width * cx_; double cpy = imageSize_.height * cy_; double mx = std::max(cpx, std::fabs(imageSize_.width - cpx)); double my = std::max(cpy, std::fabs(imageSize_.height - cpy)); return sqrt(mx * mx + my * my); } void setReferenceImageSize(const Size &size) { assert(!size.isNull()); imageSize_ = size; /* Calculate normalized centers */ double m = getM(); cnx_ = (size.width * cx_) / m; cny_ = (size.height * cy_) / m; } private: double cx_; double cy_; double cnx_; double cny_; std::array coefficients_; Size imageSize_; }; } /* namespace ipa */ #ifndef __DOXYGEN__ template<> struct YamlObject::Getter { std::optional get(const YamlObject &obj) const { std::optional cx = obj["cx"].get(); std::optional cy = obj["cy"].get(); std::optional k0 = obj["k0"].get(); std::optional k1 = obj["k1"].get(); std::optional k2 = obj["k2"].get(); std::optional k3 = obj["k3"].get(); std::optional k4 = obj["k4"].get(); if (!(cx && cy && k0 && k1 && k2 && k3 && k4)) LOG(LscPolynomial, Error) << "Polynomial is missing a parameter"; return ipa::LscPolynomial(*cx, *cy, *k0, *k1, *k2, *k3, *k4); } }; #endif } /* namespace libcamera */ type='search' size='10' name='q' value=''/>
blob: 103d3f606a766f460c0cc38a8ed5445395b0f22f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
/* SPDX-License-Identifier: BSD-2-Clause */
/*
 * Copyright (C) 2019, Raspberry Pi (Trading) Limited
 *
 * histogram.cpp - histogram calculations
 */
#include <math.h>
#include <stdio.h>

#include "histogram.hpp"

using namespace RPi;

uint64_t Histogram::CumulativeFreq(double bin) const
{
	if (bin <= 0)
		return 0;
	else if (bin >= Bins())
		return Total();
	int b = (int)bin;
	return cumulative_[b] +
	       (bin - b) * (cumulative_[b + 1] - cumulative_[b]);
}

double Histogram::Quantile(double q, int first, int last) const
{
	if (first == -1)
		first = 0;
	if (last == -1)
		last = cumulative_.size() - 2;
	assert(first <= last);
	uint64_t items = q * Total();
	while (first < last) // binary search to find the right bin
	{
		int middle = (first + last) / 2;
		if (cumulative_[middle + 1] > items)
			last = middle; // between first and middle
		else
			first = middle + 1; // after middle
	}
	assert(items >= cumulative_[first] && items <= cumulative_[last + 1]);
	double frac = cumulative_[first + 1] == cumulative_[first] ? 0
		      : (double)(items - cumulative_[first]) /
				  (cumulative_[first + 1] - cumulative_[first]);
	return first + frac;
}

double Histogram::InterQuantileMean(double q_lo, double q_hi) const
{
	assert(q_hi > q_lo);
	double p_lo = Quantile(q_lo);
	double p_hi = Quantile(q_hi, (int)p_lo);
	double sum_bin_freq = 0, cumul_freq = 0;
	for (double p_next = floor(p_lo) + 1.0; p_next <= ceil(p_hi);
	     p_lo = p_next, p_next += 1.0) {
		int bin = floor(p_lo);
		double freq = (cumulative_[bin + 1] - cumulative_[bin]) *
			      (std::min(p_next, p_hi) - p_lo);
		sum_bin_freq += bin * freq;
		cumul_freq += freq;
	}
	// add 0.5 to give an average for bin mid-points
	return sum_bin_freq / cumul_freq + 0.5;
}