OpenCV学习(8) 分水岭算法(2)

    现在我们看看OpenCV中如何使用分水岭算法。

    首先我们打开一副图像:

   // 打开另一幅图像
  cv::Mat    image= cv::imread("../tower.jpg");
    if (!image.data)
        {
        cout<<"不能打开图像!"<<endl;
        return 0;
        }

     接下来,我们要创建mark图像。mark图像格式是有符号整数,其中没有被mark的部分用0表示,其它不同区域的mark标记,我们用非零值表示,通常为1-255,但也可以为其它值,比如大于255的值,不同mark区域甚至可以用同样的值,这个值大小对最后分割可能没有影响(也可能影响),最好不同mark区域还是用不同的值表示,这样能够确保结果正确,之所以用有符号整数,是因为opencv在分水岭算法内部,要用-1,-2等来标记注水区域,最终在mark图像中生成的分水岭线就是用-1表示。

    我们通常会创建uchar格式的灰度图,指定mark区域,然后转化为有符号整数的图像格式。

    首先对整个背景区域我们创建一个mark域,是下图中白色框框住的部分,其灰度值为255,第二个选择mark域为塔,就是黑色框框住的一块区域,其灰度值为64,最后就是树mark域,蓝色框的部分,其灰度值为128。在分水岭算法时候,会分别对这个3个区域来进行注水操作,如果两个注水盆地被一个mark域覆盖,则它们之间不会有分水岭线产生。

    对于mark图像,opencv分水岭算法在初始化时候,会把最外圈的值置为-1,作为整个图像的边界,所以我们第一个mark区域,选择倒数第2外圈,因为设置到最外圈,最后还是会被冲掉。

// 标示背景图像
cv::Mat imageMask(image.size(),CV_8U,cv::Scalar(0));

cv::rectangle(imageMask,cv::Point(1,1),cv::Point(image.cols-2,image.rows-2),cv::Scalar(255),1);
// 表示塔
cv::rectangle(imageMask,cv::Point(image.cols/2-10,image.rows/2-10),
    cv::Point(image.cols/2+10,image.rows/2+10),cv::Scalar(64),10);
//树
cv::rectangle(imageMask,cv::Point(64,284),
    cv::Point(68,300),cv::Scalar(128),5);

mark图像:

 

   注意:mark图像是32bit的有符号整数,所以在使用分水岭算法前,我们先对mark图像做一个转化。算法执行完后,再转化为0-255的灰度图。

  imageMask.convertTo(imageMask,CV_32S);
    // 设置marker和处理图像 
  cv::watershed(image,imageMask);

  cv::Mat mark1;
  imageMask.convertTo(mark1,CV_8U);
  cv::namedWindow("marker");

   cv::imshow("marker",mark1);

    此时imageMask图像从无符号整数转化为uchar后,如下图所示,第一个mask区域注水,将会使得整个图像为白色,之后分别在第二个,第三个区域的盆地注水,会产生相应的注水图,注水的区域的值即为mark的值,128和64, 分水岭线则为0,注:在转化前分水岭线的值为-1,转化后成为0。

我们使用一个转化函数把分水岭线转化为黑色,其它的部分都白黑色,转化函数的公式为:

imageMask(x,y) = saturate_cast<uchar>(255*imageMask(x,y)+255)
  imageMask.convertTo(imageMask,CV_8U,255, 255);

  最后显示分水岭线,得到下图:(注:在转化前,分水岭线的值为-1)

 

源码:工程FirstOpenCV7

下载:稍后提供

 

时间: 2024-08-17 08:27:34

OpenCV学习(8) 分水岭算法(2)的相关文章

OpenCV学习(9) 分水岭算法(3)

本教程我学习一下opencv中分水岭算法的具体实现方式. 原始图像和Mark图像,它们的大小都是32*32,分水岭算法的结果是得到两个连通域的轮廓图. 原始图像:(原始图像必须是3通道图像) Mark图像: 结果图像:       初始的mark图像数据如下,黄色的部分为我们的第一个mark区域,值为255,第二个区域为褐红色的区域,值为128,第三个绿色的区域,值为64.   opencv分水岭算法描述如下: 初始化mark矩阵,生成最初的注水区域. 1.设置mark图像的边框值为-1 2.

