OpenCV霍夫变换(Hough Transform)直线检测详解

 更新时间:2018年12月26日 09:45:50   作者:Joy_Shen  
这篇文章主要为大家详细介绍了OpenCV霍夫变换直线检测的相关资料,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

霍夫变换(Hough Transform)的主要思想:

一条直线在平面直角坐标系(x-y)中可以用y=ax+b式表示,对于直线上一个确定的点(x0,y0),总符合y0-ax0=b,而它可以表示为参数平面坐标系(a-b)中的一条直线。因此,图像中的一个点对应参数平面的一条直线,同样,图像中的一条直线对应参数平面上的一个点。

基本Hough变换检测直线:

由于同一条直线上的不同点在参数平面中是会经过同一个点的多条线。对图像的所有点作霍夫变换,检测直线就意味着找到对应参数平面中的直线相交最多的点。对这些交点做票数累计,然后取出票数大于最小投票数的点,即为原坐标系里检测出的直线。

一般,直线的参数方程为 ρ=xcosθ+ysinθ

OpenCV中的基本霍夫变换直线检测函数 cv::HoughLines:

函数输入为一幅二值图像(有很多待检测点),其中一些点排列后形成直线,通常这是一幅边缘图像,比如来自Sobel算子或Canny算子。函数的输出是cv::Vec2f的向量,每个元素都是一对代表检测到的直线的浮点数(ρ, θ)。函数的作法是先求出原图像中每点的极坐标方程,若相交于一点的极坐标曲线的个数大于最小投票数,则将该点(ρ, θ)(参数坐标系点)放入输出向量。

#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
#include <iostream>
 
#define PI 3.1415926
 
class LineFinder{
private:
 std::vector<cv::Vec2f> lines;
 double deltaRho; // 参数坐标系的步长(theta表示与直线垂直的角度)
 double deltaTheta;
 int minVote;  // 判断是直线的最小投票数 
public:
 LineFinder() {
 deltaRho = 1;
 deltaTheta = PI / 180;
 minVote = 80;
 }
 void setAccResolution(double dRho, double dTheta) {
 deltaRho = dRho;
 deltaTheta = dTheta;
 }
 void setMinVote(int minv) {
 minVote = minv;
 }
 // Hough变换检测直线;rho=1,theta=PI/180参数坐标系里的步长,threshold=最小投票数
 void findLines(cv::Mat& binary){
 lines.clear();
 cv::HoughLines(binary, lines, deltaRho, deltaTheta, minVote);
 }
 
 void drawDetectedLines(cv::Mat& result){
 std::vector<cv::Vec2f>::const_iterator it = lines.begin();
 while (it != lines.end())
 {
 // 以下两个参数用来检测直线属于垂直线还是水平线
 float rho = (*it)[0];
 float theta = (*it)[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(result, 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(result, pt1, pt2, cv::Scalar(255), 1);
 }
 ++it;
 }
 }
};
 
int main(int argc, char *argv[])
{
 cv::Mat image = cv::imread("D:/VS_exercise/images/road1.jpg");
 cv::Mat imageGray;
 cv::Mat contours;
 cv::cvtColor(image, imageGray, cv::COLOR_RGB2GRAY);
 cv::Canny(imageGray, contours, 190, 300);
 // 在原图的拷贝上画直线
 cv::Mat result(contours.rows, contours.cols, CV_8U, cv::Scalar(255));
 image.copyTo(result);
 // Hough变换检测
 LineFinder finder;
 finder.setMinVote(130);
 finder.findLines(contours);
 finder.drawDetectedLines(result);
 
 // 显示
 cv::namedWindow("Detected Lines with Hough");
 cv::imshow("Detected Lines with Hough", result);
 cv::waitKey(0);
 return 0;
}

概率Hough变换检测线段:

霍夫变换检测直线的目的,是找到二值图像中经过足够多数量点的所有直线,当同一直线穿过许多点,便意味着这条线的存在足够明显。

概率霍夫变换在原算法的基础上增加了一些改动,主要是:

1. 不再系统地逐行扫描图像,而是随机挑选(轮廓图像的)前景点,一旦累加器中的某一项交点的票数达到给定的最小值,就搜索轮廓图像在对应直线上的前景点,连成线段(要小于maxLineGap),然后记录线段参数(起终点),最后删除所有经过的点(即使它们并未投过票)。

2. 概率霍夫变换定义了两个额外的参数:一个是可以接受的最小线段长度(minLineLength),另一个是允许组成连续线段的最大像素间隔(maxLineGap),虽然额外步骤增加了算法的复杂度,但由于参与投票的点数有所减少,因此得到了一些补偿。

openCV中的概率霍夫变换直线检测函数 cv::HoughLinesP:

函数的输出是cv::Vec4i组成的向量,每个元素是检测到的线段的两个坐标点(pt1x, pt1y, pt2x, pt2y)。

#include "opencv2/highgui.hpp"
#include "opencv2/core.hpp"
#include "opencv2/imgproc.hpp"
 
#define PI 3.1415926 
 
class LineFinder{
private:
 std::vector<cv::Vec4i> lines;
 double deltaRho; // 步长(theta表示与直线垂直的角度)
 double deltaTheta;
 int minVote;  // 判断是直线的最小投票数 
 double minLength; // 判断是直线的最小线段长度 
 double maxGap; // 允许组成连续线段的最大像素间隔
public:
 LineFinder() {
 deltaRho = 1;
 deltaTheta = PI / 180;
 minVote = 10;
 minLength = 0.0;
 maxGap = 0.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;
 }
 
