连通组件标记算法–算法修正版
昨天使用自己修改的连通组件标记算法代码去对一个稍微复杂点的图片做皮肤的最大连通
区域识别,发现Java报了栈溢出错误,自己想了想,感觉是合并标记时其中一段递归的代
码的问题,修改为非递归以后,运行结果吓我一跳,发现更加的不对,最后发现原来我读
取标记时候使用了逻辑操作符&,导致标记超过255时候被低位截取。为了找到这个错误,
花了一个下午的时间重新完成了代码与测试。
一:基本原理如下
以前的有问题的算法版本连接,看这里:
http://blog.csdn.net/jia20003/article/details/7596443
二:完整的算法代码如下:
package com.gloomyfish.face.detection;
import java.util.Arrays;
import java.util.HashMap;
/**
* fast connected component label algorithm
*
* @date 2012-05-23
* @author zhigang
*
*/
public class AdjustableConnectedComponentLabelAlg {
private int bgColor;
public int getBgColor() {
return bgColor;
}
public void setBgColor(int bgColor) {
this.bgColor = bgColor;
}
private int[] outData;
private int dw;
private int dh;
public AdjustableConnectedComponentLabelAlg() {
bgColor = 255; // black color
}
public int[] doLabel(int[] inPixels, int width, int height) {
dw = width;
dh = height;
int nextlabel = 1;
int result = 0;
outData = new int[dw * dh];
for(int i=0; i<outData.length; i++) {
outData[i] = 0;
}
// we need to define these two variable arrays.
int[] eightNeighborhoodPixels = new int[8];
int[] eightNeighborhoodLabels = new int[8];
int[] knownLabels = new int[8];
int srcrgb = 0, index = 0;
boolean existedLabel = false;
for(int row = 0; row < height; row ++) {
for(int col = 0; col < width; col++) {
index = row * width + col;
srcrgb = inPixels[index] & 0x000000ff;
if(srcrgb == bgColor) {
result = 0; // which means no labeled for this pixel.
} else {
// we just find the eight neighborhood pixels.
eightNeighborhoodPixels[0] = getPixel(inPixels, row-1, col); // upper cell
eightNeighborhoodPixels[1] = getPixel(inPixels, row, col-1); // left cell
eightNeighborhoodPixels[2] = getPixel(inPixels, row+1, col); // bottom cell
eightNeighborhoodPixels[3] = getPixel(inPixels, row, col+1); // right cell
// four corners pixels
eightNeighborhoodPixels[4] = getPixel(inPixels, row-1, col-1); // upper left corner
eightNeighborhoodPixels[5] = getPixel(inPixels, row-1, col+1); // upper right corner
eightNeighborhoodPixels[6] = getPixel(inPixels, row+1, col-1); // left bottom corner
eightNeighborhoodPixels[7] = getPixel(inPixels, row+1, col+1); // right bottom corner
// get current possible existed labels
eightNeighborhoodLabels[0] = getLabel(outData, row-1, col); // upper cell
eightNeighborhoodLabels[1] = getLabel(outData, row, col-1); // left cell
eightNeighborhoodLabels[2] = getLabel(outData, row+1, col); // bottom cell
eightNeighborhoodLabels[3] = getLabel(outData, row, col+1); // right cell
// four corners labels value
eightNeighborhoodLabels[4] = getLabel(outData, row-1, col-1); // upper left corner
eightNeighborhoodLabels[5] = getLabel(outData, row-1, col+1); // upper right corner
eightNeighborhoodLabels[6] = getLabel(outData, row+1, col-1); // left bottom corner
eightNeighborhoodLabels[7] = getLabel(outData, row+1, col+1); // right bottom corner
int minLabel = 0;
int count = 0;
for(int i=0; i<knownLabels.length; i++) {
if(eightNeighborhoodLabels[i] > 0) {
existedLabel = true;
knownLabels[i] = eightNeighborhoodLabels[i];
minLabel = eightNeighborhoodLabels[i];
count++;
}
}
if(existedLabel) {
if(count == 1) {
result = minLabel;
} else {
int[] tempLabels = new int[count];
int idx = 0;
for(int i=0; i<knownLabels.length; i++) {
if(knownLabels[i] > 0){
tempLabels[idx++] = knownLabels[i];
}
if(minLabel > knownLabels[i] && knownLabels[i] > 0) {
minLabel = knownLabels[i];
}
}
result = minLabel;
mergeLabels(index, result, tempLabels);
}
} else {
result = nextlabel;
nextlabel++;
}
outData[index] = result;
// reset and cleanup the known labels now...
existedLabel = false;
for(int kl = 0; kl < knownLabels.length; kl++) {
knownLabels[kl] = 0;
}
}
}
}
// labels statistic
HashMap<Integer, Integer> labelMap = new HashMap<Integer, Integer>();
for(int d=0; d<outData.length; d++) {
if(outData[d] != 0) {
if(labelMap.containsKey(outData[d])) {
Integer count = labelMap.get(outData[d]);
count+=1;
labelMap.put(outData[d], count);
} else {
labelMap.put(outData[d], 1);
}
}
}
// try to find the max connected component
Integer[] keys = labelMap.keySet().toArray(new Integer[0]);
Arrays.sort(keys);
int maxKey = 1;
int max = 0;
for(Integer key : keys) {
if(max < labelMap.get(key)){
max = labelMap.get(key);
maxKey = key;
}
System.out.println( "Number of " + key + " = " + labelMap.get(key));
}
System.out.println("maxkey = " + maxKey);
System.out.println("max connected component number = " + max);
return outData;
}
private void mergeLabels (int index, int result, int[] labels) {
for(int i=0; i<labels.length; i++) {
if(labels[i] == result) continue;
mergeLabel(index, result, labels[i]);
}
}
private void mergeLabel(int index, int result, int i) {
int row = index / dw;
int idx = 0;
for(int k = 0; k <= row; k++) {
for(int col = 0; col < dw; col++) {
idx = k * dw + col;
if(outData[idx] == i) {
outData[idx] = result;
}
}
}
}
private int getLabel(int[] data, int row, int col) {
// handle the edge pixels
if(row < 0 || row >= dh) {
return 0;
}
if(col < 0 || col >= dw) {
return 0;
}
int index = row * dw + col;
return (data[index] & 0xffffffff);
// it's difficulty for me to find the data overflow issue......
// return (data[index] & 0x000000ff); defect, @_@
}
private int getPixel(int[] data, int row, int col) {
// handle the edge pixels
if(row < 0 || row >= dh) {
return bgColor;
}
if(col < 0 || col >= dw) {
return bgColor;
}
int index = row * dw + col;
return (data[index] & 0x000000ff);
}
/**
* binary image data:
*
* 255, 0, 0, 255, 0, 255, 255, 0, 255, 255, 255,
* 255, 0, 0, 255, 0, 255, 255, 0, 0, 255, 0,
* 255, 0, 0, 0, 255, 255, 255, 255, 255, 0, 0,
* 255, 255, 0, 255, 255, 255, 0, 255, 0, 0, 255
* 255, 255, 0, 0, 0, 0, 255, 0, 0, 0, 0
*
* height = 5, width = 11
* @param args
*/
public static int[] imageData = new int[]{
255, 0, 0, 255, 0, 255, 255, 0, 255, 255, 255,
255, 0, 0, 255, 0, 255, 255, 0, 0, 255, 0,
255, 0, 0, 255, 255, 255, 255, 255, 255, 0, 0,
255, 255, 0, 255, 255, 255, 0, 255, 0, 0, 255,
255, 255, 0, 0, 0, 0, 255, 255, 0, 0, 0,
255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
255, 0, 255, 0, 255, 0, 0, 255, 255, 255, 255,
255, 255, 0, 0, 255, 255, 255, 0, 0, 255, 255
};
public static void main(String[] args) {
AdjustableConnectedComponentLabelAlg ccl = new AdjustableConnectedComponentLabelAlg();
int[] outData = ccl.doLabel(imageData, 11, 8);
for(int i=0; i<8; i++) {
System.out.println("--------------------");
for(int j = 0; j<11; j++) {
int index = i * 11 + j;
if(j != 0) {
System.out.print(",");
}
System.out.print(outData[index]);
}
System.out.println();
}
}
}
分享到:
相关推荐
在标记算法执行后,可以进一步分析连通组件的属性,如面积、周长、形状等,这些信息有助于识别图像中的物体和特征。 6. **代码实现**: 提供的"标记算法"文件可能包含了两种不同的实现方式,可能是C++、Python或...
### 高效的一遍扫描式连通区域标记算法解析 #### 一、引言与背景 连通区域标记是图像处理、计算机视觉以及模式识别领域中的基础性技术之一。其核心在于对二值图像中的各个连通区域进行唯一性的标记,从而便于后续...
"YACCLAB连通组件标记源码.zip"提供的正是一个实现这种算法的源代码库,名为YACCLAB。 YACCLAB,全称为Yet Another Connected Component Labeling Benchmark,是一个开源项目,专注于提供多种连通组件标记算法的...
在图像处理领域,连通区域标记(Connected Component Labeling,简称CCL)是一种常见的算法,用于将具有相同特征(如颜色、亮度等)的相邻像素集合分组为不同的区域或对象。C++作为一门强大的编程语言,也常被用于...
连通区域标记算法通常包括两步:扫描图像并构建连通组件,然后对这些组件进行标记。在基于模糊理论的算法中,首先会对图像中的每个像素应用模糊隶属函数,确定其属于某个连通区域的程度。接着,使用一种类似于凝聚...
### 基于跑长码的连通区域标记算法 #### 概述 在图像处理领域,连通区域标记是一项非常重要的技术,它主要用于识别和提取图像中的连通区域(即具有相同属性或特征的像素集合)。传统的连通区域标记方法如种子增长...
一次扫描连通区域标记算法C++
在二值图像中,连接组件标记的目的在于为图像中每一个连通组件(即每一个独立的对象)的所有像素分配一个唯一的标签。这项技术对于区分二值图像中的不同对象至关重要,是图像分析、物体识别等高级处理步骤的前提和...
二值图像连通域标记算法与代码 二值图像连通域标记算法是计算机视觉和图像处理中的一种常见算法,用于标记二值图像中的连通域。该算法的主要思想是将二值图像中的连通域标记为不同的标记值,以便于后续的图像处理和...
本代码根据计算机视觉的二值图像分析的逐行标记算法编写,实现连通成分标记功能
这是非常实用的VC代码,用于二值图像连通区域的标记,请大家参考
连通域标记算法是图像处理中的一种重要技术,用于标记图像中的连通区域。本文将详细介绍二值图像连通域标记算法的原理和实现代码。 一、直接扫描标记算法 直接扫描标记算法是最基本的连通域标记算法。该算法将图像...
采用灰度图像创建Maxtree的基本思想,提出一种新的二值图像连通区域标记算法。该算法主要采用8邻域搜索及排序队列方式实现,通过一次扫描二值图像即可完成连通区域标记。提出一种新的8邻域搜索策略,可以将...
总结来说,"一种二值图像连通区域标记的新算法"是对现有技术的重要贡献,它通过创新的策略实现了对大规模二值图像连通区域的快速标记,具有广泛的应用前景,尤其是在需要实时处理和高效计算的图像处理系统中。...
**基于标记的分水岭算法MATLAB程序** 在图像处理领域,分水岭算法是一种广泛应用于图像分割的技术,尤其在处理具有多个区域或物体的图像时。传统的分水岭算法虽然能够有效地找到图像中的区域边界,但往往会出现“过...
给大家分享一个我写的用FPGA实现的实时连通区识别源代码。具体介绍请看下文。源代码附件里有,或者给我发邮件索取 此算法的特点是: 1)仅用一片低端FPGA即可实现,无需外接任何存储器。用Xilinx的LX25就能装下,...