PPC的C/C++和人工智能学习笔记
每一篇学习笔记,都只是为了更好地掌握和理解

数字图像处理与opencv(18)-霍夫变换直线检测和圆检测

本次学习:openCV的霍夫变换以及使用它进行直线检测和圆检测。

霍夫(Hough)变换是图像处理中从图像识别几何形状的基本方法之一,霍夫变换寻找直线和圆的方法,有非常好的抗噪声干扰能力。经典的霍夫变换常用来检测直线,圆,椭圆等等。

Hough变换的基本原理在于利用点与线的对偶性,将原始图像空间的给定曲线通过曲线表达形式变为参数空间的一个点。这样就把原始图像给定曲线的检测问题,转化为检测参数空间的峰值问题。也就是把检测整体特性转化为检测局部特性。比如直线,椭圆,圆,弧线等。

Hough变换的基本思想

设已知一黑白图像上画了一条直线,要求出这条直线所在的位置。我们知道,直线的方程可以用y=k*x+b 来表示,其中k和b是参数,分别是斜率和截距。也就是说,我们将原始图像需要检测的直线,表示成y = k*x + b, 只要找出唯一的k,b即可检测出该直线。该直线在原始图中是一系列离散点的集合,过该直线上某一点(x0,y0)的所有直线的参数都会满足方程y0=kx0+b。即点(x0,y0)确定了一族直线。而方程y0=kx0+b在参数k–b平面上是一条直线,(你也可以是方程b=-x0*k+y0对应的直线).即点(x0,y0)在参数空间确定了一条直线。这样,图像x–y平面上的一个前景像素点就对应到参数平面上的一条直线。因此,图像x-y内需检测直线上的N个点,在参数平面会有N条直线。而图像x-y内的直线有唯一一个k,b,因此,相应的参数平面N条直线必然有唯一一个交点。我们举个例子说明解决前面那个问题的原理。设图像上的直线是y=x, 我们先取上面的三个点:A(0,0), B(1,1), C(22)。可以求出,过A点的直线的参数要满足方程b=0, 过B点的直线的参数要满足方程1=k+b, 过C点的直线的参数要满足方程2=2k+b, 这三个方程就对应着参数平面上的三条直线,而这三条直线会相交于一点(k=1,b=0)。 同理,原图像上直线y=x上的其它点(如(3,3),(4,4)等) 对应参数平面上的直线也会通过点(k=1,b=0)。这个性质就为我们解决问题提供了方法,就是把图像平面上的点对应到参数平面上的线,最后通过统计特性来解决问题。假如图像平面上有两条直线,那么最终在参数平面上就会看到两个峰值点,依此类推。

简而言之,Hough变换思想为:在原始图像坐标系下的一个点对应了参数坐标系中的一条直线,同样参数坐标系的一条直线对应了原始坐标系下的一个点,然后,原始坐标系下呈现直线的所有点,它们的斜率和截距是相同的,所以它们在参数坐标系下对应于同一个点。这样在将原始坐标系下的各个点投影到参数坐标系下之后,看参数坐标系下有没有聚集点,这样的聚集点就对应了原始坐标系下的直线。

在实际应用中,y=k*x+b形式的直线方程没有办法表示x=c形式的直线(这时候,直线的斜率为无穷大)。所以实际应用中,利用极坐标的方式,将直线方程表示成:ρ=x*cos(ξ)+y*sin(ξ)。其中ρ表示直角坐标系中原点到直线的距离,ξ表示x轴与直线法线的夹角,取逆时针方向。这样,图像平面上的一个点就对应到ρ-ξ平面上的一条曲线上,其它的还是一样。

在实现的图像处理领域,图像的像素坐标P(x, y)是已知的,而ρ,ξ 则是我们要寻找的变量。如果我们能根据像素点坐标P(x, y)值绘制每个(ρ,ξ)值的话,那么就从图像笛卡尔坐标系统转换到极坐标霍夫空间系统,这种从点到曲线的变换称为直线的霍夫变换。变换通过量化霍夫参数空间为有限个值间隔等分或者累加格子。当霍夫变换算法开始,每个像素坐标点P(x, y)被转换到(r, theta)的曲线点上面,累加到对应的格子数据点,当一个波峰出现时候,说明有直线存在。同样的原理,我们可以用来检测圆,只是对于圆的参数方程变为如下等式:

