【OpenCV图像处理】二十四、霍夫(Hough)检测

霍夫变换:

通常图像中直线对应重要的边缘信息,在计算机视觉中直线检测是一项具有重要意义的技术。由于直线具有特定的特征,因此提取方法也不同于一般的边缘检测方法。

一、霍夫变换直线检测

Hough变换直线检测是一种参数空间提取直线的方法,它将直线上点的坐标变换到过点的系数域,利用了共线点与直线相交之间的关系,将直线检测问题转换为技术问题。这种方法的主要优点是受直线中间隙和噪声的影响较小。

主要思想原理如下:

在O-xy平面内,直线的斜截式方程为:y=ux+v,其中u为斜率,v为截距

→对于给定的一条直线,对应一个数对(u,v),反之,给定一个数对(u,v),就对应一条直线 y= ux+v

→因此,O-xy平面上的直线y=ux+v与O-uv平面上的(u,v)一一对应,这个关系也就是Hough变换的基本原理

→同理,O-xy平面上任意一点(x,y)与O-uv平面的一条直线u=-xv+y也一一对应,也就是说,对于O-xy平面上的直线y=ux+v,直线上的没一点(x,y)都对应O-uv平面上的一条直线,并且这些直线交于一点(u,v)

→Hough变换就是利用这个性质检测共线点,从而提取出直线


(1)极坐标中Hough变换的实现

→由于直线的斜率可能存在无限大, 因此为了使变换域有意义,通常采用直线的极坐标方程表示为:

ρ=xcosθ + ysinθ

上式中,数对(ρ,θ)定义了从原点到直线距离的向量,这个向量与直线垂直,ρ表示的是向量的长度,θ表示向量方向,如下图所示:


所以,O-xy平面上的直线ρ=xcosθ + ysinθ与O-ρθ平面上的数对(ρ,θ)一一对应。

同理,O-xy平面上的一点与O-ρθ平面上一条正弦曲线也是一一对应的关系。具体关系是O-xy平面上的共线点对应于O-ρθ平面上的正弦曲线相交于一点。

为了寻找共线点对应所构成的直线,将O-ρθ平面量化为小格,参数空间中每一个小格对应与一个数对(ρ,θ)以及对应一个计数累加器A(ρ,θ)。

→对于O-xy平面上的点(x,y),由ρ=xcosθ + ysinθ 计算各个量化θ对应的ρ值并进行量化,然后将相应的计数累加器A(ρ,θ)进行加1操作

→将所有的点(x,y)变换到参数空间后,对各个小格对应的计数累加器进行统计,落入同一小格的O-xy平面上个点接近于共线,假设图像中存在n条待检测的直线,选择前n个最大计数值得小格,利用最小二成你和计算落在每一个小格中各点所在的直线方程。

→参数ρ和θ量化步长对共线点的检测有很大影响,

→→若太粗,则非共线点有可能落在参数空间内同一小格,由于野点的存在,导致ρ和θ估计不准确

→→若太细,则共线点落入参数空间中的多个小格内


(2)OpenCV中Hough直线检测的使用

首先需要说明的是,在OpenCV中的霍夫变换有下面三种

