目录
1--原理
2--Opencv API
3--实例代码
4--霍夫变换检测圆
具体原理可参考 博客1 和 视频讲解1;
霍夫变换检测直线的核心思想是:在笛卡尔坐标系下,一条直线(两个点(x1, y1)和(x2, y2)确定一条直线)可以变换为霍夫空间中的一个点(r, θ),由霍夫空间的一个点表示笛卡尔坐标系的一条直线;
对于图像中的直线而言,其由许多个像素点组成;而笛卡尔坐标系中的像素点可以映射为霍夫空间中的一条直线(因为一个像素点可以组成无数条直线,每一条直线对应霍夫空间的一个点),即霍夫空间的一条直线,对应笛卡尔坐标系的一个点;
对于霍夫空间中的每一条直线,其存在交点,霍夫空间的多条直线相交于一个交点,这个交点对应于笛卡尔坐标系下的一条直线,通过在霍夫空间中检测交点的个数及确定交点的坐标(r, θ),可以检测笛卡尔坐标系下的直线。
进行霍夫变换直线检测时,通常配合 Canny边缘检测算法 进行,先对图片进行边缘检测,再进行直线检测;
# include
# include
# include
int main(int argc, char** argv){
cv::Mat src;
src = cv::imread("C:/Users/Liujinfu/Desktop/opencv_bilibili/test_1218.jpg");
if (src.empty()){
printf("could not load image..\n");
return -1;
}
cv::imshow("input", src);
cv::Mat canny, dst;
cv::Canny(src, canny, 150, 200); // 配合canny算法使用
cv::cvtColor(canny, dst, cv::COLOR_GRAY2BGR); //灰度图转换为彩色图
cv::imshow("edge", canny);
std::vector plines;
cv::HoughLinesP(canny, plines, 1, CV_PI / 180.0, 5, 0, 10);
cv::Scalar color = cv::Scalar(0, 0, 255);
for(size_t i = 0; i < plines.size(); i++){
cv::Vec4f hline = plines[i];
cv::line(dst, cv::Point(hline[0], hline[1]), cv::Point(hline[2], hline[3]), color, 3, cv::LINE_AA);
}
cv::imshow("output", dst);
cv::waitKey(0);
return 0;
}
① 原理建议参考视频讲解2;
② Opencv API
参数说明:
cv::InputArray image:表示输入图像;
cv::OutputArray circles:圆的参数,包含圆心坐标和圆的半径;
int method:采用的检测方法,默认使用霍夫梯度法;
double dp:累加器分辨率与图像分辨率的反比。dp=1表示累加器具有与输入图像相同的分辨率。
double minDist:标新两个圆心之间的最小距离;
double param1 = (100.0):表示边缘检测对应的参数。对于霍夫梯度法而言,表示为传递给canny边缘检测算子的高阈值,而低阈值则为高阈值的一半;
double param2 = (100.0):表示检测方法对应的参数。对于霍夫梯度法而言,表示在检测阶段圆心的累加器阈值。参数值越小就越可以检测出更多不存在的圆;反之,检测出的圆一般都很完美;
int minRadius = 0:表示半径的最小值;
int maxRadius = 0:表示半径的最大值;
③ 代码实例
# include
# include
# include
int main(int argc, char** argv){
cv::Mat src;
src = cv::imread("C:/Users/Liujinfu/Desktop/opencv_bilibili/test_1221.jpg");
if (src.empty()){
printf("could not load image..\n");
return -1;
}
cv::imshow("input", src);
cv::Mat temp, gray, dst;
cv::medianBlur(src, temp, 3); // 中值滤波去除噪声
cv::cvtColor(temp, gray, cv::COLOR_BGR2GRAY); // 灰度化
// 霍夫圆检测
std::vector pcircles;
cv::HoughCircles(gray, pcircles, cv::HOUGH_GRADIENT, 1, 20, 100, 100, 1, 100);
src.copyTo(dst);
for(size_t i = 0; i < pcircles.size(); i++){
cv::Vec3f cc = pcircles[i]; // cc[0] -> x cc[1] -> y cc[2] -> r
cv::circle(dst, cv::Point(cc[0], cc[1]), cc[2], cv::Scalar(0, 0, 255), 2, cv::LINE_AA); // 可视化圆弧
cv::circle(dst, cv::Point(cc[0], cc[1]), 1, cv::Scalar(255, 0, 0), 2, cv::LINE_AA); // 可视化圆心
}
cv::imshow("output", dst);
cv::waitKey(0);
return 0;
}