OpenCV探索之路(七):霍夫变换

我们如何在图像中快速识别出其中的圆和直线?一个非常有效的方法就是霍夫变换,它是图像中识别各种几何形状的基本算法之一。

霍夫线变换

霍夫线变换是一种在图像中寻找直线的方法。OpenCV中支持三种霍夫线变换,分别是标准霍夫线变换、多尺度霍夫线变换、累计概率霍夫线变换。

在OpenCV中可以调用函数HoughLines来调用标准霍夫线变换和多尺度霍夫线变换。HoughLinesP函数用于调用累积概率霍夫线变换。

我们都知道,二维坐标轴上表示一条直线的方程式y = a*x + b,我们想求出一条直线就得想方设法求出其中的a和b的值。如果用极坐标来表示就是

theta就是直线与水平线所成的角度,而rho就是圆的半径(也可以理解为原点到直线的距离),同样地,这两个参数也是表征一条直线的重要参数,确定他们俩了,也就确定一条直线了。正如下图所示。

在OpenCV里,我们只需调用HoughLines就是可以得到表征一条直线的这两个参数值!

HoughLines用法

#include <iostream>
#include <opencv2\opencv.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
    Mat srcImage = imread("4.jpg");
    imshow("Src Pic", srcImage);

    Mat midImage, dstImage;
    //边缘检测
    Canny(srcImage, midImage, 50, 200, 3);
    //灰度化
    cvtColor(midImage, dstImage, CV_GRAY2BGR);
    // 定义矢量结构存放检测出来的直线
    vector<Vec2f> lines;
    //通过这个函数,我们就可以得到检测出来的直线集合了
    HoughLines(midImage, lines, 1, CV_PI / 180, 150, 0, 0);
    //这里注意第五个参数,表示阈值,阈值越大,表明检测的越精准,速度越快,得到的直线越少(得到的直线都是很有把握的直线)
    //这里得到的lines是包含rho和theta的,而不包括直线上的点,所以下面需要根据得到的rho和theta来建立一条直线

    //依次画出每条线段
    for (size_t i = 0; i < lines.size(); i++)
    {
        float rho = lines[i][0]; //就是圆的半径r
        float 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, LINE_AA); //Scalar函数用于调节线段颜色,就是你想检测到的线段显示的是什么颜色

        imshow("边缘检测后的图", midImage);
        imshow("最终效果图", dstImage);
    }
    waitKey();
    return 0;
}

原图

阈值我设为250,看看直线检测的效果。你会发现,怎么图中一些很明显的的直线都没检测出来啊?原因是,我们阈值写的有点高了,只有那些有足够的把握认为是直线的直线才可能检测出来。

然后我把阈值改为150,直线检测效果就变成这样子了。显然多了很多直线,这是我们把我们的要求降低了,把那些“可能是直线”的直线都当做是直线了。所以,阈值的选择很重要,就看你是要精确查找还是模糊查找了。

后来我又加了一句打印进去,想看看角度的单位是什么

    cout << "line " << i << ": " << "rho:" << rho << " theta:" << theta << endl;

可以看到,角度theta用的单位不是我们所说的度数(70度、80度),而是数学上的π/2,π/3。

要想转为我们所说的度数,自己写个转换吧

float angle = theta / CV_PI * 180;

可以看出,转换后的角度范围就是我们想要的度数!值得注意的是,rho表示离坐标原点(就是图片左上角的点)的距离,theta是直线的旋转角度(0度表示垂直线,90度表示水平线)。

HoughLinesP用法

此函数在HoughLines的基础上在末尾加了一个代表Probabilistic(概率)的P,表明使用的是累计概率变换。

