/* SPDX-License-Identifier: GPL-2.0-or-later */ /* * Copyright (C) 2023, Ideas On Board Oy * * 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)