Trying to detect blue color from image using opencv, and getting unexpected result

痞子三分冷 提交于 2019-11-28 11:46:41

There are multiple traps in converting an image to HSV color space and using HSV color space.

  1. OpenCV uses a compressed hue range because original, hue ranges from 0 to 360 which means that the values can't fit in 1 byte (values 0 to 255) while saturation and value channels are exactly covered by 1 byte. Therefore, OpenCV uses hue values divided by 2. So the hue channel will be covered by matrix entries between 0 and 180. Regarding this, your hue range from 170 to 270 should be divided by 2 = range 65 to 135 in OpenCV.

  2. hue tells you about the color tone, but saturation and value are still important to reduce noise, so set your threshold to some minimum saturation and value, too

  3. very important: OpenCV uses BGR memory ordering for rendering and image saving. This means that if your image has RGB(a) ordering and you save it without color conversion, you swap R and B channels, so assumed red color will become blue etc. Unfortunately normally you can't read from the image data itself, whether it is RGB or BGR ordered, so you should try to find it out from the image source. OpenCV allows several flags to convert either from RGB(A) to HSV and/or from BGR(A) to HSV, and/or from RGB to BGR etc, so that is no problem, as long as you know which memory format your image uses. However, displaying and saving always assumes BGR ordering, so if you want to display or save the image, convert it to BGR! HSV values however will be the same, no matter whether you convert a BGR image with BGR2HSV or whether you convert a RGB image with RGB2HSV. But it will have wrong values if you convert a BGR image with RGB2HSV or a RGB image with BGR2HSV... I'm not 100% sure about Java/Python/Android APIs of openCV, but your image really looks like B and R channels are swapped or misinterpreted (but since you use RGBA2HSV conversion that's no problem for the hsv colors).

about your contour extraction, there is a tiny (copy paste?) bug in your code that everyone might observe once in a while:

MatOfPoint largestContour = contours.get(0);
    double largestContourArea = Imgproc.contourArea(largestContour);
    for ( int i=1; i<contours.size(); ++i) {//NB Notice the prefix increment.
        // HERE you had MatOfPoint currentContour = contours.get(0); so you tested the first contour in each iteration
        MatOfPoint currentContour = contours.get(i);
        double currentContourArea = Imgproc.contourArea(currentContour);
        if (currentContourArea > largestContourArea) {
            largestContourArea = currentContourArea;
            largestContour = currentContour;
        }
    }

so probably just this has to be changed to use i instead of 0 in the loop

MatOfPoint currentContour = contours.get(i);

Probably the range you are using is wrong for blue, In OpenCV the hue range is from 0-180 and you have given it's 170-270. Find the correct hue value for blue and use in inRange.

  1. http://answers.opencv.org/question/30547/need-to-know-the-hsv-value/#30564
  2. http://answers.opencv.org/question/28899/correct-hsv-inrange-values-for-red-objects/#28901

You can refer the answer here for choosing correct hsv value.

Below is the code for segmenting red color, check it with your code, and make sure it segmenting red object.

    Imgproc.cvtColor(rgbaFrame, hsv, Imgproc.COLOR_RGB2HSV,4); // Convert to hsv for color segmentation.      
    Core.inRange(hsv,new Scalar(0,50,40,0), new Scalar(10,255,255,0),thr);//upper red range of hue cylinder 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!