hough检测圆的思路:
(1)图像中取出圆的轮廓(灰度值为255)
(2)根据圆的极坐标公式:
现在已知的是圆上的点,则x,y已知,反推出x0 和 y0(圆心的位置)。
的范围是0~360度,不过注意要转化成弧度。
(3)投票机制:
每次根据(2)公式得到的点,都在数组相应坐标+1
(4)归一化:
得到最大投票数的点,生成的图像在该点的像素灰度置为255。
(5)画圆。
根据搜索的半径,画圆。
#include <opencv2/opencv.hpp>
#include <iostream>
#include <vector>
using namespace std;
using namespace cv;
bool range(Mat &im, int x, int y)//判定是否在图片区域内
{
if(x >= 0 && x < im.cols && y >= 0 && y < im.rows)
return true;
return false;
}
void houghCircle(Mat &image, int r)
{
int mat_size = image.cols * image.rows;
int *p_map = new int[mat_size];
memset(p_map, 0, 4 * mat_size);
int max_value = 0;
for(int i = 0; i < image.cols; i++)
{
for(int j = 0; j < image.rows; j++)
{
if(image.at<uchar>(j,i) == 255)
for(int a = 0; a < 360; a++)
{
double theta = a * CV_PI / 180;//转成弧度制
int x = i - r * cos(theta);//得到理想圆心x坐标
int y = j - r * sin(theta);//得到理想圆心y坐标
if(range(image, x, y))
{
p_map[y * image.cols + x]++;
int value_ = p_map[y * image.cols + x];
max_value = max_value < value_ ? value_ : max_value;//记录最大投票数
}
}
}
}
for(int i = 0; i < image.cols; i++)
{
for(int j = 0; j < image.rows; j++)
{
p_map[j * image.cols + i] = p_map[j * image.cols + i] * 255 / max_value;//归一化
}
}
Mat dst_mat = Mat::zeros(image.size(), CV_8UC1);
Point center;
for(int i = 0; i < dst_mat.cols; i++)
{
for(int j = 0; j < dst_mat.rows; j++)
{
uchar * color_ptemp = dst_mat.ptr<uchar>(j);
color_ptemp[i] = p_map[j * image.cols + i];
if(color_ptemp[i] == 255)
center = Point(i, j);//记录投票数最大的为圆心
}
}
circle(dst_mat, center, r, Scalar(255),1);
delete []p_map;
imshow("dst_mat",dst_mat);
}
int main()
{
Mat image = imread("c.jpg",IMREAD_GRAYSCALE);
imshow("image",image);
houghCircle(image,50);
waitKey();
return 0;
}
原图:
hough检测圆: