在colorizer.org网站上,它们的HSV范围为H = 0-360,S = 0-100,V = 0-100。我们也知道OpenCV中的HSV范围是H = 0-180,S = 0-255,V = 0-255。
我想为任何一种蓝色(我们认为是蓝色)选择一个范围,所以我查看了colorizer.org,发现蓝色Hue的范围大约是170到270。因此我将这个Hue范围除以了2,得到85-135。
现在,我从网站上的预览中获取了彩色[H=216, S=96, V=67]
的以下屏幕截图
然后,我在手机上运行该应用程序,并从笔记本电脑屏幕上捕获了以下相机框架。我了解HSV channel 值会在一定程度上与网站上的有所不同,因为在我捕获相机框架时,还有其他条件,例如房间中有其他光线(HSV中的V)等。
然后,我通过Mat
将此Imgproc.cvtColor(rgbaFrame, hsvImage, Imgproc.COLOR_RGB2HSV_FULL);
转换为HSV颜色空间,从而得到下图。
然后我调用了inRange
函数:
Core.inRange(hsvImage, new Scalar(85, 50, 40), new Scalar(135, 255, 255), maskedImage);
这导致了以下maskedImage。
问题是,当我包含所有可能的蓝色色相范围时,为什么不检测蓝色?
重要:除了第一个原始图像外,所有图像都使用
Highgui.imwrite
函数存储在sdcard中,因此我可以将它们移动到计算机上以便在Stackoverflow上上传它们。您必须已经注意到,第一个原始屏幕截图中的蓝色在第二个图像中转换为红色。原因是由相机捕获的帧(即由手机相机捕获的第一个屏幕快照的照片/帧)是RGBA图像。但是,OpenCV在将所有图像保存到某些东西的sdcard时,默认情况下会将所有图像转换为BRG。因此,请确保原始图像为RGBA,并且仅由OpenCV在内部将其转换为BGR以保存到sdcard中。这就是为什么红色显示为蓝色。
最佳答案
使用此代码确实对我有用(C++):
cv::Mat input = cv::imread("../inputData/HSV_RGB.jpg");
//assuming your image to be in RGB format after loading:
cv::Mat hsv;
cv::cvtColor(input,hsv,CV_RGB2HSV);
// hue range:
cv::Mat mask;
inRange(hsv, cv::Scalar(85, 50, 40), cv::Scalar(135, 255, 255), mask);
cv::imshow("blue mask", mask);
我使用了此输入图像(虽然实际上是RGB图像,但以BGR格式保存和加载,这就是为什么我们必须使用RGB2HSV而不是BGR2HSV的原因):
产生这个面具:
与您的代码不同的是,我使用
CV_RGB2HSV
而不是CV_RGB2HSV_FULL
。标记CV_RGB2HSV_FULL
使用整个字节存储色相值,因此0 .. 360 degrees
范围将缩放为0 .. 255
而不是0 .. 180
中的CV_RGB2HSV
我可以通过使用以下部分的代码来验证这一点:
// use _FULL flag:
cv::cvtColor(input,hsv,CV_RGB2HSV_FULL);
// but scale the hue values accordingly:
double hueScale = 2.0/1.41176470588;
cv::Mat mask;
// scale hue values:
inRange(hsv, cv::Scalar(hueScale*85, 50, 40), cv::Scalar(hueScale*135, 255, 255), mask);
得到这个结果:
对于任何想要测试“正确”图像的人:
这是转换为BGR的输入:如果要直接使用该输入,则必须将转换从RGB2HSV转换为BGR2HSV。但是我认为最好也显示输入的BGR版本...
关于android - 当我将蓝色的整个可能色相范围赋予蓝色时,为什么inRange函数无法检测到蓝色?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34200353/