zoukankan      html  css  js  c++  java
  • OpenCV学习(9) 分水岭算法(3)

    本教程我学习一下opencv中分水岭算法的具体实现方式。

    原始图像和Mark图像,它们的大小都是32*32,分水岭算法的结果是得到两个连通域的轮廓图。

    原始图像:(原始图像必须是3通道图像)

    image

    Mark图像:

    image

    结果图像:

    image

          初始的mark图像数据如下,黄色的部分为我们的第一个mark区域,值为255,第二个区域为褐红色的区域,值为128,第三个绿色的区域,值为64。

    image

     

    opencv分水岭算法描述如下:

    初始化mark矩阵,生成最初的注水区域。

    1.设置mark图像的边框值为-1

    2. 标记每个mark区域的边界为-2

    3. 对于mark图像一个像素值,如果它本身值为0,但上下左右四邻域有一个像素值不为0,则把该点按照RGB高度值放入相应的队列。

          举例说明:如下图像素点,它的mark值为0,但左和上像素值不为0,此时,我们求原始图像中对应像素的高度值,高度值的计算方式如下面公式,其中R表示Red通道值,G表示Green通道值,B表示Blue通道值,下标L表示左,R表示右,T表示上,B表示下,abs表示取绝对值,min和max分别为最小值和最大值函数:

    min(max(abs(R-RL), abs(G-GL), abs(B-BL)),max(abs(R-RT), abs(G-GT), abs(B-BT)),max(abs(R-RR), abs(G-GR), abs(B-BR)),max(abs(R-RB), abs(G-GB), abs(B-BB)))

    image

    上图中指定的像素,它的高度值显然为0,所以我们把(2,2)点放入高度为0的队列中(总共有256个队列,对应0-255的高度)

    image

     

       初始化阶段完成后,我们得到下面的mark图,并把-2对应的边界像素点,按照其对应的RGB高度值放入相应的队列。

    image

    之后就进入了递归注水过程,递归过程描述如下:

    for(; ; )

    {

        扫描0-255高度值队列,如果找到一个像素标记,则弹出该标记,并退出扫描。

        如果该像素的四邻域中存在两个不同的非0值,表示该点为两个注水盆地的边缘,即分水岭线,在mark图像中标记该点为-1。

        扫描该点的四邻域,是否存在为0的mark域,存在的话这把该邻域点按照rgb高度值,放入相应的队列。

    }

    经过上述的递归过程,最后我们得到的mark图像如下所示,其中绿色格子的-1即为所有的分水岭边界:

    image

    代码参见工程:FirstOpenCV10

          我们也可以把输入图像换成灰度图,这样求高度值时,就比较简单,void WatershedGray(cv::Mat &src, cv::Mat &dst);该函数演示灰度图的分水岭算法。

  • 相关阅读:
    前缀判断 蓝桥杯
    dedecms 网站内容静态化和动态化的切换
    dedecms 频道标签 channel.lib.php的分析
    JavaScript通过闭包解决只能取得包含函数中任何变量最后一个值的问题
    JavaScript闭包 取for循环i 【转】
    JavaScript装饰模式
    JavaScript闭包意义谈
    JavaScriptjs闭包测试
    JavaScript闭包的作用谈(转)
    Zend Engine 简介
  • 原文地址:https://www.cnblogs.com/mikewolf2002/p/3317929.html
Copyright © 2011-2022 走看看