为什么 inRange 函数在我已经为蓝色提供了整个可能的 Hue 范围后检测不到蓝色?
Why isn't inRange function detecting blue color when I have given it the entire possible Hue range for the blue color?
在网站 colorizer.org 上,它们的 HSV 范围为 H=0-360,S=0-100,V=0-100。我们也知道 OpenCV 中的 HSV 范围是 H=0-180, S=0-255, V=0-255.
我想 select 任何(我们认为的)蓝色阴影的范围,所以我查看了 colorizer.org,发现蓝色色调的范围大致在 170 到 270 之间。所以我通过除以 2 将这个 Hue 范围缩放到 OpenCV,得到 85-135。
现在,我从网站
的预览中截取了以下颜色[H=216, S=96, V=67]
的屏幕截图
然后我 运行 我 phone 上的应用程序并从笔记本电脑屏幕上捕获了以下相机画面。 我了解到HSV通道值与网站上的值会有一定程度的差异,因为在我拍摄相机画面时房间内还有其他条件,例如额外的光线(HSV中的V)等
然后我通过Imgproc.cvtColor(rgbaFrame, hsvImage, Imgproc.COLOR_RGB2HSV_FULL);
将这个Mat
转换为HSV颜色space,结果如下图。
然后我调用了inRange
函数:
Core.inRange(hsvImage, new Scalar(85, 50, 40), new Scalar(135, 255, 255), maskedImage);
这导致了以下蒙版图像。
问题是,当我真的包含所有可能的蓝色色调范围时,为什么它没有检测到蓝色?
重要提示:除了第一张原图,所有图片都使用Highgui.imwrite
功能存储在sdcard中,这样我就可以将它们移动到我的电脑上,以便将它们上传到 Whosebug。您一定已经注意到,第一个原始屏幕截图中的蓝色在第二个图像中转换为红色。原因是相机拍摄的帧(即移动phone相机拍摄的第一个屏幕截图photo/frame)是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);
我使用了这个输入图像(以 BGR 格式保存和加载,尽管它实际上是 RGB 图像,这就是为什么我们必须使用 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);
给出这个结果:
任何想要使用 "right" 图片进行测试的人:
这是转换为 BGR 的输入:如果您想直接使用它,则必须将转换从 RGB2HSV 切换为 BGR2HSV。但我认为最好也显示输入的 BGR 版本...
在网站 colorizer.org 上,它们的 HSV 范围为 H=0-360,S=0-100,V=0-100。我们也知道 OpenCV 中的 HSV 范围是 H=0-180, S=0-255, V=0-255.
我想 select 任何(我们认为的)蓝色阴影的范围,所以我查看了 colorizer.org,发现蓝色色调的范围大致在 170 到 270 之间。所以我通过除以 2 将这个 Hue 范围缩放到 OpenCV,得到 85-135。
现在,我从网站
的预览中截取了以下颜色[H=216, S=96, V=67]
的屏幕截图
然后我 运行 我 phone 上的应用程序并从笔记本电脑屏幕上捕获了以下相机画面。 我了解到HSV通道值与网站上的值会有一定程度的差异,因为在我拍摄相机画面时房间内还有其他条件,例如额外的光线(HSV中的V)等
然后我通过Imgproc.cvtColor(rgbaFrame, hsvImage, Imgproc.COLOR_RGB2HSV_FULL);
将这个Mat
转换为HSV颜色space,结果如下图。
然后我调用了inRange
函数:
Core.inRange(hsvImage, new Scalar(85, 50, 40), new Scalar(135, 255, 255), maskedImage);
这导致了以下蒙版图像。
问题是,当我真的包含所有可能的蓝色色调范围时,为什么它没有检测到蓝色?
重要提示:除了第一张原图,所有图片都使用Highgui.imwrite
功能存储在sdcard中,这样我就可以将它们移动到我的电脑上,以便将它们上传到 Whosebug。您一定已经注意到,第一个原始屏幕截图中的蓝色在第二个图像中转换为红色。原因是相机拍摄的帧(即移动phone相机拍摄的第一个屏幕截图photo/frame)是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);
我使用了这个输入图像(以 BGR 格式保存和加载,尽管它实际上是 RGB 图像,这就是为什么我们必须使用 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);
给出这个结果:
任何想要使用 "right" 图片进行测试的人:
这是转换为 BGR 的输入:如果您想直接使用它,则必须将转换从 RGB2HSV 切换为 BGR2HSV。但我认为最好也显示输入的 BGR 版本...