[libcamera-devel] [PATCH v5 08/12] test: Add unit test for Transform and Orientation
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Wed Oct 18 22:54:16 CEST 2023
Hi Jacopo,
Thank you for the patch.
On Fri, Sep 01, 2023 at 05:02:11PM +0200, Jacopo Mondi via libcamera-devel wrote:
> 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 at ideasonboard.com>
> Reviewed-by: David Plowman <david.plowman at raspberrypi.com>
> ---
> test/meson.build | 1 +
> test/transform.cpp | 331 +++++++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 332 insertions(+)
> create mode 100644 test/transform.cpp
>
> 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..4a6cf7387f02
> --- /dev/null
> +++ b/test/transform.cpp
> @@ -0,0 +1,331 @@
> +/* 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.
> + */
> + struct RotationTestEntry {
static const
> + Orientation o1;
> + Orientation o2;
> + Transform t;
> + } testEntries[] = {
> + /* Test identities transforms first. */
> + {
> + Orientation::rotate0, Orientation::rotate0,
> + Transform::Identity,
> + },
> + {
> + Orientation::rotate0Flip, Orientation::rotate0Flip,
> + Transform::Identity,
> + },
> + {
> + Orientation::rotate180, Orientation::rotate180,
> + Transform::Identity,
> + },
> + {
> + Orientation::rotate180Flip, Orientation::rotate180Flip,
> + Transform::Identity,
> + },
> + {
> + Orientation::rotate90, Orientation::rotate90,
> + Transform::Identity,
> + },
> + {
> + Orientation::rotate90Flip, Orientation::rotate90Flip,
> + Transform::Identity,
> + },
> + {
> + Orientation::rotate270, Orientation::rotate270,
> + Transform::Identity,
> + },
> + {
> + Orientation::rotate270Flip, Orientation::rotate270Flip,
> + 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::rotate0Flip,
> + Transform::HFlip
> + },
> + {
> + Orientation::rotate0Flip, Orientation::rotate0,
> + Transform::HFlip
> + },
> + {
> + Orientation::rotate180, Orientation::rotate180Flip,
> + Transform::HFlip
> + },
> + {
> + Orientation::rotate180Flip, Orientation::rotate180,
> + Transform::HFlip
> + },
> + {
> + Orientation::rotate90, Orientation::rotate90Flip,
> + Transform::HFlip
> + },
> + {
> + Orientation::rotate90Flip, Orientation::rotate90,
> + Transform::HFlip
> + },
> + {
> + Orientation::rotate270, Orientation::rotate270Flip,
> + Transform::HFlip
> + },
> + {
> + Orientation::rotate270Flip, Orientation::rotate270,
> + Transform::HFlip
> + },
> + {
> + Orientation::rotate0, Orientation::rotate0Flip,
> + Transform::HFlip
> + },
> + /*
> + * More exotic transforms which include Transpositions and
> + * mirroring.
> + */
> + {
> + /*
> + * o2 t o1
> + * ------------------
> + * BC * (V) = AD
> + * AD BC
> + */
> + Orientation::rotate90Flip, Orientation::rotate270,
> + Transform::VFlip,
> + },
> + {
> + /*
> + * o2 t o1
> + * ------------------
> + * CB * (T) = CD
> + * DA BA
> + */
> + Orientation::rotate180, Orientation::rotate270Flip,
> + Transform::Transpose,
> + },
> + {
> + /*
> + * o2 t o1
> + * ------------------
> + * AD * (T) = AB
> + * BC DC
> + */
> + Orientation::rotate0, Orientation::rotate90Flip,
> + Transform::Transpose,
> + },
> + {
> + /*
> + * o2 t o1
> + * ------------------
> + * AD * (V) = BC
> + * BC AD
> + */
> + Orientation::rotate270, Orientation::rotate90Flip,
> + Transform::VFlip,
> + },
> + {
> + /*
> + * o2 t o1
> + * ------------------
> + * DA * (V) = CB
> + * CB DA
> + */
> + Orientation::rotate270Flip, Orientation::rotate90,
> + Transform::VFlip,
> + },
> + {
> + /*
> + * o2 t o1
> + * --------------------------
> + * CB * (V|H) = BC AD
> + * DA AD BC
> + */
> + Orientation::rotate90Flip, Orientation::rotate270Flip,
> + Transform::Rot180,
> + },
> + };
> +
> + for (const auto &entry : testEntries) {
> + Transform transform = entry.o1 / entry.o2;
> + cout << "Testing: " << entry.o1 << " / " << entry.o2
> + << " = " << transformToString(transform) << endl;
I would drop this message, it's unnecessarily verbose when everything
runs fine. The error messages below are enough.
Reviewed-by: Laurent Pinchart <laurent.pinchart at ideasonboard.com>
> + 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)
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list