2012-04-30 133 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以及)