【问题标题】:Using inRange() in OpenCV to detect colors in a range在 OpenCV 中使用 inRange() 检测范围内的颜色
【发布时间】:2017-10-14 09:08:33
【问题描述】:

我正在使用 OpenCV 编写一个用于月球陨石坑检测的 C++ 程序,它似乎只能准确地检测到一小部分陨石坑。我对这种方法的策略是首先将图像转换为 HSV,然后使用 inRange() 捕捉一系列值中的颜色以产生阈值,然后对其进行高斯模糊并使用 HoughCircles() 检测圆圈。

我不完全理解的一件事是,当我给 inRange() 一个颜色的低阈值和高阈值时,它根本不会返回任何东西。只是一个黑色的图像。它仅在我将低阈值设置为 Scalar(0,0,0) 时才有效,但我相信这使它有些不准确。有什么我不明白的吗?我的测试图如下。

月球表面

这是我用来测试这张图片的代码:

#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;
}

【问题讨论】:

  • 我假设您尝试使用(28,50,100) 的下限和(7, 216, 213) 的上限调用inRange?该文档非常清楚该功能的作用。在这种情况下,对于通道 0,您正在计算 28 &lt;= x &lt;= 7 的结果,这永远不会是真的。由于单个通道的所有结果都经过 AND 运算,因此总体结果也永远不会为真。阅读文档!
  • @DanMašek 不,这不正确,我没有尝试调用它。这只是我针对 (0,0,0) 的下限测试的几个 上限 的未标记注释。是的,我彻底审查了文档,这是我做的第一件事。
  • 那么,不工作的部分是什么?我的意思是该函数只有一个调用,根据您所写的“它仅在我将低阈值设置为Scalar(0,0,0) 时才有效”。此外,如果 cmets 不相关,则不要在问题中显示它们(删除不相关的垃圾需要几秒钟)。
  • @DanMašek 正如我在问题中提到的“当我给 inRange() 一个颜色周围的低阈值和高阈值时,它根本不会返回任何东西。只是一个黑色图像”所以要详细说明我将举一个例子。假设我的 RGB 颜色为 (66,53,10),当我在两个边界上使用 inRange 时(假设 (13,206,56) 到 (33,226, 76)围绕该颜色,它只是返回一个黑色图像,就好像它没有找到任何颜色一样。我这样做是否正确?即使我进一步打开边界,它似乎也不起作用。
  • @shakked :D 在 Stack Overflow 上多花点时间,如果你仍然持有这种观点,请告诉我。恕我直言,opencv 标签本身就是相反的充分证据。

标签: c++ opencv feature-detection hough-transform


【解决方案1】:

这是我的尝试:

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;
}

与您的代码的主要区别在于我不使用HoughCircles。我不确定它是否会产生良好的效果,因为陨石坑没有完美的圆形。相反,我使用findContours 来环绕陨石坑。这是我的结果: 希望对您有所帮助!

【讨论】:

  • 哇,这真是一个很棒的解决方案。我有点意识到 HoughCircles 对这个应用程序的限制,但我不知道你的 findContours 解决方案!非常感谢你的帮忙!另外,我不知道以这种方式组合两个阈值是可能的。感谢您的帮助,这很棒。
猜你喜欢
  • 2014-02-27
  • 2018-06-15
  • 2018-08-17
  • 1970-01-01
  • 2014-06-19
  • 2012-11-11
  • 2019-02-04
  • 2012-06-12
相关资源
最近更新 更多