问题
I am using EMGU.CV 3.4.1.2976 (latest) library to analyze images but I am not getting the results I expect. I benchmark against ImageJ but any image package should do.
To test functionality, I am analyzing a simple blue 640x320 jpeg like below. The RGB value for this image is 0,0,255.
Hue histogram from ImageJ (value is 170, count 2048000)
Using code below I get a spike at 120 instead of the 170 - count 2048000 is correct though. What am I doing wrong?
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);
UPDATE
It turns I need to convert to a different color space but it still is not 100 % correct. arr
now returns 171 instead of 170. It is of course only a slight difference but for more complex images it is noticable.
What can be the problem?
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);
回答1:
I don't use ImageJ or EMGU.CV but I'll share some things to consider...
(1)
Correct hue value is 240 (not 170) degrees.
The hue for blue (0,0,255) is 240 degrees in the color wheel. Note that it can also be said as -120.
This logic might explain why you "get a spike at 120" for that specific hue inAnalyzeEmgu
function.
Can recover from minus mode by adding 360. Eg: myHue = (-120) + 360;
which gives result: 240
.
(Above) Image credit: http://www.graphic-design.com/Photoshop/color_cast/visible_color_spectrum.html
(2)
Why does Hue histogram from ImageJ give 170?
If you look at the Image histogram it maxes at 255 but wheel/circle should max at 360. No logic why they did it like that, but it can be fixed:
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"
Try
myHue = 360 - 120; //gives 240
In the image below made in Photoshop, I am showing that (starting from top) if we get to blue it is correctly listed as 240 degrees and is found at 88 pixels "distance" when travelling downwards.
The opposite is to travel upwards from bottom, and we see that the same distance of 88 pixels now gives 120 (a green hue).
Your code's color wheel is flipped (upside down). Compare A against B side by side.
Photoshop uses system A, but your value suggests your code thinks like system B.
来源:https://stackoverflow.com/questions/52451681/get-hue-hsv-hsb-value-of-rgb-using-emgu-c-sharp-yields-wrong-result