为什么 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 版本...