opencv学习笔记(六)霍夫直线检测和圆检测

1.霍夫变换直线检测和圆检测

霍夫变换是一种从空间域到极坐标域的转换。已知二维空间的一条直线有很多表现方式,例如截距式斜率式比如:y=kx+b,一旦我们知道k和b,就知道了这条直线,而k和b在坐标上表示的只是一个点而已,如果直线的k相同也就是直线平行,那么表现在kb坐标域也就是条k直线。那么问题在于,如何在kb坐标系表示一个点呢?显然不是很好表示,因为过一个点直线的kb不同的话,kb值表示了一整个坐标系。如果点表示出来是一条直线或者曲线是不是就很好了呢?

霍夫变换和这种想法类似,归根到底是寻找直线的不同表现方法,霍夫变换使用原点到直线的距离p和对一个角度θ表示方程为:
ρ = x c o s θ + y s i n θ \rho =xcos\theta+ysin\theta ρ=xcosθ+ysinθ
而过一个点的直线,在相应极坐标域中表示为一条正弦曲线,正弦曲线相交两点就共线,这样就达到了一开始的目的,找到了一条直线。

变换到极坐标中,从[0~360]空间,可以得到r的大小

属于同一条直线上点在极坐标空(r, theta)必然在一个点上有最强的信号出现,根据此反算到平面坐标中就可以得到直线上各点的像素坐标。从而得到直线

同样根据类似原理可以进行任意形状的检测,归根到底就是找出形状的点的相同之处,例如使用一个关于角度的函数和一个关于距离的函数表达任意形状,根据已知形状构建直角空间到这两个函数之间的映射关系,在将一幅图中的所有点都去进行该变换,查表如果点都集中在一个地方说明满足形状这一特征。可以总结为变换(找特征)+阈值(分类)问题。

圆检测的源码原理https://www.cnblogs.com/ql698214/p/5412822.html

API:

直线检测:

cv::HoughLinesP(

InputArray src, // 输入图像,必须8-bit的灰度图像

OutputArray lines, // 输出的极坐标来表示直线

double rho, // 生成极坐标时候的像素扫描步长 一般取1

double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180

int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线

double minLineLength=0;// 最小直线长度

double maxLineGap=0;// 最大间隔

)

返回vec2 rho 和theta

cv::HoughLines(

InputArray src, // 输入图像,必须8-bit的灰度图像

OutputArray lines, // 输出的极坐标来表示直线

double rho, // 生成极坐标时候的像素扫描步长

double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180

int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线

double srn=0;// 是否应用多尺度的霍夫变换,如果不是设置0表示经典霍夫变换

double stn=0;//是否应用多尺度的霍夫变换,如果不是设置0表示经典霍夫变换

double min_theta=0; // 表示角度扫描范围 0 ~180之间, 默认即可

double max_theta=CV_PI

)

返回vec4 两点坐标

圆检测:

HoughCircles(

InputArray image, // 输入图像 ,必须是8位的单通道灰度图像

OutputArray circles, // 输出结果,发现的圆信息

Int method, // 方法 - HOUGH_GRADIENT

Double dp, // dp = 1;

Double mindist, // 10 最短距离-可以分辨是两个圆的,否则认为是同心圆- src_gray.rows*/8*

Double param1, // canny edge detection low threshold

Double param2, // 中心点累加器阈值 – 候选圆心

Int minradius, // 最小半径

Int maxradius//最大半径

)

返回vec3 圆心和半径

代码案例:

#include"pch.h"
#include<opencv2/opencv.hpp>
#include<iostream>

using namespace std;
using namespace cv;


Mat src, gray_src, dst_line, dst_circle;


int main(int argc, char** argv) {
	src = imread("test.png");
	if (!src.data) {
		printf("没找到图像");
		return-1;
	}
	Canny(src, gray_src, 150, 200);
	cvtColor(gray_src, dst_line, CV_GRAY2BGR);
	dst_line.copyTo(dst_circle);


	namedWindow("input", CV_WINDOW_AUTOSIZE);
	imshow("input", gray_src);

	vector<Vec2f>lines;//选择容器类型

	//API缺陷在于返回的是ρ和θ,代表一条直线,并不是返回这些点。因此画出来的直线之能是全屏直线,无法是某段线段。

	HoughLines(gray_src, lines, 1, CV_PI / 180, 70, 0, 0);//返回类型是含有θ和ρ的矢量lines


	for (size_t i = 1; i < lines.size(); i++) {

		float rho = lines[i][0]; 
		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));
		Scalar color= Scalar(0, 0, 255);
		line(dst_line, pt1, pt2, color, 1, CV_AA);//通过1000控制两个点之间的间隔,连线
		
	}

	vector<Vec4f>plines;
	HoughLinesP(gray_src, plines, 1, CV_PI / 180, 30, 0, 0);//返回空间域坐标,也就是点的坐标因此出来的结果是线段
	for (size_t i = 1; i < plines.size(); i++) {
		Vec4f hline = plines[i];
		line(dst_line, Point(hline[0], hline[1]), Point(hline[2], hline[3]), Scalar(255,0,255), 3, LINE_AA);
	}
	namedWindow("output", CV_WINDOW_AUTOSIZE);
	imshow("output", dst_line);

	vector<Vec3f>cir;
	HoughCircles(gray_src, cir, HOUGH_GRADIENT, 1,10,40,40,100);
	for (size_t i = 1; i < cir.size(); i++) {
		Vec3f circlepoint = cir[i];
		circle(dst_circle, Point(circlepoint[0], circlepoint[1]), circlepoint[2], Scalar(0, 255, 0), 1);
	}
	namedWindow("output2", CV_WINDOW_AUTOSIZE);
	imshow("output2", dst_circle);

	waitKey(0);
	return 0;

}

结果:
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值