可以通过圆的大小,圆心间距离等参数来调节结果输出。
原理:
圆形的表达式为(x−xcenter)2+(y−ycenter)2=r2(x−xcenter)2+(y−ycenter)2=r2,一个圆环的确定需要三个参数。那么霍夫变换的累加器必须是三维的,但是这样的计算效率很低。
这里opencv中使用霍夫梯度的方法,这里利用了边界的梯度信息。
首先对图像进行canny边缘检测,对边缘中的每一个非0点,通过Sobel算法计算局部梯度。那么计算得到的梯度方向,实际上就是圆切线的法线。三条法线即可确定一个圆心,同理在累加器中对圆心通过的法线进行累加,就得到了圆环的判定。
cv2.HoughCircles函数的参数
cv2.HoughCircles(image, method, dp, minDist, circles, param1, param2, minRadius, maxRadius)
1
image为输入图像,需要灰度图
method为检测方法,常用CV_HOUGH_GRADIENT
dp为检测内侧圆心的累加器图像的分辨率于输入图像之比的倒数,如dp=1,累加器和输入图像具有相同的分辨率,如果dp=2,累计器便有输入图像一半那么大的宽度和高度
minDist表示两个圆之间圆心的最小距离
param1有默认值100,它是method设置的检测方法的对应的参数,对当前唯一的方法霍夫梯度法cv2.HOUGH_GRADIENT,它表示传递给canny边缘检测算子的高阈值,而低阈值为高阈值的一半
param2有默认值100,它是method设置的检测方法的对应的参数,对当前唯一的方法霍夫梯度法cv2.HOUGH_GRADIENT,它表示在检测阶段圆心的累加器阈值,它越小,就越可以检测到更多根本不存在的圆,而它越大的话,能通过检测的圆就更加接近完美的圆形了
minRadius有默认值0,圆半径的最小值
maxRadius有默认值0,圆半径的最大值
import os
import cv2
import numpy as np
img_paths=[
r"E:\jinji\0001.png",
r"E:\jinji\0010.jpg"
]
for path in img_paths:
img = cv2.imread(path,0)
# img = cv2.medianBlur(img,3)
cv2.imshow('img_o',img)
img = cv2.GaussianBlur(img, (3, 3), 0)
img = cv2.medianBlur(img, 5)
cimg = cv2.cvtColor(img,cv2.COLOR_GRAY2BGR)
circles = cv2.HoughCircles(img,cv2.HOUGH_GRADIENT,1,60,param1=30,param2=12,minRadius=2,maxRadius=30)
circles = np.uint16(np.around(circles))
for i in circles[0,:]:
# draw the outer circle
cv2.circle(cimg,(i[0],i[1]),i[2],(0,255,0),1)
# draw the center of the circle
cv2.circle(cimg,(i[0],i[1]),2,(0,0,255),1)
cv2.imshow('detected circles',cimg)
cv2.waitKey(0)
cv2.destroyAllWindows()
也可以用均值漂移来过滤背景
img_o=cv2.imread(path)
# img = cv2.medianBlur(img,3)
cv2.imshow('img_o',img_o)
# img = cv2.medianBlur(img,5)
img = cv2.pyrMeanShiftFiltering(src=img_o, sp=5, sr=16) # good4
转载:
OpenCV霍夫圆检测调参心得_chengchaopeng520的博客-CSDN博客_opencv霍夫圆检测
通过圆检测,来找异常的圆的方法:
#include <iostream>
//#include "cv.h"
//#include "highgui.h"
#include <math.h>
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace std;
using namespace cv;
int main(int argc , char* argv)
{
Mat img_input,img_cvt,img_threshold,img_hough,img_warp;
img_input = imread("1.png");
Mat img_copy;
img_input.copyTo(img_copy);
cvtColor(img_input, img_cvt,CV_BGR2GRAY);
threshold(img_cvt, img_threshold, 0, 255, CV_THRESH_BINARY + CV_THRESH_OTSU);
vector<Vec3f> circles;
HoughCircles(img_cvt, circles, CV_HOUGH_GRADIENT,1,10, 100,10,5,13);
//第五个参数 是圆心与圆心之间的距离
//第六个参数 就设为默认值就OK
//第七个参数这个根据你的图像中的圆 大小设置,如果圆越小,则设置越小
//第八个和第九个参数 是你检测圆 最小半径和最大半径是多少 这个是经验值
for (int i = 0; i < circles.size(); i++)
{
Point center(cvRound(circles[i][0]), cvRound(circles[i][1]));
int R = cvRound(circles[i][2]);
circle(img_input, center, 3, Scalar(0, 255, 0), -1, 8, 0);
circle(img_input, center, R, Scalar(0, 0, 255), 3, 8, 0);
}
float x_min = 0;
float y_min = 0;
float x_max = 0;
float y_max = 0;
float x_min_y = 0;
x_min = circles[1][0];
x_max = circles[1][0];
y_min = circles[1][1];
y_max = circles[1][1];
for (int i = 0; i < circles.size();i++)
{
x_min = circles[i][0]< x_min ? circles[i][0] : x_min;
x_max = circles[i][0]> x_max ? circles[i][0] : x_max;
}
for (int i = 0; i < circles.size(); i++)
{
y_min = circles[i][1]< y_min ? circles[i][1] : y_min;
y_max = circles[i][1]> y_max ? circles[i][1] : y_max;
}
for (int i = 0; i < circles.size();i++)
{
if (circles[i][0] == x_min)
{
x_min_y = circles[i][1];
}
}
float angle1 = ((y_max - x_min_y) / (x_max - x_min));
double angle2 = atan(angle1);
float angle = (angle2 * 360) /(2*3.14) ; //从弧度 转化为 角度
Mat rotmat(2, 3, CV_32FC1);
Point center = Point(img_input.cols / 2, img_input.rows / 2);
rotmat = getRotationMatrix2D(center, angle, 1);
warpAffine(img_copy, img_warp, rotmat, img_input.size()); //矫正完成;
// 矫正工作完成
Mat img_warp_cvt;
cvtColor(img_warp, img_warp_cvt, CV_BGR2GRAY);
//threshold(img_cvt, img_threshold, 0, 255, CV_THRESH_BINARY + CV_THRESH_OTSU);
vector<Vec3f> circles1;
HoughCircles(img_warp_cvt, circles1, CV_HOUGH_GRADIENT, 1,10, 100, 10, 5, 13);
//这里的参数设置,第一个,参数可以设置为1就行
//第五个参数 是圆心与圆心之间的距离
//第六个参数 就设为默认值就OK
//第七个参数这个根据你的图像中的圆 大小设置,如果圆越小,则设置越小
//第八个和第九个参数 是你检测圆 最小半径和最大半径是多少 这个是经验值
for (int m = 0; m < circles1.size(); m++)
{
int count = 0;
for (int n = 0; n < circles1.size(); n++)
{
float r = sqrt((circles1[m][0] - circles1[n][0])* (circles1[m][0] - circles1[n][0]) + (circles1[m][1] - circles1[n][1])*(circles1[m][1] - circles1[n][1]));
printf("%f\n", r);
if (r>0 && r<30)
{
count++;
if (count>=4)
{
Point center(cvRound(circles1[m][0]), cvRound(circles1[m][1]));
int radius = cvRound(circles1[m][2]);
//绘制圆心
circle(img_warp, center, 3, Scalar(255, 255, 255), 1, 8, 0);
//绘制圆轮廓
circle(img_warp, center, radius, Scalar(0, 255, 0), 2, 8, 0);
count = 0;
}
}
}
}
/* for (int i = 0; i < circles1.size(); i++)
{
Point center(cvRound(circles1[i][0]), cvRound(circles1[i][1]));
int R = cvRound(circles1[i][2]);
circle(img_warp, center, 3, Scalar(0, 255, 0), -1, 8, 0);
circle(img_warp, center, R, Scalar(0, 0, 255), 3, 8, 0);
}
*/
/*
vector<Vec3f> B;
for (int i = 0; i < circles1.size()-2; i++)
{
if (circles1[i + 1][1] - circles1[i][1] >= 3 && circles1[i + 1][1] - circles1[i][1] <= 7 )
{
B.push_back(circles1[i + 1]);
}
}
Point center3(cvRound(B[0][0]), cvRound(B[0][1]));
circle(img_warp, center3, 3, Scalar(255, 0, 0), -1, 8, 0);
*/
imshow("img_copy", img_copy);
imshow("img_warp", img_warp);
imshow("img_input", img_input);
waitKey();
return 0;
}
python参考: