|
Appendix B RGB/HSV/HLS/HSI Color Model Conversion Routines
#define DEGREES_PER_RADIAN (180.0 / 3.14159265358979)
#define UNDEFINED_HUE -1.000
#define ZERO_SATURATION 0.0
struct RgbTriadStruct {
USGC Red;
USGC Green;
USGC Blue;
};
struct HsvTriadStruct {
double Hue;
double Saturation;
double Value;
};
struct HlsTriadStruct {
double Hue;
double Lightness;
double Saturation;
};
struct HsiTriadStruct {
double Hue;
double Saturation;
double Intensity;
};
int RgbToHsv(struct RgbTriadStruct *RgbTriadStructPtr,
struct HsvTriadStruct *HsvTriadStructPtr)
{
USGI MaxPrimaryValue, MinPrimaryValue, MaxMinDelta;
MaxPrimaryValue = (RgbTriadStructPtr->Red > RgbTriadStructPtr->Green) ?
RgbTriadStructPtr->Red : RgbTriadStructPtr->Green;
MaxPrimaryValue = (RgbTriadStructPtr->Blue > MaxPrimaryValue) ?
RgbTriadStructPtr->Blue : MaxPrimaryValue;
HsvTriadStructPtr->Value = ((double) MaxPrimaryValue) / 255.0;
if (!MaxPrimaryValue)
{
HsvTriadStructPtr->Value = 0.0;
HsvTriadStructPtr->Hue = UNDEFINED_HUE;
HsvTriadStructPtr->Saturation = ZERO_SATURATION;
return 0;
} else
{
HsvTriadStructPtr->Value = ((double) MaxPrimaryValue) / 255.0;
}
MinPrimaryValue = (RgbTriadStructPtr->Red < RgbTriadStructPtr->Green) ?
RgbTriadStructPtr->Red : RgbTriadStructPtr->Green;
MinPrimaryValue = (RgbTriadStructPtr->Blue < MinPrimaryValue) ?
RgbTriadStructPtr->Blue : MinPrimaryValue;
if (!(MaxMinDelta = MaxPrimaryValue - MinPrimaryValue))
{
HsvTriadStructPtr->Hue = UNDEFINED_HUE;
HsvTriadStructPtr->Saturation = ZERO_SATURATION;
return 0;
}
HsvTriadStructPtr->Saturation =
((double) MaxMinDelta) / ((double) MaxPrimaryValue);
if (RgbTriadStructPtr->Red == MaxPrimaryValue)
HsvTriadStructPtr->Hue = 0.0 +
((double) (RgbTriadStructPtr->Green - RgbTriadStructPtr->Blue))
/
((double) MaxMinDelta);
else if (RgbTriadStructPtr->Green == MaxPrimaryValue)
HsvTriadStructPtr->Hue = 2.0 +
((double) (RgbTriadStructPtr->Blue - RgbTriadStructPtr->Red))
/
((double) MaxMinDelta);
else if (RgbTriadStructPtr->Blue == MaxPrimaryValue)
HsvTriadStructPtr->Hue = 4.0 +
((double) (RgbTriadStructPtr->Red - RgbTriadStructPtr->Green))
/
((double) MaxMinDelta);
HsvTriadStructPtr->Hue *= 60.0;
if (HsvTriadStructPtr->Hue < 0)
HsvTriadStructPtr->Hue += 360.0;
return 0;
}
int HsvToRgb(struct HsvTriadStruct *HsvTriadStructPtr,
struct RgbTriadStruct *RgbTriadStructPtr)
{
USGI IntValue;
double OneSixtythHue, DoubleDecimal, P, Q, T, V;
if (HsvTriadStructPtr->Saturation == ZERO_SATURATION)
{
if (HsvTriadStructPtr->Hue == UNDEFINED_HUE)
{
RgbTriadStructPtr->Red =
RgbTriadStructPtr->Green =
RgbTriadStructPtr->Blue =
HsvTriadStructPtr->Value * 255.0 + 0.5;
} else
{
printf("\n\nHsvToRgb: Illegal HSV hue value (saturation == 0)");
printf("\nHue == %5.3f, Saturation = %5.3f, Value == %5.3f",
HsvTriadStructPtr->Hue,
HsvTriadStructPtr->Saturation,
HsvTriadStructPtr->Value);
}
return 0;
}
if (HsvTriadStructPtr->Hue > 359.9)
HsvTriadStructPtr->Hue = 0.0;
OneSixtythHue = (HsvTriadStructPtr->Hue / 60.0);
IntValue = (USGI) OneSixtythHue;
DoubleDecimal = OneSixtythHue - ((double) IntValue);
P = HsvTriadStructPtr->Value *
(1.0 - HsvTriadStructPtr->Saturation);
Q = HsvTriadStructPtr->Value *
(1.0 - (HsvTriadStructPtr->Saturation * DoubleDecimal));
T = HsvTriadStructPtr->Value *
(1.0 - (HsvTriadStructPtr->Saturation * (1.0 - DoubleDecimal)));
V = HsvTriadStructPtr->Value;
switch (IntValue)
{
case 0:
RgbTriadStructPtr->Red = (USGI) (V * 255.0 + 0.5);
RgbTriadStructPtr->Green = (USGI) (T * 255.0 + 0.5);
RgbTriadStructPtr->Blue = (USGI) (P * 255.0 + 0.5);
break;
case 1:
RgbTriadStructPtr->Red = (USGI) (Q * 255.0 + 0.5);
RgbTriadStructPtr->Green = (USGI) (V * 255.0 + 0.5);
RgbTriadStructPtr->Blue = (USGI) (P * 255.0 + 0.5);
break;
case 2:
RgbTriadStructPtr->Red = (USGI) (P * 255.0 + 0.5);
RgbTriadStructPtr->Green = (USGI) (V * 255.0 + 0.5);
RgbTriadStructPtr->Blue = (USGI) (T * 255.0 + 0.5);
break;
case 3:
RgbTriadStructPtr->Red = (USGI) (P * 255.0 + 0.5);
RgbTriadStructPtr->Green = (USGI) (Q * 255.0 + 0.5);
RgbTriadStructPtr->Blue = (USGI) (V * 255.0 + 0.5);
break;
case 4:
RgbTriadStructPtr->Red = (USGI) (T * 255.0 + 0.5);
RgbTriadStructPtr->Green = (USGI) (P * 255.0 + 0.5);
RgbTriadStructPtr->Blue = (USGI) (V * 255.0 + 0.5);
break;
case 5:
RgbTriadStructPtr->Red = (USGI) (V * 255.0 + 0.5);
RgbTriadStructPtr->Green = (USGI) (P * 255.0 + 0.5);
RgbTriadStructPtr->Blue = (USGI) (Q * 255.0 + 0.5);
break;
}
return 0;
}
int RgbToHls(struct RgbTriadStruct *RgbTriadStructPtr,
struct HlsTriadStruct *HlsTriadStructPtr)
{
USGI MaxPrimaryValue, MinPrimaryValue, MaxMinDelta;
double H;
MaxPrimaryValue = (RgbTriadStructPtr->Red > RgbTriadStructPtr->Green)?
RgbTriadStructPtr->Red : RgbTriadStructPtr->Green;
MaxPrimaryValue = (RgbTriadStructPtr->Blue > MaxPrimaryValue) ?
RgbTriadStructPtr->Blue : MaxPrimaryValue;
MinPrimaryValue = (RgbTriadStructPtr->Red < RgbTriadStructPtr->Green)?
RgbTriadStructPtr->Red : RgbTriadStructPtr->Green;
MinPrimaryValue = (RgbTriadStructPtr->Blue < MinPrimaryValue) ?
RgbTriadStructPtr->Blue : MinPrimaryValue;
HlsTriadStructPtr->Lightness =
((double) (MaxPrimaryValue + MinPrimaryValue))
/
(2.0 * 255.0);
if (MaxPrimaryValue == MinPrimaryValue)
{
HlsTriadStructPtr->Hue = UNDEFINED_HUE;
HlsTriadStructPtr->Saturation = ZERO_SATURATION;
return 0;
}
MaxMinDelta = MaxPrimaryValue - MinPrimaryValue;
if (HlsTriadStructPtr->Lightness < 0.5)
HlsTriadStructPtr->Saturation =
((double) MaxMinDelta)
/
((double) (MaxPrimaryValue + MinPrimaryValue));
else
HlsTriadStructPtr->Saturation =
((double) MaxMinDelta)
/
((double) (2 * 255 - (MaxPrimaryValue + MinPrimaryValue)));
if (RgbTriadStructPtr->Red == MaxPrimaryValue)
HlsTriadStructPtr->Hue = 0.0 +
((double) (RgbTriadStructPtr->Green - RgbTriadStructPtr->Blue))
/
((double) MaxMinDelta);
else if (RgbTriadStructPtr->Green == MaxPrimaryValue)
HlsTriadStructPtr->Hue = 2.0 +
((double) (RgbTriadStructPtr->Blue - RgbTriadStructPtr->Red))
/
((double) MaxMinDelta);
else if (RgbTriadStructPtr->Blue == MaxPrimaryValue)
HlsTriadStructPtr->Hue = 4.0 +
((double) (RgbTriadStructPtr->Red - RgbTriadStructPtr->Green))
/
((double) MaxMinDelta);
HlsTriadStructPtr->Hue *= 60.0;
if (HlsTriadStructPtr->Hue < 0)
HlsTriadStructPtr->Hue += 360.0;
return 0;
}
int HlsToRgb(struct HlsTriadStruct *HlsTriadStructPtr,
struct RgbTriadStruct *RgbTriadStructPtr)
{
double M1, M2;
if (HlsTriadStructPtr->Lightness < 0.5)
M2 = HlsTriadStructPtr->Lightness *
(1.0 + HlsTriadStructPtr->Saturation);
else
M2 = HlsTriadStructPtr->Lightness +
HlsTriadStructPtr->Saturation -
(HlsTriadStructPtr->Lightness * HlsTriadStructPtr->Saturation);
M1 = 2.0 * HlsTriadStructPtr->Lightness - M2;
if (HlsTriadStructPtr->Saturation == ZERO_SATURATION)
{
if (HlsTriadStructPtr->Hue == UNDEFINED_HUE)
{
RgbTriadStructPtr->Red =
RgbTriadStructPtr->Green =
RgbTriadStructPtr->Blue =
HlsTriadStructPtr->Lightness * 255.0 + 0.5;
} else
{
printf("\n\nHlsToRgb: Illegal Hls hue value (saturation == 0)");
printf("\nHue == %5.3f, Lightness = %5.3f, Saturation == %5.3f",
HlsTriadStructPtr->Hue,
HlsTriadStructPtr->Lightness,
HlsTriadStructPtr->Saturation);
}
return 0;
}
RgbTriadStructPtr->Red = RgbCubeValue(M1, M2,
HlsTriadStructPtr->Hue + 120.0);
RgbTriadStructPtr->Green = RgbCubeValue(M1, M2,
HlsTriadStructPtr->Hue);
RgbTriadStructPtr->Blue = RgbCubeValue(M1, M2,
HlsTriadStructPtr->Hue - 120.0);
return 0;
}
int RgbCubeValue(double N1, double N2, double Hue)
{
double Value;
if (Hue > 360.0) Hue -= 360.0;
if (Hue < 0.0) Hue += 360.0;
if (Hue < 60.0) Value = N1 + (N2 - N1) * Hue / 60.0;
else if (Hue < 180.0) Value = N2;
else if (Hue < 240.0) Value = N1 + (N2 - N1) * (240 - Hue) / 60.0;
else Value = N1;
return (USGI) (Value * 255.0 + 0.5);
}
int HlsToRgb2(struct HlsTriadStruct *HlsTriadStructPtr,
struct RgbTriadStruct *RgbTriadStructPtr)
{
int Sextant;
double Min, V, Sv, H, Vsf;
double Mid1, Mid2, Fract;
if (HlsTriadStructPtr->Lightness <= 0.5)
V = HlsTriadStructPtr->Lightness *
(1.0 + HlsTriadStructPtr->Saturation);
else
V = HlsTriadStructPtr->Lightness +
HlsTriadStructPtr->Saturation -
(HlsTriadStructPtr->Lightness * HlsTriadStructPtr->Saturation);
if (V <= 0.0)
{
RgbTriadStructPtr->Red =
RgbTriadStructPtr->Green =
RgbTriadStructPtr->Blue = (USGC) 0;
} else
{
Min = HlsTriadStructPtr->Lightness +
HlsTriadStructPtr->Lightness - V;
Sv = (V - Min) / V;
H = HlsTriadStructPtr->Hue / 60.0;
Sextant = (int) H;
Fract = H - (double) Sextant;
Vsf = V * Sv * Fract;
Mid1 = Min + Vsf;
Mid2 = V - Vsf;
V *= 255.0; if (V > 255.0) V = 255.0;
Min *= 255.0; if (Min > 255.0) Min = 255.0;
Mid1 *= 255.0; if (Mid1 > 255.0) Mid1 = 255.0;
Mid2 *= 255.0; if (Mid2 > 255.0) Mid2 = 255.0;
switch (Sextant)
{
case 0 : RgbTriadStructPtr->Red = (USGC) V;
RgbTriadStructPtr->Green = (USGC) Mid1;
RgbTriadStructPtr->Blue = (USGC) Min;
break;
case 1 : RgbTriadStructPtr->Red = (USGC) Mid2;
RgbTriadStructPtr->Green = (USGC) V;
RgbTriadStructPtr->Blue = (USGC) Min;
break;
case 2 : RgbTriadStructPtr->Red = (USGC) Min;
RgbTriadStructPtr->Green = (USGC) V;
RgbTriadStructPtr->Blue = (USGC) Mid1;
break;
case 3 : RgbTriadStructPtr->Red = (USGC) Min;
RgbTriadStructPtr->Green = (USGC) Mid2;
RgbTriadStructPtr->Blue = (USGC) V;
break;
case 4 : RgbTriadStructPtr->Red = (USGC) Mid1;
RgbTriadStructPtr->Green = (USGC) Min;
RgbTriadStructPtr->Blue = (USGC) V;
break;
case 5 : RgbTriadStructPtr->Red = (USGC) V;
RgbTriadStructPtr->Green = (USGC) Min;
RgbTriadStructPtr->Blue = (USGC) Mid2;
break;
default: RgbTriadStructPtr->Red = (USGC) 255;
RgbTriadStructPtr->Green = (USGC) 0;
RgbTriadStructPtr->Blue = (USGC) 0;
break;
}
}
return 0;
}
int RgbToHsi(struct RgbTriadStruct *RgbTriadStructPtr,
struct HsiTriadStruct *HsiTriadStructPtr)
{
double R, G, B, Sum, Quotient;
double Radians, Angle, MinValue, MaxValue, TempDouble1, TempDouble2;
R = ((double) RgbTriadStructPtr->Red) / 255.0;
G = ((double) RgbTriadStructPtr->Green) / 255.0;
B = ((double) RgbTriadStructPtr->Blue) / 255.0;
Sum = R + G + B;
HsiTriadStructPtr->Intensity = Sum / 3.0;
MinValue = (R < G) ? R : G;
MinValue = (B < MinValue) ? B : MinValue;
MaxValue = (R > G) ? R : G;
MaxValue = (B > MaxValue) ? B : MaxValue;
if (HsiTriadStructPtr->Intensity < 0.00001)
HsiTriadStructPtr->Saturation = ZERO_SATURATION;
else
HsiTriadStructPtr->Saturation = 1.0 - (3.0 * MinValue) / Sum;
if (MinValue == MaxValue)
{
HsiTriadStructPtr->Hue = UNDEFINED_HUE;
HsiTriadStructPtr->Saturation = ZERO_SATURATION;
return 0;
}
TempDouble1 = (((R - G) + (R - B)) / 2.0);
TempDouble2 = (R - G)*(R - G) + (R - B)*(G - B);
Quotient = (TempDouble1 / sqrt(TempDouble2));
if (Quotient > 0.99999999999999999)
Radians = 0.0;
else if (Quotient < -0.99999999999999999)
Radians = 3.1415926535;
else
Radians = acos(TempDouble1 / sqrt(TempDouble2));
Angle = Radians * DEGREES_PER_RADIAN;
if (B > G)
HsiTriadStructPtr->Hue = 360.0 - Angle;
else
HsiTriadStructPtr->Hue = Angle;
return 0;
}
int HsiToRgb(struct HsiTriadStruct *HsiTriadStructPtr,
struct RgbTriadStruct *RgbTriadStructPtr)
{
double r, g, b, Hue, Fraction, MaxDouble;
if (HsiTriadStructPtr->Saturation == ZERO_SATURATION)
{
if (HsiTriadStructPtr->Hue == UNDEFINED_HUE)
{
RgbTriadStructPtr->Red =
RgbTriadStructPtr->Green =
RgbTriadStructPtr->Blue =
HsiTriadStructPtr->Intensity * 255.0 + 0.5;
} else
{
printf("\n\nHsiToRgb: Illegal HSI hue value (saturation == 0)");
printf("\nHue == %5.3f, Saturation = %5.3f, Intensity == %5.3f",
HsiTriadStructPtr->Hue,
HsiTriadStructPtr->Saturation,
HsiTriadStructPtr->Intensity);
}
return 0;
}
if (HsiTriadStructPtr->Hue > 0.0 &&
HsiTriadStructPtr->Hue <= 120.0 )
{
b = (1.0 - HsiTriadStructPtr->Saturation) / 3.0;
Hue = HsiTriadStructPtr->Hue;
Fraction = (HsiTriadStructPtr->Saturation *
cos(Hue / DEGREES_PER_RADIAN))
/
cos((60.0 - Hue) / DEGREES_PER_RADIAN);
r = (1.0 + Fraction) / 3.0;
g = 1.0 - (r + b);
} else if (HsiTriadStructPtr->Hue > 120.0 &&
HsiTriadStructPtr->Hue <= 240.0 )
{
Hue = HsiTriadStructPtr->Hue - 120.0;
r = (1.0 - HsiTriadStructPtr->Saturation) / 3.0;
Fraction = (HsiTriadStructPtr->Saturation *
cos(Hue / DEGREES_PER_RADIAN))
/
cos((60.0 - Hue) / DEGREES_PER_RADIAN);
g = (1.0 + Fraction) / 3.0;
b = 1.0 - (r + g);
} else
{
Hue=
HsiTriadStructPtr->Hue - 240.0;
g = (1.0 - HsiTriadStructPtr->Saturation) / 3.0;
Fraction = (HsiTriadStructPtr->Saturation *
cos(Hue / DEGREES_PER_RADIAN))
/
cos((60.0 - Hue) / DEGREES_PER_RADIAN);
b = (1.0 + Fraction) / 3.0;
r = 1.0 - (g + b);
}
MaxDouble = ((r > g) ? r : g);
MaxDouble = ((MaxDouble > b) ? MaxDouble : b);
if (3.0 * HsiTriadStructPtr->Intensity * MaxDouble > 1.0)
HsiTriadStructPtr->Intensity = (1.0 / (3.0 * MaxDouble));
r *= 255.0;
g *= 255.0;
b *= 255.0;
RgbTriadStructPtr->Red =
(USGC) ((3.0 * HsiTriadStructPtr->Intensity * r) + 0.5);
RgbTriadStructPtr->Green =
(USGC) ((3.0 * HsiTriadStructPtr->Intensity * g) + 0.5);
RgbTriadStructPtr->Blue =
(USGC) ((3.0 * HsiTriadStructPtr->Intensity * b) + 0.5);
return 0;
}
/*=================== End of File ===================*/
|