2017-05-15 23 views
2

私は、月のクレーター検出のためのOpenCVを使ってC++プログラムを作成しています。このアプローチの私の戦略は、最初に画像をHSVに変換した後、inRange()を使用して値の範囲内の色をキャッチして閾値を生成し、それをぼかしてHoughCircles()を使用して円を検出します。OpenCVのinRange()を使用して範囲内の色を検出する

私が完全に理解していないことの1つは、inRange()に色の周りの低いしきい値と高いしきい値を指定すると、何も返されないということです。ちょうど黒いイメージ。これは、低しきい値をScalar(0,0,0)に設定した場合にのみ機能しますが、これはやや不正確と思われます。私はこれについて理解していない何かがありますか?私のテストイメージは以下の通りです。

月面enter image description here

これは私がこのイメージをテストするために使用されるコードである:ここでは

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

['inRange'](http://docs.opencv.org/2.4/modules/core/doc/operations_on_arrays.html#inrange)を'(28,50,100) 'の下限で呼び出すとします。 '(7,216,213)'の上限は?ドキュメントは、関数が何をしているかについてはっきりしています。この場合、チャネル0の場合、 '28 <= x <= 7'の結果を計算します。これは決して真実ではありません。個々のチャンネルのすべての結果と一緒にANDした結果、全体的な結果も決して真実ではありません。ドキュメントを読む! –

+0

@DanMašekそれは正しくない、私はそれを呼び出すことを試みなかった。これは、(0,0,0)の下限に対してテストしたいくつかの_upper bounds_のラベルのないコメントでした。はい、私は徹底的にドキュメントをレビューしました。これが私が最初にやったことでした。 –

+0

それでは、動作しない部分は何ですか?私は、その関数への呼び出しが1つだけで、あなたが書いたことに応じて「Scalar(0,0,0)に低しきい値を設定すると動作します。また、コメントが関係ない場合は、質問に表示しないでください(無関係のジャンクを削除するのに数秒かかる)。 –

答えて

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を使ってクレーターを丸くしました。ここに私が持っている結果です: crater detection result それは助けてくれることを願っています!

+1

Oh wowこれは本当に素晴らしい解決策です。私はこのアプリケーションにHoughCirclesの限界を幾分認識していましたが、私はあなたのfindContoursソリューションについて知らなかったのです!だからこそありがとう!また、私はそれが2つの閾値を組み合わせることが可能であることを知らなかった。これが素晴らしいことを助けてくれてありがとう。 –

関連する問題