霍夫变换(Hough Transform)是图像处理中的一种特征提取技术,该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状的集合作为霍夫变换结果。霍夫变换于1962年由Paul Hough 首次提出,后于1972年由Richard Duda和Peter Hart推广使用,经典霍夫变换用来检测图像中的直线,后来霍夫变换扩展到任意形状物体的识别,多为圆和椭圆。
霍夫变换运用两个坐标空间之间的变换将在一个空间中具有相同形状的曲线或直线映射到另一个坐标空间的一个点上形成峰值,从而把检测任意形状的问题转化为统计峰值问题。
一条直线在直角坐标系下可以用y=kx+b表示, 霍夫变换的主要思想是将该方程的参数和变量交换,即b=-kx+y。图像空间中所有经过y=kx+b的点经过Hough变换后在参数空间都会相交于点(k,b),如图一。通过Hough变换,就可以将图像空间中直线的检测转化为参数空间中对点的检测。
图一
为了计算方便我们改写成极坐标形式,因为同一条直线上的点对应的(r,θ)是相同的。
对于原图内任一点(x,y)都可以在参数空间形成一条直线,所有属于同一条直线上的点会在参数空间交于一点,该点即为对应直线的参数。一般来说, 一条直线能够通过在平面θ-r寻找交于一点的曲线数量来检测. 越多曲线交于一点也就意味着这个交点表示的直线由更多的点组成. 一般来说我们可以通过设置直线上点的阈值来定义多少条曲线交于一点我们才认为检测到了一条直线。这就是霍夫线变换要做的. 它追踪图像中每个点对应曲线间的交点. 如果交于一点的曲线的数量超过了阈值, 那么可以认为这个交点所代表的参数对(θ,r)在原图像中为一条直线。
opencv中的hough变换有三种:
- 标准霍夫变换(StandardHough Transform,SHT)由HoughLines函数调用。
- 多尺度霍夫变换(Multi-ScaleHough Transform,MSHT)也是由HoughLines函数调用。
- 累计概率霍夫变换(ProgressiveProbabilistic Hough Transform,PPHT),由HoughLinesP函数调用。
<pre name="code" class="plain"><pre name="code" class="plain">// Hough_Tran.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include "opencv2/imgproc/imgproc.hpp"
using namespace cv;
using namespace std;
int _tmain(int argc, _TCHAR* argv[])
{
const char* imagename = "23.png";
//从文件中读入图像
Mat src = imread(imagename);
//如果读入图像失败
if(src.empty())
{
fprintf(stderr, "Can not load image %s\n", imagename);
return -1;
}
namedWindow("Source", CV_WINDOW_AUTOSIZE);
imshow("Source", src);
Mat img;
cvtColor(src, img, CV_RGB2GRAY);
GaussianBlur(img, img, Size(3,3), 0, 0);
Canny(img, img, 50, 200, 3);
namedWindow("Canny", CV_WINDOW_AUTOSIZE);
imshow("Canny", img);
vector<Vec2f> lines;
HoughLines(img, lines, 1, CV_PI/180, 150,0,0); // 返回直线坐标对
for (size_t i=0; i<lines.size(); i++) {
float rho = lines[i][0];
float theta = lines[i][1];
Point pt1,pt2;
double a=cos(theta);
double b=sin(theta);
double x0 = rho*a;
double y0 = rho*b;
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(src, pt1, pt2, Scalar(0,255,0), 1, CV_AA);
}
namedWindow("Hough", 1);
imshow("Hough", src);
waitKey();
return 0;
}
效果图: