将 RGB 转换为 HSB(又名 HSV)
Converting RGB to HSB (aka HSV)
我正在尝试实现一个简单的 RGB 到 HSB 例程,我一直严格遵循 wikipedia reference article 的说明。
我写的代码是:
#include <iostream>
#include <cmath>
struct RGB { float red, green, blue; };
struct HSB { float hue, saturation, brightness; }; // aka HSV
// https://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB
static void HSBToRGB(HSB const & hsb, RGB & rgb )
{
/*
* Given a color with hue H ∈ [0°, 360°), saturation SHSV ∈ [0, 1], and value
* V ∈ [0, 1], we first find chroma:
*/
const float H = hsb.hue;
const float S_HSV = hsb.saturation;
const float V = hsb.brightness;
const float C = V * S_HSV;
/*
* Then we can find a point (R1, G1, B1) along the bottom three faces of the RGB
* cube, with the same hue and chroma as our color (using the intermediate value X
* for the second largest component of this color):
*/
const float H_prime = H / 60.;
const float X = C * ( 1 - std::abs( (int)H_prime % 2 - 1) );
float R1, G1, B1;
if( isnan( H ) )
{
R1 = G1 = B1 = 0;
}
else if( 0 <= H_prime && H_prime < 1 )
{
R1 = C; G1 = X; B1 = 0;
}
else if( 1 <= H_prime && H_prime < 2 )
{
R1 = X; G1 = C; B1 = 0;
}
else if( 2 <= H_prime && H_prime < 3 )
{
R1 = 0; G1 = C; B1 = X;
}
else if( 3 <= H_prime && H_prime < 4 )
{
R1 = 0; G1 = X; B1 = C;
}
else if( 4 <= H_prime && H_prime < 5 )
{
R1 = X; G1 = 0; B1 = C;
}
else if( 5 <= H_prime && H_prime < 6 )
{
R1 = C; G1 = 0; B1 = X;
}
/*
* Finally, we can find R, G, and B by adding the same amount to each component,
* to match value:
*/
const float m = V - C;
rgb.red = R1 + m;
rgb.green = G1 + m;
rgb.blue = B1 + m;
}
int main()
{
HSB const hsb = { 251.1f, 0.887f, 0.918f };
RGB rgb = { 0.255f , 0.104f , 0.918f };
std::cout << "Reference: " << rgb.red << "," << rgb.green << "," << rgb.blue << std::endl;
HSBToRGB(hsb, rgb);
std::cout << "Computed: " << rgb.red << "," << rgb.green << "," << rgb.blue << std::endl;
return 0;
}
编译后 运行 在 linux debian/jessie amd64 上,我得到的是:
$ ./ref
Reference: 0.255,0.104,0.918
Computed: 0.103734,0.103734,0.918
现在,如果您查找正确的参考值(same article,table 中的第 11 行),它应该是相同的。我不明白的是 Hue 的大差异值 (0.255 != 0.103734)。
我一直在用维基百科文章描述的内容仔细检查我的实现,但没有发现任何差异。
使用 java 作为参考,我可以检查 RGB 值是否正确,例如:
import java.awt.Color;
public class HSBToRGBExample {
public static void main(String[] args) {
float hue = 251.1f / 360;
float saturation = 0.887f;
float brightness = 0.918f;
int rgb = Color.HSBtoRGB(hue, saturation, brightness);
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
System.out.println((float)red / 255 + " " + (float)green / 255 + " " + (float)blue / 255);
}
}
维基百科文章中是否有错字?或者我的实现中缺少什么?
您想要浮点模数,但您正在转换为 int
(可能是为了消除编译器关于 %
仅适用于整数的抱怨)。
在 C++ 中它将是
std::abs(std::fmod(H_prime, 2) - 1);
(由于浮点不精确,您仍然会看到差异。)
我正在尝试实现一个简单的 RGB 到 HSB 例程,我一直严格遵循 wikipedia reference article 的说明。
我写的代码是:
#include <iostream>
#include <cmath>
struct RGB { float red, green, blue; };
struct HSB { float hue, saturation, brightness; }; // aka HSV
// https://en.wikipedia.org/wiki/HSL_and_HSV#Converting_to_RGB
static void HSBToRGB(HSB const & hsb, RGB & rgb )
{
/*
* Given a color with hue H ∈ [0°, 360°), saturation SHSV ∈ [0, 1], and value
* V ∈ [0, 1], we first find chroma:
*/
const float H = hsb.hue;
const float S_HSV = hsb.saturation;
const float V = hsb.brightness;
const float C = V * S_HSV;
/*
* Then we can find a point (R1, G1, B1) along the bottom three faces of the RGB
* cube, with the same hue and chroma as our color (using the intermediate value X
* for the second largest component of this color):
*/
const float H_prime = H / 60.;
const float X = C * ( 1 - std::abs( (int)H_prime % 2 - 1) );
float R1, G1, B1;
if( isnan( H ) )
{
R1 = G1 = B1 = 0;
}
else if( 0 <= H_prime && H_prime < 1 )
{
R1 = C; G1 = X; B1 = 0;
}
else if( 1 <= H_prime && H_prime < 2 )
{
R1 = X; G1 = C; B1 = 0;
}
else if( 2 <= H_prime && H_prime < 3 )
{
R1 = 0; G1 = C; B1 = X;
}
else if( 3 <= H_prime && H_prime < 4 )
{
R1 = 0; G1 = X; B1 = C;
}
else if( 4 <= H_prime && H_prime < 5 )
{
R1 = X; G1 = 0; B1 = C;
}
else if( 5 <= H_prime && H_prime < 6 )
{
R1 = C; G1 = 0; B1 = X;
}
/*
* Finally, we can find R, G, and B by adding the same amount to each component,
* to match value:
*/
const float m = V - C;
rgb.red = R1 + m;
rgb.green = G1 + m;
rgb.blue = B1 + m;
}
int main()
{
HSB const hsb = { 251.1f, 0.887f, 0.918f };
RGB rgb = { 0.255f , 0.104f , 0.918f };
std::cout << "Reference: " << rgb.red << "," << rgb.green << "," << rgb.blue << std::endl;
HSBToRGB(hsb, rgb);
std::cout << "Computed: " << rgb.red << "," << rgb.green << "," << rgb.blue << std::endl;
return 0;
}
编译后 运行 在 linux debian/jessie amd64 上,我得到的是:
$ ./ref
Reference: 0.255,0.104,0.918
Computed: 0.103734,0.103734,0.918
现在,如果您查找正确的参考值(same article,table 中的第 11 行),它应该是相同的。我不明白的是 Hue 的大差异值 (0.255 != 0.103734)。
我一直在用维基百科文章描述的内容仔细检查我的实现,但没有发现任何差异。
使用 java 作为参考,我可以检查 RGB 值是否正确,例如:
import java.awt.Color;
public class HSBToRGBExample {
public static void main(String[] args) {
float hue = 251.1f / 360;
float saturation = 0.887f;
float brightness = 0.918f;
int rgb = Color.HSBtoRGB(hue, saturation, brightness);
int red = (rgb >> 16) & 0xFF;
int green = (rgb >> 8) & 0xFF;
int blue = rgb & 0xFF;
System.out.println((float)red / 255 + " " + (float)green / 255 + " " + (float)blue / 255);
}
}
维基百科文章中是否有错字?或者我的实现中缺少什么?
您想要浮点模数,但您正在转换为 int
(可能是为了消除编译器关于 %
仅适用于整数的抱怨)。
在 C++ 中它将是
std::abs(std::fmod(H_prime, 2) - 1);
(由于浮点不精确,您仍然会看到差异。)