(a.标准霍夫变换,由HoughLines函数进行调用

(b.多尺度霍夫变换,由HoughLines函数进行调用

(c.累计概率霍夫变换,由HoughLinesP函数进行调用

下面首先介绍标准霍夫变换

(a.标准霍夫变换,HoughLines()函数

这个函数的作用是找出采用标准霍夫变换的二值图像线条。函数的原型如下:

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

第一个参数是InputArray类型的图像image,表示输入图像,也就是源图像,需要是8位单通道的二进制图像,可以将任意源图像载入进来,再使用函数修改成这个格式后,再填到这里。

第二个参数是InputArray类型的lines,经过调用HoughLines函数后存储了活肤变换检测到线条的输出矢量。每一条线具有两个元素的矢量(ρ,θ)表示,其中,ρ表示的是距离坐标原点(左上角点)的距离,θ是弧度线条旋转角度。

第三个参数是double类型的rho,表示的是一像素为单位的距离精度。另一种表述方式是直线搜索时的进步尺寸的单位半径

第四个参数是double类型的theta,表示以弧度为单位的角度精度。另一种标书方式是直线搜索时的进步尺寸的单位角度

第五个参数是int类型的threshold,表示累加平面的阈值参数,也就是识别某部分为图中一条直线时它在累加平面中必须达到的值,大于阈值threshold的线段才可以被检测通过并返回到结果中。

第六个参数是double类型的srn,有默认值0,对于多尺度的火狐变换,这是第三个参数进步尺寸rho的除数距离。粗略的累加器进步尺寸直接是第三个参数rho,而精确的累加器进步尺寸为rho/srn。

第七个参数是double累心的stn,有默认值0,对于多尺度霍夫变换,stn表示第四个参数进步尺寸的单位角度theta的除数距离。且如果srn和stn同时为0,就表示使用景点的霍夫变换,否则,这两个参数都应该是正数。

下面是使用这个函数的具体程序实例:

//霍夫变换直线检测
#include <iostream>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat srcImage = imread("building.jpg");
	if (!srcImage.data)
	{
		cout << "读入图片错误!" << endl;
		system("pause");
		return 0;
	}
	Mat tempImage, dstImage;
	//进行边缘检测并转换为灰度图
	Canny(srcImage, tempImage,50, 200, 3);
	cvtColor(tempImage, dstImage, CV_GRAY2BGR);

	//进行霍夫变换
	vector<Vec2f>lines;	//定义一个矢量结构lines用于存放得到的线段矢量集合
	HoughLines(tempImage, lines, 1, CV_PI / 180, 150, 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 + 100 * (-b));
		pt1.y = cvRound(y0 + 100 * (a));
		pt2.x = cvRound(x0 - 100 * (-b));
		pt2.y = cvRound(y0 - 100 * (a));
		line(dstImage, pt1, pt2, Scalar(0, 0, 255), 1, CV_AA);
	}
	//显示原始图
	imshow("原始图像", srcImage);
	//显示边缘检测图像
	imshow("边缘检测图像", tempImage);
	//显示直线检测图像
	imshow("直线检测图像", dstImage);


	waitKey();
	return 0;
}

(b.累积概率霍夫变换:HoughLinesP()函数

这个函数在HoughLines函数的基础上,在末尾加了一个代表Probabilistic(概率)的P,表明它可以采用累积概率霍夫变换(PPHT)来找出二值图像中的直线。

函数的原型如下所示:

void HoughLinesP( InputArray image, OutputArray lines,double rho, double theta, int threshold,
                               double minLineLength=0, double maxLineGap=0 );
第一个参数表示输入图像,也就是源图像,需要是8位的单通道二进制图像。

第二个参数是lines,表示经过调用这个函数后存储了检测到的线条的输出矢量,每一条线由具有四个元素的矢量(x_1,y_1,x_2,y_2)表示,其中(x_1,y_1)和(x_2,y_2)是每个检测到的线段的结束点

第三个参数是double类型的rho,一像素为单位的距离精度。另一种标书方法是直线搜索是的进步尺寸的单位半径。

第四个参数是double类型的theta,表示的是以弧度为单位的角度精度。另一种标书方式是直线搜索时进步尺寸的单位角度。

第五个参数是int类型的threshold,表示累加平面的阈值参数,也就是识别某部分为图中一条直线时它在累加平面中必须达到的值,大于阈值threshold的线段才可以被检测通过并返回到结果中。
第六个参数是double类型的minLineLength,有默认值0,表示最低线段的长度,比这个参数短的线段就不能被检测出来。

第七个参数是double类型的maxLineGap,有默认参数0,表示将同一行点与点之间连接起来的最大距离

具体使用实例如下所示:

//霍夫变换直线检测
#include <iostream>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat srcImage = imread("building.jpg");
	if (!srcImage.data)
	{
		cout << "读入图片错误!" << endl;
		system("pause");
		return 0;
	}
	Mat tempImage, dstImage;
	//进行边缘检测并转换为灰度图
	Canny(srcImage, tempImage,50, 200, 3);
	cvtColor(tempImage, dstImage, CV_GRAY2BGR);

	//进行霍夫变换
	vector<Vec4i>lines;	//定义一个矢量结构lines用于存放得到的线段矢量集合
	HoughLinesP(tempImage, 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(0, 0, 255), 1, CV_AA);
	}
	//显示原始图
	imshow("原始图像", srcImage);
	//显示边缘检测图像
	imshow("边缘检测图像", tempImage);
	//显示直线检测图像
	imshow("直线检测图像", dstImage);
	waitKey();
	return 0;
}

一、霍夫变换圆形检测

霍夫变换适用于形式为的任何函数,其中x为坐标向量,c为参数向量

→二维空间中的圆函数有三个未知参数,圆的标准方程为:


→其中(α,β)是圆心,r是半径,这三个参数构成三维参数空间的技术累加器,根据O-xy平面上每一个点(x,y)递增α和β的值,计算相应的r值并进行量化,同事,将相应的技术累加器A(α,β,r)加1

→霍夫变换检测的复杂度随着参数个数的增加呈几何增长

→通常利用Hough变换进行圆形检测时,预先估计处圆的半径,从而可以将参数向量降低到二维

→在二维空间中,Hough变换圆形检测复杂度与直线检测复杂度相同


原理:

O-xy平面上一个圆与O-αβ平面上一个点(圆心)是一一对应关系,同理,O-xy平面上一个点与O-αβ平面上一个圆也是一一对应关系

对于O-xy平面上固定半径为r的圆,圆上每一个点对应于O-αβ平面上一个圆。这些圆形交于一点(α,β)

当圆形的半径估计过大或过小时,均无法正确确定(α,β)

→在已知圆半径时,参数空间尺寸为原图像行宽和列宽分别加上2r,

→在参数空间照片那个是将上以图像中每一个点为圆心进行画圆。


在OpenCV中可以利用HoughCircles函数检测处灰度图像中的圆。它相比之前的霍夫函数,一个比较明显的区别是不需要源图像是二值图像

函数原型如下所示:

void HoughCircles( InputArray image, OutputArray circles, int method, double dp, double minDist,
                               double param1=100, double param2=100, int minRadius=0, int maxRadius=0 );
第一个参数image表示输入图像,也就是源图像,需要是8位的灰度单通道图像

第二个参数circles表示经过调用这个函数后存储的检测到的圆的输出矢量,每个矢量由包含了3个元素的浮点矢量(x,y,radius)表示

第三个参数是int类型的method,表示的是使用的检测方法,目前OpenCV中只有霍夫梯度法这一种方法可以使用,标识符是CV_HOUGH_GRADIENT,在这里使用这个标识符即可。

第四个参数是double类型的dp,用来检测圆心的累加器图像的分辨率与输入图像之比的倒数,而且这个参数允许创建一个比输入图像分辨率低的累加器。

→→dp=1,累加器和输入图像具有一样的分辨率,如果dp=2,累加器有输入图像一半大的宽度和高度

第五个参数是double类型的minDist,是霍夫变换检测到的圆的圆心之间的最小距离

第六个参数是double类型的param1,有默认值100,它是第三个参数method设置的检测方法的对应的参数。对当前唯一的方法霍夫梯度法,它表示传递给canny边缘检测算子高阈值,而低阈值为高阈值的一半

第七个参数double类型的param2,也有默认值100,这个参数越小,就可以检测到更多根本不存在的圆,它越大,能通过检测的圆就更加接近完美的圆形

第八个参数是int类型的minRadius,有默认值0,表示圆半径的最小值

第九个参数是int类型的maxRadius,有默认值0,表示圆半径的最大值


→→需要注意的是:

使用这个函数可以很容易的检测处圆形的圆心,但是它可能找不到合适的半径,我们可以通过第八个参数和第九个参数进行指定圆的半径,来辅助进行圆形检测

相关实例如下所示:

//Hough变换圆形检测
#include <iostream>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>

using namespace cv;
using namespace std;

int main()
{
	Mat srcImage = imread("circle.jpg");
	Mat grayImage, dstImage;
	//显示原始图像
	imshow("原始图像", srcImage);
	//转换为灰度图像并进行平滑
	cvtColor(srcImage, grayImage, CV_BGR2GRAY);
	GaussianBlur(grayImage, grayImage, Size(9, 9), 2, 2);
	//进行霍夫圆形变换
	vector<Vec3f>circles;
	HoughCircles(grayImage, circles, CV_HOUGH_GRADIENT, 1.5, 10, 200, 100, 0, 0);
	//在图中绘制出圆形
	for (size_t i= 0; i < circles.size(); i++)
	{
		//参数定义
		Point center(cvRound(circles[i][0]), 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(0, 0, 255), 3, 8, 0);
	}
	imshow("效果图", srcImage);
	waitKey();
	return 0;
}

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
import cv2 as cv import numpy as np def hough_circle(image): #因为霍夫检测对噪声很明显,所以需要先滤波一下。 dst =cv.pyrMeanShiftFiltering(image,10,100) cimage=cv.cvtColor(dst,cv.COLOR_BGR2GRAY) circles = cv.HoughCircles(cimage,cv.HOUGH_GRADIENT,1,40,param1=40,param2=29,minRadius=30,maxRadius=0) #把circles包含的圆心和半径的值变为整数 circles = np.uint16(np.around(circles)) for i in circles[0]: cv.circle(image,(i[0],i[1]),i[2],(0,255,0),3) cv.imshow("circle",image) src = cv.imread("E:/opencv/picture/coins.jpg") cv.imshow("inital_window",src) hough_circle(src) cv.waitKey(0) cv.destroyAllWindows() 霍夫圆变换的基本思路是认为图像上每一个非零像素点都有可能是一个潜在的圆上的一点, 跟霍夫线变换一样,也是通过投票,生成累积坐标平面,设置一个累积权重来定位圆。 在笛卡尔坐标系中圆的方程为: 其中(a,b)是圆心,r是半径,也可以表述为: 即 在笛卡尔的xy坐标系中经过某一点的所有圆映射到abr坐标系中就是一条三维的曲线: 经过xy坐标系中所有的非零像素点的所有圆就构成了abr坐标系中很多条三维的曲线。 在xy坐标系中同一个圆上的所有点的圆方程是一样的,它们映射到abr坐标系中的是同一个点,所以在abr坐标系中该点就应该有圆的总像素N0个曲线相交。 通过判断abr中每一点的相交(累积)数量,大于一定阈值的点就认为是圆。 以上是标准霍夫圆变换实现算法。 问题是它的累加到一个三维的空间,意味着比霍夫线变换需要更多的计算消耗。 Opencv霍夫圆变换对标准霍夫圆变换做了运算上的优化。 它采用的是“霍夫梯度法”。它的检测思路是去遍历累加所有非零点对应的圆心,对圆心进行考量。 如何定位圆心呢?圆心一定是在圆上的每个点的模向量上,即在垂直于该点并且经过该点的切线的垂直线上,这些圆上的模向量的交点就是圆心。 霍夫梯度法就是要去查找这些圆心,根据该“圆心”上模向量相交数量的多少,根据阈值进行最终的判断。 bilibili: 注意: 1.OpenCV霍夫圆变换函数原型为:HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]]) -> circles image参数表示8位单通道灰度输入图像矩阵。 method参数表示圆检测方法,目前唯一实现的方法是HOUGH_GRADIENT。 dp参数表示累加器与原始图像相比的分辨率的反比参数。例如,如果dp = 1,则累加器具有与输入图像相同的分辨率。如果dp=2,累加器分辨率是元素图像的一半,宽度和高度也缩减为原来的一半。 minDist参数表示检测到的两个圆心之间的最小距离。如果参数太小,除了真实的一个圆圈之外,可能错误地检测到多个相邻的圆圈。如果太大,可能会遗漏一些圆圈。 circles参数表示检测到的圆的输出向量,向量内第一个元素是圆的横坐标,第二个是纵坐标,第三个是半径大小。 param1参数表示Canny边缘检测的高阈值,低阈值会被自动置为高阈值的一半。 param2参数表示圆心检测的累加阈值,参数值越小,可以检测越多的假圆圈,但返回的是与较大累加器值对应的圆圈。 minRadius参数表示检测到的圆的最小半径。 maxRadius参数表示检测到的圆的最大半径。 2.OpenCV画圆的circle函数原型:circle(img, center, radius, color[, thickness[, lineType[, shift]]]) -> img img参数表示源图像。 center参数表示圆心坐标。 radius参数表示圆的半径。 color参数表示设定圆的颜色。 thickness参数:如果是正数,表示圆轮廓的粗细程度。如果是负数,表示要绘制实心圆。 lineType参数表示圆线条的类型。 shift参数表示圆心坐标和半径值中的小数位数。
霍夫直线检测Hough Line Transform)是一种常用的图像处理技术,用于检测图像中的直线。OpenCV库中包含了对霍夫直线检测的支持。 在OpenCV中,使用`HoughLines`函数进行霍夫直线检测。函数的基本使用方法如下: ```python lines = cv2.HoughLines(image, rho, theta, threshold) ``` 参数说明: - `image`:输入的二值化图像,通常为边缘检测后的图像。 - `rho`:表示ρ(rho)参数的精确度,一般取1。 - `theta`:表示θ(theta)参数(角度)的精确度,一般取π/180。 - `threshold`:用于筛选直线的阈值,只有当累加器中的值大于阈值时,才被认为是一条直线。 函数返回的是一个由直线参数组成的数组,每个直线参数是一个(rho, theta)对,表示检测到的一条直线。可以根据需要对返回的直线进行后续处理或绘制。 另外,OpenCV还提供了`HoughLinesP`函数,它可以直接返回直线在图像上的起点和终点坐标,方便进行直线的绘制。 ```python lines = cv2.HoughLinesP(image, rho, theta, threshold, minLineLength, maxLineGap) ``` 除了上述参数外,`HoughLinesP`还包含两个额外的参数: - `minLineLength`:表示线段的最小长度,小于该长度的线段会被排除。 - `maxLineGap`:表示两条线段之间的最大间隔,超过该间隔的线段会被视为不同的线段。 希望这些信息能帮助到你进行霍夫直线检测!如有更多问题,请继续提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值