opencv 分水岭算法

哎哟, 我本来是想提取dem的山谷线和山脊线的,然后就搜索了一下,试了好多方法,acm的floodfill都用上了,opencv 的分水岭算法也试了,结果别人的图都运行的好好的,我的图就乱七八糟,反正今天一上午也想不出来什么好的解决方法,干脆写个博客记录一下,万一后面用得着呢,谁知道呢。

分水岭算法原理:

所有的灰度图像都可视为拓扑平面,灰度值高的区域看成山峰,灰度值低的区域看成山谷,我们向图像上所有的"山谷"注入不同颜色的水,不断的注水,水位则不断上升,注入的水将灌满山谷,并可能淹没山峰,为了防止不同颜色的山谷中的水溢出汇合,我们可在汇合的地方筑起堤坝,故可将堤坝看作是对图像的分割后形成的边界

链接1: https://blog.csdn.net/kakiebu/article/details/82965629

这个上面的代码我试了,可以直接运行,前提是配好了opencv的库

但是我直接从网站上截得一模一样的图,运行结果不一样?!!!什么玩意儿啊!!!

这是本表表原图,我怀疑因为之前的博主上传的是截过得图,所以结果不太一样,要想对比结果的话,直接原图比较好

opencv 分水岭算法_第1张图片

这是我的结果图

opencv 分水岭算法_第2张图片

