[libcamera-devel,v6,08/12] test: Add unit test for Transform and Orientation
diff mbox series

Message ID 20231019140133.32090-9-jacopo.mondi@ideasonboard.com
State Accepted
Headers show
Series
  • libcamera: Replace CameraConfiguration::transform
Related show

Commit Message

Jacopo Mondi Oct. 19, 2023, 2:01 p.m. UTC
Add a unit test for Transform and Orientation to validate the
implementation of the operations between the two types.

In particular, test that:

	o1 / o2 = t
	o2 * t = o1

Signed-off-by: Jacopo Mondi <jacopo.mondi@ideasonboard.com>
Reviewed-by: David Plowman <david.plowman@raspberrypi.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 test/meson.build   |   1 +
 test/transform.cpp | 329 +++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 330 insertions(+)
 create mode 100644 test/transform.cpp

Patch
diff mbox series

diff --git a/test/meson.build b/test/meson.build
index b227be818419..189e1428485a 100644
--- a/test/meson.build
+++ b/test/meson.build
@@ -46,6 +46,7 @@  public_tests = [
     {'name': 'public-api', 'sources': ['public-api.cpp']},
     {'name': 'signal', 'sources': ['signal.cpp']},
     {'name': 'span', 'sources': ['span.cpp']},
+    {'name': 'transform', 'sources': ['transform.cpp']},
 ]
 
 internal_tests = [
diff --git a/test/transform.cpp b/test/transform.cpp
new file mode 100644
index 000000000000..fbc0308c5d45
--- /dev/null
+++ b/test/transform.cpp
@@ -0,0 +1,329 @@ 
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2023, Ideas On Board Oy
+ *
+ * transform.cpp - Transform and Orientation tests
+ */
+
+#include <iostream>
+
+#include <libcamera/orientation.h>
+#include <libcamera/transform.h>
+
+#include "test.h"
+
+using namespace std;
+using namespace libcamera;
+
+class TransformTest : public Test
+{
+protected:
+	int run();
+};
+
+int TransformTest::run()
+{
+	/*
+	 * RotationTestEntry collects two Orientation and one Transform that
+	 * gets combined to validate that (o1 / o2 = T) and (o1 = o2 * T)
+	 *
+	 * o1 / o2 = t computes the Transform to apply to o2 to obtain o1
+	 * o2 * t = o1 combines o2 with t by applying o2 first then t
+	 *
+	 * The comments on the (most complex) transform show how applying to
+	 * an image with orientation o2 the Transform t allows to obtain o1.
+	 *
+	 * The image with basic rotation0 is assumed to be:
+	 *
+	 * 	AB
+	 * 	CD
+	 *
+	 * And the Transform operators are:
+	 *
+	 * 	V = vertical flip
+	 * 	H = horizontal flip
+	 * 	T = transpose
+	 *
+	 * the operator '* (T|V)' applies V first then T.
+	 */
+	static const struct RotationTestEntry {
+		Orientation o1;
+		Orientation o2;
+		Transform t;
+	} testEntries[] = {
+		/* Test identities transforms first. */
+		{
+			Orientation::Rotate0, Orientation::Rotate0,
+			Transform::Identity,
+		},
+		{
+			Orientation::Rotate0Mirror, Orientation::Rotate0Mirror,
+			Transform::Identity,
+		},
+		{
+			Orientation::Rotate180, Orientation::Rotate180,
+			Transform::Identity,
+		},
+		{
+			Orientation::Rotate180Mirror, Orientation::Rotate180Mirror,
+			Transform::Identity,
+		},
+		{
+			Orientation::Rotate90, Orientation::Rotate90,
+			Transform::Identity,
+		},
+		{
+			Orientation::Rotate90Mirror, Orientation::Rotate90Mirror,
+			Transform::Identity,
+		},
+		{
+			Orientation::Rotate270, Orientation::Rotate270,
+			Transform::Identity,
+		},
+		{
+			Orientation::Rotate270Mirror, Orientation::Rotate270Mirror,
+			Transform::Identity,
+		},
+		/*
+		 * Combine 0 and 180 degrees rotation as they're the most common
+		 * ones.
+		 */
+		{
+			/*
+			 *      o2      t               o1
+			 *      --------------------------
+			 *	CD  * (H|V) =  	BA	AB
+			 *	BA		CD	CD
+			 */
+			Orientation::Rotate0, Orientation::Rotate180,
+			Transform::Rot180,
+		},
+		{
+			/*
+			 *      o2      t               o1
+			 *      --------------------------
+			 *	AB  * (H|V) =  	CD	DC
+			 *	CD		AB	BA
+			 */
+			Orientation::Rotate180, Orientation::Rotate0,
+			Transform::Rot180
+		},
+		/* Test that transpositions are handled correctly. */
+		{
+			/*
+			 *      o2      t               o1
+			 *      --------------------------
+			 *	AB  * (T|V) =  	CD	CA
+			 *	CD		AB	DB
+			 */
+			Orientation::Rotate90, Orientation::Rotate0,
+			Transform::Rot90,
+		},
+		{
+			/*
+			 *      o2      t               o1
+			 *      --------------------------
+			 *	CA  * (T|H) =  	AC	AB
+			 *	DB		BD	CD
+			 */
+			Orientation::Rotate0, Orientation::Rotate90,
+			Transform::Rot270,
+		},
+		{
+			/*
+			 *      o2      t               o1
+			 *      --------------------------
+			 *	AB  * (T|H) =  	BA	BD
+			 *	CD		DC	AC
+			 */
+			Orientation::Rotate270, Orientation::Rotate0,
+			Transform::Rot270,
+		},
+		{
+			/*
+			 *      o2      t               o1
+			 *      --------------------------
+			 *	BD  * (T|V) =  	AC	AB
+			 *	AC		BD	CD
+			 */
+			Orientation::Rotate0, Orientation::Rotate270,
+			Transform::Rot90,
+		},
+		{
+			/*
+			 *      o2      t               o1
+			 *      --------------------------
+			 *	CD  * (T|H) =  	DC	DA
+			 *	BA		AB	CB
+			 */
+			Orientation::Rotate90, Orientation::Rotate180,
+			Transform::Rot270,
+		},
+		{
+			/*
+			 *      o2      t               o1
+			 *      --------------------------
+			 *	DA  * (T|V) =  	CB	CD
+			 *	CB		DA	BA
+			 */
+			Orientation::Rotate180, Orientation::Rotate90,
+			Transform::Rot90,
+		},
+		{
+			/*
+			 *      o2      t               o1
+			 *      --------------------------
+			 *	CD  * (T|V) =  	BA	BC
+			 *	BA		CD	AD
+			 */
+			Orientation::Rotate270, Orientation::Rotate180,
+			Transform::Rot90,
+		},
+		{
+			/*
+			 *      o2      t               o1
+			 *      --------------------------
+			 *	BC  * (T|H) =  	CB	CD
+			 *	AD		DA	BA
+			 */
+			Orientation::Rotate180, Orientation::Rotate270,
+			Transform::Rot270,
+		},
+		{
+			/*
+			 *      o2      t               o1
+			 *      --------------------------
+			 *	DA  * (V|H) =  	AD	BC
+			 *	CB		BC	AD
+			 */
+			Orientation::Rotate270, Orientation::Rotate90,
+			Transform::Rot180,
+		},
+		/* Test that mirroring is handled correctly. */
+		{
+			Orientation::Rotate0, Orientation::Rotate0Mirror,
+			Transform::HFlip
+		},
+		{
+			Orientation::Rotate0Mirror, Orientation::Rotate0,
+			Transform::HFlip
+		},
+		{
+			Orientation::Rotate180, Orientation::Rotate180Mirror,
+			Transform::HFlip
+		},
+		{
+			Orientation::Rotate180Mirror, Orientation::Rotate180,
+			Transform::HFlip
+		},
+		{
+			Orientation::Rotate90, Orientation::Rotate90Mirror,
+			Transform::HFlip
+		},
+		{
+			Orientation::Rotate90Mirror, Orientation::Rotate90,
+			Transform::HFlip
+		},
+		{
+			Orientation::Rotate270, Orientation::Rotate270Mirror,
+			Transform::HFlip
+		},
+		{
+			Orientation::Rotate270Mirror, Orientation::Rotate270,
+			Transform::HFlip
+		},
+		{
+			Orientation::Rotate0, Orientation::Rotate0Mirror,
+			Transform::HFlip
+		},
+		/*
+		 * More exotic transforms which include Transpositions and
+		 * mirroring.
+		 */
+		{
+			/*
+			 *      o2      t       o1
+			 *      ------------------
+			 *	BC  * (V) =  	AD
+			 *	AD		BC
+			 */
+			Orientation::Rotate90Mirror, Orientation::Rotate270,
+			Transform::VFlip,
+		},
+		{
+			/*
+			 *      o2      t       o1
+			 *      ------------------
+			 *	CB  * (T) =  	CD
+			 *	DA		BA
+			 */
+			Orientation::Rotate180, Orientation::Rotate270Mirror,
+			Transform::Transpose,
+		},
+		{
+			/*
+			 *      o2      t       o1
+			 *      ------------------
+			 *	AD  * (T) =  	AB
+			 *	BC		DC
+			 */
+			Orientation::Rotate0, Orientation::Rotate90Mirror,
+			Transform::Transpose,
+		},
+		{
+			/*
+			 *      o2      t       o1
+			 *      ------------------
+			 *	AD  * (V) =  	BC
+			 *	BC		AD
+			 */
+			Orientation::Rotate270, Orientation::Rotate90Mirror,
+			Transform::VFlip,
+		},
+		{
+			/*
+			 *      o2      t       o1
+			 *      ------------------
+			 *	DA  * (V) =  	CB
+			 *	CB		DA
+			 */
+			Orientation::Rotate270Mirror, Orientation::Rotate90,
+			Transform::VFlip,
+		},
+		{
+			/*
+			 *      o2      t               o1
+			 *      --------------------------
+			 *	CB  * (V|H) =	BC  	AD
+			 *	DA		AD	BC
+			 */
+			Orientation::Rotate90Mirror, Orientation::Rotate270Mirror,
+			Transform::Rot180,
+		},
+	};
+
+	for (const auto &entry : testEntries) {
+		Transform transform = entry.o1 / entry.o2;
+		if (transform != entry.t) {
+			cerr << "Failed to validate: " << entry.o1
+			     << " / " << entry.o2
+			     << " = " << transformToString(entry.t) << endl;
+			cerr << "Got back: "
+			     << transformToString(transform) << endl;
+			return TestFail;
+		}
+
+		Orientation adjusted = entry.o2 * entry.t;
+		if (adjusted != entry.o1) {
+			cerr << "Failed to validate: " << entry.o2
+			     << " * " << transformToString(entry.t)
+			     << " = " << entry.o1 << endl;
+			cerr << "Got back: " << adjusted << endl;
+			return TestFail;
+		}
+	}
+
+	return TestPass;
+}
+
+TEST_REGISTER(TransformTest)