[libcamera-devel] [PATCH v6 1/7] libcamera: Add ColorSpace class

Umang Jain umang.jain at ideasonboard.com
Tue Nov 23 15:41:41 CET 2021


Hi,

On 11/23/21 12:50 PM, Umang Jain wrote:
> Hi David,
>
> Thank you for the patch.
>
> On 11/18/21 8:49 PM, David Plowman wrote:
>> This class represents a color space by defining its color primaries,
>> YCbCr encoding, the transfer (gamma) function it uses, and whether the
>> output is full or limited range.
>>
>> Signed-off-by: David Plowman <david.plowman at raspberrypi.com>
>> Reviewed-by: Naushir Patuck <naush at raspberrypi.com>
>> ---
>>   include/libcamera/color_space.h |  79 +++++++++++
>>   include/libcamera/meson.build   |   1 +
>>   src/libcamera/color_space.cpp   | 243 ++++++++++++++++++++++++++++++++
>>   src/libcamera/meson.build       |   1 +
>>   4 files changed, 324 insertions(+)
>>   create mode 100644 include/libcamera/color_space.h
>>   create mode 100644 src/libcamera/color_space.cpp
>>
>> diff --git a/include/libcamera/color_space.h 
>> b/include/libcamera/color_space.h
>> new file mode 100644
>> index 00000000..44ac077a
>> --- /dev/null
>> +++ b/include/libcamera/color_space.h
>> @@ -0,0 +1,79 @@
>> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
>> +/*
>> + * Copyright (C) 2021, Raspberry Pi (Trading) Limited
>> + *
>> + * color_space.h - color space definitions
>> + */
>> +
>> +#ifndef __LIBCAMERA_COLOR_SPACE_H__
>> +#define __LIBCAMERA_COLOR_SPACE_H__
>> +
>> +#include <optional>
>> +#include <string>
>> +
>> +namespace libcamera {
>> +
>> +class ColorSpace
>> +{
>> +public:
>> +    enum class Primaries : int {
>> +        Raw,
>> +        Smpte170m,
>> +        Rec709,
>> +        Rec2020,
>> +    };
>> +
>> +    enum class YcbcrEncoding : int {
>> +        Rec601,
>> +        Rec709,
>> +        Rec2020,
>> +    };
>> +
>> +    enum class TransferFunction : int {
>> +        Linear,
>> +        Srgb,
>> +        Rec709,
>> +    };
>> +
>> +    enum class Range : int {
>> +        Full,
>> +        Limited,
>> +    };
>> +
>> +    constexpr ColorSpace(Primaries p, YcbcrEncoding e, 
>> TransferFunction t, Range r)
>> +        : primaries(p), ycbcrEncoding(e), transferFunction(t), range(r)
>> +    {
>> +    }
>> +
>> +    static const ColorSpace Raw;
>> +    static const ColorSpace Jpeg;
>> +    static const ColorSpace Srgb;
>> +    static const ColorSpace Smpte170m;
>> +    static const ColorSpace Rec709;
>> +    static const ColorSpace Rec2020;
>> +
>> +    Primaries primaries;
>> +    YcbcrEncoding ycbcrEncoding;
>> +    TransferFunction transferFunction;
>> +    Range range;
>> +
>> +    const std::string toString() const;
>> +    static const std::string toString(const 
>> std::optional<ColorSpace> &colorSpace);
>> +};
>> +
>> +constexpr ColorSpace ColorSpace::Raw = { Primaries::Raw, 
>> YcbcrEncoding::Rec601, TransferFunction::Linear, Range::Full };
>> +constexpr ColorSpace ColorSpace::Jpeg = { Primaries::Rec709, 
>> YcbcrEncoding::Rec601, TransferFunction::Srgb, Range::Full };
>> +constexpr ColorSpace ColorSpace::Srgb = { Primaries::Rec709, 
>> YcbcrEncoding::Rec601, TransferFunction::Srgb, Range::Limited };
>> +constexpr ColorSpace ColorSpace::Smpte170m = { Primaries::Smpte170m, 
>> YcbcrEncoding::Rec601, TransferFunction::Rec709, Range::Limited };
>> +constexpr ColorSpace ColorSpace::Rec709 = { Primaries::Rec709, 
>> YcbcrEncoding::Rec709, TransferFunction::Rec709, Range::Limited };
>> +constexpr ColorSpace ColorSpace::Rec2020 = { Primaries::Rec2020, 
>> YcbcrEncoding::Rec2020, TransferFunction::Rec709, Range::Limited };
>> +
>> +bool operator==(const ColorSpace &lhs, const ColorSpace &rhs);
>> +static inline bool operator!=(const ColorSpace &lhs, const 
>> ColorSpace &rhs)
>> +{
>> +    return !(lhs == rhs);
>> +}
>> +
>> +} /* namespace libcamera */
>> +
>> +#endif /* __LIBCAMERA_COLOR_SPACE_H__ */
>> diff --git a/include/libcamera/meson.build 
>> b/include/libcamera/meson.build
>> index 7155ff20..131e1740 100644
>> --- a/include/libcamera/meson.build
>> +++ b/include/libcamera/meson.build
>> @@ -5,6 +5,7 @@ libcamera_include_dir = 'libcamera' / 'libcamera'
>>   libcamera_public_headers = files([
>>       'camera.h',
>>       'camera_manager.h',
>> +    'color_space.h',
>>       'compiler.h',
>>       'controls.h',
>>       'file_descriptor.h',
>> diff --git a/src/libcamera/color_space.cpp 
>> b/src/libcamera/color_space.cpp
>> new file mode 100644
>> index 00000000..1a5fc7a2
>> --- /dev/null
>> +++ b/src/libcamera/color_space.cpp
>> @@ -0,0 +1,243 @@
>> +/* SPDX-License-Identifier: LGPL-2.1-or-later */
>> +/*
>> + * Copyright (C) 2021, Raspberry Pi (Trading) Limited
>> + *
>> + * color_space.cpp - color spaces.
>> + */
>> +
>> +#include <libcamera/color_space.h>
>> +
>> +#include <algorithm>
>> +#include <sstream>
>> +#include <vector>
>> +
>> +/**
>> + * \file color_space.h
>> + * \brief Class and enums to represent color spaces
>> + */
>> +
>> +namespace libcamera {
>> +
>> +/**
>> + * \class ColorSpace
>> + * \brief Class to describe a color space
>> + *
>> + * The ColorSpace class defines the color primaries, the Y'CbCr 
>> encoding,
>> + * the transfer function associated with the color space, and the range
>> + * (sometimes also referred to as the quantisation) of the color space.
>> + *
>> + * Certain combinations of these fields form well-known standard color
>> + * spaces such as "JPEG" or "REC709".
>> + *
>> + * In the strictest sense a "color space" formally only refers to the
>> + * color primaries and white point. Here, however, the ColorSpace class
>> + * adopts the common broader usage that includes the transfer function,
>> + * Y'CbCr encoding method and quantisation.
>> + *
>> + * For more information on the specific color spaces described here, 
>> please
>> + * see:
>> + *
>> + * <a 
>> href="https://www.kernel.org/doc/html/v5.10/userspace-api/media/v4l/colorspaces-details.html#col-srgb">sRGB</a>
>> + * <a 
>> href="https://www.kernel.org/doc/html/v5.10/userspace-api/media/v4l/colorspaces-details.html#col-jpeg">JPEG</a>
>> + * <a 
>> href="https://www.kernel.org/doc/html/v5.10/userspace-api/media/v4l/colorspaces-details.html#col-smpte-170m">SMPTE 
>> 170M</a>
>> + * <a 
>> href="https://www.kernel.org/doc/html/v5.10/userspace-api/media/v4l/colorspaces-details.html#col-rec709">Rec.709</a>
>> + * <a 
>> href="https://www.kernel.org/doc/html/v5.10/userspace-api/media/v4l/colorspaces-details.html#col-bt2020">Rec.2020</a>
>> + */
>> +
>> +/**
>> + * \enum ColorSpace::Primaries
>> + * \brief The color primaries for this color space
>> + *
>> + * \var ColorSpace::Primaries::Raw
>> + * \brief These are raw colors directly from a sensor
>> + * \var ColorSpace::Primaries::Smpte170m
>> + * \brief SMPTE 170M color primaries
>> + * \var ColorSpace::Primaries::Rec709
>> + * \brief Rec.709 color primaries
>> + * \var ColorSpace::Primaries::Rec2020
>> + * \brief Rec.2020 color primaries
>> + */
>> +
>> +/**
>> + * \enum ColorSpace::YcbcrEncoding
>> + * \brief The Y'CbCr encoding
>> + *
>> + * \var ColorSpace::YcbcrEncoding::Rec601
>> + * \brief Rec.601 Y'CbCr encoding
>> + * \var ColorSpace::YcbcrEncoding::Rec709
>> + * \brief Rec.709 Y'CbCr encoding
>> + * \var ColorSpace::YcbcrEncoding::Rec2020
>> + * \brief Rec.2020 Y'CbCr encoding
>> + */
>> +
>> +/**
>> + * \enum ColorSpace::TransferFunction
>> + * \brief The transfer function used for this color space
>> + *
>> + * \var ColorSpace::TransferFunction::Linear
>> + * \brief This color space uses a linear (identity) transfer function
>> + * \var ColorSpace::TransferFunction::Srgb
>> + * \brief sRGB transfer function
>> + * \var ColorSpace::TransferFunction::Rec709
>> + * \brief Rec.709 transfer function
>> + */
>> +
>> +/**
>> + * \enum ColorSpace::Range
>> + * \brief The range (sometimes "quantisation") for this color space
>> + *
>> + * \var ColorSpace::Range::Full
>> + * \brief This color space uses full range pixel values
>> + * \var ColorSpace::Range::Limited
>> + * \brief This color space uses limited range pixel values, being
>> + * 16 to 235 for Y' and 16 to 240 for Cb and Cr (8 bits per sample)
>> + * or 64 to 940 for Y' and 16 to 960 for Cb and Cr (10 bits)
>> + */
>> +
>> +/**
>> + * \fn ColorSpace::ColorSpace(Primaries p, Encoding e, 
>> TransferFunction t, Range r)
>> + * \brief Construct a ColorSpace from explicit values
>> + * \param[in] p The color primaries
>> + * \param[in] e The Y'CbCr encoding
>> + * \param[in] t The transfer function for the color space
>> + * \param[in] r The range of the pixel values in this color space
>> + */
>> +
>> +/**
>> + * \brief Assemble and return a readable string representation of the
>> + * ColorSpace
>> + * \return A string describing the ColorSpace
>> + */
>> +const std::string ColorSpace::toString() const
>> +{
>> +    /* Print out a brief name only for standard color sapces. */
>
>
> s/sapces/spaces
>
>> +
>> +    static const std::vector<std::pair<ColorSpace, const char *>> 
>> colorSpaceNames = {
>> +        { ColorSpace::Raw, "Raw" },
>> +        { ColorSpace::Jpeg, "Jpeg" },
>> +        { ColorSpace::Srgb, "Srgb" },
>> +        { ColorSpace::Smpte170m, "Smpte170m" },
>> +        { ColorSpace::Rec709, "Rec709" },
>> +        { ColorSpace::Rec2020, "Rec2020" },
>> +    };
>
>
> Should we maintain this class-wide in its definition instead?
>
>> +    auto it = std::find_if(colorSpaceNames.begin(), 
>> colorSpaceNames.end(),
>> +                   [this](const auto &item) {
>> +                       return *this == item.first;
>> +                   });
>> +    if (it != colorSpaceNames.end())
>> +        return std::string(it->second);
>> +
>
>
> I am not sure I follow this code-path.
>
> If we cannot find a winner from colorSpaceNames vector, we return a 
> bunch of color-spcae specific information below? Can you please cover 
> this here (via a comment) and in doxygen documentation above of the 
> function?


Ok, this got cleared up in an conversion on IRC. It will print a valid 
ColorSpace which is not a part of constexpr ColorSpaces defined in header.

>
>> +    static const char *primariesNames[] = {
>> +        "Raw",
>> +        "Smpte170m",
>> +        "Rec709",
>> +        "Rec2020",
>> +    };
>> +    static const char *encodingNames[] = {
>> +        "Rec601",
>> +        "Rec709",
>> +        "Rec2020",
>> +    };
>> +    static const char *transferFunctionNames[] = {
>> +        "Linear",
>> +        "Srgb",
>> +        "Rec709",
>> +    };
>> +    static const char *rangeNames[] = {
>> +        "Full",
>> +        "Limited",
>> +    };


This does match the enums so does it make  sense to collate this under a 
single structure - for easier to extension in future

Overall looks good to me

Reviewed-by: Umang Jain <umang.jain at ideasonboard.com>

>> +
>> +    std::stringstream ss;
>> +    ss << std::string(primariesNames[static_cast<int>(primaries)]) 
>> << "/"
>> +       << 
>> std::string(encodingNames[static_cast<int>(ycbcrEncoding)]) << "/"
>> +       << 
>> std::string(transferFunctionNames[static_cast<int>(transferFunction)]) 
>> << "/"
>> +       << std::string(rangeNames[static_cast<int>(range)]);
>> +
>> +    return ss.str();
>> +}
>> +
>> +/**
>> + * \brief Assemble and return a readable string representation of an
>> + * optional ColorSpace
>> + * \return A string describing the optional ColorSpace
>> + */
>> +const std::string ColorSpace::toString(const 
>> std::optional<ColorSpace> &colorSpace)
>> +{
>> +    if (!colorSpace)
>> +        return "Unknown";
>> +
>> +    return colorSpace->toString();
>> +}
>> +
>> +/**
>> + * \var ColorSpace::primaries
>> + * \brief The color primaries
>> + */
>> +
>> +/**
>> + * \var ColorSpace::ycbcrEncoding
>> + * \brief The Y'CbCr encoding
>> + */
>> +
>> +/**
>> + * \var ColorSpace::transferFunction
>> + * \brief The transfer function for this color space
>> + */
>> +
>> +/**
>> + * \var ColorSpace::range
>> + * \brief The pixel range used by this color space
>> + */
>> +
>> +/**
>> + * \var ColorSpace::Undefined
>> + * \brief A constant representing a fully undefined color space
>> + */
>> +
>> +/**
>> + * \var ColorSpace::Raw
>> + * \brief A constant representing a raw color space (from a sensor)
>> + */
>> +
>> +/**
>> + * \var ColorSpace::Jpeg
>> + * \brief A constant representing the JPEG color space used for
>> + * encoding JPEG images (and regarded as being the same as the sRGB
>> + * color space)
>> + */
>> +
>> +/**
>> + * \var ColorSpace::Smpte170m
>> + * \brief A constant representing the SMPTE170M color space
>> + */
>> +
>> +/**
>> + * \var ColorSpace::Rec709
>> + * \brief A constant representing the Rec.709 color space
>> + */
>> +
>> +/**
>> + * \var ColorSpace::Rec2020
>> + * \brief A constant representing the Rec.2020 color space
>> + */
>> +
>> +/**
>> + * \brief Compare color spaces for equality
>> + * \return True if the two color spaces are identical, false otherwise
>> + */
>> +bool operator==(const ColorSpace &lhs, const ColorSpace &rhs)
>> +{
>> +    return lhs.primaries == rhs.primaries &&
>> +           lhs.ycbcrEncoding == rhs.ycbcrEncoding &&
>> +           lhs.transferFunction == rhs.transferFunction &&
>> +           lhs.range == rhs.range;
>> +}
>> +
>> +/**
>> + * \fn bool operator!=(const ColorSpace &lhs, const ColorSpace &rhs)
>> + * \brief Compare color spaces for inequality
>> + * \return True if the two color spaces are not identical, false 
>> otherwise
>> + */
>> +
>> +} /* namespace libcamera */
>> diff --git a/src/libcamera/meson.build b/src/libcamera/meson.build
>> index 6727a777..e7371d20 100644
>> --- a/src/libcamera/meson.build
>> +++ b/src/libcamera/meson.build
>> @@ -8,6 +8,7 @@ libcamera_sources = files([
>>       'camera_manager.cpp',
>>       'camera_sensor.cpp',
>>       'camera_sensor_properties.cpp',
>> +    'color_space.cpp',
>>       'controls.cpp',
>>       'control_serializer.cpp',
>>       'control_validator.cpp',


More information about the libcamera-devel mailing list