C++如何用OpenCV中实现图像的边缘检测和轮廓提取?

最近有个项目需要做细孔定位和孔距测量,需要做边缘检测和轮廓提取,先看初步效果图:

主要实现代码:


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);
}