博客
关于我
形态学分水岭算法原理及示例实现
阅读量:799 次
发布时间:2023-04-15

本文共 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;}

分割效果

基于标记的分水岭算法能够显著减少过度分割现象,生成更稳健、实用的图像分割结果。以下是分割前后的对比:

  • 标记:人工或计算标记为灰度层级,确保洪水淹没从定义高度开始。
  • 原图+标记:结合标记后的图像,清晰展示分割区域轮廓。
  • 分割效果:最终分割图像,清晰区分不同区域,避免了过度分割。

参考内容

转载地址:http://urrfk.baihongyu.com/

你可能感兴趣的文章
mutiplemap 总结
查看>>
MySQL DELETE 表别名问题
查看>>
MySQL Error Handling in Stored Procedures---转载
查看>>
MVC 区域功能
查看>>
MySQL FEDERATED 提示
查看>>
mysql generic安装_MySQL 5.6 Generic Binary安装与配置_MySQL
查看>>
Mysql group by
查看>>
MySQL I 有福啦,窗口函数大大提高了取数的效率!
查看>>
mysql id自动增长 初始值 Mysql重置auto_increment初始值
查看>>
MySQL in 太多过慢的 3 种解决方案
查看>>
MySQL InnoDB 三大文件日志,看完秒懂
查看>>
Mysql InnoDB 数据更新导致锁表
查看>>
Mysql Innodb 锁机制
查看>>
MySQL InnoDB中意向锁的作用及原理探
查看>>
MySQL InnoDB事务隔离级别与锁机制深入解析
查看>>
Mysql InnoDB存储引擎 —— 数据页
查看>>
Mysql InnoDB存储引擎中的checkpoint技术
查看>>
Mysql InnoDB存储引擎中缓冲池Buffer Pool、Redo Log、Bin Log、Undo Log、Channge Buffer
查看>>
MySQL InnoDB引擎的锁机制详解
查看>>
Mysql INNODB引擎行锁的3种算法 Record Lock Next-Key Lock Grap Lock
查看>>