(x -a ) ^2 + (y-b) ^ 2 = r^2其中(a, b)为圆的中心点坐标,r圆的半径。这样霍夫的参数空间就变成一个三维参数空间。给定圆半径转为二维霍夫参数空间,变换相对简单,也比较常用。

 

Hough变换推广

1、已知半径的圆

其实Hough变换可以检测任意的已知表达形式的曲线,关键是看其参数空间的选择,参数空间的选择可以根据它的表达形式而定。比如圆的表达形式为,所以当检测某一半径的圆的时候,可以选择与原图像空间同样的空间作为参数空间。那么圆图像空间中的一个圆对应了参数空间中的一个点,参数空间中的一个点对应了图像空间中的一个圆,圆图像空间中在同一个圆上的点,它们的参数相同即a,b相同,那么它们在参数空间中的对应的圆就会过同一个点(a,b),所以,将原图像空间中的所有点变换到参数空间后,根据参数空间中点的聚集程度就可以判断出图像空间中有没有近似于圆的图形。如果有的话,这个参数就是圆的参数。

2、未知半径的圆

对于圆的半径未知的情况下,可以看作是有三个参数的圆的检测,中心和半径。这个时候原理仍然相同,只是参数空间的维数升高,计算量增大。图像空间中的任意一个点都对应了参数空间中的一簇圆曲线。,其实是一个圆锥型。参数空间中的任意一个点对应了图像空间中的一个圆。

3、椭圆

椭圆有5个自由参数,所以它的参数空间是5维的,因此他的计算量非常大,所以提出了许多的改进算法。

 

Hough变换总结

图像空间中的在同一个圆,直线,椭圆上的点,每一个点都对应了参数空间中的一个图形,在图像空间中这些点都满足它们的方程这一个条件,所以这些点,每个投影后得到的图像都会经过这个参数空间中的点。也就是在参数空间中它们会相交于一点。所以,当参数空间中的这个相交点的越大的话,那么说明元图像空间中满足这个参数的图形越饱满。越象我们要检测的东西。

Hough变换能够查找任意的曲线,只要你给定它的方程。Hough变换在检验已知形状的目标方面具有受曲线间断影响小和不受图形旋转的影响的优点,即使目标有稍许缺损或污染也能被正确识别。

 

OpenCV中的霍夫线变换有如下三种:

<1> 标准霍夫变换(StandardHough Transform,SHT),由HoughLines函数调用。

<2> 多尺度霍夫变换(Multi-ScaleHough Transform,MSHT),由HoughLines函数调用。

<3> 累计概率霍夫变换(ProgressiveProbabilistic Hough Transform,PPHT),由HoughLinesP函数调用。

 

HoughLines函数:

void HoughLines( InputArray image, OutputArray lines,

double rho, double theta, int threshold,

double srn = 0, double stn = 0,

double min_theta = 0, double max_theta = CV_PI );

 

参数:lines 输出的极坐标来表示直线

double rho 像素扫描步长,一般为1像素

double theta 角度步长,一般为CV_PI/180

int threshold 阈值,需要大于该值(交点数)

double srn 是否应用多尺度霍夫变换?

Double stn 是否应用多尺度霍夫变换?

此函数一般情况是有经验的开发者使用,需要自己反变换到平面空间。使用例子,lines里面存的是r和theta:

for (size_t i = 0; i < lines.size(); i++)
{
float rho = lines[i][0], theta = lines[i][1];
Point 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(dstImage, pt1, pt2, Scalar(55, 100, 195), 1, CV_AA);
}

HoughLinesP函数,常用这个

