形态学分水岭算法原理及示例实现
发布日期:2025-06-18 16:06:21
浏览次数:5
分类:精选文章
本文共 4319 字,大约阅读时间需要 14 分钟。
分水岭算法与OpenCV实现
分水岭算法的原理
分水岭算法(Watershed Algorithm)是一种经典的数学形态学分割方法。其核心思想是将灰度图像转换为梯度图像,将梯度变化视为高低起伏的山岭,将局部极小值及其邻域视为“集水盆”。通过对图像进行仿射,计算水位上升并最终确定分割线,从而将图像分割为多个连通区域。
过度分割的问题
传统分水岭算法在处理真实图像时,常常会因噪声或干扰因素的存在而产生过度分割。例如,许多微小的局部极值点会被错误地识别为分割线,导致分割效果毫无实用价值。
基于标记的分水岭算法
为了解决过度分割问题,研究者提出了基于标记(Mark)的分水岭算法。通过人工或计算标记,可以为分水岭算法提供先验知识,指导分割过程。标记图像通常定义灰度层级,确保洪水淹没过程从特定高度开始,从而避免对微小噪声区域进行分割。
OpenCV接口实现
OpenCV提供了分水岭算法的接口函数watershed,该函数接受输入图像和标记图像。标记图像由轮廓组成,每个轮廓有唯一编号,通常通过findContours函数生成。分水岭算法从标记点开始,根据梯度信息对图像进行分割,区域分界处标记为-1以区分不同区域。
示例代码解析
以下是基于OpenCV的分水岭算法实现代码示例:
#include#include #include #include using namespace cv;using namespace std;static void help() { cout << "\nThis program demonstrates the famous watershed segmentation algorithm in OpenCV: watershed()\n" << "Usage:\n" << "./watershed [image_name -- default is ../data/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), 1, 8, 0); line(img, prevPt, pt, Scalar::all(255), 1, 8, 0); prevPt = pt; imshow("image", img); }}int main(int argc, char** argv) { cv::CommandLineParser parser(argc, argv, "{help h | | }{@input | I:/Learning-and-Practice/2019Change/Image process algorithm/Img/lung2.jpeg | }"); if (parser.has("help")) { help(); return 0; } string filename = parser.get ("@input"); Mat img0 = imread(filename, 1), imgGray; if (img0.empty()) { cout << "couldn't open image " << filename << ". Usage: watershed \n"; return 0; } help(); 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 = waitKey(0); if (c == 27) break; if (c == 'r') { markerMask = Scalar::all(0); img0.copyTo(img); imshow("image", img); } if (c == 'w' || c == ' ') { vector contours; vector 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 colorTab; for (int 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(); Mat tmp = Mat::zeros(markers.size(), CV_8U); markers.convertTo(tmp, CV_8U, 255); imshow("markers", tmp); watershed(img0, markers); t = (double)getTickCount() - t; printf("execution time = %gms\n", t * 1000. / getTickFrequency()); Mat wshed(markers.size(), CV_8UC3); for (int i = 0; i < markers.rows; i++) { for (int j = 0; j < markers.cols; j++) { int index = markers.at (i, j); if (index == -1) { wshed.at (i, j) = Vec3b(255, 255, 255); } else if (index <= 0 || index > compCount) { wshed.at (i, j) = Vec3b(0, 0, 0); } else { wshed.at (i, j) = colorTab[index - 1]; } } } wshed = wshed * 0.5 + imgGray * 0.5; imshow("watershed transform", wshed); } } return 0;}
分割效果
基于标记的分水岭算法能够显著减少过度分割现象,生成更稳健、实用的图像分割结果。以下是分割前后的对比:
- 标记:人工或计算标记为灰度层级,确保洪水淹没从定义高度开始。
- 原图+标记:结合标记后的图像,清晰展示分割区域轮廓。
- 分割效果:最终分割图像,清晰区分不同区域,避免了过度分割。
参考内容
- OpenCV官方文档:OpenCV Watershed Algorithm
- 分水岭算法相关研究:Watershed Algorithm Overview
发表评论
最新留言
很好
[***.229.124.182]2026年06月10日 19时45分32秒
关于作者
喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!
推荐文章
php预定义常量&变量
2023-03-02
R 集成算法③ 随机森林
2023-03-02
php验证码背景色设置无效
2023-03-02
php验证邮箱是否有效
2023-03-02
PHP高性能分布式应用服务器框架-SwooleDistributed
2023-03-02
PHP高效、轻量级表格数据处理库 OpenSpout
2023-03-02
R 数据缺失的处理
2023-03-02
php,nginx重启
2023-03-02
php:$_ENV 和 getenv区别
2023-03-02
PHP:PDOStatement::bindValue参数类型php5和php7问题
2023-03-02
Q媒体播放器.如何播放具有多个音频的视频?
2023-03-02
pickle
2023-03-02
Pickle thread.lock(Pymongo)
2023-03-02
pickle模块
2023-03-02
qYKVEtqdDg
2023-03-02
pid控制
2023-03-02
PID控制介绍-ChatGPT4o作答
2023-03-02
PID控制器数字化
2023-03-02
Qwen-VL项目使用指南
2023-03-02