在上篇文章我们已经检测到了内圆,本篇将根据上篇得到的内圆来检测外圆。步骤如下:
第一步:
用下面的这个算子对原图做卷积操作,这个算子可以叫作Vertical Filter
-1,0,1,
-1,0,1,
-1,0,1,
-1,0,1,
-1,0,1
卷积后的结果如下:
第二步:对第一步得到的结果进行二值化,这个我设的阈值是10。二值化后的结果如下
第三步:计算规矩规定角度范围弧线上的白点的数量,注意这个是针对不同的半径都要计算,半径的变化范围从1.8*内圆半径开始逐渐变大,一直到三倍的半径。下图是角度范围的约定。从下图可以看图角度的范围是左右两边各向下的60度区间,但在我实验中是左右两边各向下30度的区间。
第四步:找到在规定弧线上白点最大的半径,这个半径就是最后的外圆半径。最后的结果如下:
外圆检测加上内圆检测的全部opencv代码如下:
#include
#include
using namespace cv;
using namespace std;
int main()
{
Mat srcImage=imread("C://150.bmp");
Mat midImage,dstImage,edge;
Mat srcImage1=srcImage.clone();
imshow("原始图",srcImage);
//外圆
Mat kern = (Mat_(5,3) << -1, 0 ,1,
-1, 0 ,1,
-1, 0 ,1,
-1, 0 ,1,
-1, 0 ,1);
Mat dst;
filter2D(srcImage,dst,srcImage.depth(),kern);
namedWindow("卷积",WINDOW_AUTOSIZE);
imshow("卷积",dst);
threshold(dst,dst,10,255,CV_THRESH_BINARY);
namedWindow("二值化",WINDOW_AUTOSIZE);
imshow("二值化",dst);
threshold(srcImage, srcImage, 30, 200.0, CV_THRESH_BINARY);//二值化
imshow("二值化1",srcImage);
int cn=0;//cn是圆的个数
int radius=0;
float ratio = 0;
float maxratio = 0;
float result[3];
cvtColor(srcImage,midImage,COLOR_BGR2GRAY);
blur(midImage,edge,Size(3,3));
Canny(edge,edge,3,9,3);
GaussianBlur(midImage,midImage,Size(9,9),2,2);
vector circles;
HoughCircles(midImage,circles,CV_HOUGH_GRADIENT,2,10,200,80,0,0);
for(cn=0;cn(i,j)[2]; //cvGetReal2D(img,i,j);
if(value == 0)
count++;
}
}
ratio = float(count)/(3.14*radius*radius);
if (ratio >= maxratio)
{
result[0] = circles[cn][0];
result[1] = circles[cn][1];
result[2] = radius;
maxratio = ratio;
}
}
printf("黑色点像素的个数:%d\n",count);
printf("瞳孔重合比率:%f\n",ratio);
Point center1(cvRound(result[0]),cvRound(result[1]));
circle(srcImage1,center1,3,Scalar(0,255,0),-1,8,0);
circle(srcImage1,center1,result[2],Scalar(155,50,255),3,8,0);
}
//外圆
int r=result[2];
int value;
int tmp_count = 0;
int test=0;
int outer_r = 0;
int max_count = 0;
int ti,tj;
for(double tr = 1.8*r;tr< 3*r;tr++ ) // 半径的长度 1.8倍的半径到3倍的半径
{
tmp_count = 0;
for(double angle = 0;angle<=60;angle++)
{
ti = cvRound(result[1] + tr*cos(angle));
tj = cvRound(result[0]+tr*sin(angle));
if ((ti < dst.rows) && (ti>0)&&(dst.cols)&&(tj>0))
value =dst.at(ti,tj)[2];
else break;
if( value == 255)
tmp_count++;
}
if (tmp_count>=max_count) //白点个数最大的值,然后这个时候半径就是外圆的半径
{
max_count = tmp_count;
outer_r = tr;
test++;
}
}
printf("outer radius = %d\n",outer_r);
//画外圆,已经知道内圆的圆心,外圆也是这个圆心,外圆半径的大小为outer_r
Point center1(cvRound(result[0]),cvRound(result[1]));
circle(srcImage1,center1,3,Scalar(0,255,0),-1,8,0);
circle(srcImage1,center1,outer_r,Scalar(155,50,255),3,8,0);
if(cn==0)
{
printf("No Circle Detected!!Please Check!!\n");
system("pause");
}
imshow("效果图",srcImage1);
waitKey(0);
return 0;
}
这样就能实现 虹膜内外圆的精定位了!