[libcamera-devel,v3,4/6] src: ipa: raspberrypi: Compute inverse of piecewise linear function
diff mbox series

Message ID 20201208204441.9356-5-david.plowman@raspberrypi.com
State Accepted
Headers show
Series
  • Raspberry Pi AGC: initial frame drop count
Related show

Commit Message

David Plowman Dec. 8, 2020, 8:44 p.m. UTC
Add a method to the piecewise linear function (Pwl) class to compute
the inverse of a given Pwl. If the input function is non-monotonic we
can only produce a best effort "pseudo" inverse, and we signal this to
the caller.

Signed-off-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Naushir Patuck <naush@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 src/ipa/raspberrypi/controller/pwl.cpp | 30 ++++++++++++++++++++++++++
 src/ipa/raspberrypi/controller/pwl.hpp |  3 +++
 2 files changed, 33 insertions(+)

Patch
diff mbox series

diff --git a/src/ipa/raspberrypi/controller/pwl.cpp b/src/ipa/raspberrypi/controller/pwl.cpp
index aa134a1f..130c820b 100644
--- a/src/ipa/raspberrypi/controller/pwl.cpp
+++ b/src/ipa/raspberrypi/controller/pwl.cpp
@@ -114,6 +114,36 @@  Pwl::PerpType Pwl::Invert(Point const &xy, Point &perp, int &span,
 	return PerpType::None;
 }
 
+Pwl Pwl::Inverse(bool *true_inverse, const double eps) const
+{
+	bool appended = false, prepended = false, neither = false;
+	Pwl inverse;
+
+	for (Point const &p : points_) {
+		if (inverse.Empty())
+			inverse.Append(p.y, p.x, eps);
+		else if (std::abs(inverse.points_.back().x - p.y) <= eps ||
+			 std::abs(inverse.points_.front().x - p.y) <= eps)
+			/* do nothing */;
+		else if (p.y > inverse.points_.back().x) {
+			inverse.Append(p.y, p.x, eps);
+			appended = true;
+		} else if (p.y < inverse.points_.front().x) {
+			inverse.Prepend(p.y, p.x, eps);
+			prepended = true;
+		} else
+			neither = true;
+	}
+
+	// This is not a proper inverse if we found ourselves putting points
+	// onto both ends of the inverse, or if there were points that couldn't
+	// go on either.
+	if (true_inverse)
+		*true_inverse = !(neither || (appended && prepended));
+
+	return inverse;
+}
+
 Pwl Pwl::Compose(Pwl const &other, const double eps) const
 {
 	double this_x = points_[0].x, this_y = points_[0].y;
diff --git a/src/ipa/raspberrypi/controller/pwl.hpp b/src/ipa/raspberrypi/controller/pwl.hpp
index 4f168551..484672f6 100644
--- a/src/ipa/raspberrypi/controller/pwl.hpp
+++ b/src/ipa/raspberrypi/controller/pwl.hpp
@@ -80,6 +80,9 @@  public:
 	};
 	PerpType Invert(Point const &xy, Point &perp, int &span,
 			const double eps = 1e-6) const;
+	// Compute the inverse function. Indicate if it is a proper (true)
+	// inverse, or only a best effort (e.g. input was non-monotonic).
+	Pwl Inverse(bool *true_inverse = nullptr, const double eps = 1e-6) const;
 	// Compose two Pwls together, doing "this" first and "other" after.
 	Pwl Compose(Pwl const &other, const double eps = 1e-6) const;
 	// Apply function to (x,y) values at every control point.