Using inRange() in OpenCV to detect colors in a range

元气小坏坏 提交于 2021-02-06 12:54:31

问题


I'm writing a C++ program with OpenCV for lunar crater detection which seems to detect only a small fraction of craters accurately. My strategy for this approach was to first convert the image to HSV, then use inRange() to catch the colors in a range of values to produce a threshold, then Gaussian blur it and use HoughCircles() to detect the circles.

One thing that I am not fully understanding is that when I give inRange() a low and high threshold around a color, it simply does not return anything. Just a black image. It only works when I set the low threshold to Scalar(0,0,0) however I believe this makes it somewhat inaccurate. Is there something I am not understanding about this? My test image is below.

Lunar Surface

This is the code that I used to test this image:

#include <cstdio>
#include <iostream>

#include "opencv2/core/core.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/features2d/features2d.hpp"

using namespace std;
using namespace cv;

int main(int argc, char** argv) {
    // using namespace cv;

    printf("%s\n", argv[1]);
    Mat src=imread(argv[1]);

    if (!src.data) {
        std::cout << "ERROR:\topening image" <<std::endl;
        return -1;
    }

    // converts the image to hsv so that circle detection is more accurate
    Mat hsv_image;
    cvtColor(src, hsv_image, COLOR_BGR2HSV);
    // high contrast black and white
    Mat imgThreshold;
    inRange(hsv_image,
        Scalar(0, 0, 0),
        Scalar(48, 207, 74),
        imgThreshold);

    // Applies a gaussian blur to the image
    GaussianBlur( imgThreshold, imgThreshold, Size(9, 9), 2, 2 );
    // fastNlMeansDenoisingColored(imgThreshold, imgThreshold, 10, 10, 7, 21);

    vector<Vec3f> circles;
    // applies a hough transform to the image
    HoughCircles(imgThreshold, circles, CV_HOUGH_GRADIENT,
        2, // accumulator resolution (size of image / 2)
        100, //minimum dist between two circles
        400, // Canny high threshold
        10, // minimum number of votes
        10, 65); // min and max radius

    cout << circles.size() << endl;
    cout << "end of test" << endl;

    vector<Vec3f>::
          const_iterator itc = circles.begin();
    // Draws the circles on the source image
    while (itc!=circles.end()) {

        circle(src, // src_gray2
            Point((*itc)[0], (*itc)[1]), // circle center
            (*itc)[2],       // circle radius
            Scalar(0,0,255), // color
            5);              // thickness

        ++itc;
    }
    namedWindow("Threshold",CV_WINDOW_AUTOSIZE);
    resize(imgThreshold, imgThreshold, Size(src.cols/2,src.rows/2) ); // resizes it so it fits on our screen
    imshow("Threshold",imgThreshold); // displays the source iamge

    namedWindow("HSV Color Space",CV_WINDOW_AUTOSIZE);
    resize(hsv_image, hsv_image, Size(src.cols/2,src.rows/2) ); // resizes it so it fits on our screen
    imshow("HSV Color Space",hsv_image); // displays the source iamge

    namedWindow("Source Image",CV_WINDOW_AUTOSIZE);
    resize(src, src, Size(src.cols/2,src.rows/2) ); // resizes it so it fits on our screen
    imshow("Source Image",src); // displays the source iamge

    waitKey(0);
    return 0;
}

回答1:


Here is my try:

int main(int argc, char** argv)
{
    Mat src;
    src = imread("craters1.jpg", 1);
    cvtColor(src, hsv_image, COLOR_BGR2HSV);

    Mat imgThreshold1, imgThreshold2, imgThreshold;
    inRange(hsv_image,
        Scalar(0, 0, 0),
        Scalar(48, 207, 74),
        imgThreshold1);

    inRange(hsv_image,
        Scalar(140, 0, 0),
        Scalar(180, 207, 114),
        imgThreshold2);

    imgThreshold = max(imgThreshold1, imgThreshold2); // combining the two thresholds

    Mat element_erode = getStructuringElement(MORPH_ELLIPSE, Size(5, 5));
    Mat element_dilate = getStructuringElement(MORPH_ELLIPSE, Size(10, 10));
    /// Apply the erosion and dilation operations
    erode(imgThreshold, imgThreshold, element_erode);
    dilate(imgThreshold, imgThreshold, element_dilate);

    GaussianBlur(imgThreshold, imgThreshold, Size(9, 9), 2, 2);

    vector<vector<Point> > contours;
    vector<Vec4i> hierarchy;
    /// Find contours
    findContours(imgThreshold, contours, hierarchy, CV_RETR_TREE, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

    for (int i = 0; i < contours.size(); i++)
    {
        drawContours(src, contours, i, Scalar(0,0,255), 2, 8, hierarchy, 0, Point());
    }

    namedWindow("Display Image", WINDOW_AUTOSIZE);
    imshow("Display Image", imgThreshold);
    imshow("Final result", src);

    waitKey(0);

    return 0;
}

The main difference with your code is that I don't use HoughCircles. I'm not sure it will give good results as craters don't have a perfect circular shape. Instead, I used findContours to circle the craters. Here is the result I have: Hope it helps!



来源:https://stackoverflow.com/questions/43981903/using-inrange-in-opencv-to-detect-colors-in-a-range

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!