使用 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(绿色色调)。

您的代码色轮已翻转(上下颠倒)。并排比较 AB
Photoshop 使用系统 A,但您的值表明您的代码像系统 B.

一样思考