• 实现二值图像连通区标记之区域生长法


    http://blog.csdn.net/songzitea/article/details/26105609

    连通区标记是最基本的图像处理算法之一。该算法中,按从左至右、从上至下的顺序,对整幅图像进行扫描,通过比较每个前景像素的邻域进行连通区标记,并创建等效标记列表。最后,合并等效标记列表,并再次扫描图像以更新标记。算法的优点的是通俗易懂,缺点是需要两次扫描图像,效率不高。

    区域生长法利用区域生长的思想,一次生长过程可以标记一整个连通区,只需对图像进行一次扫描就能标记出所有连通区。算法描述如下:

    1. 输入待标记图像bitmap,初始化一个与输入图像同样尺寸的标记矩阵labelmap,一个队列queue以及标记计数labelIndex;
    2. 按从左至右、从上至下的顺序扫描bitmap,当扫描到一个未被标记的前景像素p时,labelIndex加1,并在labelmap中标记p(相应点的值赋为labelIndex),同时,扫描p的八邻域点,若存在未被标记的前景像素,则在labelmap中进行标记,并放入queue中,作为区域生长的种子;
    3. 当queue不为空时,从queue中取出一个生长种子点p1,扫描p1的八邻域点,若存在未被标记过的前景像素,则在labelmap中进行标记,并放入queue中;
    4. 重复3直至queue为空,一个连通区标记完成;
    5. 转到2,直至整幅图像被扫描完毕,得到标记矩阵labelmap和连通区的个数labelIndex。

    该算法最坏情况下,将对每个像素点都进行一次八邻域搜索,算法复杂度为O(n)。

    [cpp] view plain copy
     
     print?在CODE上查看代码片派生到我的代码片
    1. typedef struct QNode{  
    2.     int data;  
    3.     struct QNode *next;  
    4. }QNode;  
    5.   
    6. typedef struct Queue{  
    7.     struct QNode* first;  
    8.     struct QNode* last;  
    9. }Queue;  
    10.   
    11. void PushQueue(Queue *queue, int data){  
    12.     QNode *p = NULL;  
    13.     p = (QNode*)malloc(sizeof(QNode));  
    14.     p->data = data;  
    15.     if(queue->first == NULL){  
    16.         queue->first = p;  
    17.         queue->last = p;  
    18.         p->next = NULL;  
    19.     }  
    20.     else{  
    21.         p->next = NULL;  
    22.         queue->last->next = p;  
    23.         queue->last = p;  
    24.     }  
    25. }  
    26.   
    27. int PopQueue(Queue *queue){  
    28.     QNode *p = NULL;  
    29.     int data;  
    30.     if(queue->first == NULL){  
    31.         return -1;  
    32.     }  
    33.     p = queue->first;  
    34.     data = p->data;  
    35.     if(queue->first->next == NULL){  
    36.         queue->first = NULL;  
    37.         queue->last = NULL;  
    38.     }  
    39.     else{  
    40.         queue->first = p->next;  
    41.     }  
    42.     free(p);  
    43.     return data;  
    44. }  
    45.   
    46. static int NeighborDirection[8][2] = {{0,1},{1,1},{1,0},{1,-1},{0,-1},{-1,-1},{-1,0},{-1,1}};  
    47.   
    48. void SearchNeighbor(unsigned char *bitmap, int width, int height, int *labelmap,   
    49.                     int labelIndex, int pixelIndex, Queue *queue){  
    50.     int searchIndex, i, length;  
    51.     labelmap[pixelIndex] = labelIndex;  
    52.     length = width * height;  
    53.     for(i = 0;i < 8;i++){  
    54.         searchIndex = pixelIndex + NeighborDirection[i][0] * width + NeighborDirection[i][1];  
    55.         if(searchIndex > 0 && searchIndex < length &&   
    56.             bitmap[searchIndex] == 255 && labelmap[searchIndex] == 0){  
    57.             labelmap[searchIndex] = labelIndex;  
    58.             PushQueue(queue, searchIndex);  
    59.         }  
    60.     }  
    61. }  
    62.   
    63. int ConnectedComponentLabeling(unsigned char *bitmap, int width, int height, int *labelmap){  
    64.     int cx, cy, index, popIndex, labelIndex = 0;  
    65.     Queue *queue = NULL;  
    66.     queue = (Queue*)malloc(sizeof(Queue));  
    67.     queue->first = NULL;  
    68.         queue->last = NULL;  
    69.     memset(labelmap, 0, width * height);  
    70.     for(cy = 1; cy < height - 1; cy++){  
    71.         for(cx = 1; cx < width - 1; cx++){  
    72.             index = cy * width + cx;  
    73.             if(bitmap[index] == 255 && labelmap[index] == 0){  
    74.                 labelIndex++;  
    75.                 SearchNeighbor(bitmap, width, height, labelmap, labelIndex, index, queue);  
    76.   
    77.                 popIndex = PopQueue(queue);  
    78.                 while(popIndex > -1){  
    79.                 SearchNeighbor(bitmap, width, height, labelmap, labelIndex, popIndex, queue);  
    80.                     popIndex = PopQueue(queue);  
    81.                 }  
    82.             }  
    83.         }  
    84.     }  
    85.     free(queue);  
    86.     return labelIndex;  
    87. }  
  • 相关阅读:
    庖丁解牛识控件
    打开地图文件和shape文件代码加载Mxd文档
    IMapControl3 Interface(1) Properties属性
    避免事件响应传递依赖
    提示:ArcGIS version not specified. You must call RuntimeManager.Bind before creating any ArcGIS components.错误
    我的联想笔记本电脑为啥字母键变成数字键怎么切换过来
    C#读取word文件
    TensorFlow笔记(基础篇):加载数据之预加载数据与填充数据
    7.1 TensorFlow笔记(基础篇):加载数据之预加载数据与填充数据
    7.2 TensorFlow笔记(基础篇): 生成TFRecords文件
  • 原文地址:https://www.cnblogs.com/zkwarrior/p/5807491.html
Copyright © 2020-2023  润新知