summaryrefslogtreecommitdiff
path: root/src/ipa/libipa/lsc_polynomial.h
blob: c898faeb13db28e848618c9c2c2db9d39e8260d8 (plain)
1
2
3
4
5
6
7
8
9
10
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-unlock"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"></rect><path d="M7 11V7a5 5 0 0 1 9.9-1"></path></svg>
ef='#n71'>71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
/* 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 <algorithm>
#include <array>
#include <assert.h>
#include <cmath>

#include <libcamera/base/log.h>
#include <libcamera/base/span.h>

#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<double, 5> coefficients_;

	Size imageSize_;
};

} /* namespace ipa */

#ifndef __DOXYGEN__

template<>
struct YamlObject::Getter<ipa::LscPolynomial> {
	std::optional<ipa::LscPolynomial> get(const YamlObject &obj) const
	{
		std::optional<double> cx = obj["cx"].get<double>();
		std::optional<double> cy = obj["cy"].get<double>();
		std::optional<double> k0 = obj["k0"].get<double>();
		std::optional<double> k1 = obj["k1"].get<double>();
		std::optional<double> k2 = obj["k2"].get<double>();
		std::optional<double> k3 = obj["k3"].get<double>();
		std::optional<double> k4 = obj["k4"].get<double>();

		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 */