void HoughLinesP( InputArray image, OutputArray lines,

double rho, double theta, int threshold,

double minLineLength = 0, double maxLineGap = 0 );

参数:lines 输出的极坐标来表示直线

double rho 像素扫描步长,一般为1像素

double theta 角度步长,一般为CV_PI/180

int threshold 阈值,需要大于该值(交点数)

double minLineLength 最小直线长度

double maxKuneGap 最大间隔,小于此间隔认为同一条直线

 

vector<Vec4f> plines;

for (int i = 0; i < plines.size(); i++) {

//直线起点: Point(plines[i][0], plines[i][1])

//直线终点: Point(plines[i][2], plines[i][3]) }

//霍夫变换_直线检测
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main() {
 Mat src, gray_src;
 src = imread("2.jpg");
 if (src.empty()) return -1;
 Canny(~src, gray_src, 60, 130);
 //cvtColor(~src, gray_src, CV_BGR2GRAY);
 threshold(gray_src, gray_src, 0, 255, THRESH_BINARY | THRESH_OTSU);
 imshow("Canny", gray_src);
 vector<Vec4f> plines;
 HoughLinesP(gray_src, plines, 1, CV_PI / 180.0, 20, 10, 5); //交点数阈值,最短,间隙
 cout << plines.size() << endl;
 Mat dst;
 cvtColor(gray_src, dst, CV_GRAY2BGR);
 for (int i = 0; i < plines.size(); i++) {
 cout << "(" << plines[i][0] << "," << plines[i][1] << ")-->(" 
 << plines[i][2] << "," << plines[i][3] << ")" << endl;
 line(dst, Point(plines[i][0], plines[i][1]), 
 Point(plines[i][2], plines[i][3]), Scalar(0, 0, 255), 1, 8);
 }
 imshow("dst", dst);
 waitKey(0);
 return 0;
}

霍夫变换-圆检测:

霍夫变换圆检测对噪声比较敏感,一般先对图像做中值滤波。

基于效率考虑,openCV中实现的霍夫变换圆检测是基于图像的梯度实现,分为两步:第一步是检测边缘,发现可能的圆心。第二步是从候选圆心开始计算最佳半径大小。

HoughCircles函数:

void HoughCircles( InputArray image, OutputArray circles,

int method, double dp, double minDist,

double param1 = 100, double param2 = 100,

int minRadius = 0, int maxRadius = 0 );

参数:int method 方法,HOUGH_GRADIENT 基于梯度

double dp ,1表示原图上找,2表示在缩小1倍的图上找

double minDist,一般选10啥的,最短距离可以分辨两个圆的,否则认为同心圆

double param1,Canny边缘检测的 低阈值参数

double param2,中心点累加器阈值(交叉点的数量)

int minRadius ,最小半径

int maxRadius ,最大半径

 

//霍夫变换--圆检测

#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;

int main() {
 Mat src = imread("3.jpg");
 //if (!src.data) return -1;
 //imshow("src", src);
 Mat dst;
 //先中值滤波
 medianBlur(src, dst, 3);
 //转灰度图
 cvtColor(dst, dst, CV_BGR2GRAY);
 //霍夫变换
 vector<Vec3f> pcircles;
 HoughCircles(dst, pcircles, HOUGH_GRADIENT, 1, 10, 100, 40, 5, 50);
 printf("%d\n", pcircles.size());
 for (size_t i=0; i < pcircles.size(); ++i) {
 Vec3f cc = pcircles[i];
 circle(src, Point(cc[0], cc[1]), cc[2], Scalar(0, 0, 255),2,8);
 circle(src, Point(cc[0], cc[1]), 2, Scalar(244, 100, 255), 2, 8); //画出圆心
 }
 imshow("src", src);
 waitKey(0);
 return 0;
}

(2017-03-28 www.vsppc.com)

学习笔记未经允许不得转载:PPC的C/C++和人工智能学习笔记 » 数字图像处理与opencv(18)-霍夫变换直线检测和圆检测

分享到:更多 ()

评论 4

评论前必须登录!