[libcamera-devel] [PATCH 1/5] libcamera: Add Transform class
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Wed Jul 29 17:12:34 CEST 2020
Hi David,
Thank you for the patch.
On Wed, Jul 29, 2020 at 10:31:50AM +0100, David Plowman wrote:
> Add implementation of 2d plane transforms, and include a Transform
> field in the CameraConfiguration to record the application's choice of
> image transform for this session.
> ---
> include/libcamera/camera.h | 3 +
> include/libcamera/meson.build | 1 +
> include/libcamera/transform.h | 193 ++++++++++++++++++++++++++++++++++
> 3 files changed, 197 insertions(+)
> create mode 100644 include/libcamera/transform.h
>
> diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h
> index 4d1a4a9..fd9355e 100644
> --- a/include/libcamera/camera.h
> +++ b/include/libcamera/camera.h
> @@ -16,6 +16,7 @@
> #include <libcamera/request.h>
> #include <libcamera/signal.h>
> #include <libcamera/stream.h>
> +#include <libcamera/transform.h>
>
> namespace libcamera {
>
> @@ -60,6 +61,8 @@ public:
> bool empty() const;
> std::size_t size() const;
>
> + Transform userTransform;
> +
> protected:
> CameraConfiguration();
>
This needs to be documented in the CameraConfiguration class. Didn't
doxygen warn you ? I would also split this to a separate patch, and
update the existing pipeline handlers to always set userTransform to
Identity in their validate() function.
> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> index cdb8e03..7fae5e5 100644
> --- a/include/libcamera/meson.build
> +++ b/include/libcamera/meson.build
> @@ -19,6 +19,7 @@ libcamera_public_headers = files([
> 'span.h',
> 'stream.h',
> 'timer.h',
> + 'transform.h',
> ])
>
> include_dir = join_paths(libcamera_include_dir, 'libcamera')
> diff --git a/include/libcamera/transform.h b/include/libcamera/transform.h
> new file mode 100644
> index 0000000..cfd5026
> --- /dev/null
> +++ b/include/libcamera/transform.h
> @@ -0,0 +1,193 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2020, Google Inc.
As mentioned in the reply to the cover letter, this should have your
copyright.
> + *
> + * transform.h - Implementation of 2d plane transforms
'2d' or '2D' ?
> + */
> +
> +#ifndef __LIBCAMERA_TRANSFORM_H__
> +#define __LIBCAMERA_TRANSFORM_H__
> +
> +#include <string>
You should also include stdint.h for int32_t, although I think you could
use int instead of int32_t.
> +
> +namespace libcamera {
> +
> +class Transform
> +{
> +public:
> + constexpr Transform()
> + : Transform(Identity)
> + {
> + }
> +
> + constexpr static Transform identity()
> + {
> + return Transform(Identity);
> + }
> +
> + constexpr static Transform rot0()
> + {
> + return identity();
> + }
> +
> + constexpr static Transform hflip()
> + {
> + return Transform(HFlip);
> + }
> +
> + constexpr static Transform vflip()
> + {
> + return Transform(VFlip);
> + }
> +
> + constexpr static Transform hvflip()
> + {
> + return Transform(HVFlip);
> + }
> +
> + constexpr static Transform rot180()
> + {
> + return hvflip();
> + }
> +
> + constexpr static Transform transpose()
> + {
> + return Transform(Transpose);
> + }
> +
> + constexpr static Transform rot270()
> + {
> + return Transform(Rot270);
> + }
> +
> + constexpr static Transform rot90()
> + {
> + return Transform(Rot90);
> + }
> +
> + constexpr static Transform rot180Transpose()
> + {
> + return Transform(Rot180Transpose);
> + }
> +
> + constexpr static Transform hvflipTranspose()
> + {
> + return rot180Transpose();
> + }
> +
Wouldn't it be simpler to make the Type enum public, as well as the
constructor that takes a Type ? I will also be way less code to type :-)
> + constexpr static bool rotation(int32_t angle, Transform &xfm)
> + {
> + bool success = true;
> + angle = angle % 360;
> + if (angle < 0)
> + angle += 360;
> +
> + if (angle == 0)
> + xfm = identity();
> + else if (angle == 90)
> + xfm = rot90();
> + else if (angle == 180)
> + xfm = rot180();
> + else if (angle == 270)
> + xfm = rot270();
> + else
> + success = false;
> +
> + return success;
> + }
> +
> + constexpr bool rotation(int32_t &angle) const
> + {
> + bool success = true;
> +
> + if (type_ == Identity)
> + angle = 0;
> + else if (type_ == Rot90)
> + angle = 90;
> + else if (type_ == HVFlip)
> + angle = 180;
> + else if (type_ == Rot270)
> + angle = 270;
> + else
> + success = false;
> +
> + return success;
> + }
That's two "rotation" functions, one applying a rotation, the other one
returning the rotation. I think it's a bit confusing. I would turn the
former into
bool rotate(int angle);
and the later into
constexpr unsigned int rotationAngle(bool *success = nullptr) const;
I also think the two functions should be implemented in the .cpp file.
> +
> + constexpr bool contains(Transform xfm) const
> + {
> + return (type_ & xfm.type_) == xfm.type_;
> + }
This function is used in the rest of the series to check if a
transformation contains hflip, vflip or transpose. For that use case
it's fine, but it could also be used with
Transform::rot180Transpose().contains(Transform::rot270())
and return true, which is quite confusing to read. I'm not sure how to
improve that though. Maybe defining three functions, to test for hflip,
vflip and transpose separately ? isHorizontallyFlipped(),
isVerticallyFlipped, isTransposed ? Or isHFlipped(), isVFlipped() for
the first two ?
> +
> + constexpr Transform inverse() const
> + {
> + /* They're all self-inverses, except for Rot90 and Rot270. */
> + const Type inverses[] = { Identity, HFlip, VFlip, HVFlip,
> + Transpose, Rot90, Rot270, Rot180Transpose };
Shouldn't this be static const ?
> +
> + return Transform(inverses[type_]);
> + }
> +
> + constexpr Transform operator*(Transform xfm) const
> + {
> + /*
> + * Reorder the operations so that we imagine doing xfm's transpose
> + * (if any) after our flips. The effect is to swap our hflips for
> + * vflips and vice versa, after which we can just xor all the bits.
> + */
> + int reorderedType = type_;
> + if (xfm.type_ & Transpose)
> + reorderedType = (type_ & 4) | ((type_ & 1) << 1) | ((type_ & 2) >> 1);
> +
> + return Transform((Type)(reorderedType ^ xfm.type_));
> + }
I would move the implementation of these two functions to the .cpp file
too.
> +
> + bool operator==(Transform xfm) const
> + {
> + return type_ == xfm.type_;
> + }
> +
> + bool operator!=(Transform xfm) const
> + {
> + return !(*this == xfm);
> + }
> +
> + std::string toString() const
> + {
> + char const *strings[] = {
static const char ?
> + "identity",
> + "hflip",
> + "vflip",
> + "hvflip",
> + "transpose",
> + "rot270",
> + "rot90",
> + "rot180transpose"
> + };
> + return strings[type_];
> + }
Of course all this needs documentation :-) A good introduction (in the
\class Transform block) would be very useful to explain the concepts I
think.
> +
> +private:
> + enum Type : int {
> + Identity = 0,
> + HFlip = 1,
> + VFlip = 2,
> + HVFlip = HFlip | VFlip,
> + Transpose = 4,
> + Rot270 = HFlip | Transpose,
> + Rot90 = VFlip | Transpose,
> + Rot180Transpose = HFlip | VFlip | Transpose
> + };
> +
> + constexpr Transform(Type type)
> + : type_(type)
> + {
> + }
> +
> + Type type_;
> +};
> +
> +} /* namespace libcamera */
> +
> +#endif /* __LIBCAMERA_TRANSFORM_H__ */
> +
Extra blank line.
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list