当我将蓝色的整个色相范围都赋予蓝色时,为什么inRange函数无法检测到蓝色? [英] Why isn't inRange function detecting blue color when I have given it the entire possible Hue range for the blue color?

查看:362
本文介绍了当我将蓝色的整个色相范围都赋予蓝色时,为什么inRange函数无法检测到蓝色?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在网站 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,发现蓝色的色相大约在170到270之间.因此我将此色相范围缩放到了OpenCV.除以2,得出85-135.

现在,我从网站上的预览中截取了以下颜色[H=216, S=96, V=67]的屏幕截图

然后,我在手机上运行该应用程序,并从笔记本电脑屏幕上捕获了以下相机镜框. 我了解HSV频道值会与网站上的值有所不同,这是因为在捕获摄像头帧时,还存在其他条件,例如房间中的其他光线(HSV中的V)等.

然后我通过Imgproc.cvtColor(rgbaFrame, hsvImage, Imgproc.COLOR_RGB2HSV_FULL);将此Mat转换为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而不是CV_RGB2HSV

中的0 .. 180

我可以通过使用以下部分代码来验证这一点:

    // 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版本...

On the website colorizer.org, they have an HSV range of H=0-360, S=0-100, V=0-100. We are also aware that the HSV range in OpenCV is H=0-180, S=0-255, V=0-255.

I wanted to select a range for any shade of (what we perceive as) blue color, so I looked at colorizer.org, and saw that blue Hue ranges roughly from 170 to 270. So I scaled this Hue range to OpenCV by dividing by 2, which gives 85-135.

Now, I took the following screenshot of color [H=216, S=96, V=67] from the preview at the website

Then I run the app on my phone and captured the following camera frame from the laptop screen. I understand that the HSV channel values will differ from those in website to some extent because there are other conditions like additional light (V in HSV) in the room when I captured the camera frame, etc.

Then I converted this Mat to HSV color space by Imgproc.cvtColor(rgbaFrame, hsvImage, Imgproc.COLOR_RGB2HSV_FULL);, which resulted in the following image.

Then I called the inRange function:

Core.inRange(hsvImage, new Scalar(85, 50, 40), new Scalar(135, 255, 255), maskedImage);

which resulted in the following maskedImage.

The question is that why isn't it detecting the blue color when I have included all the Hue Range possible for blue color really?


IMPORTANT: Except the first original image, all the images were stored in sdcard using Highgui.imwrite function, so that I could move them to my computer in order to upload them on Stackoverflow. You must have noticed that the blue color in the first original screenshot is converted to red color in the second image. The reason is that the frame captured by the camera (that is the photo/frame of the first screenshot captured by the mobile phone camera) is an RGBA image. But OpenCV converts all images to BRG by default when it saves them to sdcard of something. So be assured that the original image is RGBA, and it is only converted to BGR internally by OpenCV for saving into sdcard. That's why red appears blue.

解决方案

using this code does work for me (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);

I used this input image (saved and loaded in BGR format although it in fact is a RGB image, that's why we have to use RGB2HSV instead of BGR2HSV):

resulting in this mask:

The difference to your code is that I used CV_RGB2HSV instead of CV_RGB2HSV_FULL. Flag CV_RGB2HSV_FULL uses the whole byte to store the hue values, so range 0 .. 360 degrees will be scaled to 0 .. 255 instead of 0 .. 180 as in CV_RGB2HSV

I could verify this by using this part of the code:

    // 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);

giving this result:

For anyone who wants to test with the "right" image:

Here's the input converted to BGR: If you want to use that directly you have to switch conversion from RGB2HSV to BGR2HSV. But I thought it would be better to show the BGR version of the input, too...

这篇关于当我将蓝色的整个色相范围都赋予蓝色时,为什么inRange函数无法检测到蓝色?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