区域增长的算法实现: 1)根据图像的不同应用选择一个或一组种 子,它或者是最亮或最暗的点,或者是位 于点簇中心的点 2...通过像素集合的区域增长 算法实现: 区域A 区域B 种子像素增长.3)增长的规则 4)
结束条件.
*************************************************************************
*
* \\函数名称:
* RegionGrow()
*
* \\输入参数:
* CDib * pDib - 指向CDib类的指针,含有原始图象信息
* unsigned char * pUnRegion - 指向区域生长结果的指针
*
* \\返回值:
* 无
*
* \\说明:
* pUnRegion指针指向的数据区存储了区域生长的结果,其中1(逻辑)表示
* 对应象素为生长区域,0表示为非生长区域
* 区域生长一般包含三个比较重要的问题:
* 1. 种子点的选取
* 2. 生长准则
* 3. 终止条件
* 可以认为,这三个问题需要具体分析,而且每个问题解决的好坏直接关系到
* 区域生长的结果。
* 本函数的种子点选取为图像的中心,生长准则是相邻象素的象素值小于
* nThreshold, 终止条件是一直进行到再没有满足生长准则需要的象素时为止
*
*************************************************************************
*/
void RegionGrow(CDib * pDib, unsigned char * pUnRegion, int nThreshold)
{
static int nDx[]={-1,0,1,0};
static int nDy[]={0,1,0,-1};
// 遍历图象的纵坐标
// int y;
// 遍历图象的横坐标
// int x;
// 图象的长宽大小
CSize sizeImage = pDib->GetDimensions();
int nWidth = sizeImage.cx ;
int nHeight = sizeImage.cy ;
// 图像在计算机在存储中的实际大小
CSize sizeImageSave = pDib->GetDibSaveDim();
// 图像在内存中每一行象素占用的实际空间
int nSaveWidth = sizeImageSave.cx;
// 初始化
memset(pUnRegion,0,sizeof(unsigned char)*nWidth*nHeight);
// 种子点
int nSeedX, nSeedY;
// 设置种子点为图像的中心
nSeedX = nWidth /2 ;
nSeedY = nHeight/2 ;
// 定义堆栈,存储坐标
int * pnGrowQueX ;
int * pnGrowQueY ;
// 分配空间
pnGrowQueX = new int [nWidth*nHeight];
pnGrowQueY = new int [nWidth*nHeight];
// 图像数据的指针
unsigned char * pUnchInput =(unsigned char * )pDib->m_lpImage;
// 定义堆栈的起点和终点
// 当nStart=nEnd, 表示堆栈中只有一个点
int nStart ;
int nEnd ;
//初始化
nStart = 0 ;
nEnd = 0 ;
// 把种子点的坐标压入栈
pnGrowQueX[nEnd] = nSeedX;
pnGrowQueY[nEnd] = nSeedY;
// 当前正在处理的象素
int nCurrX ;
int nCurrY ;
// 循环控制变量
int k ;
// 图象的横纵坐标,用来对当前象素的4邻域进行遍历
int xx;
int yy;
while (nStart<=nEnd)
{
// 当前种子点的坐标
nCurrX = pnGrowQueX[nStart];
nCurrY = pnGrowQueY[nStart];
// 对当前点的4邻域进行遍历
for (k=0; k<4; k++)
{
// 4邻域象素的坐标
xx = nCurrX+nDx[k];
yy = nCurrY+nDy[k];
// 判断象素(xx,yy) 是否在图像内部
// 判断象素(xx,yy) 是否已经处理过
// pUnRegion[yy*nWidth+xx]==0 表示还没有处理
// 生长条件:判断象素(xx,yy)和当前象素(nCurrX,nCurrY) 象素值差的绝对值
if ( (xx < nWidth) && (xx>=0) && (yy<nHeight) && (yy>=0)
&& (pUnRegion[yy*nWidth+xx]==0) && abs(pUnchInput[yy*nSaveWidth+xx] - pUnchInput[nCurrY*nSaveWidth+nCurrX])<nThreshold )
{
// 堆栈的尾部指针后移一位
nEnd++;
// 象素(xx,yy) 压入栈
pnGrowQueX[nEnd] = xx;
pnGrowQueY[nEnd] = yy;
// 把象素(xx,yy)设置成逻辑1(255)
// 同时也表明该象素处理过
pUnRegion[yy*nWidth+xx] = 255 ;
}
}
nStart++;
}
// 释放内存
delete []pnGrowQueX;
delete []pnGrowQueY;
pnGrowQueX = NULL ;
pnGrowQueY = NULL ;
}
对于2D图象的组织增长,使用递归也是一种不错的选择,但需要注意栈空间需要设大一些。
而在3D数据场上,递归几乎是不可行的,栈空间经常会出现溢出的情况,因此不具备实用性。
2D组织增长伪代码如下
组织增长(Image* pImage, int i, ing j, byte* mask)
{
if 不满足增长条件(pImage, i,j, mask)
return;
设置标记(mask, i, j);
组织增长(pImage, i-1, j, mask);
组织增长(pImage, i+1, j, mask);
组织增长(pImage, i, j-1, mask);
组织增长(pImage, i, j+1, mask);
}
至于将递归程序改为迭代程序,可以看一看《程序设计方法学》
区域增长算法递归实现
void RegionGrowTwo(int nSeedX, int nSeedY, BYTE * pUnchInput,BYTE * D, int nWidth, int nHeight, BYTE * pUnRegion,int &iLeft,int & iRight,int & iTop,int & iBottom)
{
int nDx[] = {-1,1,0,0};
int nDy[] = {0,0,-1,1};
int k=0;
int nCurrX ;
int nCurrY ;
int xx=0,yy=0;
nCurrX = nSeedX;
nCurrY = nSeedY;
if(nCurrX<iLeft)
iLeft = nCurrX;
if(nCurrX>iRight)
iRight = nCurrX;
if(nCurrY<iTop)
iTop = nCurrY;
if(nCurrY>iBottom)
iBottom = nCurrY;
// pUnRegion[nCurrY*nWidth+nCurrX] = 255 ;
// 对当前点的4邻域进行遍历
int times = 0;
for (k=0; k<4; k++)
{
// 4邻域象素的坐标
xx = nCurrX+nDx[k];
yy = nCurrY+nDy[k];
// 判断象素(xx,yy) 是否在图像内部
// 判断象素(xx,yy) 是否已经处理过
// pUnRegion[yy*nWidth+xx]==0 表示还没有处理
// 生长条件:判断象素(xx,yy)和当前象素(nCurrX,nCurrY) 象素值差的绝对值
if ( (xx < nWidth) && (xx>=0) && (yy>=0) && (yy<nHeight)
&& (pUnRegion[yy*nWidth+xx]==0) && (pUnchInput[yy*nWidth+xx]==1))
{
// 同时也表明该象素处理过
pUnRegion[yy*nWidth+xx] = 255 ;
if(xx<iLeft)
iLeft = xx;
if(xx>iRight)
iRight = xx;
if(yy<iTop)
iTop = yy;
if(yy>iBottom)
iBottom = yy;
RegionGrowTwo(xx,yy,pUnchInput,D,nWidth,nHeight,pUnRegion,iLeft,iRight,iTop,iBottom);
}
else
times++;
}
}
/*
* 区域增长,递归实现
* S,源图象
D,目标图象
ImageWidth,ImageHeight,表示图象的宽、高
*/
void RegionGrowOne(BYTE *S,BYTE *D,int ImageWidth,int ImageHeight)
{
int iLeft=0,iRight=0,iTop=0,iBottom=0;
int k1,k2,k3,k4,ii1=0,off=0;
int i=0,j=0;
LPBYTE lpFlag = new BYTE[ImageWidth*ImageHeight];
memset(lpFlag,0,ImageWidth*ImageHeight);
memcpy(D,S,ImageWidth*ImageHeight);
for (i=0; i<ImageHeight; i++)
{
for (j=0; j<ImageWidth; j++)
{
if (S[i*ImageWidth+j] == 1 && lpFlag[i*ImageWidth+j] == 0)
{
iLeft=65535,iRight=0,iTop=65535,iBottom=0;
RegionGrowTwo(j,i,S,D,ImageWidth,ImageHeight,lpFlag,iLeft,iRight,iTop,iBottom);
if((iRight-iLeft)>40 && (iBottom-iTop)>40) //表示区域大于40*40时就画出边框
{
//画边框
k1 = (iLeft -1 )<0 ?0:(iLeft -1 );
k2 = (iRight+1)>=ImageWidth?(ImageWidth-1):(iRight+1);
k3 = (iTop-1)<0?0:(iTop-1);
k4 = (iBottom+1)>=ImageHeight?(ImageHeight-1):(iBottom+1);
for(ii1 = k1;ii1 <= k2;ii1++)
{
off = ii1 + k3*ImageWidth;
D[off] = 11;
off = ii1 + k4*ImageWidth;
D[off] = 11;
}
for(ii1 = k3 ;ii1<=k4;ii1++)
{
off = ii1 * ImageWidth + k1;
D[off] = 11;
off = ii1 * ImageWidth + k2;
D[off] = 11;
}
/////////////////////////////////////////////////
}
}
}
}
if(lpFlag!=NULL)
{
delete []lpFlag;
lpFlag = NULL;
}
}
标准源码
BOOL RegionGrow(int nSeedX, int nSeedY, BYTE * pUnchInput,int nWidth, int nHeight, BYTE * pUnRegion,CRect &R)
{
int nDx[] = {-1,1,0,0};
int nDy[] = {0,0,-1,1};
int nSaveWidth = nWidth;
// 定义堆栈,存储坐标
int * pnGrowQueX ;
int * pnGrowQueY ;
// 分配空间
pnGrowQueX = new int [nWidth*nHeight];
pnGrowQueY = new int [nWidth*nHeight];
// 定义堆栈的起点和终点
// 当nStart=nEnd, 表示堆栈中只有一个点
int nStart ;
int nEnd ;
//初始化
nStart = 0 ;
nEnd = 0 ;
// 把种子点的坐标压入栈
pnGrowQueX[nEnd] = nSeedX;
pnGrowQueY[nEnd] = nSeedY;
// 当前正在处理的象素
int nCurrX ;
int nCurrY ;
// 循环控制变量
int k ;
// 图象的横纵坐标,用来对当前象素的8邻域进行遍历
int xx;
int yy;
while (nStart<=nEnd)
{
// 当前种子点的坐标
nCurrX = pnGrowQueX[nStart];
nCurrY = pnGrowQueY[nStart];
// 对当前点的4邻域进行遍历
for (k=0; k<4; k++)
{
// 4邻域象素的坐标
xx = nCurrX+nDx[k];
yy = nCurrY+nDy[k];
// 判断象素(xx,yy) 是否在图像内部
// 判断象素(xx,yy) 是否已经处理过
// pUnRegion[yy*nWidth+xx]==0 表示还没有处理
// 生长条件:判断象素(xx,yy)和当前象素(nCurrX,nCurrY) 象素值差的绝对值
if ( (xx < nWidth) && (xx>=0) && (yy>=0) && (yy<nHeight)
&& (pUnRegion[yy*nWidth+xx]==0) && (pUnchInput[yy*nSaveWidth+xx]==1))
{
// 堆栈的尾部指针后移一位
nEnd++;
// 象素(xx,yy) 压入栈
pnGrowQueX[nEnd] = xx;
pnGrowQueY[nEnd] = yy;
// 把象素(xx,yy)设置成逻辑1(255)
// 同时也表明该象素处理过
pUnRegion[yy*nWidth+xx] = 255 ;
}
}
nStart++;
}
//找出区域的范围
int nMinx=pnGrowQueX[0], nMaxx=pnGrowQueX[0], nMiny=pnGrowQueY[0], nMaxy = pnGrowQueY[0];
for (k=0; k<nEnd; k++)
{
if (pnGrowQueX[k] > nMaxx)
nMaxx = pnGrowQueX[k];
if (pnGrowQueX[k] < nMinx)
nMinx = pnGrowQueX[k];
if (pnGrowQueY[k] > nMaxy)
nMaxy = pnGrowQueY[k];
if (pnGrowQueY[k] < nMiny)
nMiny = pnGrowQueY[k];
}
if ((nMaxy - nMiny) > 40 && (nMaxx - nMinx) > 40)
{
R.left = nMinx;
R.right = nMaxx;
R.top = nMiny;
R.bottom = nMaxy;
return TRUE;
}
// 释放内存
delete []pnGrowQueX;
delete []pnGrowQueY;
pnGrowQueX = NULL ;
pnGrowQueY = NULL ;
return FALSE;
}
//调用方法
void OnButton(LPBYTE S,int ImageWidth,int ImageHeight)
{
int i=0,j=0;
CRect rect;
LPBYTE lpFlag = new BYTE[ImageWidth*ImageHeight];
memset(lpFlag,0,ImageWidth*ImageHeight);
for (i=0; i<ImageHeight; i++)
{
for (j=0; j<ImageWidth; j++)
{
if (S[i*ImageWidth+j] == 1 && lpFlag[i*ImageWidth+j] == 0)
{
RegionGrow(j, i, S, ImageWidth, ImageHeight, lpFlag,rect);
}
}
}
if(lpFlag!=NULL)
{
delete []lpFlag;
lpFlag = NULL;
}
}