看看我做的非递归进行的连通性分析是不是有点创新性的东西

tiantian88226 2009-03-23 05:10:09
开始也是想用递归,总是堆栈溢出。后来网上找资料也没有找到很好用的办法。我自己在纸上分析了半天,弄了一个用循环做的连通区域分析算法,就是对二值的二维数据,同属一个连通区域的就分给同一个标号。我这样做出来的应该是8-连通的。我不知道这个方法以前有没有很规范的先例呢?大家有没有看到过有类似的算法呢?我这个方法是不是从逻辑上讲完全正确呢(虽然我自己对我的数据跑通了)?还有没有什么分析连通性更好、适用面广、方便编程、简单实用的算法可以介绍给我吗?
我是新手,多多指教!最近做毕业设计,才找到CSDN这个广阔的天地来!
/////////////////////////主函数中的主要部分:
for(i = 0; i < (m_ImgCol_Big * m_ImgRow_Big); i++)
{
if(pImgBig[i]>=70&&pImgBig[i]<=120) /////////////////////select the range for processing
pImgBig[i]=1; //currently,change them manually
else
pImgBig[i]=0;
}
////
GDALClose(m_pGDALDataset);


////
int label_count=1; //to count the number of labels
float *lpsrc; //point to the original image,whose regions of interest have been marked with 1
int *label; // a table with the same size of the image to store the labels of connected areas
int j; // i,j and k are loop variables
int k;

label=new int[m_ImgCol_Big * m_ImgRow_Big];

int *lpdest=label; //a pointer pointing to the element in the label table
int *label_change=label; //refresh some labels which are not the same
//with their neighbors in one connected domain
for(i=0;i<m_ImgRow_Big*m_ImgCol_Big;i++)//clear the label table
{
*lpdest=0;lpdest++;
}

for(i=1;i<=m_ImgRow_Big;i++) //scan all the elements
{
for(j=1;j<=m_ImgCol_Big;j++)
{
lpsrc=pImgBig+m_ImgCol_Big*(i-1)+j-1; //separately point to the same position
lpdest=label+m_ImgCol_Big*(i-1)+j-1; // in different tables
////////
if(*lpsrc==1) //element of regions of interest
{
if(i==1&&j==1) //the first element,special handling:if it's 1,give it a label directly
{
*lpdest=label_count;
label_count++;
}
else if(i==1) //the first row expect for the first one,special handling:
{ //only consider the element before it(to its left)
if(*(lpdest-1)!=0) //if its left one has a label,then give it the same label
*lpdest=*(lpdest-1);
else if(*(lpdest-1)==0) //if its left one is 0,give it a label directly
{
*lpdest=label_count;
label_count++;
}
}
else if(j==1) //the first column expect for the first one,special handling:
{
if(*(lpdest-m_ImgCol_Big)!=0) //only consider the element above it(on its top)
*lpdest=*(lpdest-m_ImgCol_Big);
else if(*(lpdest-m_ImgCol_Big)==0)
{
*lpdest=label_count;
label_count++;
}
}
else //the others who have 4 neighbors(left,topleft,top and topright)
{
if(*(lpdest-1)==0&&*(lpdest-m_ImgCol_Big-1)==0&&*(lpdest-m_ImgCol_Big)==0&&*(lpdest-m_ImgCol_Big+1)==0)
{
*lpdest=label_count; //its neighbors have no label,then give it a new label
label_count++;
}
else if(find_4neighbors_same((lpdest-1),(lpdest-m_ImgCol_Big-1),(lpdest-m_ImgCol_Big),(lpdest-m_ImgCol_Big+1)))
{
//its neighbors which have labels have a same label, then give it the same label
*lpdest=find_4neighbors_same((lpdest-1),(lpdest-m_ImgCol_Big-1),(lpdest-m_ImgCol_Big),(lpdest-m_ImgCol_Big+1));
}
else //its neighbors which have labels have different labels
{
int *p1=find_a_different_neighbor(lpdest-1,lpdest-m_ImgCol_Big-1); //left and(or) topleft
int *p2=find_a_different_neighbor(lpdest-m_ImgCol_Big,lpdest-m_ImgCol_Big+1);//top and(or) topright
int recordp1=*p1;
int recordp2=*p2;
//if an element's neighbors have different labels
//if its left or topleft has a label A,and its top or topright has a label B
//give it A as its label,and change all the label B to A.
//So its top or(and) topright neighbors have the same label with its left or(and) topleft neighbors
*lpdest=*p1;
for(k=0;k<=(i-1)*m_ImgCol_Big+j-1;k++)
{
label_change=label+k;
if(*label_change==recordp2)
*label_change=recordp1;
}

}
}
}
////////
}
}

