[libcamera-devel] [PATCH v5 02/12] libcamera: camera: Introduce Orientation
Laurent Pinchart
laurent.pinchart at ideasonboard.com
Wed Oct 18 20:37:10 CEST 2023
Hi Jacopo,
Thank you for the patch.
On Fri, Sep 01, 2023 at 05:02:05PM +0200, Jacopo Mondi via libcamera-devel wrote:
> Introduce the Orientation enumeration which describes the possible 2D
> transformations that can be applied to an image using two basic plane
> transformations.
>
> Add to the CameraConfiguration class a new member 'orientation' which is
> used to specify the image orientation in the memory buffers delivered to
> applications.
>
> The enumeration values follow the ones defined by the EXIF specification at
> revision 2.32, Tag 274 'orientation'.
>
> The newly introduced field is meant to replace
> CameraConfiguration::transform which is not removed yet not to break
> compilation.
>
> Signed-off-by: Jacopo Mondi <jacopo.mondi at ideasonboard.com>
> Reviewed-by: David Plowman <david.plowman at raspberrypi.com>
> ---
> include/libcamera/camera.h | 2 +
> include/libcamera/meson.build | 1 +
> include/libcamera/orientation.h | 28 ++++++++++++
> src/libcamera/camera.cpp | 18 +++++++-
> src/libcamera/meson.build | 1 +
> src/libcamera/orientation.cpp | 78 +++++++++++++++++++++++++++++++++
> 6 files changed, 127 insertions(+), 1 deletion(-)
> create mode 100644 include/libcamera/orientation.h
> create mode 100644 src/libcamera/orientation.cpp
>
> diff --git a/include/libcamera/camera.h b/include/libcamera/camera.h
> index 004bc89455f5..6e9342773962 100644
> --- a/include/libcamera/camera.h
> +++ b/include/libcamera/camera.h
> @@ -19,6 +19,7 @@
> #include <libcamera/base/signal.h>
>
> #include <libcamera/controls.h>
> +#include <libcamera/orientation.h>
> #include <libcamera/request.h>
> #include <libcamera/stream.h>
> #include <libcamera/transform.h>
> @@ -67,6 +68,7 @@ public:
> std::size_t size() const;
>
> Transform transform;
> + Orientation orientation;
>
> protected:
> CameraConfiguration();
> diff --git a/include/libcamera/meson.build b/include/libcamera/meson.build
> index 408b7acf152c..a24c50d66a82 100644
> --- a/include/libcamera/meson.build
> +++ b/include/libcamera/meson.build
> @@ -12,6 +12,7 @@ libcamera_public_headers = files([
> 'framebuffer_allocator.h',
> 'geometry.h',
> 'logging.h',
> + 'orientation.h',
> 'pixel_format.h',
> 'request.h',
> 'stream.h',
> diff --git a/include/libcamera/orientation.h b/include/libcamera/orientation.h
> new file mode 100644
> index 000000000000..63ac4aba07ce
> --- /dev/null
> +++ b/include/libcamera/orientation.h
> @@ -0,0 +1,28 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2023, Ideas On Board Oy
> + *
> + * orientation.h - Image orientation
> + */
> +
> +#pragma once
> +
> +#include <iostream>
> +
> +namespace libcamera {
> +
> +enum class Orientation {
> + /* EXIF tag 274 starts from '1' */
> + rotate0 = 1,
Enumerators should start with an uppercase letter.
> + rotate0Flip,
> + rotate180,
> + rotate180Flip,
> + rotate90Flip,
> + rotate270,
I think this should be rotate90.
> + rotate270Flip,
> + rotate90,
And here, rotate270.
> +};
> +
> +std::ostream &operator<<(std::ostream &out, const Orientation &orientation);
> +
> +} /* namespace libcamera */
> diff --git a/src/libcamera/camera.cpp b/src/libcamera/camera.cpp
> index 0eecee766f00..d4ad4a553752 100644
> --- a/src/libcamera/camera.cpp
> +++ b/src/libcamera/camera.cpp
> @@ -160,7 +160,8 @@ LOG_DECLARE_CATEGORY(Camera)
> * \brief Create an empty camera configuration
> */
> CameraConfiguration::CameraConfiguration()
> - : transform(Transform::Identity), config_({})
> + : transform(Transform::Identity), orientation(Orientation::rotate0),
> + config_({})
> {
> }
>
> @@ -404,6 +405,21 @@ CameraConfiguration::Status CameraConfiguration::validateColorSpaces(ColorSpaceF
> * may adjust this field at its discretion if the selection is not supported.
> */
>
> +/**
> + * \var CameraConfiguration::orientation
> + * \brief The desired orientation of the images produced by the camera
> + *
> + * The orientation field is a user-specified 2D plane transformation that
s/field/member/
The word "field" in the C++ specification is used for bit-field only.
"fields" of a class or structure are named "members" (or "data member"
if you want to differentiate them from member functions).
> + * specifies how the application wants the camera images to be rotated in
> + * the memory buffers.
As the whole point of this series is to move from transform to
orientation, can we try to avoid using "transformation" to define the
orientation ? How about the following ?
* The orientation specifies how the application wants images to be oriented in
* memory buffers. The camera will rotate and flip images as appropriate to
* obtain the desired orientation.
> + *
> + * If the application requested orientation cannot be obtained the validate()
s/obtained/obtained,/
> + * function will Adjust this field to the actual orientation of the images
s/this field/the orientation member/
> + * as produced by the camera pipeline.
I recall we discussed that, in this case, the camera shouldn't try to
pick a value it considers the closest to the requested orientation, but
don't transform the image at all. Is that right ? If so, let's document
it explicitly:
* If the orientation requested by the application cannot be obtained, the
* camera will not rotate or flip the images, and the validate() function will
* Adjust this value to the native image orientation produced by the camera.
> + *
> + * By default the orientation field is set to Orientation::rotate0.
s/field/member/
> + */
> +
> /**
> * \var CameraConfiguration::config_
> * \brief The vector of stream configurations
> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
> index b24f82965764..d0e26f6b4141 100644
> --- a/src/libcamera/meson.build
> +++ b/src/libcamera/meson.build
> @@ -34,6 +34,7 @@ libcamera_sources = files([
> 'mapped_framebuffer.cpp',
> 'media_device.cpp',
> 'media_object.cpp',
> + 'orientation.cpp',
> 'pipeline_handler.cpp',
> 'pixel_format.cpp',
> 'process.cpp',
> diff --git a/src/libcamera/orientation.cpp b/src/libcamera/orientation.cpp
> new file mode 100644
> index 000000000000..f2ee14dd4182
> --- /dev/null
> +++ b/src/libcamera/orientation.cpp
> @@ -0,0 +1,78 @@
> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
> +/*
> + * Copyright (C) 2023, Ideas On Board Oy
> + *
> + * orientation.cpp - Image orientation
> + */
> +
> +#include <libcamera/orientation.h>
> +
> +#include <array>
> +#include <string>
> +
> +/**
> + * \file libcamera/orientation.h
> + * \brief Image orientation definition
> + */
> +
> +namespace libcamera {
> +
> +/**
> + * \enum Orientation
> + * \brief The image orientation in a memory buffer
> + *
> + * The Orientation enumeration describes the orientation of the images
> + * produced by the camera pipeline as they get received by the application
> + * inside memory buffers.
> + *
>From here to ...
> + * All the possible 2D plane transformations of an image are expressed as the
> + * combination of two basic operations:
> + *
> + * 'a': rotate the image 90 degrees clockwise
> + * 'b': flip the image horizontally (mirroring)
> + *
> + * plus an identity operator 'e'.
> + *
> + * The composition of operations 'a' and 'b' according to the canonical function
> + * composition notion 'b * a' (where 'a' is applied first, then 'b' is applied
> + * next) gives origin to a symmetric group of order 8, or dihedral group.
> + *
> + * See https://en.wikipedia.org/wiki/Dihedral_group#/media/File:Dih4_cycle_graph.svg
> + * as an example of the 2D plane transformation and how they originate from
> + * the composition of the 'a' and 'b' operations.
> + *
> + * The image orientation expressed using the Orientation enumeration can be
> + * then inferred by applying a multiple of a 90 degrees rotation from the origin
> + * and then applying any horizontal mirroring to a base image assume to be
> + * naturally oriented (no rotation and no mirroring applied).
... here, is this a leftover of a previous implementation, or copied
from somewhere else ? It doesn't seem to match the enumeration.
> + *
> + * The enumeration numerical values follow the ones defined by the EXIF
> + * Specification version 2.32, Tag 274 "Orientation", while the names of the
> + * enumerated values report the rotation and mirroring operations performed.
> + *
> + * In example Orientation::rotate90Flip describes the image transformation
s/In example/For example,/
> + * obtained by rotating 90 degrees clockwise first and then applying an
> + * horizontal mirroring.
> + */
> +
> +/**
> + * \brief Prints human-friendly names for Orientation items
Let's be consistent with the other operator<<() implementations:
* \brief Insert a text representation of an Orientation into an output stream
> + * \param[in] out The output stream
> + * \param[in] orientation The Orientation item
s/ item//
> + * \return The output stream \a out
> + */
> +std::ostream &operator<<(std::ostream &out, const Orientation &orientation)
> +{
> + constexpr std::array<const char *, 9> orientationNames = {
> + "", /* Orientation starts counting from 1. */
> + "rotate0", "rotate0Flip",
> + "rotate180", "rotate180Flip",
> + "rotate90Flip", "rotate270",
> + "rotate270Flip", "rotate90",
> + };
> +
> + out << orientationNames[static_cast<unsigned int>(orientation)];
You can write
/* The Orientation enumeration starts counting from 1. */
out << orientationNames[static_cast<unsigned int>(orientation) - 1];
And drop the first entry from the array.
> + return out;
> +}
> +
> +} /* namespace libcamera */
--
Regards,
Laurent Pinchart
More information about the libcamera-devel
mailing list