by HPC_ZY
有时我们得到的“圆”不圆润,甚至存在缺失。针对这种情况,分享一种好方法。为更好解释算法,所以文中尽量避免使用MATLAB库函数,方便大家转化为C。
一、前面
一些实例
一些方法
我选择利用边缘进行计算,所以第一步提取图像边缘,方法很多。这里我使用形态学。
im = imsrc-imerode(imsrc,strel('disk',1)); % 原图-腐蚀图
- 质心法
利用平均坐标定位圆心,再计算平均半径。(适用于)
[cx, cy] = find(im>0); % 找到所有边缘点坐标
center = [sum(x)/length(x),sum(y)/length(y)]; % 计算均值
R = sum(sqrt((x-center(1)).^2+(y-center(2)).^2))/length(x); % 计算半径
- 最小二乘法
[x,y] = find(im>0); % 找到所有边缘点坐标
% 计算参数
n=length(x);
xx=x.*x;
yy=y.*y;
xy=x.*y;
% 构造矩阵
A=[sum(x) sum(y) n;sum(xy) sum(yy) sum(y);sum(xx) sum(xy) sum(x)];
B=[-sum(xx+yy);-sum(xx.*y+yy.*y);-sum(xx.*x+xy.*y)];
a=A\B;
% 结果
cx = -0.5*a(1);
cy = -0.5*a(2);
R = sqrt(-(a(3)-cx^2-cy^2));
二、本文方法
原理与实现
- 基本原理
利用圆上“任意弦中垂线经过圆心”+“两不平行线相交于一点”就能确定圆心,如下图(左)。
- 核心算法
为了计算方便,我们选择更特殊的弦(垂直于两坐标轴的两条弦),这样圆心坐标就如上图(右)所示。计算方法如下:
步骤一: 任意选择圆内一点Pi(圆外也行,只要保证构造出两条弦);
步骤二: 过Pi作垂线交圆与a1、a2,作水平线交圆与a3、a4;
步骤三: 计算Ci坐标。
当圆为完美圆时,任选一点进行上述操作,就能得到准确的圆心 - 统计学优化
当圆不圆或存在缺陷时,每次得到的Ci都不同,通过统计学删选就能获得较好的圆心位置。具体方法如下:
步骤一: 利用上述算法获得Ci(疑似圆心)分布图;
步骤二: 选择适当半径画圈,统计圈内疑似圆心的数量Nj;
步骤三: 计算Nmax = max(Nj);
步骤四: 选择满足{Nj | Nj>0.8*nMax}的位置,计算其平均值作为圆心。
获得圆心以后,也用该方法获取最优半径。 - 代码实现
原理已经描述清楚,大佬们可自行实现,下面只写代码大致结构。
for
% 1、遍历图像,找到满足行列都存在2个白点(或偶数个)的位置。
% 2、计算它们的平均值作为弦的中点。
% 3、按照上图(右)公式计算疑似圆心,并存储。
for
% 4、统计学删选获取圆心与半径
for
% 5、统计学删选获取半径
实验结果对比
三、其他
- 考虑到部分玩家可能懒得敲代码,或对算法优化方面想交流讨论,把测试代码上传
(包含上述完整代码,及测试数据)
代码链接