printf("%d",label_count);
//change the discontinuous labels to continuous labels
//convenient for display and summary
//(the labels are not continuously used is a shortcoming of this algorithm, because we refresh
// some labels(and these labels are just used in the middle but not used actually in the end)
// to other values in order to ensure that connected areas have the same label)
int num[1000]; //an array to store different labels from small to large
int min_before=0; //the valid minimum label is 1
int min_current=1;
lpdest=label;
i=0; //ordinal number of num[]
while(1)
{
min_current=search_min(min_before,m_ImgCol_Big,m_ImgRow_Big,label); //find current minimum
num[i]=min_current;
i++;
if(min_before!=min_current) //termination of the loop
min_before=min_current;
else break;
}
for(j=0;j<i-1;j++) //change the original labels into new ones,refer to num[]
{
for(k=0;k<(m_ImgCol_Big * m_ImgRow_Big);k++)
{
if(*(lpdest+k)==num[j])
*(lpdest+k)=j+1;
}
}
int changed_label_count=j; //define a new label count to record the amount of used labels
// which means the amount of the connected regions
// printf("\n%d\n",i);
// for(j=0;j<i;j++)
// printf("%d\t",num[j]);
printf("\nchanged_label_count=%d",changed_label_count);
printf("\n");
//
// i=500;j=188;
// printf("center=%d",*(label+m_ImgCol_Big*(i-1)+j-1));
// printf("\nleft=%d",*(label+m_ImgCol_Big*(i-1)+j-1-1));
// printf("\ntopleft=%d",*(label+m_ImgCol_Big*(i-1)+j-1-m_ImgCol_Big-1));
// printf("\ntop=%d",*(label+m_ImgCol_Big*(i-1)+j-1-m_ImgCol_Big));
// printf("\ntopright=%d",*(label+m_ImgCol_Big*(i-1)+j-1-m_ImgCol_Big+1));
///////////////////////////
...全文
75 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
tiantian88226 2009-03-27
  • 打赏
  • 举报
回复
种子点的选取怎么选呢?人工选取吗?还是事先要分析些另外什么参数的吧?LS:O(n)可以用哪种算法做到?种子生长能做到O(n)吗?我也觉得我这最不好的就是时间复杂度高了o(n*n)了,不好。
fire_woods 2009-03-27
  • 打赏
  • 举报
回复
可以做到O(n)的,你要你能想到办法合并的时候能不刷新标记, 最后一起刷新一遍就可以了.

同样,种子生长也能做到O(n)的.
fire_woods 2009-03-25
  • 打赏
  • 举报
回复
楼主刷新标记太花时间,本来是O(n)的算法(n表示像素个数),变成了O(n*n).
西_海 2009-03-25
  • 打赏
  • 举报
回复
这么麻烦。。。种子点区域生长不就行了么
tiantian88226 2009-03-23
  • 打赏
  • 举报
