zoukankan      html  css  js  c++  java
  • 二值图像求取连通域算法

    一幅图像二值化处理后往往包含多个区域,需要通过标记把它们分别提取出来。标记分割后图像中各区域的简单而有效的方法是检查各像素与其相邻像素的连通性。

    在二值图像中,背景区像素的值为0,目标区域的像素值为1。假设对一幅图像从左向右,从上向下进行扫描,要标记当前正被扫描的像素需要检查它与在它之前被扫描到的若干个近邻像素的连通性。

    考虑4连通的情形。对图像进行逐像素扫描。

    假如当前像素值为0,就移动到下一个扫描的位置。

    假如当前像素值为1,检查它左边和上边的两个邻接像素(这两个像素一定会在当前像素之前被扫描到)。这两个像素值和标记的组合有四种情况要考虑。

    1. 他们的像素值都为0。此时给该像素一个新的标记(表示一个新的连通域的开始)。

    2. 它们中间只有一个像素值为1。此时当前像素的标记=为1的像素值的标记。

    3. 它们的像素值都为1且标记相同。此时当前像素的标记=该标记。

    4. 它们的像素值为1且标记不同。将其中的较小的值赋给当前像素。之后从另一边回溯到区域的开始像素为止。每次回溯再分别执行上述四个判断步骤。

    这样即可保证所有的连通域都被标记出来。之后再通过对不同的标记赋予不同的颜色或将其加上边框即可完成标记。

      1 /// <summary>
      2 /// 回溯法标记连通域
      3 /// </summary>
      4 /// <param name="x">该点的横坐标</param>
      5 /// <param name="y">该点的纵坐标</param>
      6 /// <param name="isMarked">是否已经被标记过,用于记录回溯路线。默认值为false,如果该点已经被标记过,则应指定该参数为true。</param>
      7         private void Connect(int x, int y, bool isMarked = false)
      8         {
      9             if (x == 0 && y == 0) //mat[0, 0]
     10             {
     11                 if (f(x, y) == 1) mat[x, y] = mark; // new area
     12             }
     13 
     14             else if (x != 0 && y == 0) // First Row
     15             {
     16                 if (f(x, y) == 1)
     17                 {
     18                     if (mat[x - 1, y] != 0)
     19                     {
     20                         mat[x, y] = mat[x - 1, y]; // left one
     21                         Connect(x - 1, y, true);
     22                     }
     23                     else
     24                     {
     25                         if (isMarked == false)
     26                             mat[x, y] = ++mark; // new area
     27                     }
     28                 }
     29             }
     30 
     31             else if (x == 0 && y != 0) // First Column
     32             {
     33                 if (f(x, y) == 1)
     34                 {
     35                     if (mat[x, y - 1] != 0)
     36                     {
     37                         mat[x, y] = mat[x, y - 1]; // up one
     38                         Connect(x, y - 1, true);
     39                     }
     40                     else
     41                     {
     42                         if (isMarked == false)
     43                             mat[x, y] = ++mark;
     44                     }
     45                 }
     46             }
     47 
     48             else if (x != 0 && y != 0) // other pixel
     49             {
     50                 if (f(x, y) == 1)
     51                 {
     52                     if (mat[x, y - 1] == 0 && mat[x - 1, y] == 0) // new area
     53                     {
     54                         if (isMarked == false)
     55                             mat[x, y] = ++mark;
     56                     }
     57                     else if (mat[x, y - 1] == 0 && mat[x - 1, y] != 0)
     58                     {
     59                         if (isMarked == false)
     60                             mat[x, y] = mat[x - 1, y];
     61                         else
     62                         {
     63                             if (mat[x - 1, y] > mat[x, y])
     64                                 mat[x - 1, y] = mat[x, y];
     65                             Connect(x - 1, y, true); // 沿x方向继续回溯
     66                         }
     67                     }
     68                     else if (mat[x, y - 1] != 0 && mat[x - 1, y] == 0)
     69                     {
     70                         if (isMarked == false)
     71                             mat[x, y] = mat[x, y - 1];
     72                         else
     73                         {
     74                             if (mat[x, y - 1] > mat[x, y])
     75                                 mat[x, y - 1] = mat[x, y];
     76                             Connect(x, y - 1, true); // 沿y方向继续回溯
     77                         }
     78                     }
     79                     else if (mat[x, y - 1] != 0 && mat[x - 1, y] != 0 && mat[x, y - 1] == mat[x - 1, y])
     80                     {
     81                         if (isMarked == false)
     82                             mat[x, y] = mat[x, y - 1];
     83                         else
     84                         {
     85                             if (mat[x, y - 1] > mat[x, y])
     86                             {
     87                                 mat[x, y - 1] = mat[x - 1, y] = mat[x, y];
     88                                 Connect(x - 1, y, true); // 遇到上边和左边都有已标记像素的情况,两边同时回溯
     89                                 Connect(x, y - 1, true);
     90                             }
     91                         }
     92 
     93                     }
     94                     else if (mat[x, y - 1] != 0 && mat[x - 1, y] != 0 && mat[x, y - 1] != mat[x - 1, y])
     95                     {
     96                         mat[x, y] = Math.Min(mat[x - 1, y], mat[x, y - 1]);
     97                         mat[x - 1, y] = mat[x, y - 1] = mat[x, y]; // 直接消除等价类
     98                         Connect(x - 1, y, true);
     99                         Connect(x, y - 1, true);
    100                     }
    101                 }
    102             }

    执行效果如下:

    二值化后的图像

    标记了连通域后的图像 

    当然这个方法的一个问题是执行效率很低,对比较大的图片需要较长时间才能完成标记步骤。但准确率还是比较高的。

    参考文献:

    [1] 章毓晋. 图像分割. 科学出版社,2001年,pp.63

    [2] R.Gonzalez. 数字图像处理. 电子工业出版社, 2014年, pp.38-40

  • 相关阅读:
    问题:sqlserver 跨服务器连接;结果:Sql Server 跨服务器连接
    SpringBoot之Servlet、Filter、Listener配置
    spring boot 使用@ConfigurationProperties
    Mysql字段属性应该尽量设置为not null
    微服务—ELK分布式日志框架
    微服务—分布式服务追踪sleuth和zipkin
    微服务—熔断器Hystrix
    @RequestBody和@ResponseBody的使用情形以及RestTemplate的http报文转换
    application/x-www-form-urlencoded和multipart/form-data
    基于JWT的token身份认证方案
  • 原文地址:https://www.cnblogs.com/ryuasuka/p/4932239.html
Copyright © 2011-2022 走看看