1. C/C++

OpenCV-第十八话-霍夫变换

一.霍夫直线变换介绍

Hough Line Transform用来做直线检测

前提条件边缘检测已经完成

平面空间到极坐标空间转换

Hough Line Transform用来做直线检测

前提条件边缘检测已经完成

平面空间到极坐标空间转换

二.相关API

标准的霍夫变换 cv::HoughLines从平面坐标转换到霍夫空间,最终输出是 (Θ,r) 表示极坐标空间

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
) // 一般情况是有经验的开发者使用,需要自己反变换到平面空间

霍夫变换直线概率 cv::HoughLinesP最终输出是直线的两个点(x0,y0,x1,y1)

cv::HoughLinesP(
InputArray src, // 输入图像,必须8-bit的灰度图像
OutputArray lines, // 输出的极坐标来表示直线
double rho, // 生成极坐标时候的像素扫描步长
double theta, //生成极坐标时候的角度步长,一般取值CV_PI/180
int threshold, // 阈值,只有获得足够交点的极坐标点才被看成是直线
double minLineLength=0;// 最小直线长度
double maxLineGap=0;// 最大间隔
)

三.霍夫直线代码实现

/*
OpenCV 霍夫变换学习
Michael Jiang<sencom1997@outlook.com>
2019年7月26日14:34:37
*/

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>

using namespace cv;
using namespace std;
int main()
{
	Mat src, dst, gray, hou,fin;

	//读取图像
	src = imread("D:/test18.png", IMREAD_COLOR);

	//判断读取是否成功
	if (src.empty()) {
		printf("pic load failed!\n");
		return -1;
	}
	imshow("src", src);

	src.copyTo(fin);

	//高斯模糊
	GaussianBlur(src, dst, Size(3, 3), 0, 0, BORDER_DEFAULT);

	//转灰度
	cvtColor(dst, gray, COLOR_BGR2GRAY);
	imshow("gray", gray);

	//Canny边缘检测
	Canny(gray, hou, 50, 70);

	vector<Vec4f> lines;
	//霍夫直线变换
	HoughLinesP(hou,lines,1,CV_PI/180.0,10,50,20);
	for (size_t i = 0; i < lines.size(); i++) {
		Vec4f h = lines[i];
		line(fin, Point(h[0], h[1]), Point(h[2], h[3]), Scalar(0, 0, 0), 3, LINE_AA);
	}
	imshow("fin", fin);

	waitKey(0);
	return 0;
}

直线全部被检测出来

四.霍夫圆变换

1.原理

从平面坐标到极坐标转换三个参数C(x0,y0,r)其中x0,y0是圆心

假设平面坐标的任意一个圆上的点,转换到极坐标中:C(x0,y0,r)处有最大值,霍夫变换正是利用这个原理实现圆的检测。

2.相关API

相关API cv::HoughCircles

因为霍夫圆检测对噪声比较敏感,所以首先要对图像做中值滤波。

基于效率考虑,Opencv中实现的霍夫变换圆检测是基于图像梯度的实现,分为两步:

  1. 检测边缘,发现可能的圆心
  2. 基于第一步的基础上从候选圆心开始计算最佳半径大小
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//最大半径 
)

3.代码实现

/*
OpenCV 霍夫变换学习
Michael Jiang<sencom1997@outlook.com>
2019年7月26日15:05:25
*/

#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>

using namespace cv;
using namespace std;
int main()
{
	Mat src, dst, gray, hou,fin;

	//读取图像
	src = imread("D:/test18.png", IMREAD_COLOR);

	//判断读取是否成功
	if (src.empty()) {
		printf("pic load failed!\n");
		return -1;
	}
	imshow("src", src);

	src.copyTo(fin);

	//高斯模糊
	GaussianBlur(src, dst, Size(3, 3), 0, 0, BORDER_DEFAULT);

	//转灰度
	cvtColor(dst, gray, COLOR_BGR2GRAY);
	imshow("gray", gray);

	//Canny边缘检测
	Canny(gray, hou, 50, 70);

	vector<Vec4f> circles;
	//霍夫圆变换
	HoughCircles(hou, circles,HOUGH_GRADIENT,1,10,100,30,5,145);
	for (size_t i = 0; i < circles.size(); i++) {
		Vec4f h = circles[i];
		circle(fin, Point(h[0], h[1]), h[2], Scalar(0, 0, 255), 3, LINE_AA);
		circle(fin, Point(h[0], h[1]), 2, Scalar(0, 255, 0), 3, LINE_AA);
	}
	imshow("fin", fin);

	waitKey(0);
	return 0;
}