贴一下自己的代码咯,是看的链接的

    const char *str_out = "D:\\Point2Img.png";

    input_win[] = "input image";
    char watershed_win[] = "watershed segementation demo";
    Mat src = imread(str_out);
    resize(src, src, Size(), 0.25, 0.25, 1);

    if (src.empty()) {
        puts("could not load images");
        //return -1;
    }

    namedWindow(input_win, CV_WINDOW_AUTOSIZE);
    imshow(input_win, src);


    //1. 将白色背景编程黑色背景 - 目的是为了后面变的变换做准备
    for (int row = 0; row < src.rows; row++) {
        for (int col = 0; col < src.cols; col++) {
            if (src.at(row, col) == Vec3b(255, 255, 255)) {
                //我这里和视频教程图片不一样,所以这一步不同
                 src.at(row, col)[0] = 0;
                 src.at(row, col)[1] = 0;
                 src.at(row, col)[2] = 0;
            }
        }
    }
    namedWindow("black background", CV_WINDOW_AUTOSIZE);
    imshow("black background", src);
    imwrite("D://black background.jpg", src);


    //2. 使用filter2D与拉普拉斯算子实现图像对比度的提高 - sharp
    Mat kernel1 = (Mat_(3, 3) << 1, 1, 1, 1, -8, 1, 1, 1, 1);
    Mat imgLaplance;
    Mat imgSharpen;
    filter2D(src, imgLaplance, CV_32F, kernel1, Point(-1, -1), 0, BORDER_DEFAULT);

    src.convertTo(imgSharpen, CV_32F);
    Mat imgResult = imgSharpen - imgLaplance;
    imgResult.convertTo(imgResult, CV_8UC3);
    imgLaplance.convertTo(imgLaplance, CV_8UC3);
    imshow("sharpen img", imgResult);
    imwrite("D://sharpen img.jpg", imgResult);


    //3. 转为二值图像通过threshold
    Mat imgBinary;
    cvtColor(imgResult, imgResult, CV_BGR2GRAY);
    threshold(imgResult, imgBinary, 40, 255, THRESH_BINARY | THRESH_OTSU);

    Mat temp;
    imgBinary.copyTo(temp, Mat());
    Mat kernel2 = getStructuringElement(MORPH_RECT, Size(2, 2), Point(-1, -1));
    morphologyEx(temp, temp, CV_MOP_TOPHAT, kernel2, Point(-1, -1), 1);

    for (int row = 0; row < src.rows; row++) {
        for (int col = 0; col < src.cols; col++) {
            imgBinary.at(row, col) = saturate_cast(imgBinary.at(row, col) - temp.at(row, col));
        }
    }

    imshow("sharpen img", imgResult);
    imshow("binary img", imgBinary);
    imwrite("D://sharpen img2.jpg", imgResult);
    imwrite("D://binary.jpg", imgBinary);


    //4. 距离变换
    Mat imgDist;
    distanceTransform(imgBinary, imgDist, CV_DIST_L1, 3);


    //5. 对距离变换结果进行归一化[0-1]之间
    normalize(imgDist, imgDist, 0, 1, NORM_MINMAX);
    imshow("distance result normalize", imgDist);
    imwrite("D://distance result normalize.jpg", imgDist*10000);


    //2. 使用filter2D与拉普拉斯算子实现图像对比度的提高 - sharp
    Mat kernel0 = (Mat_(3, 3) << 1, 1, 1, 1, -8, 1, 1, 1, 1);
    Mat imgLaplance2;
    Mat imgSharpen2;
    filter2D(imgDist, imgLaplance2, CV_32F, kernel0, Point(-1, -1), 0, BORDER_DEFAULT);

    imgDist.convertTo(imgSharpen2, CV_32F);
    Mat imgResult2 = imgSharpen2 - imgLaplance2;
    imgResult2.convertTo(imgResult2, CV_8UC3);
    imgLaplance2.convertTo(imgLaplance2, CV_8UC3);
    imshow("sharpen img2", imgResult2);
    imwrite("D://sharpen img2.jpg", imgResult2);


    //6. 使用阈值,在此二值化,得到标记
    threshold(imgDist, imgDist, 0.5, 1, CV_THRESH_BINARY);
    imshow("distance result threshold", imgDist);
    imwrite("D://distance result threshold.jpg", imgDist);


    //7. 腐蚀每个peak erode
    Mat kernel3 = Mat::zeros(15, 15, CV_8UC1);
    erode(imgDist, imgDist, kernel3, Point(-1, -1), 2);
    imshow("distance result erode", imgDist);
    imwrite("D://distance result erode.jpg", imgDist);


    //8. 发现轮廓 findContours
    Mat imgDist8U;
    imgDist.convertTo(imgDist8U, CV_8U);
    vector> contour;
    findContours(imgDist8U, contour, RETR_EXTERNAL, CHAIN_APPROX_SIMPLE, Point(0, 0));


    //9. 绘制轮廓 drawContours
    Mat maskers = Mat::zeros(imgDist8U.size(), CV_32SC1);
    for (size_t i = 0; i < contour.size(); i++) {
        drawContours(maskers, contour, static_cast(i), Scalar::all(static_cast(i) + 1));
    }
    imshow("maskers", maskers*10000);
    imwrite("D://maskers.jpg", maskers);


    //10.分水岭变换 watershed
    watershed(src, maskers);
    Mat mark = Mat::zeros(maskers.size(), CV_8UC1);
    maskers.convertTo(mark, CV_8UC1);
    bitwise_not(mark, mark, Mat());
    imshow("watershed", mark);
    imwrite("D://watershed.jpg", mark);


    //11.对每个分割区域着色输出结果
    vector colors;
    for (size_t i = 0; i < contour.size(); i++) {
        int r = theRNG().uniform(0, 255);
        int g = theRNG().uniform(0, 255);
        int b = theRNG().uniform(0, 255);
        colors.push_back(Vec3b((uchar)r, (uchar)g, (uchar)b));
    }

    Mat dst = Mat::zeros(maskers.size(), CV_8UC3);
    for (int row = 0; row < src.rows; row++) {
        for (int col = 0; col < src.cols; col++) {
            int index = maskers.at(row, col);
            if (index > 0 && index <= static_cast(contour.size())) {
                dst.at(row, col) = colors[index - 1];
            }
            else {
                dst.at(row, col) = Vec3b(0, 0, 0);
            }
        }
    }
    imshow("dst", dst);
    imwrite("D://dst.jpg", dst);
 

然后看一下本人的图,算了算了,不忍直视


 

 

你可能感兴趣的:(opencv图像处理)