如何判断轮廓是否为圆?
判断一个轮廓是否为圆?这看似简单的问题,在opencv中并没有现成的函数。当我真正想运用的时候,却发现还是有许多内容在里面的。
比如这幅图片,由于瓶口是有缺陷的,造成找到的最大外轮廓不闭合。那么该如何判断这个轮廓是否是圆了。
我认为从两点来考虑。
一个是圆的定义:
“平面上到定点的距离等于定长的所有点组成的图形叫做圆.定点称为圆心,定长称为半径.”
那么就来判断当前轮廓到一个定点的距离是否为定长。这里这个定点就可以采用外接圆圆心。而这里的度量是标准差。
经过试验发现,对于这些有缺陷的情况,其标准差都是比较大的(一般大于5),而对于没有缺陷的情况来说,其标准差都比较小(小于1)。
但是这并不能完全地解决问题,比如存在这样的情况,其轮廓上所有点到定点的标准差也是不大的,但是这个轮廓没有构成一个闭合曲线,所以也没有构成圆。
//根据轮廓点和圆心计算方差
float ComputeVariance(std::vector<cv::Point> theContour,Point2f theCenter)
{
int a[65535],n;
float aver,s;
float sum=0,e=0;
n = theContour.size();
for(int i=0;i<n;i++)
{
a[i] = GetDistance(theContour[i],theCenter);
sum+=a[i];
}
aver=sum/n;
for(int i=0;i<n;i++)
e+=(a[i]-aver)*(a[i]-aver);
e/=n-1;
s=sqrt(e);
return e;
}
那么二点就是曲线闭合的定义.
闭曲线:起点与终点重合的曲线。平面(或空间)中的闭曲线即为单位圆周到平面(或空间)中的连续映射的像。
不是很好理解,但是可以这样简化,就是对于闭曲线中的任意一点,遍历闭曲线,都能够回到这一点。换句话说,就是不存在“端点”。这里可以再转换为这样的理解:
“对于闭曲线中的所有点,除了它本身之外,和这个点距离为最小值(比如1)的点都有两个。”
//判断轮廓是否闭合。闭合曲线返回为0
intComputeClose(std::vector<cv::Point>MaxContour)
{
//TODO 计算第一个点和最后一个点相对于圆心的角度.最后变成计算这两点的距离
int itmp =0;
int iret =0;
for(int i=0;i<MaxContour.size();i++)
{
for(int j=0;j<MaxContour.size();j++)
{
if(i!=j)
{
if(GetDistance(MaxContour[i],MaxContour[j])<1)
{
itmp++;
}
}
}
if(itmp ==1)//存在端点
{
iret ++;
}
itmp=0;
}
return iret;
}
小结一下:数学还是很强的,很多时候,借助定义本身,能够解决问题。