OpenCV核心模块核心提炼(五) —— 线条检测:Hough线变换

  1. 如您所知,图像空间中的一条线可以用两个变量表示。例如:

    1. 笛卡尔坐标系中: 参数:(M,B)
    2. 极坐标系中:参数:(R,\ THETA)
    线变量

    对于霍夫变换,我们将在极地系统中表达线条。因此,线方程可以写成:

    y = \ left( -  \ dfrac {\ cos \ theta} {\ sin \ theta} \ right)x + \ left(\ dfrac {r} {\ sin \ theta} \ right)

安排条款: r = x \ cos \ theta + y \ sin \ theta

  1. 通常对于每个点(x_ {0},y_ {0}),我们可以定义经过该点的行族:

    r _ {\ theta} = x_ {0} \ cdot \ cos \ theta + y_ {0} \ cdot \ sin \ theta

    意味着每对(R _ {\ THETA},\ THETA)代表经过的每一条线(x_ {0},y_ {0})

  2. 如果对于给定的(x_ {0},y_ {0})我们绘制经过它的线族,我们得到一个正弦曲线。例如,对于x_ {0} = 8y_ {0} = 6我们得到如下图(在一个平面上\ THETA[R):

    一个点的线族的极地情节

    我们只考虑这样的点r> 00 <\ theta <2 \ pi

  3. 我们可以对图像中的所有点执行相同的操作。如果两个不同点的曲线在平面中相交\ THETA[R这意味着两个点都属于同一条线。举例来说,上面的例子以下和绘图积两分以上:x_ {1} = 4y_ {1} = 9x_ {2} = 12y_ {2} = 3我们得到:

    极点情节系列为三点

    所述三条曲线相交在一个单点(0.925,9.6),这些坐标是参数(\ theta,r)或线,其中(x_ {0},y_ {0})(x_ {1},y_ {1})(x_ {2},y_ {2})铺设。

  4. 上面的所有东西意味着什么?这意味着通常可以通过查找曲线之间的交叉点数来检测线。交叉的曲线越多意味着该交点所代表的线具有更多的点。通常,我们可以定义检测线所需的最小交叉点数量的阈值

  5. 这就是霍夫线变换所做的。它跟踪图像中每个点的曲线之间的交点。如果交叉点的数量高于某个阈值,则它将其声明为具有(\ theta,r _ {\ theta})交叉点参数的线。

标准和概率Hough线变换

OpenCV实现了两种Hough Line变换:

  1. 标准霍夫变换
  • 它包含了我们刚才在前一节中解释过的内容。它为您提供了一对夫妇的矢量(\ theta,r _ {\ theta})
  • 在OpenCV中,它使用函数HoughLines实现
  1. 概率Hough线变换
  • Hough Line变换的更有效实现。它将检测到的线的极值作为输出(x_ {0},y_ {0},x_ {1},y_ {1})
  • 在OpenCV中,它使用函数HoughLinesP实现

代码

  1. 这个程序做什么用的?
    • 加载图像
    • 应用标准Hough线变换概率线变换
    • 在两个窗口中显示原始图像和检测到的线条。
  2. 我们将解释的示例代码可以从这里下载 。可以在此处找到稍微更漂亮的版本(显示Hough标准和带轨迹栏的概率以更改阈值) 。
#include  “opencv2 / highgui / highgui.hpp”
#include  “opencv2 / imgproc / imgproc.hpp”

#include  

使用 命名空间 cv ; 
using  namespace  std ;

void  help ()
{ 
 cout  <<  \ n 此程序演示使用Hough变换进行寻线。\ n 
         “用法:\ n 
         “./houghlines ,默认为pic1.jpg \ n  <<  endl ; 
}

int  main int  argc , char **  argv )
{ 
 const  char *  filename  =  argc  > =  2   argv [ 1 ]   “pic1.jpg” ;

 Mat  src  =  imread (filename , 0 ); 
 如果(SRC 。空())
 { 
     帮助(); 
     cout  <<  “无法打开”  <<  filename  <<  endl ; 
     返回 - 1 ; 
 }

 Mat  dst , cdst ; 
 Canny算子(SRC , DST , 50 200 3 ); 
 cvtColor (dst , cdst , CV_GRAY2BGR );

 #if 0
  vector 行; 
  HoughLines(dst,lines,1,CV_PI / 180,100,0,0);

  for(size_t i = 0; i 
  { 
     float rho = lines [i] [0],theta = lines [i] [1]; 
     点pt1,pt2; 
     double a = cos(theta),b = sin(theta); 
     double x0 = a * rho,y0 = b * rho; 
     pt1.x = cvRound(x0 + 1000 *( -  b)); 
     pt1.y = cvRound(y0 + 1000 *(a)); 
     pt2.x = cvRound(x0  -  1000 *( -  b)); 
     pt2.y = cvRound(y0  -  1000 *(a)); 
     line(cdst,pt1,pt2,Scalar(0,0,255),3,CV_AA); 
  } 
#else 
  vector < Vec4i >  行; 
  HoughLinesP (dst , lines , 1 , CV_PI / 180 50 50 10  ); 
  为size_t =  0 ;  我 <  线。大小();  我++  )
  { 
    Vec4i  升 =  线[ 我]; 
    line ( cdst , Point (l [ 0 ], l [ 1 ]), Point (l [ 2 ], l [ 3 ]), Scalar (00 255 ), 3 , CV_AA ); 
  } 
 #endif 
 imshow (“source” , src ); 
 imshow (“检测到的行” , cdst );

 waitKey ();

 返回 0 ; 
}

说明

  1. 加载图像

    Mat  src  =  imread (filename , 0 ); 
    如果(SRC 。空())
    { 
      帮助(); 
      cout  <<  “无法打开”  <<  filename  <<  endl ; 
      返回 - 1 ; 
    }
    
  2. 使用Canny检测器检测图像的边缘

    Canny算子(SRC , DST , 50 200 3 );
    

    现在我们将应用霍夫线变换。我们将解释如何使用可用于此目的的两个OpenCV函数:

  3. 标准霍夫线变换

    1. 首先,您应用变换:

      vector < Vec2f >  行; 
      HoughLines (DST , 线, 1 , CV_PI / 180 100 0 0  );
      

      使用以下参数:

      • dst:边缘检测器的输出。它应该是灰度图像(虽然实际上它是二进制图像)
      • lines:一个向量,用于存储(R,\ THETA)检测到的行的参数
      • rho:参数的分辨率,[R以像素为单位。我们使用1个像素。
      • theta\ THETA以弧度表示的参数分辨率。我们使用1度(CV_PI / 180)
      • 阈值:“ 检测 ”线的最小交叉点数
      • srnstn:默认参数为零。查看OpenCV参考以获取更多信息。
    2. 然后通过绘制线条显示结果。

      为size_t =  0 ;  我 <  线。大小();  我++  )
      { 
        浮子 RHO  =  线[ 我] [ 0 ], THETA  =  线[ 我] [ 1 ]; 
        点 pt1 , pt2 ; 
        double  a  =  cos (theta ), b  =  sin (theta ); 
        double  x0  =  a* rho , y0  =  b * rho ; 
        pt1 。x  =  cvRound (x0  +  1000 * - b )); 
        pt1 。y  =  cvRound (y0  +  1000 * (a )); 
        pt2 。x  =  cvRound (x0  -  1000 * - b )); 
        pt2 。y  =  cvRound (y0 -  1000 * (a )); 
        线( cdst , PT1 , PT2 , 标量(0 0 255 ), 3 , CV_AA ); 
      }
      
  4. 概率Hough线变换

    1. 首先应用转换:

      vector < Vec4i >  行; 
      HoughLinesP (DST , 线, 1 , CV_PI / 180 50 50 10  );
      

      与参数:

      • dst:边缘检测器的输出。它应该是灰度图像(虽然实际上它是二进制图像)
      • lines:一个向量,用于存储(x_ {start},y_ {start},x_ {end},y_ {end})检测到的行的参数
      • rho:参数的分辨率,[R以像素为单位。我们使用1个像素。
      • theta\ THETA以弧度表示的参数分辨率。我们使用1度(CV_PI / 180)
      • 阈值:“ 检测 ”线的最小交叉点数
      • minLinLength:可以形成一条线的最小点数。忽略少于此点数的行。
      • maxLineGap:在同一行中考虑的两点之间的最大间隙。
    2. 然后通过绘制线条显示结果。

      为size_t =  0 ;  我 <  线。大小();  我++  )
      { 
        Vec4i  升 =  线[ 我]; 
        线( cdst , 点(升[ 0 ], 升[ 1 ]), 点(升[ 2 ], 升[ 3 ]), 标量(0 0 255 ), 3, CV_AA ); 
      }
      
  5. 显示原始图像和检测到的线条:

    imshow (“source” , src ); 
    imshow (“检测到的行” , cdst );
    
  6. 等到用户退出程序

    waitKey ();
    

结果

注意

 

下面的结果是使用我们在“ 规范”部分中提到的略微更加漂亮的版本获得的。它仍然实现与上面相同的内容,只为阈值添加了Trackbar。

使用输入图像,例如:

OpenCV核心模块核心提炼(五) —— 线条检测:Hough线变换_第1张图片

我们通过使用概率Hough线变换得到以下结果:

OpenCV核心模块核心提炼(五) —— 线条检测:Hough线变换_第2张图片

 

你可能感兴趣的:(计算机视觉,计算机视觉)