【OpenCV】利用霍夫变换进行直线检测

news/2024/7/21 6:27:08 标签: OpenCV霍夫线检测, 图像处理

    1.最简单的霍夫变换是在图像中识别直线。在平面直角坐标系(x-y)中,一条直线可以用下式表示:y=kx+b。

    这表示参数平面(k-b)中的一条直线。因此,图像中的一个点对应参数平面中的一条直线,图像中的一条直线对应参数平面中的一个点。对图像上所有的点作霍夫变换,最终所要检测的直线对应的一定是参数平面中直线相交最多的那个点。这样就在图像中检测出了直线。在实际应用中,直线通常采用参数方程:p=x\cos\theta+y\sin\theta

    Opencv里有以下函数检测直线(最基本的霍夫变换): 

void HoughLines(InputArray image, OutputArray lines, double rho, double theta, int threshold, double srn=0, double stn=0 )

    具体用法看代码就知道了:(现在版本的OpenCV使用函数cvHoughLines2)

#include "opencv2/opencv.hpp"
#define PI 3.1415926

int main(int argc, char *argv[])
{
    cv::Mat image = cv::imread ("road.jpg");
    cv::Mat result;
    cv::cvtColor (image,result,CV_BGRA2GRAY);
    cv::Mat contours;
    cv::Canny (result,contours,125,350);  //边缘检测
    std::vector<cv::Vec2f> lines;
    /*霍夫变换,获得一组极坐标参数(rho,theta),每一对对应一条直线,保存到lines
      第3,4个参数表示在(rho,theta)坐标系里横纵坐标的最小单位,即步长*/
    cv::HoughLines (contours,lines,1,PI/180,80);
    std::vector<cv::Vec2f>::const_iterator iter = lines.begin ();
    std::cout<<lines.size ()<<std::endl;
    while(iter != lines.end())
    {
        float rho = (*iter)[0];
        float theta = (*iter)[1];
        if(theta<PI/4.||theta>3.*PI/4)
	{   //画交点在上下两边的直线
            cv::Point pt1(rho/cos(theta),0);
            cv::Point pt2((rho-result.rows*sin(theta))/cos(theta),result.rows);
            cv::line(image,pt1,pt2,cv::Scalar(255),1);
        }
       else 
        {   //画交点在左右两边的直线
            cv::Point pt1(0,rho/sin(theta));
            cv::Point pt2(result.cols,(rho-result.cols*cos(theta)/sin(theta)));
            cv::line(image,pt1,pt2,cv::Scalar(255),1);
        }
        ++iter;
    }
    cv::namedWindow ("hough");
    cv::imshow("hough",image);
    cv::waitKey (0);
}                                                                                                                                                         

    测试结果如下: 

    2.可以看出,上面的直线检测存在以下问题:

    1)只能检测出线段所在的直线,而不知道具体线段位置,也不知道线段长度;

    2)同一直线可能检测出多条直线;

    3)偶然地也可能误判段直线。

    针对这些问题,opencv有那么一个函数:(现在版本的OpenCV使用同一个函数cvHoughLines2)

void HoughLinesP(InputArray image, OutputArray lines, double rho, double theta, int threshold, dou-
ble minLineLength=0, double maxLineGap=0)
    这个方法是通过概率霍夫变换实现的:

    1)随机获取边缘图片上的前景点,映射到级坐标系画曲线;

    2)当极坐标系里面有交点达到最小投票数,将该点对应x-y坐标系的直线L找出来;

    3)搜索边缘图片上前景点,在直线L上的点(且点与点之间距离小于maxLineGap的)连成线段,然后这些点全部删除,并且记录该线段的参数,就是起始点和终止点。(当然这里线段长度要满足最小长度的,否则就不用记录了)

    4)重复1),2),3)

    其使用方法见代码:

#include "opencv2/opencv.hpp"
#define PI 3.1415926

class LineFinder
{
private:
        std::vector<cv::Vec4i> lines;  // 直线对应的点参数向量
        double deltaRho;  //步长
        double deltaTheta;
        int minVote;  // 判断是直线的最小投票数
        double minLength;  // 判断是直线的最小长度
        double maxGap;  // 同一条直线上点之间的距离容忍度
public:
        LineFinder() : deltaRho(1), deltaTheta(PI/180),
        minVote(10), minLength(0.), maxGap(0.) {}  //初始化
		
        void setAccResolution(double dRho, double dTheta)   // 设置步长
        {
            deltaRho= dRho;
            deltaTheta= dTheta;
        }
        
        void setMinVote(int minv)  // 设置最小投票数
	{
            minVote= minv;
        }
        
        void setLineLengthAndGap(double length, double gap)  // 设置最小线段长度和线段间距容忍度 
	{
            minLength= length;
            maxGap= gap;
        }

        
        std::vector<cv::Vec4i> findLines(cv::Mat& binary)  //寻找线段
	{
            lines.clear();
            cv::HoughLinesP(binary,lines, deltaRho, deltaTheta, minVote,minLength, maxGap);
            return lines;
        }

