1588 lines
50 KiB
C++
1588 lines
50 KiB
C++
// ____ ______ __
|
|
// / __ \ / ____// /
|
|
// / /_/ // / / /
|
|
// / ____// /___ / /___ PixInsight Class Library
|
|
// /_/ \____//_____/ PCL 2.4.23
|
|
// ----------------------------------------------------------------------------
|
|
// pcl/RGBColorSystem.h - Released 2022-03-12T18:59:29Z
|
|
// ----------------------------------------------------------------------------
|
|
// This file is part of the PixInsight Class Library (PCL).
|
|
// PCL is a multiplatform C++ framework for development of PixInsight modules.
|
|
//
|
|
// Copyright (c) 2003-2022 Pleiades Astrophoto S.L. All Rights Reserved.
|
|
//
|
|
// Redistribution and use in both source and binary forms, with or without
|
|
// modification, is permitted provided that the following conditions are met:
|
|
//
|
|
// 1. All redistributions of source code must retain the above copyright
|
|
// notice, this list of conditions and the following disclaimer.
|
|
//
|
|
// 2. All redistributions in binary form must reproduce the above copyright
|
|
// notice, this list of conditions and the following disclaimer in the
|
|
// documentation and/or other materials provided with the distribution.
|
|
//
|
|
// 3. Neither the names "PixInsight" and "Pleiades Astrophoto", nor the names
|
|
// of their contributors, may be used to endorse or promote products derived
|
|
// from this software without specific prior written permission. For written
|
|
// permission, please contact info@pixinsight.com.
|
|
//
|
|
// 4. All products derived from this software, in any form whatsoever, must
|
|
// reproduce the following acknowledgment in the end-user documentation
|
|
// and/or other materials provided with the product:
|
|
//
|
|
// "This product is based on software from the PixInsight project, developed
|
|
// by Pleiades Astrophoto and its contributors (https://pixinsight.com/)."
|
|
//
|
|
// Alternatively, if that is where third-party acknowledgments normally
|
|
// appear, this acknowledgment must be reproduced in the product itself.
|
|
//
|
|
// THIS SOFTWARE IS PROVIDED BY PLEIADES ASTROPHOTO AND ITS CONTRIBUTORS
|
|
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
|
// TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
|
// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL PLEIADES ASTROPHOTO OR ITS
|
|
// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
|
// EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, BUSINESS
|
|
// INTERRUPTION; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; AND LOSS OF USE,
|
|
// DATA OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
// POSSIBILITY OF SUCH DAMAGE.
|
|
// ----------------------------------------------------------------------------
|
|
|
|
#ifndef __PCL_RGBColorSystem_h
|
|
#define __PCL_RGBColorSystem_h
|
|
|
|
/// \file pcl/RGBColorSystem.h
|
|
|
|
#include <pcl/Defs.h>
|
|
|
|
#include <pcl/Math.h>
|
|
#include <pcl/ReferenceCounter.h>
|
|
#include <pcl/Vector.h>
|
|
|
|
#define _1_3 3.333333333333333e-01 // 1/3
|
|
#define _1_6 1.666666666666667e-01 // 1/6
|
|
#define _2_3 6.666666666666667e-01 // 2/3
|
|
#define _16_116 1.379310344827586e-01 // 16/116
|
|
#define CIEEpsilon 8.856451679035631e-03 // 216/24389
|
|
#define CIEKappa 9.032962962962963e+02 // 24389/27
|
|
#define CIEKappa116 7.787037037037037e+00 // CIEKappa/116
|
|
#define sRGBEpsilon 0.04045
|
|
#define sRGBEpsilonInv 0.0031308
|
|
#define sRGBGamma 2.4
|
|
#define sRGBGammaInv 4.166666666666667e-01 //1/sRGBGamma
|
|
|
|
namespace pcl
|
|
{
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
/*!
|
|
* \class RGBColorSystem
|
|
* \brief A colorimetrically defined RGB working color space.
|
|
*
|
|
* %RGBColorSystem is a rigorous and efficient implementation of a RGB working
|
|
* space (RGBWS). This class provides all conversions between the supported
|
|
* color spaces: RGB, CIE XYZ, CIE L*a*b*, CIE L*c*h* and grayscale, plus the
|
|
* HSV and HSI color ordering systems, which are also supported for
|
|
* convenience, although obviously not linked to any particular RGBWS.
|
|
*
|
|
* Color components and channel values are represented as reals by means of
|
|
* \c double floating point variables. Normalization of components and channel
|
|
* values to the standard real range [0,1] is ensured for all supported color
|
|
* spaces and color ordering systems.
|
|
*
|
|
* Chrominance coordinates and luminance coefficients are always considered
|
|
* relative to the D50 reference white, in conformance to the ICC standard.
|
|
*
|
|
* Finally, our implementation maximizes dynamic range usage (coding
|
|
* efficiency) by ensuring that all components and channel values make use of
|
|
* the entire [0,1] normalized real range to the maximum possible extent.
|
|
*
|
|
* \sa ImageColor, AbstractImage, GenericImage, ImageVariant
|
|
*/
|
|
class PCL_CLASS RGBColorSystem
|
|
{
|
|
public:
|
|
|
|
/*!
|
|
* The type used to represent components and channel values for all
|
|
* supported color spaces and color ordering systems.
|
|
*/
|
|
typedef double sample;
|
|
|
|
/*!
|
|
* Constructs a %RGBColorSystem object as a new instance of the default RGB
|
|
* working space. The default RGBWS is sRGB in current versions of the
|
|
* PixInsight platform.
|
|
*
|
|
* This constructor increments the reference counter of the source RGB
|
|
* working space data.
|
|
*/
|
|
RGBColorSystem()
|
|
: m_data( RGBColorSystem::sRGB.m_data )
|
|
{
|
|
if ( m_data != nullptr )
|
|
m_data->Attach();
|
|
else
|
|
m_data = new Data( 2.2F/*gamma*/, true/*issRGB*/, sRGB_x, sRGB_y, sRGB_Y );
|
|
}
|
|
|
|
/*!
|
|
* Constructs a %RGBColorSystem object as a copy of an existing instance.
|
|
*
|
|
* This constructor increments the reference counter of the source RGB
|
|
* working space data.
|
|
*/
|
|
RGBColorSystem( const RGBColorSystem& s )
|
|
: m_data( s.m_data )
|
|
{
|
|
m_data->Attach();
|
|
}
|
|
|
|
/*!
|
|
* Constructs a new %RGBColorSystem instance by its RGB working space
|
|
* parameters.
|
|
*
|
|
* \param gamma Gamma value of the RGB working space.
|
|
*
|
|
* \param issRGB If true, this space uses the sRGB gamma function. If this
|
|
* parameter is false, the space uses a standard raise gamma
|
|
* function.
|
|
*
|
|
* \param x,y Vectors of chromaticity coordinates of the RGB working
|
|
* space, relative to the D50 reference white.
|
|
*
|
|
* \param Y Vector of luminance coefficients of the RGB working space,
|
|
* with respect to the D50 reference white.
|
|
*
|
|
* This constructor creates a new RGB working space data object with a
|
|
* reference count value of one.
|
|
*/
|
|
RGBColorSystem( float gamma, bool issRGB, const FVector& x, const FVector& y, const FVector& Y )
|
|
{
|
|
m_data = new Data( gamma, issRGB, x, y, Y );
|
|
}
|
|
|
|
/*!
|
|
* Constructs a new %RGBColorSystem instance by its RGB working space
|
|
* parameters.
|
|
*
|
|
* \param gamma Gamma value of the RGB working space.
|
|
*
|
|
* \param issRGB If true, this space uses the sRGB gamma function. If this
|
|
* parameter is false, the space uses a standard raise gamma
|
|
* function.
|
|
*
|
|
* \param x,y Arrays of chromaticity coordinates of the RGB working
|
|
* space, relative to the D50 reference white.
|
|
*
|
|
* \param Y Arrays of luminance coefficients of the RGB working space,
|
|
* with respect to the D50 reference white.
|
|
*
|
|
* This constructor creates a new RGB working space data object with a
|
|
* reference count value of one.
|
|
*/
|
|
RGBColorSystem( float gamma, bool issRGB, const float* x, const float* y, const float* Y )
|
|
{
|
|
m_data = new Data( gamma, issRGB, FVector( x, 3 ), FVector( y, 3 ), FVector( Y, 3 ) );
|
|
}
|
|
|
|
/*!
|
|
* Destroys a %RGBColorSystem instance.
|
|
*
|
|
* Decrements the reference count of the RGB working space data object. If
|
|
* the data object becomes \e garbage, i.e. if its reference count becomes
|
|
* zero, it is destroyed and its allocated space is disposed.
|
|
*/
|
|
virtual ~RGBColorSystem()
|
|
{
|
|
if ( m_data != nullptr )
|
|
{
|
|
DetachFromData();
|
|
m_data = nullptr;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this %RGBColorSystem object uniquely references its RGB
|
|
* working space data.
|
|
*/
|
|
bool IsUnique() const
|
|
{
|
|
return m_data->IsUnique();
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this %RGBColorSystem object is an alias of another
|
|
* %RGBColorSystem instance \a s.
|
|
*
|
|
* Two instances of %RGBColorSystem are aliases if both share the same RGB
|
|
* working space data.
|
|
*/
|
|
bool IsAliasOf( const RGBColorSystem& s ) const
|
|
{
|
|
return m_data == s.m_data;
|
|
}
|
|
|
|
/*!
|
|
* Ensures that this %RGBColorSystem object uniquely references its RGB
|
|
* working space data.
|
|
*
|
|
* If necessary, this member function generates a duplicate of the RGB
|
|
* working space data, references it, and then decrements the reference
|
|
* counter of the original data.
|
|
*/
|
|
void EnsureUnique()
|
|
{
|
|
if ( !IsUnique() )
|
|
{
|
|
Data* newData = new Data( *m_data );
|
|
DetachFromData();
|
|
m_data = newData;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Returns the gamma value of this RGB working space.
|
|
*
|
|
* \note If this space uses a sRGB gamma function, the returned value is
|
|
* 2.2, but the space doesn't use that value as the exponent of a standard
|
|
* raise gamma function.
|
|
*/
|
|
float Gamma() const
|
|
{
|
|
return m_data->gamma;
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this space uses a sRGB gamma function.
|
|
*/
|
|
bool IsSRGB() const
|
|
{
|
|
return m_data->issRGB;
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff this space uses a linear gamma function.
|
|
*
|
|
* A linear RGB space has gamma=1 and doesn't use a sRGB gamma function.
|
|
*/
|
|
bool IsLinear() const
|
|
{
|
|
return m_data->isLinear;
|
|
}
|
|
|
|
/*!
|
|
* Returns a reference to a vector with the elements of the immutable 3x3
|
|
* RGB to CIE XYZ conversion matrix used in this RGB working space.
|
|
*
|
|
* The RGB->XYZ conversion matrix is a function of the luminance
|
|
* coefficients and chromaticity coordinates that define this RGB color
|
|
* space.
|
|
*
|
|
* The nine matrix elements are stored contiguously in row order in the
|
|
* returned vector: M[0][0], M[0][1], ..., M[2][2].
|
|
*/
|
|
const Vector& RGBToXYZMatrix() const
|
|
{
|
|
return m_data->M;
|
|
}
|
|
|
|
/*!
|
|
* Returns a reference to a vector with the elements of the immutable 3x3
|
|
* CIE XYZ to RGB inverse conversion matrix used in this RGB working space.
|
|
*
|
|
* The XYZ->RGB inverse conversion matrix is a function of the luminance
|
|
* coefficients and chromaticity coordinates that define this RGB color
|
|
* space.
|
|
*
|
|
* The nine inverse matrix elements are stored contiguously in row order in
|
|
* the returned vector: M_[0][0], M_[0][1], ..., M_[2][2].
|
|
*/
|
|
const Vector& XYZToRGBMatrix() const
|
|
{
|
|
return m_data->M_;
|
|
}
|
|
|
|
/*!
|
|
* Returns a reference to the immutable vector of X chromaticity coordinates
|
|
* in this RGB working space.
|
|
*
|
|
* In PCL, chromaticity coordinates are relative to the D50 reference white.
|
|
*/
|
|
const FVector& ChromaticityXCoordinates() const
|
|
{
|
|
return m_data->x;
|
|
}
|
|
|
|
/*!
|
|
* Returns a reference to the immutable vector of Y chromaticity coordinates
|
|
* in this RGB working space.
|
|
*
|
|
* In PCL, chromaticity coordinates are relative to the D50 reference white.
|
|
*/
|
|
const FVector& ChromaticityYCoordinates() const
|
|
{
|
|
return m_data->y;
|
|
}
|
|
|
|
/*!
|
|
* Returns a reference to the immutable vector of luminance coefficients in
|
|
* this RGB working space.
|
|
*
|
|
* In PCL, luminance coefficients are relative to the D50 reference white.
|
|
*/
|
|
const FVector& LuminanceCoefficients() const
|
|
{
|
|
return m_data->Y;
|
|
}
|
|
|
|
/*!
|
|
* Returns true iff two %RGBColorSystem instances define the same RGB working
|
|
* space. This happens when either both instances are aliases, or if they
|
|
* define exactly the same RGB space parameters.
|
|
*/
|
|
friend bool operator ==( const RGBColorSystem& S1, const RGBColorSystem& S2 )
|
|
{
|
|
return S1.IsAliasOf( S2 ) || *S1.m_data == *S2.m_data;
|
|
}
|
|
|
|
/*!
|
|
* Causes this %RGBColorSystem instance to reference the same RGB working
|
|
* space as another instance.
|
|
*
|
|
* The reference count of the previously referenced space is decremented,
|
|
* and the previous space is deleted if it becomes unreferenced. The
|
|
* reference count of the new space is then incremented.
|
|
*/
|
|
void Assign( const RGBColorSystem& s )
|
|
{
|
|
s.m_data->Attach();
|
|
DetachFromData();
|
|
m_data = s.m_data;
|
|
}
|
|
|
|
/*!
|
|
* Assignment iterator. Returns a reference to this object.
|
|
*
|
|
* This operator calls Assign() with the specified source space \a s.
|
|
*/
|
|
RGBColorSystem& operator =( const RGBColorSystem& s )
|
|
{
|
|
Assign( s );
|
|
return *this;
|
|
}
|
|
|
|
/*!
|
|
* Returns the lightness component in the CIE L*a*b* space corresponding to
|
|
* a set of specified RGB components.
|
|
*
|
|
* \param R,G,B RGB components from which lightness will be calculated.
|
|
*
|
|
* \note A synonym for this function is CIEL().
|
|
*/
|
|
sample Lightness( sample R, sample G, sample B ) const
|
|
{
|
|
XYZLab( R = m_data->CIEY( R, G, B ) );
|
|
return sample( (1.16 * R) - 0.16 );
|
|
}
|
|
|
|
// ### Deprecated - retained for compatibility -> suppress in PCL 2.x
|
|
sample Luminance( sample R, sample G, sample B ) const
|
|
{
|
|
return Lightness( R, G, B );
|
|
}
|
|
|
|
/*!
|
|
* A synonym for Lightness().
|
|
*/
|
|
sample CIEL( sample R, sample G, sample B ) const
|
|
{
|
|
return Lightness( R, G, B );
|
|
}
|
|
|
|
/*!
|
|
* Calculates the lightness component in the CIE L*a*b* space corresponding
|
|
* to a set of RGB components, and copies it to a specified variable \a K.
|
|
*
|
|
* \param[out] K Reference to an output variable for the calculated
|
|
* lightness component.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*/
|
|
void RGBToGray( sample& K, sample R, sample G, sample B ) const
|
|
{
|
|
K = Lightness( R, G, B );
|
|
}
|
|
|
|
/*!
|
|
* Returns the Value channel value in the HSV color ordering system,
|
|
* corresponding to a specified set of RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* \note This is an utility function provided for convenience; HSV is not a
|
|
* color space, but a color ordering system not based on a RGBWS.
|
|
*/
|
|
sample Value( sample R, sample G, sample B ) const
|
|
{
|
|
return pcl::Max( pcl::Max( R, G ), B );
|
|
}
|
|
|
|
/*!
|
|
* Returns the Intensity channel value in the HSI color ordering system,
|
|
* corresponding to a specified set of RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* \note HSI is more often known as HSL; however we reserve the L channel
|
|
* identifier exclusively for the CIE L* component (lightness) in PCL.
|
|
*
|
|
* \note This is an utility function provided for convenience; HSI is not a
|
|
* color space, but a color ordering system not based on a RGBWS.
|
|
*/
|
|
sample Intensity( sample R, sample G, sample B ) const
|
|
{
|
|
return sample( 0.5*( pcl::Min( pcl::Min( R, G ), B )
|
|
+ pcl::Max( pcl::Max( R, G ), B ) ) );
|
|
}
|
|
|
|
/*!
|
|
* Returns the Hue channel value in the HSV and HSI color ordering systems,
|
|
* corresponding to a specified set of RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* The returned value is a <em>normalized hue</em>, which is the hue angle
|
|
* rescaled to the normalized [0,1[ range. A normalized hue value of 1
|
|
* corresponds to a hue angle of 2*pi radians, or 360 degrees.
|
|
*
|
|
* \note This is an utility function, provided for convenience. HSV and HSI
|
|
* are not color spaces, but color ordering systems not based on any RGBWS.
|
|
*/
|
|
sample Hue( sample R, sample G, sample B ) const
|
|
{
|
|
sample max = pcl::Max( pcl::Max( R, G ), B );
|
|
sample delta = max - pcl::Min( pcl::Min( R, G ), B );
|
|
if ( delta != 0 )
|
|
{
|
|
sample H;
|
|
if ( R == max )
|
|
H = (G - B)/delta; // between yellow & magenta
|
|
else if ( G == max )
|
|
H = 2 + (B - R)/delta; // between cyan & yellow
|
|
else
|
|
H = 4 + (R - G)/delta; // between magenta & cyan
|
|
|
|
H /= 6;
|
|
if ( H < 0 )
|
|
H += 1;
|
|
return H;
|
|
}
|
|
|
|
// Achromatic case: R = G = B
|
|
// Hue is undefined (H is set to 0 conventionally)
|
|
return 0;
|
|
}
|
|
|
|
/*!
|
|
* Returns the Saturation channel value in the HSV color ordering system,
|
|
* corresponding to a specified set of RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* \note This is an utility function provided for convenience; HSV is not a
|
|
* color space, but a color ordering system not based on a RGBWS.
|
|
*/
|
|
sample HSVSaturation( sample R, sample G, sample B ) const
|
|
{
|
|
sample max = pcl::Max( pcl::Max( R, G ), B );
|
|
sample delta = max - pcl::Min( pcl::Min( R, G ), B );
|
|
return sample( (1.0 + max != 1.0) ? delta/max : 0.0 );
|
|
}
|
|
|
|
/*!
|
|
* Returns the Saturation channel value in the HSI color ordering system,
|
|
* corresponding to a specified set of RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* \note HSI is more often known as HSL; however we reserve the L channel
|
|
* identifier exclusively for the CIE L* component (lightness) in PCL.
|
|
*
|
|
* \note This is an utility function provided for convenience; HSI is not a
|
|
* color space, but a color ordering system not based on a RGBWS.
|
|
*/
|
|
sample HSISaturation( sample R, sample G, sample B ) const
|
|
{
|
|
sample min = pcl::Min( pcl::Min( R, G ), B );
|
|
sample max = pcl::Max( pcl::Max( R, G ), B );
|
|
sample delta = max - min;
|
|
if ( delta != 0 )
|
|
{
|
|
sample sum = min + max;
|
|
return delta/((sum <= 1) ? sum : 2-sum);
|
|
}
|
|
return sample( 0 );
|
|
}
|
|
|
|
/*!
|
|
* Returns the Saturation channel value in the HSV color ordering system,
|
|
* corresponding to a specified set of RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* This function is a synonym for HSVSaturation().
|
|
*/
|
|
sample Saturation( sample R, sample G, sample B ) const
|
|
{
|
|
return HSVSaturation( R, G, B );
|
|
}
|
|
|
|
/*!
|
|
* Converts a set of RGB components to the corresponding channel values in
|
|
* the HSV (Hue, Saturation, Value) color ordering system.
|
|
*
|
|
* \param[out] H,S,V References to the variables where output HSV channel
|
|
* values will be copied.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* The output \a H value is a <em>normalized hue</em>, which is the hue
|
|
* angle rescaled to the normalized [0,1] range. A normalized hue value of
|
|
* one corresponds to a hue angle of 2*pi radians, or 360 degrees.
|
|
*
|
|
* \note This is a static function provided for convenience; HSV is not a
|
|
* color space, but a color ordering system not based on a RGBWS.
|
|
*/
|
|
static void RGBToHSV( sample& H, sample& S, sample& V, sample R, sample G, sample B )
|
|
{
|
|
V = pcl::Max( pcl::Max( R, G ), B ); // V = Value( R, G, B );
|
|
|
|
sample delta = V - pcl::Min( pcl::Min( R, G ), B );
|
|
if ( delta != 0 )
|
|
{
|
|
S = delta/V;
|
|
|
|
if ( R == V )
|
|
H = (G - B)/delta; // between yellow & magenta
|
|
else if ( G == V )
|
|
H = 2 + (B - R)/delta; // between cyan & yellow
|
|
else
|
|
H = 4 + (R - G)/delta; // between magenta & cyan
|
|
|
|
H /= 6;
|
|
if ( H < 0 )
|
|
H += 1;
|
|
}
|
|
else
|
|
{
|
|
// Achromatic case: R = G = B
|
|
// S = 0, and H is undefined (H is set to 0 conventionally)
|
|
S = H = 0;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Converts a set of RGB components to the corresponding channel values in
|
|
* the HSI (Hue, Saturation, Intensity) color ordering system.
|
|
*
|
|
* \param[out] H,S,I References to the variables where output HSI channel
|
|
* values will be copied.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* The output \a H value is a <em>normalized hue</em>, which is the hue
|
|
* angle rescaled to the normalized [0,1] range. A normalized hue value of
|
|
* one corresponds to a hue angle of 2*pi radians, or 360 degrees.
|
|
*
|
|
* \note HSI is more often known as HSL; however we reserve the L channel
|
|
* identifier exclusively for the CIE L* component (lightness) in PCL.
|
|
*
|
|
* \note This is a static function provided for convenience; HSV is not a
|
|
* color space, but a color ordering system not based on a RGBWS.
|
|
*/
|
|
static void RGBToHSI( sample& H, sample& S, sample& I, sample R, sample G, sample B )
|
|
{
|
|
sample min = pcl::Min( pcl::Min( R, G ), B );
|
|
sample max = pcl::Max( pcl::Max( R, G ), B );
|
|
sample delta = max - min;
|
|
sample sum = min + max;
|
|
|
|
I = 0.5*sum;
|
|
|
|
if ( delta != 0 )
|
|
{
|
|
S = delta/((sum <= 1) ? sum : 2-sum);
|
|
|
|
if ( R == max )
|
|
H = (G - B)/delta; // between yellow & magenta
|
|
else if ( G == max )
|
|
H = 2 + (B - R)/delta; // between cyan & yellow
|
|
else
|
|
H = 4 + (R - G)/delta; // between magenta & cyan
|
|
|
|
H /= 6;
|
|
if ( H < 0 )
|
|
H += 1;
|
|
}
|
|
else
|
|
{
|
|
// Achromatic case: R = G = B
|
|
// S = 0, and H is undefined (H is set to 0 conventionally)
|
|
S = H = 0;
|
|
}
|
|
}
|
|
|
|
/*!
|
|
* Converts a set of RGB components to the corresponding channel values in
|
|
* the HSV (Hue, Saturation, Value) color ordering system, plus the
|
|
* L* component (lightness) in the CIE L*a*b* space.
|
|
*
|
|
* \param[out] H,S,V References to the variables where output HSV channel
|
|
* values will be copied.
|
|
*
|
|
* \param[out] L Reference to a variable where the output CIE L*
|
|
* component will be copied.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* The output \a H value is a <em>normalized hue</em>, which is the hue
|
|
* angle rescaled to the normalized [0,1] range. A normalized hue value of
|
|
* one corresponds to a hue angle of 2*pi radians, or 360 degrees.
|
|
*/
|
|
void RGBToHSVL( sample& H, sample& S, sample& V, sample& L, sample R, sample G, sample B ) const
|
|
{
|
|
RGBToHSV( H, S, V, R, G, B );
|
|
L = Lightness( R, G, B );
|
|
}
|
|
|
|
/*!
|
|
* Converts a set of RGB components to the corresponding channel values in
|
|
* the HSI (Hue, Saturation, Intensity) color ordering system, plus the
|
|
* L* component (lightness) in the CIE L*a*b* space.
|
|
*
|
|
* \param[out] H,S,I References to the variables where output HSI channel
|
|
* values will be copied.
|
|
*
|
|
* \param[out] L Reference to a variable where the output CIE L*
|
|
* component will be copied.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* The output \a H value is a <em>normalized hue</em>, which is the hue
|
|
* angle rescaled to the normalized [0,1] range. A normalized hue value of
|
|
* one corresponds to a hue angle of 2*pi radians, or 360 degrees.
|
|
*
|
|
* \note HSI is more often known as HSL; however we reserve the L channel
|
|
* identifier exclusively for the CIE L* component (lightness) in PCL.
|
|
*/
|
|
void RGBToHSIL( sample& H, sample& S, sample& I, sample& L, sample R, sample G, sample B ) const
|
|
{
|
|
RGBToHSI( H, S, I, R, G, B );
|
|
L = Lightness( R, G, B );
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the RGB color space to the CIE XYZ color space.
|
|
*
|
|
* \param[out] X,Y,Z References to the variables where output CIE XYZ
|
|
* components will be copied.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*/
|
|
void RGBToCIEXYZ( sample& X, sample& Y, sample& Z, sample R, sample G, sample B ) const
|
|
{
|
|
m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
|
|
}
|
|
|
|
/*!
|
|
* Calculates the chrominance components in the CIE XYZ color space
|
|
* corresponding to a specified set of RGB components.
|
|
*
|
|
* \param[out] X,Z References to the variables where output CIE X and Z
|
|
* components will be copied.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* This function avoids the calculation of the CIE Y component, which saves
|
|
* computing time when only the chrominance components are required.
|
|
*/
|
|
void RGBToCIEXZ( sample& X, sample& Z, sample R, sample G, sample B ) const
|
|
{
|
|
m_data->RGBToCIEXZ( X, Z, R, G, B );
|
|
}
|
|
|
|
/*!
|
|
* CIE X component from RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*/
|
|
sample CIEX( sample R, sample G, sample B ) const
|
|
{
|
|
return m_data->CIEX( R, G, B );
|
|
}
|
|
|
|
/*!
|
|
* CIE Y component from RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*/
|
|
sample CIEY( sample R, sample G, sample B ) const
|
|
{
|
|
return m_data->CIEY( R, G, B );
|
|
}
|
|
|
|
/*!
|
|
* CIE Z component from RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*/
|
|
sample CIEZ( sample R, sample G, sample B ) const
|
|
{
|
|
return m_data->CIEZ( R, G, B );
|
|
}
|
|
|
|
/*!
|
|
* CIE L* component from CIE Y.
|
|
*
|
|
* \param Y Source CIE Y component.
|
|
*/
|
|
sample CIEYToCIEL( sample Y ) const
|
|
{
|
|
XYZLab( Y ); return 1.16*Y - 0.16;
|
|
}
|
|
|
|
/*!
|
|
* CIE Y component from CIE L*.
|
|
*
|
|
* \param L Source CIE L* component.
|
|
*/
|
|
sample CIELToCIEY( sample L ) const
|
|
{
|
|
LabXYZ( L = (L + 0.16)/1.16 ); return L;
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the RGB color space to the CIE L*a*b* color space.
|
|
*
|
|
* \param[out] L,a,b References to the variables where output CIE L*a*b*
|
|
* components will be copied.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*/
|
|
void RGBToCIELab( sample& L, sample& a, sample& b, sample R, sample G, sample B ) const
|
|
{
|
|
sample X, Y, Z;
|
|
m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
|
|
CIEXYZToCIELab( L, a, b, X, Y, Z );
|
|
}
|
|
|
|
/*!
|
|
* Calculates the chrominance components in the CIE L*a*b* color space
|
|
* corresponding to a specified set of RGB components.
|
|
*
|
|
* \param[out] a,b References to the variables where output CIE a* and b*
|
|
* components will be copied.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* This function avoids the calculation of the CIE L* component, which saves
|
|
* computing time when only the chrominance components are required.
|
|
*/
|
|
void RGBToCIEab( sample& a, sample& b, sample R, sample G, sample B ) const
|
|
{
|
|
sample X, Y, Z;
|
|
m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
|
|
XYZLab( X ); XYZLab( Y ); XYZLab( Z );
|
|
a = (5*(X - Y) + m_data->abOffset)/m_data->abDelta;
|
|
b = (2*(Y - Z) + m_data->abOffset)/m_data->abDelta;
|
|
}
|
|
|
|
/*!
|
|
* Returns the a* chrominance component in the CIE L*a*b* color space,
|
|
* corresponding to a specified set of RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* This function avoids calculation of the L* and b* components, which
|
|
* saves computing time when only the a* component is required.
|
|
*/
|
|
sample CIEa( sample R, sample G, sample B ) const
|
|
{
|
|
sample X, Y;
|
|
m_data->RGBToCIEXY( X, Y, R, G, B );
|
|
XYZLab( X ); XYZLab( Y );
|
|
return (5*(X - Y) + m_data->abOffset)/m_data->abDelta;
|
|
}
|
|
|
|
/*!
|
|
* Returns the b* chrominance component in the CIE L*a*b* color space,
|
|
* corresponding to a specified set of RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* This function avoids the calculation of the L* and a* channels, which
|
|
* saves computing time when only the b* chrominance component is required.
|
|
*/
|
|
sample CIEb( sample R, sample G, sample B ) const
|
|
{
|
|
sample Y, Z;
|
|
m_data->RGBToCIEYZ( Y, Z, R, G, B );
|
|
XYZLab( Y ); XYZLab( Z );
|
|
return (2*(Y - Z) + m_data->abOffset)/m_data->abDelta;
|
|
}
|
|
|
|
/*!
|
|
* Returns the c* chrominance component in the CIE L*c*h* color space,
|
|
* corresponding to a specified set of RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* This function avoids the calculation of the L* and h* channels, which
|
|
* saves computing time when only the c* chrominance component is required.
|
|
*/
|
|
sample CIEc( sample R, sample G, sample B ) const
|
|
{
|
|
sample X, Y, Z;
|
|
m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
|
|
XYZLab( X ); XYZLab( Y ); XYZLab( Z );
|
|
sample a = 5*(X - Y);
|
|
sample b = 2*(Y - Z);
|
|
return pcl::Sqrt( a*a + b*b )/m_data->cDelta;
|
|
}
|
|
|
|
/*!
|
|
* Returns the normalized h* chrominance component in the CIE L*c*h* color
|
|
* space, corresponding to a specified set of RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* This function avoids the calculation of the L* and c* channels, which
|
|
* saves computing time when only the h* chrominance component is required.
|
|
*
|
|
* The returned value is the hue angle normalized to the range [0,1[, where
|
|
* 0 corresponds to a hue angle of zero degrees, and 1 to an angle of 360
|
|
* degrees (2*pi radians).
|
|
*/
|
|
sample CIEh( sample R, sample G, sample B ) const
|
|
{
|
|
return CIEhr( R, G, B )/Const<sample>::_2pi();
|
|
}
|
|
|
|
/*!
|
|
* Returns the h* chrominance component in the CIE L*c*h* color space,
|
|
* expressed in radians, corresponding to a specified set of RGB components.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* This function avoids the calculation of the L* and c* channels, which
|
|
* saves computing time when only the h* chrominance component is required.
|
|
*
|
|
* The returned value is the hue angle in radians, in the range [0,2pi[.
|
|
*/
|
|
sample CIEhr( sample R, sample G, sample B ) const
|
|
{
|
|
sample X, Y, Z;
|
|
m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
|
|
XYZLab( X ); XYZLab( Y ); XYZLab( Z );
|
|
sample h = ArcTan( 2*(Y - Z), 5*(X - Y) );
|
|
if ( h < 0 )
|
|
h += Const<sample>::_2pi();
|
|
return h;
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the RGB color space to the CIE L*c*h* color space.
|
|
*
|
|
* \param[out] L,c,h References to the variables where output CIE L*c*h*
|
|
* components will be copied.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*/
|
|
void RGBToCIELch( sample& L, sample& c, sample& h, sample R, sample G, sample B ) const
|
|
{
|
|
sample X, Y, Z;
|
|
m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
|
|
XYZLab( X ); XYZLab( Y ); XYZLab( Z );
|
|
L = sample( (1.16 * Y) - 0.16 );
|
|
sample a = 5*(X - Y);
|
|
sample b = 2*(Y - Z);
|
|
c = pcl::Sqrt( a*a + b*b )/m_data->cDelta;
|
|
h = ArcTan( b, a );
|
|
if ( h < 0 )
|
|
h += Const<sample>::_2pi();
|
|
h /= Const<sample>::_2pi();
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the RGB color space to the CIE L*a*b* color space, with
|
|
* optimized, on-the-fly calculation of the CIE c* component.
|
|
*
|
|
* \param[out] L,a,b References to the variables where output CIE L*a*b*
|
|
* components will be copied.
|
|
*
|
|
* \param[out] c Reference to a variable where the output CIE c*
|
|
* component will be copied.
|
|
*
|
|
* \param R,G,B Input RGB components.
|
|
*
|
|
* If only the CIE c* component is required besides CIE L*a*b* components,
|
|
* this function is much faster than performing two separate conversions to
|
|
* the CIE L*a*b* and L*c*h* color spaces.
|
|
*/
|
|
void RGBToCIELabc( sample& L, sample& a, sample& b, sample& c, sample R, sample G, sample B ) const
|
|
{
|
|
sample X, Y, Z;
|
|
m_data->RGBToCIEXYZ( X, Y, Z, R, G, B );
|
|
XYZLab( X ); XYZLab( Y ); XYZLab( Z );
|
|
L = sample( (1.16 * Y) - 0.16 );
|
|
a = ((X = 5*(X - Y)) + m_data->abOffset)/m_data->abDelta;
|
|
b = ((Z = 2*(Y - Z)) + m_data->abOffset)/m_data->abDelta;
|
|
c = pcl::Sqrt( X*X + Z*Z )/m_data->cDelta;
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the HSV color ordering system to the RGB color space.
|
|
*
|
|
* \param[out] R,G,B References to the variables where output RGB
|
|
* components will be copied.
|
|
*
|
|
* \param H,S,V Input HSV channel values.
|
|
*
|
|
* The input \a H value must be a <em>normalized hue</em>, which is the hue
|
|
* angle rescaled to the normalized [0,1] range. A normalized hue value of
|
|
* one corresponds to a hue angle of 2*pi radians, or 360 degrees.
|
|
*
|
|
* \note This is a static function provided for convenience; HSV is not a
|
|
* color space, but a color ordering system not based on a RGBWS.
|
|
*/
|
|
static void HSVToRGB( sample& R, sample& G, sample& B, sample H, sample S, sample V )
|
|
{
|
|
if ( S != 0 )
|
|
{
|
|
H *= 6; // degrees -> quadrant index
|
|
|
|
int i = TruncInt( Floor( H ) ); // i = sector 0 to 5
|
|
sample f = H - i; // f = fractional part of H
|
|
sample p = V*(1 - S);
|
|
sample q = V*(1 - S*f);
|
|
sample t = V*(1 - S*(1 - f));
|
|
|
|
switch( i )
|
|
{
|
|
case 0: R = V; G = t; B = p; break;
|
|
case 1: R = q; G = V; B = p; break;
|
|
case 2: R = p; G = V; B = t; break;
|
|
case 3: R = p; G = q; B = V; break;
|
|
case 4: R = t; G = p; B = V; break;
|
|
case 5: R = V; G = p; B = q; break;
|
|
default: R = G = B = V; break; // out-of-range H argument
|
|
}
|
|
}
|
|
else
|
|
R = G = B = V; // achromatic
|
|
}
|
|
|
|
/*!
|
|
* Transformation from separate HSV chrominance and CIE L* components to the
|
|
* RGB color space.
|
|
*
|
|
* \param[out] R,G,B References to the variables where output RGB
|
|
* components will be copied.
|
|
*
|
|
* \param H,S,V Input HSV channel values for chrominance.
|
|
*
|
|
* \param L Input CIE L* (lightness) component.
|
|
*
|
|
* The lightness implicitly defined by the input HSV values is discarded
|
|
* and replaced with the specified CIE L* component.
|
|
*
|
|
* Strictly speaking, the resulting chrominance is not colorimetrically
|
|
* defined, since it derives from HSV channel values. However, the
|
|
* chrominance is supposed to be expressed in the RGB working space
|
|
* referenced by this %RGBColorSystem instance.
|
|
*
|
|
* The input \a H value must be a <em>normalized hue</em>, which is the hue
|
|
* angle rescaled to the normalized [0,1] range. A normalized hue value of
|
|
* one corresponds to a hue angle of 2*pi radians, or 360 degrees.
|
|
*
|
|
* The primary usefulness of this function is implementing accurate
|
|
* hue/saturation image transformations in the HSV system with full
|
|
* preservation of the CIE lightness component.
|
|
*/
|
|
void HSVLToRGB( sample& R, sample& G, sample& B, sample H, sample S, sample V, sample L ) const
|
|
{
|
|
HSVToRGB( R, G, B, H, S, V );
|
|
#define a H
|
|
#define b S
|
|
RGBToCIEab( a, b, R, G, B );
|
|
CIELabToRGB( R, G, B, L, a, b );
|
|
#undef a
|
|
#undef b
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the HSI color ordering system to the RGB color space.
|
|
*
|
|
* \param[out] R,G,B References to the variables where output RGB
|
|
* components will be copied.
|
|
*
|
|
* \param H,S,I Input HSI channel values.
|
|
*
|
|
* The input \a H value must be a <em>normalized hue</em>, which is the hue
|
|
* angle rescaled to the normalized [0,1] range. A normalized hue value of
|
|
* one corresponds to a hue angle of 2*pi radians, or 360 degrees.
|
|
*
|
|
* \note HSI is more often known as HSL; however we reserve the L channel
|
|
* identifier exclusively for the CIE L* component (lightness) in PCL.
|
|
*
|
|
* \note This is a static function provided for convenience; HSI is not a
|
|
* color space, but a color ordering system not based on a RGBWS.
|
|
*/
|
|
static void HSIToRGB( sample& R, sample& G, sample& B, sample H, sample S, sample I )
|
|
{
|
|
if ( S != 0 )
|
|
{
|
|
sample v2 = (I < 0.5) ? I*(1 + S) : I + S - S*I;
|
|
sample v1 = I+I - v2;
|
|
R = HSIH2RGB( v1, v2, H+_1_3 );
|
|
G = HSIH2RGB( v1, v2, H );
|
|
B = HSIH2RGB( v1, v2, H-_1_3 );
|
|
}
|
|
else
|
|
R = G = B = I; // achromatic
|
|
}
|
|
|
|
/*!
|
|
* Transformation from separate HSI chrominance and CIE L* components to the
|
|
* RGB color space.
|
|
*
|
|
* \param[out] R,G,B References to the variables where output RGB
|
|
* components will be copied.
|
|
*
|
|
* \param H,S,I Input HSI channel values for chrominance.
|
|
*
|
|
* \param L Input CIE L* component (lightness).
|
|
*
|
|
* The lightness implicitly defined by the input HSI values is discarded
|
|
* and replaced with the specified CIE L* component.
|
|
*
|
|
* Strictly speaking, the resulting chrominance is not colorimetrically
|
|
* defined, since it derives from HSI channel values. However, the
|
|
* chrominance is supposed to be expressed in the RGB working space
|
|
* referenced by this %RGBColorSystem instance.
|
|
*
|
|
* The input \a H value must be a <em>normalized hue</em>, which is the hue
|
|
* angle rescaled to the normalized [0,1] range. A normalized hue value of
|
|
* one corresponds to a hue angle of 2*pi radians, or 360 degrees.
|
|
*
|
|
* The primary usefulness of this function is implementing accurate
|
|
* hue/saturation image transformations in the HSI system with full
|
|
* preservation of the CIE lightness component.
|
|
*
|
|
* \note HSI is more often known as HSL; however we reserve the L channel
|
|
* identifier exclusively for the CIE L* component (lightness) in PCL.
|
|
*/
|
|
void HSILToRGB( sample& R, sample& G, sample& B, sample H, sample S, sample I, sample L ) const
|
|
{
|
|
HSIToRGB( R, G, B, H, S, I );
|
|
#define a H
|
|
#define b S
|
|
RGBToCIEab( a, b, R, G, B );
|
|
CIELabToRGB( R, G, B, L, a, b );
|
|
#undef a
|
|
#undef b
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the CIE XYZ color space to the RGB color space.
|
|
*
|
|
* \param[out] R,G,B References to the variables where output RGB
|
|
* components will be copied.
|
|
*
|
|
* \param X,Y,Z Input CIE XYZ components.
|
|
*/
|
|
void CIEXYZToRGB( sample& R, sample& G, sample& B, sample X, sample Y, sample Z ) const
|
|
{
|
|
m_data->CIEXYZToRGB( R, G, B, X, Y, Z );
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the CIE XYZ color space to the CIE L*a*b* color space.
|
|
*
|
|
* \param[out] L,a,b References to the variables where output CIE L*a*b*
|
|
* components will be copied.
|
|
*
|
|
* \param X,Y,Z Input CIE XYZ components.
|
|
*/
|
|
void CIEXYZToCIELab( sample& L, sample& a, sample& b, sample X, sample Y, sample Z ) const
|
|
{
|
|
XYZLab( X ); XYZLab( Y ); XYZLab( Z );
|
|
L = sample( (1.16 * Y) - 0.16 );
|
|
a = (5*(X - Y) + m_data->abOffset)/m_data->abDelta;
|
|
b = (2*(Y - Z) + m_data->abOffset)/m_data->abDelta;
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the CIE L*a*b* color space to the RGB color space.
|
|
*
|
|
* \param[out] R,G,B References to the variables where output RGB
|
|
* components will be copied.
|
|
*
|
|
* \param L,a,b Input CIE L*a*b* components.
|
|
*/
|
|
void CIELabToRGB( sample& R, sample& G, sample& B, sample L, sample a, sample b ) const
|
|
{
|
|
sample X, Y, Z;
|
|
CIELabToCIEXYZ( X, Y, Z, L, a, b );
|
|
m_data->CIEXYZToRGB( R, G, B, X, Y, Z );
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the CIE L*a*b* color space to the CIE XYZ color space.
|
|
*
|
|
* \param[out] X,Y,Z References to the variables where output CIE XYZ
|
|
* components will be copied.
|
|
*
|
|
* \param L,a,b Input CIE L*a*b* components.
|
|
*/
|
|
void CIELabToCIEXYZ( sample& X, sample& Y, sample& Z, sample L, sample a, sample b ) const
|
|
{
|
|
Y = sample( (L + 0.16)/1.16 );
|
|
X = (m_data->abDelta*a - m_data->abOffset)/5 + Y;
|
|
Z = Y - (m_data->abDelta*b - m_data->abOffset)/2;
|
|
LabXYZ( X ); LabXYZ( Y ); LabXYZ( Z );
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the CIE L*a*b* color space to the CIE L*c*h* color space.
|
|
*
|
|
* \param[out] L,c,h References to the variables where output CIE L*c*h*
|
|
* components will be copied.
|
|
*
|
|
* \param L0,a,b Input CIE L*a*b* components.
|
|
*
|
|
* \note The output L component is always identical to the input L0
|
|
* component; the L parameter of this function has been included for the
|
|
* sake of coherence in function signatures.
|
|
*/
|
|
void CIELabToCIELch( sample& L, sample& c, sample& h, sample L0, sample a, sample b ) const
|
|
{
|
|
L = L0;
|
|
a = m_data->abDelta*a - m_data->abOffset;
|
|
b = m_data->abDelta*b - m_data->abOffset;
|
|
c = Sqrt( a*a + b*b )/m_data->cDelta;
|
|
h = ArcTan( b, a )/Const<sample>::pi();
|
|
if ( h < 0 )
|
|
h += 1;
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the CIE L*c*h* color space to the RGB color space.
|
|
*
|
|
* \param[out] R,G,B References to the variables where output RGB
|
|
* components will be copied.
|
|
*
|
|
* \param L,c,h Input CIE L*c*h* components.
|
|
*/
|
|
void CIELchToRGB( sample& R, sample& G, sample& B, sample L, sample c, sample h ) const
|
|
{
|
|
sample a, b;
|
|
SinCos( h*Const<sample>::_2pi(), b, a );
|
|
c *= m_data->cDelta;
|
|
a *= c;
|
|
b *= c;
|
|
sample Y = sample( (L + 0.16)/1.16 );
|
|
sample X = a/5 + Y;
|
|
sample Z = Y - b/2;
|
|
LabXYZ( X ); LabXYZ( Y ); LabXYZ( Z );
|
|
m_data->CIEXYZToRGB( R, G, B, X, Y, Z );
|
|
}
|
|
|
|
/*!
|
|
* Conversion from the CIE L*c*h* color space to the CIE L*a*b* color space.
|
|
*
|
|
* \param[out] L,a,b References to the variables where output CIE L*a*b*
|
|
* components will be copied.
|
|
*
|
|
* \param L0,c,h Input CIE L*c*h* components.
|
|
*
|
|
* \note The output L component is always identical to the input L0
|
|
* component; the L parameter of this function has been included for the
|
|
* sake of coherence in function signatures.
|
|
*/
|
|
void CIELchToCIELab( sample& L, sample& a, sample& b, sample L0, sample c, sample h ) const
|
|
{
|
|
L = L0;
|
|
SinCos( h*Const<sample>::_2pi(), b, a );
|
|
c *= m_data->cDelta;
|
|
a = (c*a + m_data->abOffset)/m_data->abDelta;
|
|
b = (c*b + m_data->abOffset)/m_data->abDelta;
|
|
}
|
|
|
|
protected:
|
|
|
|
struct Data : public ReferenceCounter
|
|
{
|
|
float gamma, gammaInv; // gamma, 1/gamma
|
|
bool issRGB; // true if sRGB gamma function is being used
|
|
bool isLinear; // true if gamma=1.0 and is not sRGB, for optimization
|
|
|
|
/*
|
|
* Chromaticity coordinates w.r.t. the D50 reference white
|
|
*/
|
|
FVector x, y;
|
|
|
|
/*
|
|
* Luminance coefficients w.r.t. the D50 reference white
|
|
*/
|
|
FVector Y;
|
|
|
|
/*
|
|
* RGB <-> CIE XYZ transformation matrices
|
|
*/
|
|
Vector M; // RGB -> CIE XYZ
|
|
Vector M_; // CIE XYZ -> RGB
|
|
|
|
/*
|
|
* Normalization coefficients for X and Z coordinates
|
|
*/
|
|
sample mX, mZ;
|
|
|
|
/*
|
|
* Normalization of CIE a*, b* and c* components
|
|
*/
|
|
sample abOffset;
|
|
sample abDelta;
|
|
sample cDelta;
|
|
|
|
Data( float, bool, const FVector&, const FVector&, const FVector& );
|
|
Data( float, bool, const float*, const float*, const float* );
|
|
Data( const Data& ) = default;
|
|
|
|
void Initialize();
|
|
|
|
bool operator ==( const RGBColorSystem::Data& data ) const
|
|
{
|
|
return gamma == data.gamma &&
|
|
issRGB == data.issRGB &&
|
|
Y == data.Y &&
|
|
x == data.x && y == data.y;
|
|
}
|
|
|
|
/*
|
|
* Primary gamma functions
|
|
*/
|
|
|
|
void LinearRGB( sample& x ) const
|
|
{
|
|
x = issRGB ?
|
|
((x > sRGBEpsilon) ?
|
|
Pow( sample( (x + 0.055)/1.055 ), sample( sRGBGamma ) ) : sample( x/12.92 )) :
|
|
Pow( x, sample( gamma ) );
|
|
}
|
|
|
|
void GammaRGB( sample& x ) const
|
|
{
|
|
x = issRGB ?
|
|
((x > sRGBEpsilonInv) ?
|
|
sample( 1.055*Pow( x, sample( sRGBGammaInv ) ) - 0.055 ) : sample( 12.92*x )) :
|
|
Pow( x, sample( gammaInv ) );
|
|
}
|
|
|
|
/*
|
|
* Primary linear transformations
|
|
*/
|
|
|
|
void RGBToCIEXYZ( sample& X, sample& Y, sample& Z, sample R, sample G, sample B ) const
|
|
{
|
|
if ( !isLinear )
|
|
{
|
|
LinearRGB( R );
|
|
LinearRGB( G );
|
|
LinearRGB( B );
|
|
}
|
|
|
|
X = Range( (R*M[0] + G*M[1] + B*M[2])/mX );
|
|
Y = Range( R*M[3] + G*M[4] + B*M[5] );
|
|
Z = Range( (R*M[6] + G*M[7] + B*M[8])/mZ );
|
|
}
|
|
|
|
void CIEXYZToRGB( sample& R, sample& G, sample& B, sample X, sample Y, sample Z ) const
|
|
{
|
|
X *= mX;
|
|
Z *= mZ;
|
|
R = Range( X*M_[0] + Y*M_[1] + Z*M_[2] );
|
|
G = Range( X*M_[3] + Y*M_[4] + Z*M_[5] );
|
|
B = Range( X*M_[6] + Y*M_[7] + Z*M_[8] );
|
|
|
|
if ( !isLinear )
|
|
{
|
|
GammaRGB( R );
|
|
GammaRGB( G );
|
|
GammaRGB( B );
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Utility functions for fast partial luminance/chrominance calculations
|
|
*/
|
|
|
|
sample CIEX( sample R, sample G, sample B ) const
|
|
{
|
|
if ( !isLinear )
|
|
{
|
|
LinearRGB( R );
|
|
LinearRGB( G );
|
|
LinearRGB( B );
|
|
}
|
|
|
|
return Range( (R*M[0] + G*M[1] + B*M[2])/mX );
|
|
}
|
|
|
|
sample CIEY( sample R, sample G, sample B ) const
|
|
{
|
|
if ( !isLinear )
|
|
{
|
|
LinearRGB( R );
|
|
LinearRGB( G );
|
|
LinearRGB( B );
|
|
}
|
|
|
|
return Range( R*M[3] + G*M[4] + B*M[5] );
|
|
}
|
|
|
|
sample CIEZ( sample R, sample G, sample B ) const
|
|
{
|
|
if ( !isLinear )
|
|
{
|
|
LinearRGB( R );
|
|
LinearRGB( G );
|
|
LinearRGB( B );
|
|
}
|
|
|
|
return Range( (R*M[6] + G*M[7] + B*M[8])/mZ );
|
|
}
|
|
|
|
void RGBToCIEXY( sample& X, sample& Y, sample R, sample G, sample B ) const
|
|
{
|
|
if ( !isLinear )
|
|
{
|
|
LinearRGB( R );
|
|
LinearRGB( G );
|
|
LinearRGB( B );
|
|
}
|
|
|
|
X = Range( (R*M[0] + G*M[1] + B*M[2])/mX );
|
|
Y = Range( R*M[3] + G*M[4] + B*M[5] );
|
|
}
|
|
|
|
void RGBToCIEYZ( sample& Y, sample& Z, sample R, sample G, sample B ) const
|
|
{
|
|
if ( !isLinear )
|
|
{
|
|
LinearRGB( R );
|
|
LinearRGB( G );
|
|
LinearRGB( B );
|
|
}
|
|
|
|
Y = Range( R*M[3] + G*M[4] + B*M[5] );
|
|
Z = Range( (R*M[6] + G*M[7] + B*M[8])/mZ );
|
|
}
|
|
|
|
void RGBToCIEXZ( sample& X, sample& Z, sample R, sample G, sample B ) const
|
|
{
|
|
if ( !isLinear )
|
|
{
|
|
LinearRGB( R );
|
|
LinearRGB( G );
|
|
LinearRGB( B );
|
|
}
|
|
|
|
X = Range( (R*M[0] + G*M[1] + B*M[2])/mX );
|
|
Z = Range( (R*M[6] + G*M[7] + B*M[8])/mZ );
|
|
}
|
|
|
|
static bool ValidateParameters( const FVector& x, const FVector& y, const FVector& Y );
|
|
|
|
static sample Range( const sample& x ) // Ensure nominal [0,1] range
|
|
{
|
|
return pcl::Range( x, sample( 0 ), sample( 1 ) );
|
|
}
|
|
};
|
|
|
|
Data* m_data = nullptr;
|
|
|
|
void DetachFromData()
|
|
{
|
|
if ( !m_data->Detach() )
|
|
delete m_data;
|
|
}
|
|
|
|
static void XYZLab( sample& x )
|
|
{
|
|
x = (x > CIEEpsilon) ? Pow( x, sample( _1_3 ) ) : sample( CIEKappa116*x + _16_116 );
|
|
}
|
|
|
|
static void LabXYZ( sample& x )
|
|
{
|
|
sample x3 = x*x*x;
|
|
x = (x3 > CIEEpsilon) ? x3 : sample( (x - _16_116)/CIEKappa116 );
|
|
}
|
|
|
|
static sample HSIH2RGB( sample v1, sample v2, sample H )
|
|
{
|
|
if ( H < 0 )
|
|
H += 1;
|
|
else if ( H > 1 )
|
|
H -= 1;
|
|
|
|
if ( H < _1_6 )
|
|
return v1 + 6*H*(v2 - v1);
|
|
|
|
if ( H < 0.5 )
|
|
return v2;
|
|
|
|
if ( H < _2_3 )
|
|
return v1 + 6*(_2_3 - H)*(v2 - v1);
|
|
|
|
return v1;
|
|
}
|
|
|
|
friend struct Data;
|
|
|
|
public:
|
|
|
|
/*!
|
|
* sRGB x chromaticity coordinates (D50).
|
|
*/
|
|
static const float sRGB_x[ 3 ];
|
|
|
|
/*!
|
|
* sRGB y chromaticity coordinates (D50).
|
|
*/
|
|
static const float sRGB_y[ 3 ];
|
|
|
|
/*!
|
|
* sRGB luminance coefficients (D50).
|
|
*/
|
|
static const float sRGB_Y[ 3 ];
|
|
|
|
/*!
|
|
* The sRGB (D50) working space.
|
|
*/
|
|
static const RGBColorSystem sRGB;
|
|
|
|
#ifdef __PCL_WITH_STANDARD_RGB_WORKING_SPACES
|
|
|
|
/*
|
|
* Adobe RGB 1998
|
|
*/
|
|
static const float AdobeRGB1998_x[ 3 ];
|
|
static const float AdobeRGB1998_y[ 3 ];
|
|
static const float AdobeRGB1998_Y[ 3 ];
|
|
|
|
/*
|
|
* Apple RGB
|
|
*/
|
|
static const float AppleRGB_x[ 3 ];
|
|
static const float AppleRGB_y[ 3 ];
|
|
static const float AppleRGB_Y[ 3 ];
|
|
|
|
/*
|
|
* Best RGB
|
|
*/
|
|
static const float BestRGB_x[ 3 ];
|
|
static const float BestRGB_y[ 3 ];
|
|
static const float BestRGB_Y[ 3 ];
|
|
|
|
/*
|
|
* Beta RGB (by Bruce Lindbloom)
|
|
*/
|
|
static const float BetaRGB_x[ 3 ];
|
|
static const float BetaRGB_y[ 3 ];
|
|
static const float BetaRGB_Y[ 3 ];
|
|
|
|
/*
|
|
* Bruce RGB
|
|
*/
|
|
static const float BruceRGB_x[ 3 ];
|
|
static const float BruceRGB_y[ 3 ];
|
|
static const float BruceRGB_Y[ 3 ];
|
|
|
|
/*
|
|
* CIE RGB
|
|
*/
|
|
static const float CIERGB_x[ 3 ];
|
|
static const float CIERGB_y[ 3 ];
|
|
static const float CIERGB_Y[ 3 ];
|
|
|
|
/*
|
|
* Color Match RGB
|
|
*/
|
|
static const float ColorMatchRGB_x[ 3 ];
|
|
static const float ColorMatchRGB_y[ 3 ];
|
|
static const float ColorMatchRGB_Y[ 3 ];
|
|
|
|
/*
|
|
* NTSC RGB
|
|
*/
|
|
static const float NTSCRGB_x[ 3 ];
|
|
static const float NTSCRGB_y[ 3 ];
|
|
static const float NTSCRGB_Y[ 3 ];
|
|
|
|
/*
|
|
* PAL/SECAM RGB
|
|
*/
|
|
static const float PALSECAMRGB_x[ 3 ];
|
|
static const float PALSECAMRGB_y[ 3 ];
|
|
static const float PALSECAMRGB_Y[ 3 ];
|
|
|
|
/*
|
|
* ProPhoto RGB
|
|
*/
|
|
static const float ProPhotoRGB_x[ 3 ];
|
|
static const float ProPhotoRGB_y[ 3 ];
|
|
static const float ProPhotoRGB_Y[ 3 ];
|
|
|
|
/*
|
|
* SMPTE-C RGB
|
|
*/
|
|
static const float SMPTECRGB_x[ 3 ];
|
|
static const float SMPTECRGB_y[ 3 ];
|
|
static const float SMPTECRGB_Y[ 3 ];
|
|
|
|
/*
|
|
* Wide Gamut RGB
|
|
*/
|
|
static const float WideGamutRGB_x[ 3 ];
|
|
static const float WideGamutRGB_y[ 3 ];
|
|
static const float WideGamutRGB_Y[ 3 ];
|
|
|
|
#endif // __PCL_WITH_STANDARD_RGB_WORKING_SPACES
|
|
|
|
};
|
|
|
|
// ----------------------------------------------------------------------------
|
|
|
|
} // pcl
|
|
|
|
#undef _1_3
|
|
#undef _1_6
|
|
#undef _2_3
|
|
#undef _16_116
|
|
#undef CIEEpsilon
|
|
#undef CIEKappa
|
|
#undef CIEKappa116
|
|
#undef sRGBEpsilon
|
|
#undef sRGBEpsilonInv
|
|
#undef sRGBGamma
|
|
#undef sRGBGammaInv
|
|
|
|
#endif // __PCL_RGBColorSystem_h
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// EOF pcl/RGBColorSystem.h - Released 2022-03-12T18:59:29Z
|