汽车工业领域的法兰盘分布有螺纹孔,实际生产过程中,螺纹孔因加工问题未安上螺纹,本项目旨在对法兰盘螺纹孔定位并检测。
定位圆环ROI过程如下所示
一、Canny算子边缘检测得到边缘图
cv::Mat cannyImg;
int low_Val = 100, high_Val = 2 * low_Val; //进行Canny边缘检测的高阈值与低阈值
cv::Canny(image0, cannyImg, low_Val, high_Val, 3); //Canny边缘检测参数,默认apertureSize = 3
二、闭运算
Mat closeSmallImg;
cv::Mat elementSmall = cv::getStructuringElement(cv::MORPH_ELLIPSE,
cv::Size(3, 3)
);
//不用开运算会把轮廓去掉
//不用9*9,9*9得到的螺纹孔更多,但背景的圆不易被剔除掉,后续思考改进
cv::morphologyEx(cannyImg, closeSmallImg, cv::MORPH_CLOSE, elementSmall);
//将小空隙填满,将临近的轮廓连接
三、轮廓跟踪寻找轮廓
vector<cv::Vec4i> hierarchy;
vector<vector<cv::Point> > contours;
cv::findContours(closeSmallImg, contours, hierarchy,
cv::RETR_TREE, cv::CHAIN_APPROX_NONE, cv::Point(0, 0));
Mat drawImg = Mat::zeros(cannyImg.size(), CV_8UC3);
cv::RNG rng(12345);
for (int i = 0; i < contours.size(); i++)
{
cv::Scalar color = cv::Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255));
cv::drawContours(drawImg, contours, i, color, 2, 8, hierarchy, 0, cv::Point());
}
cv::imshow("s3 Contours Image", drawImg);
四、预设置参数
//轮廓长度与轮廓间距离设置
int minCDis = 50; //筛选轮廓时,允许的最小轮廓间距离
int minCircleLen = 65; //筛选轮廓时定位圆孔的最小轮廓长度
int maxCircleLen = 75; //筛选轮廓时定位圆孔的最大轮廓长度
//圆环半径设置
float RH_mm = 140; //检测圆盘圆孔的半径 单位:毫米
float R0_mm = 115; //检测圆盘的内径 单位:毫米
float R1_mm = 160; //检测圆环的外径 单位:毫米
//二、标记ROI预览显示ROI
cv::Point estimateCenter = cv::Point(750, 500); //估计的ROI区域的中心坐标
int estimateRadius = 500; //估计的ROI区域的半径
Mat subImg = Mat::zeros(image0.size(), CV_8UC1); //初始化一个mat,其大小与srcImg一样,类型为8位单通道类型
image0.copyTo(subImg); //把src里的图像复制到subimg中
cv::cvtColor(subImg, subImg, cv::COLOR_GRAY2RGB); //把subimg转变为彩色图像
//thickness为1,lineType为8,shift为对应给定点的小数位数(0对结果不产生影响)
cv::circle(subImg, estimateCenter,
estimateRadius, cv::Scalar(0, 0, 255), 1, 8, 0); //在subimg上画圆
cv::imshow("s0 ROI Img", subImg);
五、轮廓筛选
const cv::Scalar RED = cv::Scalar(0, 0, 255);
const cv::Scalar GREEN = cv::Scalar(0, 255, 0);
const cv::Scalar BLUE = cv::Scalar(255, 0, 0);
const cv::Scalar YELLOW = cv::Scalar(0, 255, 255);
//1.不在估计区域范围内的轮廓去掉,相同重心的轮廓只保留一个contours2
// Get the moments,得到轮廓矩
vector<cv::Moments> mu(contours.size());
for (int j = 0; j < contours.size(); j++)
{
mu[j] = moments(contours[j], false);
}
/// Get the mass centers,重心
vector<cv::Point2f> mc(contours.size());
for (int j = 0; j < contours.