回复
上面代码有点乱,下面我简单总结一下主要思想:
另建一个label表,大小与原数据行列相同。对应的位置即记录某元素所属连通区域的标号。原数据为1的地方是画面,为0是背景。
标号为0等于没标号,有意义的标号从1开始。
扫描一个二维的数组(原数据)吧,从左到右从上到下。
对每一个元素,只考虑它左上,上,右上,和左方四个元素。因为扫描的顺序,它的这几个邻居才可能是已被处理过的。
依次看该元素的(i-1,j-1),(i-1,j),(i-1,j+1),(i,j-1)邻居,如果四邻居均无标号,则赋给该元素一个新标号。如果四邻居有标号者的标号全相同(包括只有这四个中的一个邻居),从之。
如果拥有的邻居有标号不同的情况:
首先做一个归纳:如果上、右上均有标号,则它们的标号一定是相同的;
如左、左上均有标号,也一定是相同的。
(至于为什么这么归纳,是跟后面刷新标号有关系的。某元素的这四个邻居都在它的扫描顺序这前,因此认为是已经经过处理了的。)
所以,从该元素的上、右上二者中找出这个标号A(即可能情况:上、右上二者只有其一有标号另外一个没有标号;上、右上二者均有标号,标号相同。),再从左,左上二者中找出另一个标号B。然后将该元素赋给标号B,且再从头扫描至该元素的位置,对已经标过的标号,如果有标号为A,则全部改成B。此过程为刷新标号,保证了该元素的邻域也都有相同的标号。

另外:
三种元素特殊处理:
1:(1,1),首元素,直接给个新标号;
2:首行其他元素,只判断前一个元素(i,j-1);
3:首列其他元素,只判断顶上面一个(i-1,j)和右上方一个元素(i-1,j+1)

分配标号都完了以后,由于刷新标号的过程导致了标号的使用是不连续的,(比如只有两个连通区域,但标号分别为1和10)。为了后续处理的方便,再把不连续的标号处理一下弄成连续的。
tiantian88226 2009-03-23
  • 打赏
  • 举报
回复
还有三个小函数没有贴上:
int search_min(int min_before,int m_ImgCol_Big,int m_ImgRow_Big,int* label)
{ //search the current minimum in the label table
int i;
int *p=label;
int min_current;
int max=*p; //the maximum in the label table

for(i=1;i<(m_ImgCol_Big * m_ImgRow_Big);i++) // find the maximum
{ //and give it to the first min_current
if(*(p+i)>max)
max=*(p+i);
}

min_current=max;

for(i=1;i<(m_ImgCol_Big * m_ImgRow_Big);i++)
{
if(*(p+i)>min_before) //exclude the elements that have been selected as a minimum
if(*(p+i)<min_current)
min_current=*(p+i);
}
return min_current;
}

int find_4neighbors_same(int* left,int* topleft,int* top,int* topright)
{ //judge whether the four neighbors of an element have the same labels
int aa[4]; //if yes,return the value of the label
int i=0; // if not all the same,return 0
int j=1;
if(*left!=0) //if a neighbor has a label,put its label into an array for comparison
{
aa[i]=*left; i++;
}
if(*topleft!=0)
{
aa[i]=*topleft; i++;
}
if(*top!=0)
{
aa[i]=*top; i++;
}
if(*topright!=0)
{
aa[i]=*topright;i++;
}
if(i>=2)
{
for(j=1;j<i;j++)
{
if(aa[j]!=aa[j-1]) //once there is a difference, return 0
{
return 0;
}
}
} //no difference occurs,return the common label
return aa[j-1];
}


int *find_a_different_neighbor(int* one,int* two) // find one with a label between two neighbors
{ //{the two neighbors are either the same,or one
int *p; //is zero(without label) and the other is nonzero(with label)}
if(*one!=0)
p=one;
else if(*two!=0)
p=two;
return(p);
}
NewVC1978 2009-03-23
  • 打赏
  • 举报
回复
不太明白,我当时也做过一个,但我用射线方法做的。

4,506

社区成员

发帖
与我相关
我的任务
社区描述
图形图像/机器视觉
社区管理员
  • 机器视觉
  • 迪菲赫尔曼
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