#include <iostream>
#include <opencv2\opencv.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
    Mat srcImage = imread("2.jpg");
    imshow("Src Pic", srcImage);

    Mat midImage, dstImage;

    Canny(srcImage, midImage, 50, 200, 3);
    cvtColor(midImage, dstImage, CV_GRAY2BGR);

    vector<Vec4i> lines;
    //与HoughLines不同的是,HoughLinesP得到lines的是含有直线上点的坐标的,所以下面进行划线时就不再需要自己求出两个点来确定唯一的直线了
    HoughLinesP(midImage, lines, 1, CV_PI / 180, 80, 50, 10);//注意第五个参数,为阈值

    //依次画出每条线段
    for (size_t i = 0; i < lines.size(); i++)
    {
        Vec4i l = lines[i];

        line(dstImage, Point(l[0], l[1]), Point(l[2], l[3]), Scalar(186, 88, 255), 1, LINE_AA); //Scalar函数用于调节线段颜色

        imshow("边缘检测后的图", midImage);
        imshow("最终效果图", dstImage);
    }
    waitKey();
    return 0;
}

貌似效果还不错。

霍夫圆变换

刚刚的霍夫变换是检测直线的,如果我们想检测圆形,那该怎么办?那就用霍夫圆变换!用法也大同小异。

#include <iostream>
#include <opencv2\opencv.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
    Mat srcImage = imread("test5.jpg");
    Mat midImage, dstImage;//临时变量和目标图的定义  

    imshow("【原始图】", srcImage);

    //【3】转为灰度图,进行图像平滑
    cvtColor(srcImage, midImage, CV_BGR2GRAY);//转化边缘检测后的图为灰度图
    GaussianBlur(midImage, midImage, Size(9, 9), 2, 2);

    //【4】进行霍夫圆变换
    vector<Vec3f> circles;
    HoughCircles(midImage, circles, CV_HOUGH_GRADIENT, 1.5, 10, 200, 150, 0, 0); //注意第七的参数为阈值,可以自行调整,值越大,检测的圆更精准

    //【5】依次在图中绘制出圆
    for (size_t i = 0; i < circles.size(); i++)
    {
        Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
        int radius = cvRound(circles[i][2]);
        //绘制圆心
        circle(srcImage, center, 3, Scalar(0, 255, 0), -1, 8, 0);
        //绘制圆轮廓
        circle(srcImage, center, radius, Scalar(155, 50, 255), 3, 8, 0);
    }

    //【6】显示效果图
    imshow("【效果图】", srcImage);

    waitKey(0);

    return 0;
}

可以看到,有一些圆没有检测出来,同时还有一些不是圆形的确有误以为是圆形了,说明阈值选择不是很妥当。

另外提一点,霍夫圆变换的检测速度真的慢,显然进行圆检测的计算量还真不少!

时间: 2024-11-05 04:15:49

OpenCV探索之路(七):霍夫变换的相关文章

20、【opencv入门】霍夫变换:霍夫线变换,霍夫圆变换合辑

一.引言 在图像处理和计算机视觉领域中,如何从当前的图像中提取所需要的特征信息是图像识别的关键所在.在许多应用场合中需要快速准确地检测出直线或者圆.其中一种非常有效的解决问题的方法是霍夫(Hough)变换,其为图像处理中从图像中识别几何形状的基本方法之一,应用很广泛,也有很多改进算法.最基本的霍夫变换是从黑白图像中检测直线(线段). 二.霍夫变换概述 霍夫变换(Hough Transform)是图像处理中的一种特征提取技术,该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合该特定形状

OpenCV探索之路(十六):图像矫正技术深入探讨

刚进入实验室导师就交给我一个任务,就是让我设计算法给图像进行矫正.哎呀,我不太会图像这块啊,不过还是接下来了,硬着头皮开干吧! 那什么是图像的矫正呢?举个例子就好明白了. 我的好朋友小明给我拍了这几张照片,因为他的拍照技术不咋地,照片都拍得歪歪扭扭的,比如下面这些照片: 人民币 发票 文本 这些图片让人看得真不舒服!看个图片还要歪脖子看,实在是太烦人了!我叫小明帮我扫描一下一本教科书,小明把每一页书都拍成上面的文本那样了.好气啊那该怎么办呢?一页一页用PS来处理?1000页的矫正啊,当然交给计算

opencv学习笔记霍夫变换——直线检测