        void drawDetectedLines(cv::Mat &image, cv::Scalar color=cv::Scalar(255,255,255))  // 画线段
	{
	    std::vector<cv::Vec4i>::const_iterator it2=lines.begin();
            while (it2!=lines.end()) 
	    {
                cv::Point pt1((*it2)[0],(*it2)[1]);
                cv::Point pt2((*it2)[2],(*it2)[3]);
                cv::line( image, pt1, pt2, color);
                ++it2;
            }
        }
};

int main(int argc, char *argv[])
{
    cv::Mat image = cv::imread ("road.jpg");
    cv::Mat result;
    cv::cvtColor (image,result,CV_BGRA2GRAY);
    cv::Mat contours;
    cv::Canny (result,contours,125,350);  //边缘检测
    LineFinder finder;
    finder.setMinVote (80);
    finder.setLineLengthAndGap (100,20);
    finder.findLines (contours);
    finder.drawDetectedLines (image);
    std::vector<cv::Vec2f> lines;
    cv::HoughLines (contours,lines,1,PI/180,80);
    std::vector<cv::Vec2f>::const_iterator iter = lines.begin ();
    std::cout<<lines.size ()<<std::endl;
    while(iter != lines.end())
    {
        float rho = (*iter)[0];
        float theta = (*iter)[1];
        if(theta<PI/4.||theta>3.*PI/4)
	{   //画交点在上下两边的直线
            cv::Point pt1(rho/cos(theta),0);
            cv::Point pt2((rho-result.rows*sin(theta))/cos(theta),result.rows);
            cv::line(image,pt1,pt2,cv::Scalar(255),1);
        }
       else 
        {    //画交点在左右两边的直线
            cv::Point pt1(0,rho/sin(theta));
            cv::Point pt2(result.cols,(rho-result.cols*cos(theta)/sin(theta)));
            cv::line(image,pt1,pt2,cv::Scalar(255),1);
        }
        ++iter;
    }
    cv::namedWindow ("hough");
    cv::imshow("hough",image);
    cv::waitKey (0);
}

    测试结果如下:


http://www.niftyadmin.cn/n/781233.html

相关文章

python服务器开发debug_在服务器上debug python程序 VS 在本地pycharm中debug远程服务器上的程序...

在服务器上debug python程序1.安装模块 pip install ipdb2.单步调试 python -m ipdb xxx.py3.断点调试&#xff0c;在需要打断电的地方加入下述代码from ipdb import set_traceset_trace()运行到目标位置中断程序&#xff0c;出现提示符&#xff0c;进入ipython环境4.常用命令n…

【OpenCV】透视变换-将图像由不规则四边形转换成矩形

本文是在点击打开链接基础上修改而成的&#xff0c;感谢原文博主提供的参考。 代码声明&#xff1a;近期在做身份证图像处理&#xff0c;由于采集问题&#xff0c;采集到的图像存在一定的角度偏差&#xff0c;成为了不规则的四边形&#xff0c;通过透视变换可将其转换成矩形&a…

python colorbar xtick locator_Python pyplot.MaxNLocator方法代码示例

本文整理汇总了Python中matplotlib.pyplot.MaxNLocator方法的典型用法代码示例。如果您正苦于以下问题&#xff1a;Python pyplot.MaxNLocator方法的具体用法&#xff1f;Python pyplot.MaxNLocator怎么用&#xff1f;Python pyplot.MaxNLocator使用的例子&#xff1f;那么恭喜…

【C++】C++常见面试题汇总,持续更新中...

1:指针&#xff08;*&#xff09;、引用&#xff08;&&#xff09;、解引用&#xff08;*&#xff09;、取地址&#xff08;&&#xff09;、的概念和区别 概念&#xff1a; 指针指向一块内存&#xff0c;指针保存的是内存的地址&#xff1b;引用是变量的别名&#xff…

mysql 查看用户权限_在Navicat Premium中管理MySQL用户 - 第4部分:权限管理器工具

第4部分&#xff1a;Privilege Manager(权限管理器)工具在本系列教程中&#xff0c;我们一直在探索如何使用Navicat的旗舰产品Navicat Premium执行常见的用户管理任务。在上一篇文章中&#xff0c;我们查看了New User Object选项卡的Server Privileges&#xff0c;Privileges 和…

【C++】static关键字用法总结

C关键字static用法&#xff0c;总结了网络和C Primer的一些重要知识点&#xff0c;可能还有一些遗漏欢迎补充。 C的static有两种用法&#xff1a;面向过程程序设计中的static和面向对象程序设计中的static。前者应用于普通变量和函数&#xff0c;不涉及类&#xff1b;后者主要 …

qt及qt quick开发实战精解_[视频课程更新] 微信天气预报小程序 UI 开发部分

此教程属于开发实战系列视频教程&#xff0c;基于之前发布的 「60 集微信小程序开发视频教程」&#xff0c;更新的第二阶段视频课程。此系列课程将直接进入实战开发部分。此系列视频课程包含&#xff1a;项目初始化页面 UI 开发页面路由逻辑微信小程序云开发平台的使用小程序用…

【C++】const关键字用法总结

C关键字const用法&#xff0c;总结了网络和C Primer的一些重要知识点&#xff0c;可能还有一些遗漏欢迎补充。 CONST是C中常用的类型修饰符,常类型是指使用类型修饰符const说明的类型&#xff0c;常类型的变量或对象的值是不能被更新的。 一、CONST作用 二、CONST的使用 1、定…