0

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

enter image description here

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.

enter image description here

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

enter image description here

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.

enter image description here

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.

Solace
  • 8,612
  • 22
  • 95
  • 183
  • 4
    is not your photo red and black.. where is the blue ? – Humam Helfawi Dec 10 '15 at 11:18
  • @HumamHelfawi The original photo is blue and black, it was in my computer. See the first image. This is the photo. I opened it in Windows Photo Viewer on my computer, and captured it using my phone (on which the Android app was running). The captured photo is the second image- I had stored it in my sdcard by `Highgui.imwrite("/mnt/sdcard/DCIM/rgbaFrameCaptured.jpg", rgbaFrameCaptured);// check`. Blue appears red in it. Plus, you see that whitish background, it was the surrounding space around the photo opened in Windows Photo Viewer. – Solace Dec 10 '15 at 12:04
  • @HumamHelfawi Please ignore the conversion of blue to red in the second image, because RGBA is converted to BGR when we store an image, and I had stored it in sdcard so that I could transfer it to my laptop in order to upload on SO. The image is actually RGBA (I know this because this camera frame is returned by the rgba() function of OpenCVCameraViewBridge class, and according the documentation returns an rgba image) – Solace Dec 10 '15 at 12:29
  • 1
    OK in final you mean the red color I see is in real a blue one. ok, first may just try to catch the red color instead of blue. if it was catched correctly. then your problem is simply between bgr and rgb. if not, we may try to find sth else. good luck – Humam Helfawi Dec 10 '15 at 12:35
  • @HumamHelfawi OK, doing it. – Solace Dec 10 '15 at 13:09
  • 1
    I don't know what's the difference between RGB2HSV and RGB2HSV_FULL. Loading your image and converting to HSV_FULL doesn't work for me, but converting to HSV does work! Please try `Imgproc.cvtColor(rgbaFrame, hsvImage, Imgproc.COLOR_RGB2HSV);` instead – Micka Dec 10 '15 at 13:17
  • 1
    ok... COLOR_RGB2HSV_FULL means that values aren't divided by 2 but by `1.41176470588` to use the whole 256 values of one byte instead of only the values from 0 to 180 – Micka Dec 10 '15 at 13:20
  • @HumamHelfawi For red, I first checked for the range `(0, 50, 40)`-`(10, 255, 255)`, and it didn't work, nothing was found in that range. But then I checked for the range `(165, 50, 40)`-`(180, 255, 255)` (because red occurs at the start as well as at the end of the spectrum - 2 different ranges), and well yes, it found out a part of the image. The average HSV value of that blob (calculated by a piece of code in the program) is `(4, 255, 234)`. This means the frame shown in the 2nd image in the question was BGR. – Solace Dec 10 '15 at 13:22
  • 1
    yes then you should change your HSV converter if it was BGR2HSV put it RGB2HSV and if the opposite do the opposite :D and try to find blue – Humam Helfawi Dec 10 '15 at 13:23
  • @HumamHelfawi wait, I had checked the hue range of 0-10 for an original red image, and it was detected successfully. That had reinforced in my mind that the image is RGBA. I am trying it again. – Solace Dec 10 '15 at 13:26
  • 1
    @HumamHelfawi he posted the original image (file) from some website in advance, which is blue. After that he shot a photo from the screen, saved it to file and posted it in the question. That photo now shows a red color, because (probably) the photo was in RGB(A) format but saving it interpreted it as BGR(A). So in fact he wants to detect blue color, but the image is interpreted wrong during reading. BUT: as he uses `RGB2HSV_FULL` conversion, he fixes that "problem", so in his code he has to search for blue hue values. The problem is that he's looking for wrong hue values because of `_FULL` – Micka Dec 10 '15 at 13:30
  • @HumamHelfawi See! I just tested with a plane red original image and did the `inRange` between `(0, 50, 40) and (10, 255, 255)`. Yes it turned out to be blue when I saved the frame into SD card, but `inRange` did this entire red (original) image with that range, and then the code which calculates the _average_ HSV of the detected color-blob found the HSV to be `(164, 221, 255)`. If the image is really BGR, then why does it correctly find a red image with the hue range 0-10? – Solace Dec 10 '15 at 13:37
  • 2
    @Solace you may see Micka comment and answer. he has a good point that I missed. I could not totalt pass throw his though but it seems logical – Humam Helfawi Dec 10 '15 at 13:38

1 Answers1

2

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):

enter image description here

resulting in this mask:

enter image description here

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:

enter image description here

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...

enter image description here

Micka
  • 19,585
  • 4
  • 56
  • 74
  • 1
    I can't thank you enough for the explanatory answers to my question yesterday and today. Thank you so very much, God bless you =) – Solace Dec 10 '15 at 15:45