2012-04-30 372 views
2

我試圖找到中心框的邊緣在該圖像中: black and white boxOpenCV的直線檢測

我已經使用利用dRho = img_width/1000,dTheta = PI/180,和閾值= 250 HoughLines試圖 它在這個圖像很好,縮放到1/3的大小,但在全尺寸圖像上,它只是在每個方向上到處都有線...

我該怎麼做才能調整這個更準確?

回答

5

的代碼實現下面的結果是這個答案提出的一個輕微的修改:how to detect a square

enter image description here

原來的程序可以在裏面OpenCV的發現,這就是所謂的squares.cpp。下面的代碼被修改爲僅在第一個色彩平面上搜索正方形,但由於它仍然檢測到許多正方形,所以在程序結束時我會丟棄除第一個之外的所有正方形,然後致電draw_squares()以顯示檢測到的內容。你可以改變這個easilly來繪製所有這些,並查看檢測到的所有內容。

你可以做各種事情,從現在的自己,包括設定關心區域(ROI)來提取的正方形內的區域(忽略一切圍繞它)。

您可以看到檢測到的矩形與圖像中的線條不完全對齊。您應該在圖像中執行一些預處理(侵蝕?)操作,以減少線條粗細並改進檢測。但是從這裏開始,這一切都在你身上:

#include <cv.h> 
#include <highgui.h> 

using namespace cv; 

double angle(cv::Point pt1, cv::Point pt2, cv::Point pt0) { 
    double dx1 = pt1.x - pt0.x; 
    double dy1 = pt1.y - pt0.y; 
    double dx2 = pt2.x - pt0.x; 
    double dy2 = pt2.y - pt0.y; 
    return (dx1*dx2 + dy1*dy2)/sqrt((dx1*dx1 + dy1*dy1)*(dx2*dx2 + dy2*dy2) + 1e-10); 
} 

void find_squares(Mat& image, vector<vector<Point> >& squares) 
{ 
    // TODO: pre-processing 

    // blur will enhance edge detection 
    Mat blurred(image); 
    medianBlur(image, blurred, 9); 

    Mat gray0(blurred.size(), CV_8U), gray; 
    vector<vector<Point> > contours; 

    // find squares in the first color plane. 
    for (int c = 0; c < 1; c++) 
    { 
     int ch[] = {c, 0}; 
     mixChannels(&blurred, 1, &gray0, 1, ch, 1); 

     // try several threshold levels 
     const int threshold_level = 2; 
     for (int l = 0; l < threshold_level; l++) 
     { 
      // Use Canny instead of zero threshold level! 
      // Canny helps to catch squares with gradient shading 
      if (l == 0) 
      { 
       Canny(gray0, gray, 10, 20, 3); // 

       // Dilate helps to remove potential holes between edge segments 
       dilate(gray, gray, Mat(), Point(-1,-1)); 
      } 
      else 
      { 
        gray = gray0 >= (l+1) * 255/threshold_level; 
      } 

      // Find contours and store them in a list 
      findContours(gray, contours, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE); 

      // Test contours 
      vector<Point> approx; 
      for (size_t i = 0; i < contours.size(); i++) 
      { 
        // approximate contour with accuracy proportional 
        // to the contour perimeter 
        approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true)*0.02, true); 

        // Note: absolute value of an area is used because 
        // area may be positive or negative - in accordance with the 
        // contour orientation 
        if (approx.size() == 4 && 
          fabs(contourArea(Mat(approx))) > 1000 && 
          isContourConvex(Mat(approx))) 
        { 
          double maxCosine = 0; 

          for (int j = 2; j < 5; j++) 
          { 
            double cosine = fabs(angle(approx[j%4], approx[j-2], approx[j-1])); 
            maxCosine = MAX(maxCosine, cosine); 
          } 

          if (maxCosine < 0.3) 
            squares.push_back(approx); 
        } 
      } 
     } 
    } 
} 

void draw_squares(Mat& img, vector<vector<Point> > squares) 
{ 
    for (int i = 0; i < squares.size(); i++) 
    { 
     for (int j = 0; j < squares[i].size(); j++) 
     { 
      cv::line(img, squares[i][j], squares[i][(j+1) % 4], cv::Scalar(0, 255, 0), 1, CV_AA); 
     } 
    } 
} 


int main(int argc, char* argv[]) 
{ 
    Mat img = imread(argv[1]); 

    vector<vector<Point> > squares; 
    find_squares(img, squares); 

    std::cout << "* " << squares.size() << " squares were found." << std::endl; 

    // Ignore all the detected squares and draw just the first found 
    vector<vector<Point> > tmp; 
    if (squares.size() > 0) 
    { 
     tmp.push_back(squares[0]); 
     draw_squares(img, tmp); 
    } 
    //imshow("squares", img); 
    //cvWaitKey(0); 

    imwrite("out.png", img); 

    return 0; 
} 
+0

你能告訴我如何訪問我們確定的正方形長度嗎? –

+0

問問自己什麼是正方形的長度,然後注意到一個正方形被定義爲一組4個點(座標)。上面的代碼給出了你的觀點,但是計算表明它的長度取決於你寫的東西。 – karlphillip

3

嘗試使用腐蝕過濾器進行預處理。它會給你減小尺寸的效果 - 線條會變得更細,並且不會同時消失。正如chaiy所說,「模糊」過濾器也是一個好主意。

這樣(與模糊),它會成爲(變換基於內核的霍夫)類似http://www.ic.uff.br/~laffernandes/projects/kht/index.html

3

調整大小圖像時,該圖像通常首先用濾波器模糊,例如高斯,以擺脫高頻。調整其中一個更好的事實可能是因爲你的原始圖像有點嘈雜。

嘗試先模糊圖像,例如與cv::GaussianBlur(src, target, Size(0,0), 1.5),那麼它應該等同於調整大小。 (它忘了理論,如果它不工作,嘗試3和6以及)