参考大佬博文:blog.csdn.net/jia20003/article/details/7724530 lps-683.iteye.com/blog/2254368 openCV里有两个函数(比较常用)处理霍夫变换直线检测,有什么区别呢. CvHoughLine:是用于标准的霍夫变换方法 CvHoughLine2:可以使用三种霍夫变换的方法,分别是标准霍夫变换(SHT).多尺度标准霍夫变换(MSHT).累计概率霍夫变换(PPHT). 函数原型: CvSeq* cvHoughLines2( C

OpenCV探索之路(十):图像修复技术

在实际应用中,我们的图像常常会被噪声腐蚀,这些噪声或是镜头上的灰尘或水滴,或是旧照片的划痕,或者是图像遭到人为的涂画(比如马赛克)或者图像的部分本身已经损坏.如果我们想让这些受到破坏的额图片尽可能恢复到原样,Opencv能帮我们做到吗? OpenCV真的有这个妙手回春的功能!别以为图像修补的工作只能用PS或者美图秀秀那些软件去做,其实由程序员自己写代码去做更加高效! 图像修复技术的原理是什么呢? 简而言之,就是利用那些已经被破坏的区域的边缘, 即边缘的颜色和结构,根据这些图像留下的信息去推断被破

OpenCV探索之路(十五):角点检测

角点检测是计算机视觉系统中用来获取图像特征的一种方法.我们都常说,这幅图像很有特点,但是一问他到底有哪些特点,或者这幅图有哪些特征可以让你一下子就识别出该物体,你可能就说不出来了.其实说图像的特征,你可以尝试说一下这幅图有几个矩形啊几个圆形啊,有几条直线啊,当然啦,你也可以说一下有几个角点. 什么是角点? 角点通常被定义为两条边的交点.比如,三角形有三个角,矩形有四个角,这些就是角点,也是他们叫做矩形.三角形的特征,我们看到一些几何图形具有三个角,那么我们便可以脱口而出说这是一个三角形. 上面所

OpenCV探索之路(九):模板匹配

模板匹配的作用在图像识别领域作用可大了.那什么是模板匹配? 模板匹配,就是在一幅图像中寻找另一幅模板图像最匹配(也就是最相似)的部分的技术. 说的有点抽象,下面给个例子说明就很明白了. 在上面这幅全明星照中,我们想找出姚明头像的位置,并把它标记出来,可以做到吗? 可以,这就是模板匹配的要做的事情. 其实模板匹配实现的思想也是很简单很暴力的,就是拿着模板图片(姚明头像)在原图(全明星照)中从左上至右下依次滑动,直到遇到某个区域的相似度低于我们设定的阈值,那么我们就认为该区域与模板匹配了,也就是我们

OpenCV探索之路(四):膨胀、腐蚀、开闭运算

腐蚀和膨胀是最基本的形态学运算. 腐蚀和膨胀是针对白色部分(高亮部分)而言的. 膨胀就是对图像高亮部分进行"领域扩张",效果图拥有比原图更大的高亮区域:腐蚀是原图中的高亮区域被蚕食,效果图拥有比原图更小的高亮区域. 膨胀 膨胀就是求局部最大值的操作,从图像直观看来,就是将图像光亮部分放大,黑暗部分缩小. #include<opencv2\opencv.hpp> #include<opencv2\highgui\highgui.hpp> using namespa

OpenCV探索之路(十三):详解掩膜mask

在OpenCV中我们经常会遇到一个名字:Mask(掩膜).很多函数都使用到它,那么这个Mask到底什么呢? 一开始我接触到Mask这个东西时,我还真是一头雾水啊,也对无法理解Mask到底有什么用.经过查阅大量资料后,也对Mask有一点自己的理解了,下面就说说我的理解. 比如我要对一幅图进行抠图操作,这就要用到Mask了,那我就以抠图为例,解释Mask在里面的作用. 先上程序,再一句一句剖析. 该程序的功能就是抠出指定区域. #include "opencv2/highgui/highgui.hp

OpenCV探索之路(八):重映射与仿射变换

重映射 重映射就是把一幅图像中某个位置的像素放置到另一个图片中指定位置的过程. 用一个数学公式来表示就是: 其中的 f 就是映射方式,也就说,像素点在另一个图像中的位置是由 f 来计算的. 在OpenCV中,用的是remap函数实现重映射. 基本重映射 #include <iostream> #include <opencv2\opencv.hpp> #include <opencv2\imgproc\imgproc.hpp> #include <opencv2\