From 69b2dc16a09a111d8053c5d8009207cef357bcc5 Mon Sep 17 00:00:00 2001 From: Jacopo Mondi Date: Thu, 19 Oct 2023 16:01:29 +0200 Subject: test: Add unit test for Transform and Orientation 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 Reviewed-by: David Plowman Reviewed-by: Laurent Pinchart Signed-off-by: Laurent Pinchart --- test/meson.build | 1 + test/transform.cpp | 329 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 330 insertions(+) create mode 100644 test/transform.cpp diff --git a/test/meson.build b/test/meson.build index b227be81..189e1428 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 00000000..fbc0308c --- /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 + +#include +#include + +#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) -- cgit v1.2.1