最近有个项目需要做细孔定位和孔距测量,需要做边缘检测和轮廓提取,先看初步效果图:
主要实现代码:
int MainWindow::Test()
{
// 2.9 单个像素长度um 5倍
double dbUnit = 2.9/(1000*5);
// 定义显示窗口
namedWindow("src", WINDOW_NORMAL|WINDOW_KEEPRATIO);
namedWindow("threshold", WINDOW_NORMAL|WINDOW_KEEPRATIO);
namedWindow("morphologyEx x1", WINDOW_NORMAL|WINDOW_KEEPRATIO);
namedWindow("morphologyEx x2", WINDOW_NORMAL|WINDOW_KEEPRATIO);
namedWindow("canny", WINDOW_NORMAL|WINDOW_KEEPRATIO);
namedWindow("dst", WINDOW_NORMAL|WINDOW_KEEPRATIO);
resizeWindow("src", 1080,720);
resizeWindow("threshold", 1080,720);
resizeWindow("morphologyEx x1", 1080,720);
resizeWindow("morphologyEx x2", 1080,720);
resizeWindow("canny", 1080,720);
resizeWindow("dst", 1080,720);
//【1】载入图像
Mat src = imread("0.28um+5x.jpg");
Mat src_clone = src.clone();
if(src.empty()){
qDebug()<<"图片为空";
return 1;
}
imshow("src",src);
//【2】转灰度图
Mat gray;
cvtColor(src,gray,COLOR_BGR2GRAY);
//imshow("gray",gray);
//【3】图像二值化
threshold(gray,gray,130,190,THRESH_BINARY);
imshow("threshold",gray);
//【4】执行形态学开操作去除噪点
Mat kernel = getStructuringElement(MORPH_RECT,Size(15,15),Point(-1,-1));
morphologyEx(gray,gray,MORPH_CLOSE,kernel,Point(-1,-1),1);
imshow("morphologyEx x1",gray);
//【4】执行形态学开操作去除噪点
Mat kernel1 = getStructuringElement(MORPH_RECT,Size(10,10),Point(-1,-1));
morphologyEx(gray,gray,MORPH_CLOSE,kernel1,Point(-1,-1),1);
imshow("morphologyEx x2",gray);
//【5】边缘检测
Canny(gray,gray,0,255);
imshow("canny",gray);
//【6】轮廓发现
vector<vector<Point>> contours;
vector<Vec4i> her;
findContours(gray,contours,her,RETR_TREE,CHAIN_APPROX_SIMPLE);
Mat srcImg = src;
//拟合椭圆:fitEllipse()
vector<RotatedRect> box(contours.size());
Point2f rect[4];
for (int i = 0; i<contours.size(); i++)
{
Rect rect = boundingRect(contours[i]);
Point2f pRadius;
if(contours[i].size()>105){
box[i] = fitEllipse(Mat(contours[i]));
//条件过滤
if( box[i].size.aspectRatio()<0.8||box[i].size.area()>10000000||rect.width<300 )
continue;
float majorAxis = std::max(box[i].size.width, box[i].size.height);
rectangle(srcImg,rect,Scalar(0, 0, 255));
ellipse(srcImg, box[i], Scalar(255, 0, 0), 1, 8);
float x = rect.width/2.0;
float y = rect.height/2.0;
//【8】找出圆心并绘制
pRadius=Point2f(rect.x+x,rect.y+y);
cv::String det_info = cv::format("[%d] %.1f,%.1f(%dx%d),%.5f mm, %.5f mm",i,
pRadius.x, pRadius.y, rect.width, rect.height,dbUnit*rect.width, dbUnit*majorAxis);
cv::Point bbox_points;
bbox_points = cv::Point(rect.x, rect.y);
bbox_points = cv::Point(rect.x + det_info.size() * 11, rect.y);
bbox_points = cv::Point(rect.x + det_info.size() * 11, rect.y - 15);
bbox_points = cv::Point(rect.x, rect.y - 15);
cv::putText(srcImg, det_info, bbox_points, cv::FONT_HERSHEY_DUPLEX, 0.4, cv::Scalar(255, 255, 255), 1, cv::LINE_AA);
circle(srcImg,pRadius,1,Scalar(0,0,255),1);
pRadius=box[i].center;
circle(srcImg,pRadius,1,Scalar(255,0,0),1);
}
}
// 绘制结果
imshow("dst", srcImg);
// 保存结果
imwrite("dst.png", srcImg);
}