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

霍夫变换(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;
}

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

(0)

相关推荐

  • 利用Opencv中Houghline方法实现直线检测

    利用Opencv中的Houghline方法进行直线检测-python语言 这是给Python部落翻译的文章,请在这里看原文. 在图像处理中,霍夫变换用来检测任意能够用数学公式表达的形状,即使这个形状被破坏或者有点扭曲. 下面我们将看到利用HoughLine算法来阐述霍夫变化进行直线检测的原理,把此算法应用到特点图像的边缘检测是可取的.边缘检测方法请参考这篇文章–边缘检测. Houghline算法基础 直线可以表示为y=mx+c,或者以极坐标形式表示为r=xcosθ+ysinθ,其中r是原点到直线

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

    本文实例为大家分享了OpenCV利用霍夫变换进行直线检测的具体代码,供大家参考,具体内容如下 1.最简单的霍夫变换是在图像中识别直线.在平面直角坐标系(x-y)中,一条直线可以用下式表示:y=kx+b. 这表示参数平面(k-b)中的一条直线.因此,图像中的一个点对应参数平面中的一条直线,图像中的一条直线对应参数平面中的一个点.对图像上所有的点作霍夫变换,最终所要检测的直线对应的一定是参数平面中直线相交最多的那个点.这样就在图像中检测出了直线.在实际应用中,直线通常采用参数方程:p=x\cos\t

  • Java+opencv3.2.0实现hough直线检测

    hough变换是图像处理中的一种特征提取技术,该过程在一个参数空间中通过计算累计结果的局部最大值得到一个符合特定形状的集合作为hough变换结果. 发展史: 1962年由PaulHough首次提出,用来检测直线和曲线. 1972年由Richard Duda & Peter Hart推广使用,扩展到任意形状物体的识别. 原理: 一条直线在直角坐标系下的表示形式为y=k*x+b,而在极坐标系下表示为r=x*cos(theta)+y*sin(theta).hough变换的思想为在直角坐标系下的一个点对

  • Opencv Hough算法实现图片中直线检测

    本文实例为大家分享了Opencv Hough算法实现直线检测的具体代码,供大家参考,具体内容如下 (1)载入需检测的图及显示原图 Mat g_srcImage = imread("C:\\Users\\lenovo\\Pictures\\Saved Pictures\\Q.jpg"); //图片所放路径 imshow("[原始图]", g_srcImage); (2)为显示不同的效果图而设置滑动条 namedWindow("[效果图]", 1);

  • OpenCV实现图像的直线检测

    上一篇博文介绍了图像的Canny边缘检测,本文主要介绍图像的直线检测部分,主要使用概率霍夫变换来检测直线,调用的函数为HoughLinesP(),下面给出代码部分以及直线检测效果图: 1.代码部分: // Detect_Lines.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" #include <cv.h> #include "highgui.h" using namespace std; using names

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

    霍夫变换(Hough Transform)的主要思想: 一条直线在平面直角坐标系(x-y)中可以用y=ax+b式表示,对于直线上一个确定的点(x0,y0),总符合y0-ax0=b,而它可以表示为参数平面坐标系(a-b)中的一条直线.因此,图像中的一个点对应参数平面的一条直线,同样,图像中的一条直线对应参数平面上的一个点. 基本Hough变换检测直线: 由于同一条直线上的不同点在参数平面中是会经过同一个点的多条线.对图像的所有点作霍夫变换,检测直线就意味着找到对应参数平面中的直线相交最多的点.对这

  • Java OpenCV图像处理之SIFT角点检测详解

    目录 介绍 示例代码 效果图 补充 介绍 在某些情况下对图像进行缩放后,角点信息可能会丢失,这时候Harri便不能检测到所有的角点.SIFT(scale-invariant feature transform) 刚好克服了这个问题,对图像特征的检测,尽量不受图像尺寸变化的影响.SIFT并不直接检测关键点. 其中关键点的检测是由DOG(Difference of Gaussians)检测完成的(DOG是通过不同的高斯滤波器对同一张图像进行处理,来得到关键点的).SIFT仅通过特征向量来描述特征点周

  • Qt+OpenCV实现目标检测详解

    目录 一.创建项目&UI设计 二.代码与演示 演示效果 拓展阅读 一.创建项目&UI设计 创建项目,UI设计如下 文件类型判断 简单的判断文件类型 QString file("sample.jpg"); if (file.contains(".jpg") || file.contains(".bmp") || file.contains(".png")) qDebug()<<"这是图片.&

  • OpenCV学习之图像梯度算子详解

    目录 1.Sobel算子 2.Scharr算子 3.laplacian算子 本文是OpenCV图像视觉入门之路的第12篇文章,本文详细的介绍了图像梯度算子的各种操作,例如:Sobel算子Scharr算子laplacian算子等操作. 1.Sobel算子 Sobel算子是一种图像边缘检测算子,它是一种空间滤波器,可以检测图像中的边缘,而梯度运算是一种求导数的方法,可以用来检测图像中的局部变化. import cv2 import numpy as np from numpy import unic

  • Android基于OpenCV实现霍夫直线检测

    目录 霍夫直线检测 点和线的对偶性 极坐标参数方程 API 操作 效果 霍夫直线检测 点和线的对偶性 图像空间中的点,对应霍夫空间中的直线 图像空间中的直线,对应霍夫空间中的点 共点的直线,在霍夫空间中对应的点在一条直线上 共线的点,在霍夫空间中对应的直线交于一点 极坐标参数方程 对于平面中的一条直线,在笛卡尔坐标中,常见的有点斜式,两点式两种表示方法.然而在霍夫变换中,考虑的是另外一种表示方式:使用(r, theta)来表示一条直线.其中r为该直线到原点的距离,theta为该直线的垂线与x轴的

  • Python OpenCV实现识别信用卡号教程详解

    目录 通过与 OpenCV 模板匹配的 OCR 信用卡 OCR 结果 总结 今天的博文分为三个部分. 在第一部分中,我们将讨论 OCR-A 字体,这是一种专为辅助光学字符识别算法而创建的字体. 然后我们将设计一种计算机视觉和图像处理算法,它可以: 本地化信用卡上的四组四位数字. 提取这四个分组中的每一个,然后单独分割 16 个数字中的每一个. 使用模板匹配和 OCR-A 字体识别 16 个信用卡数字中的每一个. 最后,我们将看一些将信用卡 OCR 算法应用于实际图像的示例. 通过与 OpenCV

  • Python传统图像处理之皮肤区域检测详解

    目录 1.RGB空间 2.Ycrcb空间 3.Ycrcb空间+otsu 4.HSV空间 5.opencv自带肤色检测类AdaptiveSkinDetector 6.基于椭圆模型 7.直方图反向投影 1.RGB空间 肤色在RGB模型下的范围基本满足以下约束: 在均匀光照下应满足以下判别式: R>95 AND G>40 B>20 AND MAX(R,G,B)-MIN(R,G,B)>15 AND ABS(R-G)>15 AND R>G AND R>B 在侧光拍摄环境下:

  • C++ OpenCV单峰三角阈值法Thresh_Unimodal详解

    目录 需求说明 具体流程 功能函数 C++测试代码 测试效果 需求说明 在对图像进行处理时,经常会有这类需求:想通过阈值对图像进行二值化分割,以提取自己感兴趣的区域,常见的阈值分割方法有常数分割.最大类间方差法.双峰分割.三角法等等,不同的场景应用不同的阈值方法. 今天要讲的方法,适合当图像的直方图具有明显单峰特征时使用,结合了三角法的原理而设计,相比较OpenCV自带的三角法,好处是可以根据自身需求合理修改函数:如果用OpenCV库的函数,只有一个接口,若不能达到较理想的应用效果,就束手无策了

  • Opencv创建车牌图片识别系统方法详解

    目录 前言 包含功能 软件版本 软件架构 参考文档 效果图展示 车牌检测过程 图片车牌文字识别过程 部分核心代码 前言 这是一个基于spring boot + maven + opencv 实现的图像识别及训练的Demo项目 包含车牌识别.人脸识别等功能,贯穿样本处理.模型训练.图像处理.对象检测.对象识别等技术点 java语言的深度学习项目,在整个开源社区来说都相对较少: 拥有完整的训练过程.检测.识别过程的开源项目更是少之又少!! 包含功能 蓝.绿.黄车牌检测及车牌号码识别 网上常见的轮廓提

  • 基于Python实现打哈欠检测详解

    目录 效果图 基本思路 部分源码 效果图 基本思路 在 OpenCV 中使用VideoCapture方法初始化视频渲染对象 创建灰度图像 导入预训练模型,识别脸部和人脸标志 计算上唇和下唇距离(其它类似) 创建唇边距离的If条件,满足则是打哈欠,不满足则只是简单的张嘴 显示帧/图像 部分源码 suc, frame = cam.read() # 读取不到退出 if not suc: break # ---------FPS------------# ctime = time.time() fps

随机推荐