• 图像分析------连通组件标记算法 分类: 视频图像处理 2015-07-24 09:57 32人阅读 评论(0) 收藏


    连接组件标记算法(connected component labeling algorithm)是图像分析中最常用的算法之一,

    算法的实质是扫描一幅图像的每个像素,对于像素值相同的分为相同的组(group),最终得到

    图像中所有的像素连通组件。扫描的方式可以是从上到下,从左到右,对于一幅有N个像

    素的图像来说,最大连通组件个数为N/2。扫描是基于每个像素单位,对于二值图像而言,

    连通组件集合可以是V={1}或者V={0}, 取决于前景色与背景色的不同。对于灰度图像来说,

    连图组件像素集合可能是一系列在0 ~ 255之间的灰度值。

     

    算法流程如下:

    1.      首先扫描当前像素相邻的八邻域像素值,发现连通像素加以标记。

    2.      完全扫描所有像素点之后,根据标记将所有连通组件合并。

     

    算法实现Class文件解释:

    AbstractConnectedComponentLabel一个抽象的Class定义了抽象方法doConntectedLabel()

    同时完成了一些公共方法

    ConnectedComponentLabelAlgOne一个容易读懂的连接组件算法完成,没有任何优化,

    继承上面的自抽象类

    ConnectedComponentLabelAlgTwo一个快速的连接组件算法,基于算法优化,取当前像素

    的四邻域完成扫描与标记合并。

     

    LabelPixelInfo是两个数据结构,用来存储算法计算过程中的中间变量。

     

    ImageLabelFilter用来测试算法的驱动类,ImageAnalysisUI是现实测试结果的UI

     

    算法运行结果:

     

    根据标记的索引将组件着色。


    定义数据结构的代码如下:

    1. public class Label {  
    2.       
    3.     private int index;  
    4.     private Label root;  
    5.       
    6.     public Label(int index) {  
    7.         this.index = index;  
    8.         this.root = this;  
    9.     }  
    10.       
    11.     public Label getRoot() {  
    12.         if(this.root != this) {  
    13.             this.root = this.root.getRoot();  
    14.         }  
    15.         return root;  
    16.     }  
    17.   
    18.     public int getIndex() {  
    19.         return index;  
    20.     }  
    21.   
    22.     public void setIndex(int index) {  
    23.         this.index = index;  
    24.     }  
    25.   
    26.     public void setRoot(Label root) {  
    27.         this.root = root;  
    28.     }  
    29. }  

    Pixelnfo的代码如下:

    1. package com.gloomyfish.image.analysis;  
    2.   
    3. public class PixelInfo {  
    4.     private int value; // pixel value  
    5.     private int xp;  
    6.     private int yp;  
    7.       
    8.     public PixelInfo(int pixelValue, int yp, int xp) {  
    9.         this.value = pixelValue;  
    10.         this.yp = yp;  
    11.         this.xp = xp;  
    12.     }  
    13.       
    14.     public int getValue() {  
    15.         return value;  
    16.     }  
    17.     public void setValue(int value) {  
    18.         this.value = value;  
    19.     }  
    20.     public int getXp() {  
    21.         return xp;  
    22.     }  
    23.     public void setXp(int xp) {  
    24.         this.xp = xp;  
    25.     }  
    26.     public int getYp() {  
    27.         return yp;  
    28.     }  
    29.     public void setYp(int yp) {  
    30.         this.yp = yp;  
    31.     }  
    32. }  
    抽象的组件连通标记算法Class如下:

    1. public abstract class AbstractConnectedComponentLabel {  
    2.       
    3.     protected int width;  
    4.     protected int height;  
    5.     protected Color fgColor;  
    6.     protected int[] inPixels;  
    7.     protected int[][] chessborad;  
    8.     protected Map<Integer, Integer> neighbourMap;  
    9.       
    10.     public int getWidth() {  
    11.         return width;  
    12.     }  
    13.   
    14.     public void setWidth(int width) {  
    15.         this.width = width;  
    16.     }  
    17.   
    18.     public int getHeight() {  
    19.         return height;  
    20.     }  
    21.   
    22.     public void setHeight(int height) {  
    23.         this.height = height;  
    24.     }  
    25.       
    26.     public abstract Map<Integer, List<PixelInfo>> doConntectedLabel();  
    27.   
    28.     public boolean isForeGround(int tr, int tg, int tb) {  
    29.         if(tr == fgColor.getRed() && tg == fgColor.getGreen() && tb == fgColor.getBlue()) {  
    30.             return true;  
    31.         } else {  
    32.             return false;  
    33.         }  
    34.           
    35.     }  
    36.   
    37. }  
    实现抽象类的算法one的代码如下:

    1. import java.awt.Color;  
    2. import java.util.ArrayList;  
    3. import java.util.HashMap;  
    4. import java.util.List;  
    5. import java.util.Map;  
    6.   
    7. public class ConnectedComponentLabelAlgOne extends AbstractConnectedComponentLabel {  
    8.   
    9.     public ConnectedComponentLabelAlgOne(Color fgColor, int[] srcPixel, int width, int height) {  
    10.         this.fgColor = fgColor;  
    11.         this.width = width;  
    12.         this.height = height;  
    13.         this.inPixels = srcPixel;  
    14.         this.chessborad = new int[height][width];  
    15.         for(int i=0; i<height; i++) {  
    16.             for(int j=0; j<width; j++) {  
    17.                 chessborad[i][j] = 0;  
    18.             }  
    19.         }  
    20.         this.neighbourMap = new HashMap<Integer, Integer>();   
    21.     }  
    22.       
    23.     // assume the input image data is binary image.  
    24.     public Map<Integer, List<PixelInfo>> doConntectedLabel() {  
    25.         System.out.println("start to do connected component labeling algorithm");  
    26.         int index = 0;  
    27.         int labelCount = 0;  
    28.         Label currentLabel = new Label(0);  
    29.         HashMap<Integer, Label> allLabels = new HashMap<Integer, Label>();  
    30.         for(int row=0; row<height; row++) {  
    31.             int ta = 0, tr = 0, tg = 0, tb = 0;  
    32.             for(int col=0; col<width; col++) {  
    33.                 index = row * width + col;  
    34.                 ta = (inPixels[index] >> 24) & 0xff;  
    35.                 tr = (inPixels[index] >> 16) & 0xff;  
    36.                 tg = (inPixels[index] >> 8) & 0xff;  
    37.                 tb = inPixels[index] & 0xff;  
    38.                 if(isForeGround(tr, tg, tb)) {  
    39.                     getNeighboringLabels(row, col);  
    40.                     if(neighbourMap.size() == 0) {  
    41.                         currentLabel.setIndex(++labelCount);  
    42.                         allLabels.put(labelCount,new Label(labelCount));  
    43.   
    44.                     } else {  
    45.                         for(Integer pixelLabel : neighbourMap.keySet().toArray(new Integer[0])) {  
    46.                             currentLabel.setIndex(pixelLabel);  
    47.                             break;  
    48.                         }  
    49.                         mergeLabels(currentLabel.getIndex(), neighbourMap, allLabels);  
    50.                     }  
    51.                     chessborad[row][col] = currentLabel.getIndex();  
    52.                 }  
    53.             }  
    54.         }  
    55.           
    56.         Map<Integer, List<PixelInfo>> connectedLabels = consolidateAllLabels(allLabels);  
    57.         return connectedLabels;  
    58.     }  
    59.       
    60.     private Map<Integer, List<PixelInfo>> consolidateAllLabels(HashMap<Integer, Label> allLabels) {  
    61.         Map<Integer, List<PixelInfo>> patterns = new HashMap<Integer, List<PixelInfo>>();  
    62.         int patternNumber;  
    63.         List<PixelInfo> shape;  
    64.         for (int i = 0; i < this.height; i++)  
    65.         {  
    66.             for (int j = 0; j < this.width; j++)  
    67.             {  
    68.                 patternNumber = chessborad[i][j];  
    69.                 if (patternNumber != 0)  
    70.                 {  
    71.                     patternNumber = allLabels.get(patternNumber).getRoot().getIndex();  
    72.                     if (!patterns.containsKey(patternNumber))  
    73.                     {  
    74.                         shape = new ArrayList<PixelInfo>();  
    75.                         shape.add(new PixelInfo(Color.BLUE.getRGB(), i, j));  
    76.                     }  
    77.                     else  
    78.                     {  
    79.                         shape = patterns.get(patternNumber);  
    80.                         shape.add(new PixelInfo(Color.BLUE.getRGB(), i, j));  
    81.                     }  
    82.                     patterns.put(patternNumber, shape);  
    83.                 }  
    84.             }  
    85.         }  
    86.         return patterns;  
    87.     }  
    88.   
    89.     private void mergeLabels(int index, Map<Integer, Integer> neighbourMap,  
    90.             HashMap<Integer, Label> allLabels) {  
    91.         Label root = allLabels.get(index).getRoot();  
    92.         Label neighbour;  
    93.         for(Integer key : neighbourMap.keySet().toArray(new Integer[0])) {  
    94.              if (key != index)  
    95.              {  
    96.                  neighbour = allLabels.get(key);  
    97.                  if(neighbour.getRoot() != root) {  
    98.                      neighbour.setRoot(neighbour.getRoot());// thanks zhen712,  
    99.                  }  
    100.              }  
    101.         }  
    102.           
    103.     }  
    104.   
    105.     /** 
    106.      * get eight neighborhood pixels 
    107.      *  
    108.      * @param row 
    109.      * @param col 
    110.      * @return 
    111.      */  
    112.     public  void getNeighboringLabels(int row, int col) {  
    113.         neighbourMap.clear();  
    114.         for(int i=-1; i<=1; i++) {  
    115.             int yp = row + i;  
    116.             if(yp >=0 && yp < this.height) {  
    117.                 for(int j=-1; j<=1; j++) {  
    118.                     if(i == 0 && j==0continue// ignore/skip center pixel/itself  
    119.                     int xp = col + j;  
    120.                     if(xp >=0 && xp < this.width) {  
    121.                         if(chessborad[yp][xp] != 0) {  
    122.                             if(!neighbourMap.containsKey(chessborad[yp][xp])) {  
    123.                                 neighbourMap.put(chessborad[yp][xp],0);  
    124.                             }  
    125.                         }  
    126.                     }  
    127.                 }  
    128.             }  
    129.         }  
    130.     }  
    131. }  

    版权声明:本文为博主原创文章,未经博主允许不得转载。

  • 相关阅读:
    线程进程之间的关系
    socket网络编程
    Docker在github上的站点
    大型网站架构体系的演变
    centos7 安装SSH
    如何在CentOS 7中禁用IPv6
    在 Docker 上运行一个 RESTful 风格的微服务
    docker 操作命令详解
    玩转Docker镜像
    搭建自己的 Docker 私有仓库服务
  • 原文地址:https://www.cnblogs.com/mao0504/p/4706364.html
Copyright © 2020-2023  润新知