提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
最近测试了一个检测项目,需要检测出手机后置摄像头孔洞圆环周边是否全部点胶,并计算点胶完成的百分比。
点胶区域识别由前序深度学习软件识别,并在示意图中画出深度学习识别的点胶部分,如下图红色连通域。
主要方法是调用霍夫圆检测函数,并根据机械定位和先验信息约束正解。
Mat src = imread("..\\data\\0.jpg", 1);//输入图
Mat srcdisplay = Mat::zeros(src.rows, src.cols, CV_8UC1);
vector<Mat> channels;
split(src, channels);
Mat heightMapRed = channels.at(2);
//1检测圆心半径
Mat srcgray;
cvtColor(src, srcgray, COLOR_RGB2GRAY);
double circle_R = 0;
double perimeter = 0;
double circlearea = 0;
vector<Vec3f> circles;
Point circle_center;
HoughCircles(srcgray, circles, HOUGH_GRADIENT, 1, 200, 100, 30, 800, 1200);
for (size_t i = 0; i < circles.size(); i++)
{
Point center((circles[i][0]), (circles[i][1]));
int radius = (circles[i][2]);
if (center.x <2200 && center.x > 1800 && center.y < 1900 && center.y > 1500 && radius > 900 && radius < 1100)
{
circle_R = radius + 12;
circle_center = center;
cout << "圆心X=" << center.x << " " << "圆心Y=" << center.y << " " << "半径R=" << radius << endl;
circle(src, center, 3, Scalar(255, 255, 255), -1, 8, 0);
perimeter = 6.28 * circle_R;
circlearea = 3.14 * circle_R * circle_R;
}
}
即计算每一点与圆心连线与圆的交点,可由数字知识推理如下。
在求解的过程中还需要考虑一些特殊的情况。
比如当直线k值不存在,即x坐标等于圆心坐标时,y坐标可由圆心y坐标和半径直接计算;
当有两个坐标解时,可根据x坐标与圆心坐标大小来判断哪个是需要的解。
具体实现代码如下:
//2读取坐标文件
vector <Point> circlepoint;
for (int x = 0; x < srcgray.rows; x++)
{
for (int y = 0; y < srcgray.cols; y++)
{
if (heightMapRed.at<uchar>(x, y) == 255)
circlepoint.push_back(Point(y, x));
}
}
//3求圆和线交点
vector <Point> reflectepoint;
double k = 0;
double b = 0;
double a = 0;
double b1 = 0;
double c = 0;
double dlta = 0;
double x1, y1, x2, y2;
for (int i = 0; i < circlepoint.size(); i++)
{
if (circlepoint[i].x < circle_center.x)
{
k = (double)(circlepoint[i].y - circle_center.y) / (circlepoint[i].x - circle_center.x);
b = (circle_center.y - k * circle_center.x);
a = k * k + 1;
b1 = 2 * k * b - 2 * k * circle_center.y - 2 * circle_center.x;
c = circle_center.x * circle_center.x - circle_R * circle_R + (b - circle_center.y) * (b - circle_center.y);
dlta = b1 * b1 - 4 * a * c;
if (dlta >= 0)
{
x1 = (-b1 - sqrt(dlta)) / (2 * a);
x2 = (-b1 + sqrt(dlta)) / (2 * a);
y1 = k * x1 + b;
y2 = k * x2 + b;
if (x1 < circle_center.x)
{
reflectepoint.push_back(Point(x1, y1));
}
if (x2 < circle_center.x)
{
reflectepoint.push_back(Point(x2, y2));
}
}
}
else if (circlepoint[i].x > circle_center.x)
{
k = (double)(circlepoint[i].y - circle_center.y) / (circlepoint[i].x - circle_center.x);
b = (circle_center.y - k * circle_center.x);
a = k * k + 1;
b1 = 2 * k * b - 2 * k * circle_center.y - 2 * circle_center.x;
c = circle_center.x * circle_center.x - circle_R * circle_R + (b - circle_center.y) * (b - circle_center.y);
dlta = b1 * b1 - 4 * a * c;
if (dlta >= 0)
{
x1 = (-b1 - sqrt(dlta)) / (2 * a);
x2 = (-b1 + sqrt(dlta)) / (2 * a);
y1 = k * x1 + b;
y2 = k * x2 + b;
if (x1 > circle_center.x)
{
reflectepoint.push_back(Point(x1, y1));
}
if (x2 > circle_center.x)
{
reflectepoint.push_back(Point(x2, y2));
}
}
}
else
{
if (circlepoint[i].y < circle_center.y)
{
reflectepoint.push_back(Point(circlepoint[i].x, circle_center.y - circle_R));
}
if (circlepoint[i].y > circle_center.y)
{
reflectepoint.push_back(Point(circlepoint[i].x, circle_center.y + circle_R));
}
}
}
通过第二步计算得到参考圆上对应交点所围成的扇形面积与圆面积比例映射出残缺圆环所占比例
//4画出映射点
for (int i = 0; i < reflectepoint.size(); i++)
{
line(src, reflectepoint[i], reflectepoint[i], Scalar(255, 255, 255), 3);
}
//imwrite("1.jpg", src);
for (int i = 0; i < reflectepoint.size(); i++)
{
line(srcdisplay, reflectepoint[i], circle_center, Scalar(255, 255, 255), 1);
line(src, reflectepoint[i], circle_center, Scalar(255, 255, 255), 1);
}
//5预处理
Mat element = getStructuringElement(MORPH_RECT, Size(7, 7));
dilate(src, src, element);
//imwrite("2.jpg", src);
dilate(srcdisplay, srcdisplay, element);
int bowarea = 0;
int temp = 0;
for (int x = 0; x < srcdisplay.rows; x++)
{
for (int y = 0; y < srcdisplay.cols; y++)
{
temp = srcdisplay.at<uchar>(x, y);
if (temp == 255)
bowarea++;
}
}
double factor = bowarea / circlearea;
cout <<"残缺圆环占比:"<< 1 - factor << endl;
总的来说,方法思路还是很简单普通的,但代码实现起来可能有点繁琐,需要考虑特殊情况来提高代码鲁棒性和计算的准确性。
相关图片和源代码可在https://github.com/chaochaojnu下载