opencv 霍夫线变换
2015-07-31 20:09
507 查看
霍夫线变换
霍夫线变换是一种用来寻找直线的方法.是用霍夫线变换之前, 首先要对图像进行边缘检测的处理,也即霍夫线变换的直接输入只能是边缘二值图像.
它是如何实现的?
众所周知, 一条直线在图像二维空间可由两个变量表示. 例如:在 笛卡尔坐标系: 可由参数:
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/1881b126c9a42331f05b6b61e650a11fba03e74d.png)
斜率和截距表示.
在 极坐标系: 可由参数:
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/f07080129914ac008f0eb45ed5f7efa28bb1e7c6.png)
极径和极角表示
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/Hough_Lines_Tutorial_Theory_0.jpg)
对于霍夫变换, 我们将用 极坐标系 来表示直线. 因此, 直线的表达式可为:
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/3050cf05bd6f4d9b2623357fb1cc399905d75943.png)
化简得:
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/0fcd77fdfa1c3bb6a179aa0d02ea617e870ec3c4.png)
一般来说对于点
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/25e3648ce4903aa24b129162eeaec2330fed4645.png)
,
我们可以将通过这个点的一族直线统一定义为:
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/3af8e1a6da7bbaddb157c6371676051128164089.png)
这就意味着每一对
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/79ac4156f482a4985cfc0438daa976270cc86d83.png)
代表一条通过点
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/25e3648ce4903aa24b129162eeaec2330fed4645.png)
的直线.
如果对于一个给定点
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/25e3648ce4903aa24b129162eeaec2330fed4645.png)
我们在极坐标对极径极角平面绘出所有通过它的直线,
将得到一条正弦曲线. 例如, 对于给定点
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/2cf5e45d33850ec55abfe091b5d189c439a99832.png)
and
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/b5614ac3d2973e0d94e4bcac101d80c7dacf01eb.png)
我们可以绘出下图
(在平面
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/52e8ed7a3ba22130ad3984eb2cd413406475a689.png)
-
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/b55ca7a0aa88ab7d58f4fc035317fdac39b17861.png)
):
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/Hough_Lines_Tutorial_Theory_1.jpg)
只绘出满足下列条件的点
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/22ff7db3e755a8164f2344e0d3d84ea3a0fe93b3.png)
and
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/99a1c7ae0e28e6ab32a11edc1d4d9be3da55c91e.png)
.
我们可以对图像中所有的点进行上述操作. 如果两个不同点进行上述操作后得到的曲线在平面
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/52e8ed7a3ba22130ad3984eb2cd413406475a689.png)
-
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/b55ca7a0aa88ab7d58f4fc035317fdac39b17861.png)
相交,
这就意味着它们通过同一条直线. 例如, 接上面的例子我们继续对点:
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/d5e243dd84f48f005022ca6db06ebbd5df8e14ca.png)
,
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/0fd43a421096cc99759477319d149c08aac343fd.png)
和点
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/a1256f1b04a9895e2f28f40f08eb5eed5f670f27.png)
,
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/f09a7f1a339c6cd9ccd3bc1b8d8bf1b79a257910.png)
绘图,
得到下图:
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/Hough_Lines_Tutorial_Theory_2.jpg)
这三条曲线在
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/52e8ed7a3ba22130ad3984eb2cd413406475a689.png)
-
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/b55ca7a0aa88ab7d58f4fc035317fdac39b17861.png)
平面相交于点
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/ee5ec5d602f8544803b6e1164d66bf0a434691dd.png)
,
坐标表示的是参数对 (
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/41c5151da6eb0499332d0b45df78e63788aa845e.png)
) 或者是说点
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/25e3648ce4903aa24b129162eeaec2330fed4645.png)
,
点
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/76859fcc37c8dd5e7f3f5b2a070a0c269a285690.png)
和点
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/f806732d21b52d738268efd8c8de5e8c1c648e86.png)
组成的平面内的的直线.
那么以上的材料要说明什么呢? 这意味着一般来说, 一条直线能够通过在平面
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/52e8ed7a3ba22130ad3984eb2cd413406475a689.png)
-
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/b55ca7a0aa88ab7d58f4fc035317fdac39b17861.png)
寻找交于一点的曲线数量来 检测.
越多曲线交于一点也就意味着这个交点表示的直线由更多的点组成. 一般来说我们可以通过设置直线上点的 阈值 来定义多少条曲线交于一点我们才认为 检测 到了一条直线.
这就是霍夫线变换要做的. 它追踪图像中每个点对应曲线间的交点. 如果交于一点的曲线的数量超过了 阈值, 那么可以认为这个交点所代表的参数对
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/7e065ce45efb160a92773b6c4aad65a309d7535e.png)
在原图像中为一条直线.
标准霍夫线变换和统计概率霍夫线变换
OpenCV实现了以下两种霍夫线变换:标准霍夫线变换
原理在上面的部分已经说明了. 它能给我们提供一组参数对
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/7e065ce45efb160a92773b6c4aad65a309d7535e.png)
的集合来表示检测到的直线
在OpenCV 中通过函数 HoughLines 来实现
统计概率霍夫线变换
这是执行起来效率更高的霍夫线变换. 它输出检测到的直线的端点
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/20eb30037d99342a5887bea2a086e1b39e78904a.png)
在OpenCV 中它通过函数 HoughLinesP 来实现
代码
这个程序是用来做什么的?加载一幅图片
对图片进行 标准霍夫线变换 或是 统计概率霍夫线变换.
分别在两个窗口显示原图像和绘出检测到直线的图像.
我们将要说明的例程能从 这里 下载。
一个更高级的版本 (能同时演示标准霍夫线变换和统计概率霍夫线变换并带有活动条来改变变换的阈值) 能从 这里 下载。
#include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> using namespace cv; using namespace std; void help() { cout << "\nThis program demonstrates line finding with the Hough transform.\n" "Usage:\n" "./houghlines <image_name>, Default is pic1.jpg\n" << endl; } int main(int argc, char** argv) { const char* filename = argc >= 2 ? argv[1] : "pic1.jpg"; Mat src = imread(filename, 0); if(src.empty()) { help(); cout << "can not open " << filename << endl; return -1; } Mat dst, cdst; Canny(src, dst, 50, 200, 3); cvtColor(dst, cdst, CV_GRAY2BGR); #if 0 vector<Vec2f> lines; HoughLines(dst, 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( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA); } #else vector<Vec4i> lines; HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 ); for( size_t i = 0; i < lines.size(); i++ ) { Vec4i l = lines[i]; line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, CV_AA); } #endif imshow("source", src); imshow("detected lines", cdst); waitKey(); return 0; }
代码说明
加载图片Mat src = imread(filename, 0); if(src.empty()) { help(); cout << "can not open " << filename << endl; return -1; }
用Canny算子对图像进行边缘检测
Canny(src, dst, 50, 200, 3);
现在我们将要执行霍夫线变换. 我们将会说明怎样使用OpenCV的函数做到这一点:
标准霍夫线变换
首先, 你要执行变换:
vector<Vec2f> lines; HoughLines(dst, lines, 1, CV_PI/180, 100, 0, 0 );
带有以下自变量:
dst: 边缘检测的输出图像. 它应该是个灰度图 (但事实上是个二值化图)
lines: 储存着检测到的直线的参数对
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/f07080129914ac008f0eb45ed5f7efa28bb1e7c6.png)
的容器
* rho : 参数极径
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/b55ca7a0aa88ab7d58f4fc035317fdac39b17861.png)
以像素值为单位的分辨率. 我们使用 1 像素.
theta: 参数极角
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/52e8ed7a3ba22130ad3984eb2cd413406475a689.png)
以弧度为单位的分辨率.
我们使用 1度 (即CV_PI/180)
threshold: 要”检测” 一条直线所需最少的的曲线交点
srn and stn: 参数默认为0. 查缺OpenCV参考文献来获取更多信息.
通过画出检测到的直线来显示结果.
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( cdst, pt1, pt2, Scalar(0,0,255), 3, CV_AA); }
统计概率霍夫线变换
首先, 你要执行变换:
vector<Vec4i> lines; HoughLinesP(dst, lines, 1, CV_PI/180, 50, 50, 10 );
带有以下自变量:
dst: 边缘检测的输出图像. 它应该是个灰度图 (但事实上是个二值化图) * lines: 储存着检测到的直线的参数对
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/baee84de274f174bbcc7d67e86f0dea7b49a0af9.png)
的容器
rho : 参数极径
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/b55ca7a0aa88ab7d58f4fc035317fdac39b17861.png)
以像素值为单位的分辨率.
我们使用 1 像素.
theta: 参数极角
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/math/52e8ed7a3ba22130ad3984eb2cd413406475a689.png)
以弧度为单位的分辨率.
我们使用 1度 (即CV_PI/180)
threshold: 要”检测” 一条直线所需最少的的曲线交点 * minLinLength: 能组成一条直线的最少点的数量. 点数量不足的直线将被抛弃.
maxLineGap: 能被认为在一条直线上的亮点的最大距离.
通过画出检测到的直线来显示结果.
for( size_t i = 0; i < lines.size(); i++ ) { Vec4i l = lines[i]; line( cdst, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(0,0,255), 3, CV_AA); }
显示原始图像和检测到的直线:
imshow("source", src); imshow("detected lines", cdst);
等待用户按键推出程序
waitKey();
结果¶
Note得到的结果使用的是在上面 代码 部分提到的更高级版代码. 霍夫线变换的代码没有改变, 唯一不同的是在GUI的部分加入了活动条可动态改变阈值.输入图像为:
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/Hough_Lines_Tutorial_Original_Image.jpg)
通过执行统计概率霍夫线变换我们能得到下面的结果:
![](http://www.opencv.org.cn/opencvdoc/2.3.2/html/_images/Hough_Lines_Tutorial_Result.jpg)
当你使用滑动条来改变 阈值 的时候会观察到检测到线的数目的改变. 这是因为: 如果你设置了一个更大的阈值, 能检测到的线的数目将更少 (你需要更多的点来表示一条能检测到的直线).
相关文章推荐
- opencv copyto函数
- linux如何设置静态ip
- 转)Linux学习路线
- OpenCV函数 Canny 检测边缘
- OpenCV函数 Laplacian 算子实现
- opencv sobel导数
- opencv图像边界的填充
- opencv 线性滤波器
- linux服务器可以ping通,但是访问不了--Ip地址:端口--
- centos 使用nslookup命令问题
- iOS视频网站
- HLS视频协议第一弹--centos下面配置ffmpeg,segmenter以适应hls切片需要
- opencv 图像阈值分割图像
- opencv图像金字塔
- OpenSSL命令行工具的证书操作
- opencv 其他形态学变换
- centos ffmpeg m3u8切片相关
- linux下清空文件内容
- opencv 图像的腐蚀与膨胀
- 《汇编语言》第二版 王爽著 第五章 [BX]和loop指令 要点