OpenCV学习(15) 细化算法(3)

      本章我们学习一下Hilditch算法的基本原理,从网上找资料的时候,竟然发现两个有很大差别的算法描述,而且都叫Hilditch算法.不知道那一个才是正宗的,两个算法实现的效果接近,第一种算法更好一些. 第一种算法描述参考paper和代码: Linear Skeletons from Square Cupboards Speedup Method for Real-Time Thinning Algorithm http://cis.k.hosei.ac.jp/~wakahara/Hi

OpenCV学习(18) 细化算法(6)

本章我们在学习一下基于索引表的细化算法. 假设要处理的图像为二值图,前景值为1,背景值为0. 索引表细化算法使用下面的8邻域表示法: 一个像素的8邻域,我们可以用8位二进制表示,比如下面的8邻域,表示为00111000=0x38=56 我们可以枚举出各种情况下,当前像素能否删除的表,该表大小为256.它的索引即为8邻域表示的值,表中存的值为0或1,0表示当前像素不能删除,1表示可以删除.deletemark[256] 比如下图第一个表示,索引值为0,它表示孤立点,不能删除,所以deletemar

OpenCV学习(21) Grabcut算法详解

grab cut算法是graph cut算法的改进.在理解grab cut算之前,应该学习一下graph cut算法的概念及实现方式. 我搜集了一些graph cut资料:http://yunpan.cn/QGDVdBXwkXutH      grab cut算法详细描述见资料中的pdf文件:"GrabCut" - Interactive Foreground Extraction using Iterated Graph Cuts      grab cut算法是一种基于图论的图像分

OpenCV 1 图像分割--分水岭算法代码

// watershed_test20140801.cpp : 定义控制台应用程序的入口点. // #include "stdafx.h" // // ch9_watershed image // This is an exact copy of the watershed.cpp demo in the OpenCV ../samples/c directory // // Think about using a morphologically eroded forground an

OpenCV学习(14) 细化算法(2)

      前面一篇教程中,我们实现了Zhang的快速并行细化算法,从算法原理上,我们可以知道,算法是基于像素8邻域的形状来决定是否删除当前像素.还有很多与此算法相似的细化算法,只是判断的条件不一样.在综述文章, Thinning Methodologies-A Comprehensive Survey中描述了各种细化算法的实现原理,有兴趣可以阅读一下.       下面看看图像细化的定义以及细化算法的分类: 图像细化(Image Thinning),一般指二值图像的骨架化(Image Skel

OpenCV学习(17) 细化算法(5)

本章我们看下Pavlidis细化算法,参考资料http://www.imageprocessingplace.com/downloads_V3/root_downloads/tutorials/contour_tracing_Abeer_George_Ghuneim/theo.html Computer VisiAlgorithms in Image Algebra,second edition 该算法最初是做前景轮廓跟踪的. 假设使用下面的8邻域,且前景像素值为1,背景像素值为0. 下面是该算

OpenCV学习(19) 细化算法(7)

最后再来看一种通过形态学腐蚀和开操作得到骨架的方法.http://felix.abecassis.me/2011/09/opencv-morphological-skeleton/ 代码非常简单: void gThin::cvmorphThin(cv::Mat& src, cv::Mat& dst)     {     if(src.type()!=CV_8UC1)         {         printf("只能处理二值或灰度图像\n");         r

OpenCV学习(13) 细化算法(1)

程序编码参考经典的细化或者骨架算法文章: T. Y. Zhang and C. Y. Suen, "A fast parallel algorithm for thinning digital patterns," Comm. ACM, vol. 27, no. 3, pp. 236-239, 1984. 它的原理也很简单:       我们对一副二值图像进行骨架提取,就是删除不需要的轮廓点,只保留其骨架点.假设一个像素点,我们定义该点为p1,则它的八邻域点p2->p9位置如下图