1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
#include <gfx/color.h>
#include <gfx/mat3.h>
namespace gfx
{
//
// HSV conversion code based on Foley et al (2nd ed. in C, pp. 592-593)
//
static double max3(double x, double y, double z)
{
if( x>=y && x>=z ) return x;
else if( y>=x && y>=z ) return y;
else return z;
}
static double min3(double x, double y, double z)
{
if( x<=y && x<=z ) return x;
else if( y<=x && y<=z ) return y;
else return z;
}
hsvColor RGBtoHSV(const rgbColor& rgb)
{
double r=rgb[0], g=rgb[1], b=rgb[2];
double max = max3(r,g,b);
double min = min3(r,g,b);
double delta = max - min;
double h = -1; // undefined value for case where v outside [0,360]
double v = max;
double s = (max!=0) ? (delta/max) : 0;
if( s != 0 )
{
if( r==max ) h = (g-b)/delta;
else if( g==max ) h = 2 + (b-r)/delta;
else if( b==max ) h = 4 + (r-g)/delta;
h *= 60;
if( h<0 ) h+=360;
}
return hsvColor(h, s, v);
}
rgbColor HSVtoRGB(const hsvColor& hsv)
{
double h = hsv[0], s=hsv[1], v=hsv[2];
// Unsaturated means pure gray
if(s == 0) return rgbColor(v, v, v);
if( h==360.0 ) h=0.0; // these are equivalent hues
h /= 60.0; // convert to sector [0, 6)
int i = (int)floor( h ); // integral part of h
float f = h - i; // fractional part of h
// Compute RGB components
float p = v * ( 1 - s );
float q = v * ( 1 - s * f );
float t = v * ( 1 - s * ( 1 - f ) );
// Map PQT to RGB based on sector of the color cone
switch( i )
{
case 0: return rgbColor(v, t, p); break;
case 1: return rgbColor(q, v, p); break;
case 2: return rgbColor(p, v, t); break;
case 3: return rgbColor(p, q, v); break;
case 4: return rgbColor(t, p, v); break;
default: return rgbColor(v, p, q); break;
}
}
// Paul Haeberli's comments on luminance coefficients:
//
// Where rwgt is 0.3086, gwgt is 0.6094, and bwgt is 0.0820. This
// is the luminance vector. Notice here that we do not use the
// standard NTSC weights of 0.299, 0.587, and 0.114. The NTSC
// weights are only applicable to RGB colors in a gamma 2.2 color
// space. For linear RGB colors the values above are better.
//
// Grafica Obscura -- Matrix Operations for Image Processing
// http://www.sgi.com/misc/grafica/matrix/index.html
//
const rgbColor haeberli_factor(0.3086, 0.6094, 0.0820);
const rgbColor ntsc_factor(0.299, 0.587, 0.114);
float rgb_luminance_ntsc(const rgbColor& rgb) { return rgb*ntsc_factor; }
float rgb_luminance_alt(const rgbColor& rgb) { return rgb*haeberli_factor; }
const Mat3 M_yiq(ntsc_factor,
Vec3(0.596, -0.275, -0.321),
Vec3(0.212, -0.523, 0.311));
yiqColor RGBtoYIQ(const rgbColor& rgb)
{
return yiqColor(M_yiq * Vec3(rgb));
}
// Matrix conversions taken from the ColorFAQ by Charles Poynton
const Mat3 M_rgb(Vec3( 3.240479, -1.537150, -0.498535),
Vec3(-0.969256, 1.875992, 0.041556),
Vec3( 0.055648, -0.204043, 1.057311));
const Mat3 M_xyz(Vec3(0.412453, 0.357580, 0.180423),
Vec3(0.212671, 0.715160, 0.072169),
Vec3(0.019334, 0.119193, 0.950227));
// Derived from equations provided by EasyRGB:
// http://www.easyrgb.com/math.php
//
xyzColor RGBtoXYZ(const rgbColor& rgb)
{ return xyzColor(M_xyz * Vec3(rgb)); }
rgbColor XYZtoRGB(const xyzColor& xyz)
{ return rgbColor(M_rgb * Vec3(xyz)); }
xyChromaticity xyz_chromaticity(const xyzColor& xyz)
{
float w = xyz[0] + xyz[1] + xyz[2];
return xyChromaticity(xyz[0]/w, xyz[1]/w);
}
}
|