區(qū)域增長的算法實(shí)現(xiàn): 1)根據(jù)圖像的不同應(yīng)用選擇一個(gè)或一組種 子,它或者是最亮或最暗的點(diǎn),或者是位 于點(diǎn)簇中心的點(diǎn) 2...通過像素集合的區(qū)域增長 算法實(shí)現(xiàn): 區(qū)域A 區(qū)域B 種子像素增長.3)增長的規(guī)則 4)
結(jié)束條件. ************************************************************************* * * \\函數(shù)名稱: * RegionGrow() * * \\輸入?yún)?shù): * CDib * pDib - 指向CDib類的指針,含有原始圖象信息 * unsigned char * pUnRegion - 指向區(qū)域生長結(jié)果的指針 * * \\返回值: * 無 * * \\說明: * pUnRegion指針指向的數(shù)據(jù)區(qū)存儲(chǔ)了區(qū)域生長的結(jié)果,其中1(邏輯)表示 * 對(duì)應(yīng)象素為生長區(qū)域,0表示為非生長區(qū)域 * 區(qū)域生長一般包含三個(gè)比較重要的問題: * 1. 種子點(diǎn)的選取 * 2. 生長準(zhǔn)則 * 3. 終止條件 * 可以認(rèn)為,這三個(gè)問題需要具體分析,而且每個(gè)問題解決的好壞直接關(guān)系到 * 區(qū)域生長的結(jié)果。 * 本函數(shù)的種子點(diǎn)選取為圖像的中心,生長準(zhǔn)則是相鄰象素的象素值小于 * nThreshold, 終止條件是一直進(jìn)行到再?zèng)]有滿足生長準(zhǔn)則需要的象素時(shí)為止 * ************************************************************************* */ void RegionGrow(CDib * pDib, unsigned char * pUnRegion, int nThreshold) { static int nDx[]={-1,0,1,0}; static int nDy[]={0,1,0,-1}; // 遍歷圖象的縱坐標(biāo)
// int y; // 遍歷圖象的橫坐標(biāo)
// int x; // 圖象的長寬大小
CSize sizeImage = pDib->GetDimensions(); int nWidth = sizeImage.cx ; int nHeight = sizeImage.cy ; // 圖像在計(jì)算機(jī)在存儲(chǔ)中的實(shí)際大小
CSize sizeImageSave = pDib->GetDibSaveDim(); // 圖像在內(nèi)存中每一行象素占用的實(shí)際空間
int nSaveWidth = sizeImageSave.cx; // 初始化
memset(pUnRegion,0,sizeof(unsigned char)*nWidth*nHeight); // 種子點(diǎn)
int nSeedX, nSeedY; // 設(shè)置種子點(diǎn)為圖像的中心
nSeedX = nWidth /2 ; nSeedY = nHeight/2 ; // 定義堆棧,存儲(chǔ)坐標(biāo)
int * pnGrowQueX ; int * pnGrowQueY ; // 分配空間 pnGrowQueX = new int [nWidth*nHeight]; pnGrowQueY = new int [nWidth*nHeight]; // 圖像數(shù)據(jù)的指針
unsigned char * pUnchInput =(unsigned char * )pDib->m_lpImage; // 定義堆棧的起點(diǎn)和終點(diǎn) // 當(dāng)nStart=nEnd, 表示堆棧中只有一個(gè)點(diǎn) int nStart ; int nEnd ; //初始化
nStart = 0 ; nEnd = 0 ; // 把種子點(diǎn)的坐標(biāo)壓入棧
pnGrowQueX[nEnd] = nSeedX; pnGrowQueY[nEnd] = nSeedY; // 當(dāng)前正在處理的象素
int nCurrX ; int nCurrY ; // 循環(huán)控制變量
int k ; // 圖象的橫縱坐標(biāo),用來對(duì)當(dāng)前象素的4鄰域進(jìn)行遍歷
int xx; int yy; while (nStart<=nEnd)
{ // 當(dāng)前種子點(diǎn)的坐標(biāo) nCurrX = pnGrowQueX[nStart]; nCurrY = pnGrowQueY[nStart]; // 對(duì)當(dāng)前點(diǎn)的4鄰域進(jìn)行遍歷
for (k=0; k<4; k++) { // 4鄰域象素的坐標(biāo) xx = nCurrX+nDx[k]; yy = nCurrY+nDy[k]; // 判斷象素(xx,yy) 是否在圖像內(nèi)部 // 判斷象素(xx,yy) 是否已經(jīng)處理過 // pUnRegion[yy*nWidth+xx]==0 表示還沒有處理 // 生長條件:判斷象素(xx,yy)和當(dāng)前象素(nCurrX,nCurrY) 象素值差的絕對(duì)值
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)設(shè)置成邏輯1(255)
// 同時(shí)也表明該象素處理過 pUnRegion[yy*nWidth+xx] = 255 ; } } nStart++; } // 釋放內(nèi)存
delete []pnGrowQueX; delete []pnGrowQueY; pnGrowQueX = NULL ; pnGrowQueY = NULL ; } 對(duì)于2D圖象的組織增長,使用遞歸也是一種不錯(cuò)的選擇,但需要注意棧空間需要設(shè)大一些。 而在3D數(shù)據(jù)場(chǎng)上,遞歸幾乎是不可行的,??臻g經(jīng)常會(huì)出現(xiàn)溢出的情況,因此不具備實(shí)用性。 2D組織增長偽代碼如下 組織增長(Image* pImage, int i, ing j, byte* mask)
{ if 不滿足增長條件(pImage, i,j, mask) return; 設(shè)置標(biāo)記(mask, i, j); 組織增長(pImage, i-1, j, mask); 組織增長(pImage, i+1, j, mask); 組織增長(pImage, i, j-1, mask); 組織增長(pImage, i, j+1, mask); } 至于將遞歸程序改為迭代程序,可以看一看《程序設(shè)計(jì)方法學(xué)》
區(qū)域增長算法遞歸實(shí)現(xiàn)
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 ; // 對(duì)當(dāng)前點(diǎn)的4鄰域進(jìn)行遍歷 int times = 0; for (k=0; k<4; k++) { // 4鄰域象素的坐標(biāo) xx = nCurrX+nDx[k]; yy = nCurrY+nDy[k]; // 判斷象素(xx,yy) 是否在圖像內(nèi)部
// 判斷象素(xx,yy) 是否已經(jīng)處理過 // pUnRegion[yy*nWidth+xx]==0 表示還沒有處理 // 生長條件:判斷象素(xx,yy)和當(dāng)前象素(nCurrX,nCurrY) 象素值差的絕對(duì)值
if ( (xx < nWidth) && (xx>=0) && (yy>=0) && (yy<nHeight) && (pUnRegion[yy*nWidth+xx]==0) && (pUnchInput[yy*nWidth+xx]==1)) { // 同時(shí)也表明該象素處理過 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++; } }
/*
* 區(qū)域增長,遞歸實(shí)現(xiàn) * S,源圖象 D,目標(biāo)圖象 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) //表示區(qū)域大于40*40時(shí)就畫出邊框 { //畫邊框 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; } }
標(biāo)準(zhǔn)源碼
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; // 定義堆棧,存儲(chǔ)坐標(biāo) int * pnGrowQueX ; int * pnGrowQueY ; // 分配空間
pnGrowQueX = new int [nWidth*nHeight]; pnGrowQueY = new int [nWidth*nHeight]; // 定義堆棧的起點(diǎn)和終點(diǎn)
// 當(dāng)nStart=nEnd, 表示堆棧中只有一個(gè)點(diǎn) int nStart ; int nEnd ; //初始化
nStart = 0 ; nEnd = 0 ; // 把種子點(diǎn)的坐標(biāo)壓入棧
pnGrowQueX[nEnd] = nSeedX; pnGrowQueY[nEnd] = nSeedY; // 當(dāng)前正在處理的象素
int nCurrX ; int nCurrY ; // 循環(huán)控制變量
int k ; // 圖象的橫縱坐標(biāo),用來對(duì)當(dāng)前象素的8鄰域進(jìn)行遍歷
int xx; int yy; while (nStart<=nEnd)
{ // 當(dāng)前種子點(diǎn)的坐標(biāo) nCurrX = pnGrowQueX[nStart]; nCurrY = pnGrowQueY[nStart]; // 對(duì)當(dāng)前點(diǎn)的4鄰域進(jìn)行遍歷
for (k=0; k<4; k++) { // 4鄰域象素的坐標(biāo) xx = nCurrX+nDx[k]; yy = nCurrY+nDy[k]; // 判斷象素(xx,yy) 是否在圖像內(nèi)部
// 判斷象素(xx,yy) 是否已經(jīng)處理過 // pUnRegion[yy*nWidth+xx]==0 表示還沒有處理 // 生長條件:判斷象素(xx,yy)和當(dāng)前象素(nCurrX,nCurrY) 象素值差的絕對(duì)值
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)設(shè)置成邏輯1(255)
// 同時(shí)也表明該象素處理過 pUnRegion[yy*nWidth+xx] = 255 ; } } nStart++; } //找出區(qū)域的范圍 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; } // 釋放內(nèi)存 delete []pnGrowQueX; delete []pnGrowQueY; pnGrowQueX = NULL ; pnGrowQueY = NULL ; return FALSE; } //調(diào)用方法
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; } } |
|