 // Hough变换检测线段
 void findLines(cv::Mat& binary) {
 lines.clear();
 cv::HoughLinesP(binary, lines, deltaRho, deltaTheta, minVote, minLength, maxGap);
 }
 
 void drawDetectedLines(cv::Mat &image, cv::Scalar color = cv::Scalar(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, 1.5); //画线段
 ++it2;
 }
 }
};
 
int main(int argc, char *argv[])
{
 cv::Mat image = cv::imread("D:/VS_exercise/images/road1.jpg");
 cv::Mat imageGray;
 cv::Mat contours;
 cv::cvtColor(image, imageGray, cv::COLOR_RGB2GRAY);
 // 边缘检测
 cv::Canny(imageGray, contours, 190, 300);
 // Hough变换检测
 LineFinder finder;
 finder.setMinVote(80);
 finder.setLineLengthAndGap(100, 10); //概率Hough变换增加的两个参数
 finder.findLines(contours);
 finder.drawDetectedLines(image);
 
 // 显示
 cv::imshow("Detected Lines with Hough", image);
 cv::waitKey(0);
 return 0;
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持脚本之家。

相关文章

  • 关于C++中二分法详解

    关于C++中二分法详解

    大家好,本篇文章主要讲的是关于C++中二分法详解,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-02-02
  • 带你了解C++中vector的用法

    带你了解C++中vector的用法

    大家好,本篇文章主要讲的是带你了解C++中vector的用法,感兴趣的同学赶快来看一看吧,对你有帮助的话记得收藏一下
    2022-01-01
  • C语言面试C++二维数组中的查找示例

    C语言面试C++二维数组中的查找示例

    这篇文章主要介绍了C语言面试C++二维数组中的查找示例,文中给出基本能拿下面试官的操作示例,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2021-09-09
  • C++中MFC Tab Control控件的使用详解

    C++中MFC Tab Control控件的使用详解

    这篇文章主要介绍了C++中MFC Tab Control控件的使用详解的相关资料,需要的朋友可以参考下
    2015-06-06
  • C++代码实现逆波兰表达式

    C++代码实现逆波兰表达式

    这篇文章主要为大家详细介绍了C++代码实现逆波兰表达式,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-11-11
  • c语言中static的用法详细示例分析

    c语言中static的用法详细示例分析

    以下是对c语言中static函数的用法进行了详细的分析介绍,需要的朋友可以过来参考下
    2013-08-08
  • C语言小程序 如何判断三角型类型

    C语言小程序 如何判断三角型类型

    第一个判断三角形的类型,两个浮点型数据不能直接判断相等,为了输入方便一些,自己设置的精度比较低,10^(-3)
    2013-07-07
  • C++中的vector中erase用法实例代码

    C++中的vector中erase用法实例代码

    在vector数组中我们删除数组经常用的就是erase方法,但是earse的用法一不注意就会出错,今天我就遇到了,所以在这里总结一下,避免大家用错,对vector中erase用法感兴趣的朋友跟随小编一起看看吧
    2022-11-11
  • ubuntu系统vscodeC++编译环境配置与使用方式

    ubuntu系统vscodeC++编译环境配置与使用方式

    这篇文章主要介绍了ubuntu系统vscodeC++编译环境配置与使用方式,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-12-12
  • C++通信新特性协程详细介绍

    C++通信新特性协程详细介绍

    这篇文章主要给大家分享得是C++的特性协程Coroutine,下面文章内容我们将来具体介绍什么是协程,协程得好处等知识点,需要的朋友可以参考一下
    2022-10-10

最新评论