使用 Emgu C# 获取 RGB 的色调 (HSV/HSB) 值会产生错误的结果
Get hue (HSV/HSB) value of RGB using Emgu C# yields wrong result
我正在使用 EMGU.CV 3.4.1.2976 (latest) library to analyze images but I am not getting the results I expect. I benchmark against ImageJ 但任何图像包都可以。
为了测试功能,我正在分析一个简单的蓝色 640x320 jpeg,如下所示。此图像的 RGB 值为 0,0,255。
来自 ImageJ 的色调直方图(值为 170,计数 2048000)
使用下面的代码,我得到了 120 而不是 170 的尖峰 - 尽管计数 2048000 是正确的。
我做错了什么?
public void AnalyzeEmgu(object image)
{
int[] arr = new int[256];
using (Bitmap bmp = (Bitmap)image)
{
using (Image<Hsv, byte> hsvImage = new Image<Hsv, byte>(bmp))
{
Image<Gray, byte>[] channels = hsvImage.Split();
Image<Gray, byte> imgHue = channels[0];
for (int x = 0; x < imgHue.Rows; x++)
{
for (int y = 0; y < imgHue.Cols; y++)
{
var b = imgHue.Data[x, y, 0];
arr[b]++; // fill array with Hue data. Add 1 (++) to count amount.
}
}
}
}
GC.Collect();
OnImageFinished(arr); // return array
}
// call function.
Bitmap bmp =new Bitmap(@"c:\test\blue.jpg");
AnalyzeEmgu(bmp);
更新
原来我需要转换成不同的颜色 space 但它仍然不是 100% 正确。 arr
现在 returns 171 而不是 170。这当然只是一个细微的差别,但对于更复杂的图像来说,这是显而易见的。
可能是什么问题?
public void AnalyzeEmgu(object image)
{
int[] arr = new int[256];
using (Mat orig = new Mat((string)image, ImreadModes.Color))
{
using (Mat hsv = new Mat())
{
// convert color to HSV here.
CvInvoke.CvtColor(orig, hsv, ColorConversion.Bgr2HsvFull);
Mat[] channels = hsv.Split();
using (Image<Bgr, byte> img = channels[0].ToImage<Bgr, byte>())
{
for (int x = 0; x < img.Rows; x++)
{
for (int y = 0; y < img.Cols; y++)
{
var b = img.Data[x, y, 0];
arr[b]++;
}
}
}
channels[1].Dispose();
channels[2].Dispose();
}
}
GC.Collect();
}
OnImageFinished(arr);
我不使用 ImageJ 或 EMGU.CV 但我会分享一些需要考虑的事情...
(1)
Correct hue value is 240 (not 170) degrees.
蓝色 (0,0,255) 的色调在色轮中为 240 度。注意也可以写成-120.
这个逻辑可以解释为什么你 "get a spike at 120" 在 AnalyzeEmgu
函数中使用那个特定的色调。
可以通过添加 360 从负模式恢复。例如: myHue = (-120) + 360;
给出结果:240
.
(上图)图片来源:http://www.graphic-design.com/Photoshop/color_cast/visible_color_spectrum.html
(2)
Why does Hue histogram from ImageJ give 170?
如果您查看图像直方图,它的最大值为 255,但 wheel/circle 的最大值应为 360。没有逻辑为什么他们那样做,但它可以修复:
IF: 360 / 255 = 1.4117647058823529411764705882353
THEN: 170 * 1.4117647058823529411764705882353 = 240 degrees.
(3)
"Using code below I get a spike at 120 instead of the 170"
尝试
myHue = 360 - 120; //gives 240
在下面用 Photoshop 制作的图片中,我展示了(从顶部开始)如果我们变成蓝色,它会正确地列为 240 度并且在 88 像素处找到"distance" 向下行驶时。
相反的是从底部向上移动,我们看到相同的 88 像素距离现在得到 120(绿色色调)。
您的代码色轮已翻转(上下颠倒)。并排比较 A 和 B。
Photoshop 使用系统 A,但您的值表明您的代码像系统 B.
一样思考
我正在使用 EMGU.CV 3.4.1.2976 (latest) library to analyze images but I am not getting the results I expect. I benchmark against ImageJ 但任何图像包都可以。
为了测试功能,我正在分析一个简单的蓝色 640x320 jpeg,如下所示。此图像的 RGB 值为 0,0,255。
来自 ImageJ 的色调直方图(值为 170,计数 2048000)
使用下面的代码,我得到了 120 而不是 170 的尖峰 - 尽管计数 2048000 是正确的。 我做错了什么?
public void AnalyzeEmgu(object image)
{
int[] arr = new int[256];
using (Bitmap bmp = (Bitmap)image)
{
using (Image<Hsv, byte> hsvImage = new Image<Hsv, byte>(bmp))
{
Image<Gray, byte>[] channels = hsvImage.Split();
Image<Gray, byte> imgHue = channels[0];
for (int x = 0; x < imgHue.Rows; x++)
{
for (int y = 0; y < imgHue.Cols; y++)
{
var b = imgHue.Data[x, y, 0];
arr[b]++; // fill array with Hue data. Add 1 (++) to count amount.
}
}
}
}
GC.Collect();
OnImageFinished(arr); // return array
}
// call function.
Bitmap bmp =new Bitmap(@"c:\test\blue.jpg");
AnalyzeEmgu(bmp);
更新
原来我需要转换成不同的颜色 space 但它仍然不是 100% 正确。 arr
现在 returns 171 而不是 170。这当然只是一个细微的差别,但对于更复杂的图像来说,这是显而易见的。
可能是什么问题?
public void AnalyzeEmgu(object image)
{
int[] arr = new int[256];
using (Mat orig = new Mat((string)image, ImreadModes.Color))
{
using (Mat hsv = new Mat())
{
// convert color to HSV here.
CvInvoke.CvtColor(orig, hsv, ColorConversion.Bgr2HsvFull);
Mat[] channels = hsv.Split();
using (Image<Bgr, byte> img = channels[0].ToImage<Bgr, byte>())
{
for (int x = 0; x < img.Rows; x++)
{
for (int y = 0; y < img.Cols; y++)
{
var b = img.Data[x, y, 0];
arr[b]++;
}
}
}
channels[1].Dispose();
channels[2].Dispose();
}
}
GC.Collect();
}
OnImageFinished(arr);
我不使用 ImageJ 或 EMGU.CV 但我会分享一些需要考虑的事情...
(1)
Correct hue value is 240 (not 170) degrees.
蓝色 (0,0,255) 的色调在色轮中为 240 度。注意也可以写成-120.
这个逻辑可以解释为什么你 "get a spike at 120" 在 AnalyzeEmgu
函数中使用那个特定的色调。
可以通过添加 360 从负模式恢复。例如: myHue = (-120) + 360;
给出结果:240
.
(上图)图片来源:http://www.graphic-design.com/Photoshop/color_cast/visible_color_spectrum.html
(2)
Why does Hue histogram from ImageJ give 170?
如果您查看图像直方图,它的最大值为 255,但 wheel/circle 的最大值应为 360。没有逻辑为什么他们那样做,但它可以修复:
IF: 360 / 255 = 1.4117647058823529411764705882353
THEN: 170 * 1.4117647058823529411764705882353 = 240 degrees.
(3)
"Using code below I get a spike at 120 instead of the 170"
尝试
myHue = 360 - 120; //gives 240
在下面用 Photoshop 制作的图片中,我展示了(从顶部开始)如果我们变成蓝色,它会正确地列为 240 度并且在 88 像素处找到"distance" 向下行驶时。
相反的是从底部向上移动,我们看到相同的 88 像素距离现在得到 120(绿色色调)。
您的代码色轮已翻转(上下颠倒)。并排比较 A 和 B。
Photoshop 使用系统 A,但您的值表明您的代码像系统 B.