什么是霍夫变换?
霍夫变化是从图像中识别几何形状的基本图像处理方法之一,应用广泛。霍夫变换用来检测图像中的直线,其原理是利用坐标空间变换将两个坐标进行相应的转换,或通过直线映射到另一坐标空间的点形成的峰值。从而把检测任意形状的问题转化为统计峰值的问题。它的优点在于分割结果的鲁棒性,它的缺点是要求知道物体边界线的解析方程。
霍夫变化的原理
以直线检测为例,每个像素坐标点经过空间变换都编程对直线特质有贡献的统一度量。
对于二维图像数据 f(x,y),平面坐标为 (x,y),极坐标为 (r,θ)。从坐标轴可看出公式:xcosθ+ysinθ=r
对于图像像素平面坐标 (x,y),我们需要做的就是通过空间坐标映射关系,将图像笛卡尔坐标系转换到极坐标霍夫空间系统,这种点到曲线的映射变换称为霍夫变换。
霍夫线变化
在许多实际的图像处理应用中,我们可以检测图像中的轮廓部分或图形,直线检测有利于分析图像中的角度及其结构特征。
霍夫线变化是基于图像二值化的变换,利用二值化图像中的点集来确定候选直线的集合。在图像的边缘,可以用方程 f(x,p) = 0 来表示任意的曲线,其中p为曲线的参数向量,那么利用霍夫变换进行线检测算法的步骤如下:
在参数 p 的范围内量化参数空间,将霍夫空间坐标 (r,θ) 初始化为 0。
在阈值化后的梯度图像中,对每个图像点 (i,j) 进行遍历,对于满足参数 p,加权累计所有满足 f(x,p) = 0 的单位 S§,则 S§ = S§ + delta§。
计算当前霍夫空间的累计数组 S§ 的局部最大值,那么对应的就是原始图像中 f(x,p) = 0 的解析实现。
OpenCv 算法并没有直接将曲线提取出来,而是返回相应的**(r,θ)平面的局部最大值**,因此要对OpenCV中的函数参数接口进一步理解分析。
标准的霍夫变换(SHT)
参考代码:
void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength = 0, double maxLineGap = 0)
其中,image 代表输入图像,lines代表输出线向量,每个向量由四个元素 (x1, y1, x2, y2)组成,(x1, y1)和(x2, y2)为线段的终点坐标,rho代表累计像素的距离分辨率,theta代表累计弧度的角度分辨率,ehreshold代表要检测一条直线所需最少的曲线交点,minLineLength代表最小的线长度,maxLineGap代表最大的长度,用于线段连接。
#include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc_c.h> #include <opencv2/imgproc/types_c.h> #include<opencv2/imgproc.hpp> #include<iostream> using namespace std; using namespace cv; int main() { cv::Mat srcImage = cv::imread("...cc.png", 0); if (!srcImage.data) return 1; cv::Mat edgeMat, houghMat; // Canny 边缘检测 二值图像 Canny(srcImage, edgeMat, 50, 180, 3); cvtColor(edgeMat, houghMat, CV_GRAY2BGR); // 标准的霍夫变换 vector<Vec2f> lines; HoughLines(edgeMat, lines, 1, CV_PI / 180, 100, 0, 0); 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(houghMat, pt1, pt2, Scalar(0, 0, 255), 3, CV_AA); } cv::imshow("srcImage", srcImage); cv::imshow("houghMat", houghMat); cv::waitKey(); cv::waitKey(0); return 0; }
多尺度霍夫变化(MHT)
void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, double minLineLength = 0, double maxLineGap = 0)
其中,image 代表输入图像,lines代表输出线向量,每个向量由两个元素 (,θ)组成,(x1, y1)和(x2, y2)为线段的终点坐标,rho代表累计像素的距离分辨率,theta代表累计弧度的角度分辨率,ehreshold代表要检测一条直线所需最少的曲线交点,minLineLength代表最小的线长度,maxLineGap代表最大的长度,用于线段连接。
#include<opencv2/core/core.hpp> #include<opencv2/highgui/highgui.hpp> #include<opencv2/imgproc/imgproc_c.h> #include <opencv2/imgproc/types_c.h> #include<opencv2/imgproc.hpp> #include<iostream> using namespace std; using namespace cv; int main() { cv::Mat srcImage = cv::imread("...cc.png", 0); if (!srcImage.data) return 1; cv::Mat edgeMat, houghMat; // Canny 边缘检测 二值图像 Canny(srcImage, edgeMat, 50, 180, 3); cvtColor(edgeMat, houghMat, CV_GRAY2BGR); // 统计概率的霍夫变换 vector<Vec4i> lines; HoughLinesP(edgeMat, lines, 1, CV_PI / 180, 50, 50, 10); for (size_t i = 0; i < lines.size(); i++) { Vec4i l = lines[i]; // 绘制线检测结果 line(houghMat, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0, 0, 255), 3, CV_AA); } cv::imshow("srcImage", srcImage); cv::imshow("houghMat", houghMat); cv::waitKey(); cv::waitKey(0); return 0; }