2025年图像分割之分水岭分割算法

图像分割之分水岭分割算法基本思想 分水岭 watershed 是地形学中的一个经典概念 例如美国落基山脉分水岭 将美国分为两个区域 落在这个分水岭一边的雨滴 最终会到达大西洋 但是落在另一边的雨滴 最终回流到太平洋 为了提取分水岭 人们提出了各种各样的算法

大家好,我是讯享网,很高兴认识大家。

基本思想

分水岭(watershed)是地形学中的一个经典概念,例如美国落基山脉分水岭,将美国分为两个区域,落在这个分水岭一边的雨滴,最终会到达大西洋,但是落在另一边的雨滴,最终回流到太平洋。为了提取分水岭,人们提出了各种各样的算法,在这些算法中,Vincent和Soille提出了一种基于模拟沉浸的实现方法。在图像处理领域,灰度图像可以被视为地形表面,图像中每个像素的灰度代表这点的高度,其每一个局部极小值(local minima)及其影响区域成为集水盆地(catchments basin)。这样分水岭便被引入图像处理中来。设想每个区域底部刺了一个孔,水从刺过孔的海拔最低的谷底开始往上涌,慢慢地淹没图像的整个区域。当来自不同谷底的水即将汇合时,筑起一道假想的水坝来阻止它。浸没过程结束时,每个区域被水淹没,并被水坝完全包围。这些筑起的水坝确定了对应区域的分水岭,对应于图像的轮廓。此方法不仅速度更快,大大缩短了执行时间,而且结果也更加准确,这使得此算法具有使用价值。(摘自《医学图像处理及三维重建技术研究》[M])
在这里插入图片描述
讯享网

示例演示

这里展示OpenCV Demo watershed。完整代码

#include <opencv2/core/utility.hpp> #include "opencv2/imgproc.hpp" #include "opencv2/imgcodecs.hpp" #include "opencv2/highgui.hpp" #include <cstdio> #include <iostream> using namespace cv; using namespace std; static void help(char** argv) { 
    cout << "\nThis program demonstrates the famous watershed segmentation algorithm in OpenCV: watershed()\n" "Usage:\n" << argv[0] << " [image_name -- default is fruits.jpg]\n" << endl; cout << "Hot keys: \n" "\tESC - quit the program\n" "\tr - restore the original image\n" "\tw or SPACE - run watershed segmentation algorithm\n" "\t\t(before running it, *roughly* mark the areas to segment on the image)\n" "\t (before that, roughly outline several markers on the image)\n"; } Mat markerMask, img; Point prevPt(-1, -1); static void onMouse(int event, int x, int y, int flags, void*) { 
    if (x < 0 || x >= img.cols || y < 0 || y >= img.rows) return; if (event == EVENT_LBUTTONUP || !(flags & EVENT_FLAG_LBUTTON)) prevPt = Point(-1, -1); else if (event == EVENT_LBUTTONDOWN) prevPt = Point(x, y); else if (event == EVENT_MOUSEMOVE && (flags & EVENT_FLAG_LBUTTON)) { 
    Point pt(x, y); if (prevPt.x < 0) prevPt = pt; line(markerMask, prevPt, pt, Scalar::all(255), 5, 8, 0); line(img, prevPt, pt, Scalar::all(255), 5, 8, 0); prevPt = pt; imshow("image", img); } } int main(int argc, char** argv) { 
    cv::CommandLineParser parser(argc, argv, "{help h | | }{ @input | fruits.jpg | }"); if (parser.has("help")) { 
    help(argv); return 0; } //string filename = samples::findFile(parser.get<string>("@input")); string filename = "D:\\TestData\\fruits.jpg"; Mat img0 = imread(filename, 1), imgGray; if (img0.empty()) { 
    cout << "Couldn't open image "; help(argv); return 0; } help(argv); namedWindow("image", 1); img0.copyTo(img); cvtColor(img, markerMask, COLOR_BGR2GRAY); cvtColor(markerMask, imgGray, COLOR_GRAY2BGR); markerMask = Scalar::all(0); imshow("image", img); setMouseCallback("image", onMouse, 0); for (;;) { 
    char c = (char)waitKey(0); if (c == 27) break; if (c == 'r') { 
    markerMask = Scalar::all(0); img0.copyTo(img); imshow("image", img); } if (c == 'w' || c == ' ') { 
    int i, j, compCount = 0; vector<vector<Point> > contours; vector<Vec4i> hierarchy; findContours(markerMask, contours, hierarchy, RETR_CCOMP, CHAIN_APPROX_SIMPLE); if (contours.empty()) continue; Mat markers(markerMask.size(), CV_32S); markers = Scalar::all(0); int idx = 0; for (; idx >= 0; idx = hierarchy[idx][0], compCount++) drawContours(markers, contours, idx, Scalar::all(compCount + 1), -1, 8, hierarchy, INT_MAX); if (compCount == 0) continue; vector<Vec3b> colorTab; for (i = 0; i < compCount; i++) { 
    int b = theRNG().uniform(0, 255); int g = theRNG().uniform(0, 255); int r = theRNG().uniform(0, 255); colorTab.push_back(Vec3b((uchar)b, (uchar)g, (uchar)r)); } double t = (double)getTickCount(); watershed(img0, markers); t = (double)getTickCount() - t; printf("execution time = %gms\n", t*1000. / getTickFrequency()); Mat wshed(markers.size(), CV_8UC3); // paint the watershed image for (i = 0; i < markers.rows; i++) for (j = 0; j < markers.cols; j++) { 
    int index = markers.at<int>(i, j); if (index == -1) wshed.at<Vec3b>(i, j) = Vec3b(255, 255, 255); else if (index <= 0 || index > compCount) wshed.at<Vec3b>(i, j) = Vec3b(0, 0, 0); else wshed.at<Vec3b>(i, j) = colorTab[index - 1]; } wshed = wshed * 0.5 + imgGray * 0.5; imshow("watershed transform", wshed); } } return 0; } 

讯享网

运行结果

在这里插入图片描述

小讯
上一篇 2025-01-15 16:22
下一篇 2025-03-17 07:54

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/118987.html