www.gusucode.com > VC++图像分水岭分割算法控件及示例源代码-源码程序 > VC++图像分水岭分割算法控件及示例源代码-源码程序/code/WaterShedDoc.cpp
// WaterShedDoc.cpp : implementation of the CWaterShedDoc class // Download by http://www.NewXing.com #include "stdafx.h" #include "WaterShed.h" #include "WaterShedDoc.h" #include <queue> using namespace std; #include "MainFrm.h" #include "math.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define MAXV 256 // Coefficient matrix for xyz and rgb spaces static const int XYZ[3][3] = { { 4125, 3576, 1804 }, { 2125, 7154, 721 }, { 193, 1192, 9502 } }; static const double RGB[3][3] = { { (float)3.2405, (float)-1.5371, (float)-0.4985 }, {(float)-0.9693, (float)1.8760, (float)0.0416 }, { (float)0.0556, (float)-0.2040, (float)1.0573 } }; // Constants for LUV transformation static const float Xn = (float)0.9505; static const float Yn = (float)1.0; static const float Zn = (float)1.0888; static const float Un_prime = (float)0.1978; static const float Vn_prime = (float)0.4683; static const float Lt = (float)0.008856; ///////////////////////////////////////////////////////////////////////////// // CWaterShedDoc IMPLEMENT_DYNCREATE(CWaterShedDoc, CDocument) BEGIN_MESSAGE_MAP(CWaterShedDoc, CDocument) //{{AFX_MSG_MAP(CWaterShedDoc) ON_COMMAND(ID_WATERSHED, OnWatershed) //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CWaterShedDoc construction/destruction CWaterShedDoc::CWaterShedDoc() { // TODO: add one-time construction code here imageData = NULL; isImageLoaded=FALSE; imageName = ""; myImageObject = NULL; luvData = NULL; } CWaterShedDoc::~CWaterShedDoc() { if (imageData!=NULL) { delete [] imageData; imageData = NULL; } if (luvData!=NULL) { delete [] luvData; luvData = NULL; } if (myImageObject!=NULL) { delete myImageObject; myImageObject = NULL; } } BOOL CWaterShedDoc::OnNewDocument() { if (!CDocument::OnNewDocument()) return FALSE; // TODO: add reinitialization code here // (SDI documents will reuse this document) return TRUE; } ///////////////////////////////////////////////////////////////////////////// // CWaterShedDoc serialization void CWaterShedDoc::Serialize(CArchive& ar) { if (ar.IsStoring()) { // TODO: add storing code here } else { // TODO: add loading code here } } ///////////////////////////////////////////////////////////////////////////// // CWaterShedDoc diagnostics #ifdef _DEBUG void CWaterShedDoc::AssertValid() const { CDocument::AssertValid(); } void CWaterShedDoc::Dump(CDumpContext& dc) const { CDocument::Dump(dc); } #endif //_DEBUG ///////////////////////////////////////////////////////////////////////////// // CWaterShedDoc commands BOOL CWaterShedDoc::OnOpenDocument(LPCTSTR lpszPathName) { // if (!CDocument::OnOpenDocument(lpszPathName)) // return FALSE; // TODO: Add your specialized creation code here CString strPathName = lpszPathName; imageName = strPathName; while ( imageName.Find("\\", 0)>=0 && imageName!="") { imageName.Delete(0, 1); } myImageObject = new CImageObject(strPathName); if(myImageObject==NULL) { AfxMessageBox("Could not create image class!"); return FALSE; } isImageLoaded = TRUE; //以下将RGB数据存入数组以备处理; LONG width = myImageObject->GetWidth(); LONG height = myImageObject->GetHeight(); dataLen = width*height*3; if ( imageData != NULL ) { delete [] imageData; imageData = NULL; } imageData = new BYTE[width*height*3]; imageWidth = width; imageHeight = height; myImageObject->LoadDIBToBuf(imageData); //以下保存LUV数据; if ( luvData != NULL ) { delete [] luvData; luvData = NULL; } luvData = new MyLUV[width*height]; RgbtoLuvPcm(imageData, width, height, luvData); return TRUE; } void CWaterShedDoc::OnWatershed() { // TODO: Add your command handler code here BeginWaitCursor(); LONG imagelen = imageWidth*imageHeight; FLOAT* deltar = new FLOAT[imagelen];//梯度模数组; FLOAT* deltasita = new FLOAT[imagelen];//梯度角度数组; INT* flag = new INT[imagelen];//各点标识数组; INT* gradientfre = new INT[256];//图像中各点梯度值频率; INT* gradientadd = new INT[257];//各梯度起终位置; memset( gradientfre, 0, 256*sizeof(INT)); memset( gradientadd, 0, 257*sizeof(INT)); //首先得到各点梯度; GetGradient(imageData, imageWidth, imageHeight , deltar, deltasita); LONG temptime1 = GetTickCount();//初始时刻; //以下统计各梯度频率; MyImageGraPt* graposarr = new MyImageGraPt[imagelen]; LONG xstart, imagepos, deltapos; xstart = imagepos = deltapos = 0; for (INT y=0; y<imageHeight; y++) { xstart = y*imageWidth; for (INT x=0; x<imageWidth; x++) { deltapos = xstart + x; if (deltar[deltapos]>255) { deltar[deltapos] = 255; } INT tempi = (INT)(deltar[deltapos]); gradientfre[tempi] ++;//灰度值频率; } } //统计各梯度的累加概率; INT added = 0; gradientadd[0] = 0;//第一个起始位置为0; for (INT ii=1; ii<256; ii++) { added += gradientfre[ii-1]; gradientadd[ii] = added; } gradientadd[256] = imagelen;//最后位置; memset( gradientfre, 0, 256*sizeof(INT));//清零,下面用作某梯度内的指针; //自左上至右下sorting.... for (y=0; y<imageHeight; y++) { xstart = y*imageWidth; for (INT x=0; x<imageWidth; x++) { deltapos = xstart + x; INT tempi = (INT)(deltar[deltapos]);//当前点的梯度值,由于前面的步骤,最大只能为255; //根据梯度值决定在排序数组中的位置; INT tempos = gradientadd[tempi] + gradientfre[tempi]; gradientfre[tempi] ++;//梯度内指针后移; graposarr[tempos].gradient = tempi; //根据当前点的梯度将该点信息放后排序后数组中的合适位置中去; graposarr[tempos].x = x; graposarr[tempos].y = y; } } LONG temptime2 = GetTickCount();//vincent泛洪前的时刻; INT rgnumber = 0;//分割后的区域数; FloodVincent(graposarr, gradientadd, 0, 255, flag, rgnumber);//Flooding; LONG temptime3 = GetTickCount();//vincent泛洪后的时刻; LONG kk0 = temptime2 - temptime1;//排序用时; LONG kk1 = temptime3 - temptime2;//flood用时; LONG allkk = temptime3 - temptime1;//总用时; allkk = temptime3 - temptime1;//总用时; //区域增长步骤 //以下准备计算各个区域的LUV均值; MyRgnInfo* rginfoarr = new MyRgnInfo[rgnumber+1];//分割后各个区的一些统计信息,第一个元素不用,图像中各点所属区域的信息存放在flag数组中; //清空该数组; for (INT i=0; i<=rgnumber; i++) { rginfoarr[i].isflag = FALSE; rginfoarr[i].ptcount = 0; rginfoarr[i].l = 0; rginfoarr[i].u = 0; rginfoarr[i].v = 0; } for (y=0; y<imageHeight; y++) { xstart = y*imageWidth; for (INT x=0; x<imageWidth; x++) { INT pos = xstart + x; INT rgid = flag[pos];//当前位置点所属区域在区统计信息数组中的位置; //以下将该点的信息加到其所属区信息中去; rginfoarr[rgid].ptcount ++; rginfoarr[rgid].l += luvData[pos].l;////////////////////////////////// rginfoarr[rgid].u += luvData[pos].u; rginfoarr[rgid].v += luvData[pos].v; } } //求出各个区的LUV均值; for (i=0; i<=rgnumber; i++) { rginfoarr[i].l = (FLOAT) ( rginfoarr[i].l / rginfoarr[i].ptcount ); rginfoarr[i].u = (FLOAT) ( rginfoarr[i].u / rginfoarr[i].ptcount ); rginfoarr[i].v = (FLOAT) ( rginfoarr[i].v / rginfoarr[i].ptcount ); } //根据各区LUV均值(rginfoarr)和各区之间邻接关系(用flag计算)进行区域融合 INT* mergearr = new INT[rgnumber+1]; memset( mergearr, -1, sizeof(INT)*(rgnumber+1) ); INT mergednum = 0; LONG temptime4 = GetTickCount(); MergeRgs(rginfoarr, rgnumber, flag, imageWidth, imageHeight, mergearr, mergednum); LONG temptime5 = GetTickCount(); LONG kk2 = temptime5 - temptime4;//合并用时; //确定合并后各像素点所属区域; for (y=0; y<(imageHeight); y++) { xstart = y*imageWidth; for (INT x=0; x<(imageWidth); x++) { INT pos = xstart + x; INT rgid = flag[pos];//该点所属区域; flag[pos] = FindMergedRgn(rgid, mergearr); } } delete [] mergearr; mergearr = NULL; //用各区均值代替原像素点值; FLOAT* luvbuff = NULL; luvbuff = new FLOAT[imageWidth*imageHeight*3]; for (y=1; y<(imageHeight-1); y++) { xstart = y*imageWidth; for (INT x=1; x<(imageWidth-1); x++) { INT pos = xstart + x; INT rgid = flag[pos];//该点所属区域; luvData[pos].l = rginfoarr[rgid].l;//luvData用于全局保存LUV值; luvbuff[pos*3] = rginfoarr[rgid].l;//luvbuff用于传递参数给LuvToRgb(); luvData[pos].u = rginfoarr[rgid].u; luvbuff[pos*3+1] = rginfoarr[rgid].u; luvData[pos].v = rginfoarr[rgid].v; luvbuff[pos*3+2] = rginfoarr[rgid].v; } } LuvToRgb(luvbuff, imageWidth, imageHeight, imageData); delete [] luvbuff; luvbuff = NULL; delete [] rginfoarr; rginfoarr = NULL;//大小等于区域总数 //以下根据标识数组查找边界点(不管四边点以减小复杂度); for (y=1; y<(imageHeight-1); y++) { xstart = y*imageWidth; for (INT x=1; x<(imageWidth-1); x++) { INT pos = xstart + x; INT imagepos = pos * 3; INT left = pos - 1; INT up = pos - imageWidth; INT right = pos +1; INT down = pos + imageWidth; if ( ( flag[right]!=flag[pos] ) || ( flag[down]!=flag[pos] ) ) //if ( flag[pos]==0 ) { imageData[imagepos] = 255; imageData[imagepos+1] =255 ; imageData[imagepos+2] = 255; } } } delete [] gradientadd; gradientadd = NULL;//大小256 delete [] gradientfre; gradientfre = NULL;//大小256 delete [] deltasita; deltasita = NULL;//大小imagelen delete [] deltar; deltar = NULL;//大小imagelen delete [] graposarr; graposarr = NULL;//大小imagelen delete [] flag; flag = NULL;//大小imagelen RefreshImageObject(); CMainFrame* pFrame = (CMainFrame*) AfxGetApp()->GetMainWnd(); EndWaitCursor(); pFrame->pImageView->Invalidate(FALSE); } void CWaterShedDoc::GetGradient(BYTE *image, INT width, INT height, FLOAT *deltar, FLOAT *deltasita) { //下面计算各像素在水平和垂直方向上的梯度,边缘点梯度计为0; INT* deltaxarr; INT* deltayarr; INT grawidth = width; INT graheight = height; INT deltacount = grawidth * graheight; deltaxarr = new INT[deltacount]; deltayarr = new INT[deltacount]; //暂不计算边缘点; for (INT y=1; y<graheight-1; y++) { for (INT x=1; x<grawidth-1; x++) { INT inarrpos = ((y)*width + (x))*3 + 1;//在输入块中的位置; INT deltaarrpos = y*grawidth + x;//在梯度数组中的位置; //卷积计算; deltaxarr[deltaarrpos] = (INT) ( ( image[((y-1)*width + (x+1))*3 + 1] //右上 + image[((y)*width + (x+1))*3 + 1] //右 + image[((y+1)*width + (x+1))*3 + 1] //右下 - image[((y-1)*width + (x-1))*3 + 1] //左上 - image[((y)*width + (x-1))*3 + 1] //左 - image[((y+1)*width + (x-1))*3 + 1] ) / 3 );//左下 deltayarr[deltaarrpos] = (INT) ( ( image[((y-1)*width + (x+1))*3 + 1] //右上 + image[((y-1)*width + (x))*3 + 1] //上 + image[((y-1)*width + (x-1))*3 + 1] //左上 - image[((y+1)*width + (x-1))*3 + 1] //左下 - image[((y+1)*width + (x))*3 + 1] //下 - image[((y+1)*width + (x+1))*3 + 1]) / 3 );//右下 } } //边缘赋为其内侧点的值; for (y=0; y<graheight; y++) { INT x1 = 0; INT pos1 = y*grawidth + x1; deltaxarr[pos1] = deltaxarr[pos1+1]; deltayarr[pos1] = deltayarr[pos1+1]; INT x2 = grawidth-1; INT pos2 = y*grawidth + x2; deltaxarr[pos2] = deltaxarr[pos2-1]; deltayarr[pos2] = deltayarr[pos2-1]; } for (INT x=0; x<grawidth; x++) { INT y1 = 0; INT pos1 = x; INT inner = x + grawidth;//下一行; deltaxarr[pos1] = deltaxarr[inner]; deltayarr[pos1] = deltayarr[inner]; INT y2 = graheight-1; INT pos2 = y2*grawidth + x; inner = pos2 - grawidth;//上一行; deltaxarr[pos2] = deltaxarr[inner]; deltayarr[pos2] = deltayarr[inner]; } for (y=0; y<graheight; y++) { for (x=0; x<grawidth; x++) { INT temppos = y*grawidth + x; if ( (deltaxarr[temppos])==0 ) { if (deltayarr[temppos]!=0) { deltasita[temppos] = 0;//水平方向; deltar[temppos] = (FLOAT) abs(deltayarr[temppos]); }else { deltasita[temppos] = -1;//无确定方向; deltar[temppos] = (FLOAT) abs(deltayarr[temppos]); } continue; } deltasita[temppos] = (FLOAT) ( atan( (FLOAT)deltayarr[temppos] / (FLOAT)deltaxarr[temppos] ) + PI/2. ); deltar[temppos] = (FLOAT) sqrt((DOUBLE) ( deltayarr[temppos]*deltayarr[temppos] + deltaxarr[temppos]*deltaxarr[temppos] ) ); } } delete [] deltaxarr; deltaxarr = NULL; //删除水平和垂直梯度数组; delete [] deltayarr; deltayarr = NULL; } void CWaterShedDoc::RefreshImageObject() { if(NULL!=myImageObject) { delete myImageObject; myImageObject = NULL; } myImageObject = new CImageObject; myImageObject->CreateDIBFromBits(imageWidth, imageHeight, imageData); } void CWaterShedDoc::FloodVincent(MyImageGraPt *imiarr, INT *graddarr, INT minh, INT maxh, INT *flagarr, INT &outrgnumber) { const INT INIT = -2; const INT MASK = -1; const INT WATERSHED = 0; INT h = 0; INT imagelen = imageWidth * imageHeight; for (INT i=0; i<imagelen; i++) { flagarr[i] = INIT; } //memset(flagarr, INIT, sizeof(INT)*imagelen); INT* imd = new INT[imagelen];//距离数组,直接存取; for (i=0; i<imagelen; i++) { imd[i] = 0; } //memset(imd, 0, sizeof(INT)*imagelen); std::queue <int> myqueue; INT curlabel = 0;//各盆地标记; for (h=minh; h<=maxh; h++) { INT stpos = graddarr[h]; INT edpos = graddarr[h+1]; for (INT ini=stpos; ini<edpos; ini++) { INT x = imiarr[ini].x; INT y = imiarr[ini].y; INT ipos = y*imageWidth + x; flagarr[ipos] = MASK; //以下检查该点邻域是否已标记属于某区或分水岭,若是,则将该点加入fifo; INT left = ipos - 1; if (x-1>=0) { if (flagarr[left]>=0) { imd[ipos] = 1; myqueue.push(ipos);//点位置压入fifo; continue; } } INT right = ipos + 1; if (x+1<imageWidth) { if (flagarr[right]>=0) { imd[ipos] = 1; myqueue.push(ipos);//点位置压入fifo; continue; } } INT up = ipos - imageWidth; if (y-1>=0) { if (flagarr[up]>=0) { imd[ipos] = 1; myqueue.push(ipos);//点位置压入fifo; continue; } } INT down = ipos + imageWidth; if (y+1<imageHeight) { if (flagarr[down]>=0) { imd[ipos] = 1; myqueue.push(ipos);//点位置压入fifo; continue; } } } //以下根据先进先出队列扩展现有盆地; INT curdist = 1; myqueue.push(-99);//特殊标记; while (TRUE) { INT p = myqueue.front(); myqueue.pop(); if (p == -99) { if ( myqueue.empty() ) { break; }else { myqueue.push(-99); curdist = curdist + 1; p = myqueue.front(); myqueue.pop(); } } //以下找p的邻域; INT y = (INT) (p/imageWidth); INT x = p - y*imageWidth; INT left = p - 1; if (x-1>=0) { if ( ( (imd[left]<curdist) && flagarr[left]>0) || (flagarr[left]==0) ) { if ( flagarr[left]>0 ) { //ppei属于某区域(不是分水岭); if ( (flagarr[p]==MASK) || (flagarr[p]==WATERSHED) ) { //将其设为邻点所属区域; flagarr[p] = flagarr[left]; }else if (flagarr[p]!=flagarr[left]) { //原来赋的区与现在赋的区不同,设为分水岭; //flagarr[p] = WATERSHED; } }else if (flagarr[p]==MASK)//ppei为分岭; { flagarr[p] = WATERSHED; } }else if ( (flagarr[left]==MASK) && (imd[left]==0) ) //ppei中已MASK的点,但尚未标记(即不属某区也不是分水岭); { imd[left] = curdist + 1; myqueue.push(left); } } INT right = p + 1; if (x+1<imageWidth) { if ( ( (imd[right]<curdist) && flagarr[right]>0) || (flagarr[right]==0) ) { if ( flagarr[right]>0 ) { //ppei属于某区域(不是分水岭); if ( (flagarr[p]==MASK) || (flagarr[p]==WATERSHED) ) { //将其设为邻点所属区域; flagarr[p] = flagarr[right]; }else if (flagarr[p]!=flagarr[right]) { //原来赋的区与现在赋的区不同,设为分水岭; //flagarr[p] = WATERSHED; } }else if (flagarr[p]==MASK)//ppei为分岭; { flagarr[p] = WATERSHED; } }else if ( (flagarr[right]==MASK) && (imd[right]==0) ) //ppei中已MASK的点,但尚未标记(即不属某区也不是分水岭); { imd[right] = curdist + 1; myqueue.push(right); } } INT up = p - imageWidth; if (y-1>=0) { if ( ( (imd[up]<curdist) && flagarr[up]>0) || (flagarr[up]==0) ) { if ( flagarr[up]>0 ) { //ppei属于某区域(不是分水岭); if ( (flagarr[p]==MASK) || (flagarr[p]==WATERSHED) ) { //将其设为邻点所属区域; flagarr[p] = flagarr[up]; }else if (flagarr[p]!=flagarr[up]) { //原来赋的区与现在赋的区不同,设为分水岭; //flagarr[p] = WATERSHED; } }else if (flagarr[p]==MASK)//ppei为分岭; { flagarr[p] = WATERSHED; } }else if ( (flagarr[up]==MASK) && (imd[up]==0) ) //ppei中已MASK的点,但尚未标记(即不属某区也不是分水岭); { imd[up] = curdist + 1; myqueue.push(up); } } INT down = p + imageWidth; if (y+1<imageHeight) { if ( ( (imd[down]<curdist) && flagarr[down]>0) || (flagarr[down]==0) ) { if ( flagarr[down]>0 ) { //ppei属于某区域(不是分水岭); if ( (flagarr[p]==MASK) || (flagarr[p]==WATERSHED) ) { //将其设为邻点所属区域; flagarr[p] = flagarr[down]; }else if (flagarr[p]!=flagarr[down]) { //原来赋的区与现在赋的区不同,设为分水岭; //flagarr[p] = WATERSHED; } }else if (flagarr[p]==MASK)//ppei为分岭; { flagarr[p] = WATERSHED; } }else if ( (flagarr[down]==MASK) && (imd[down]==0) ) //ppei中已MASK的点,但尚未标记(既不属某区也不是分水岭); { imd[down] = curdist + 1; myqueue.push(down); } } }//以上现有盆地的扩展; //以下处理新发现的盆地; for (ini=stpos; ini<edpos; ini++) { INT x = imiarr[ini].x; INT y = imiarr[ini].y; INT ipos = y*imageWidth + x; imd[ipos] = 0;//重置所有距离 if (flagarr[ipos]==MASK) { //经过前述扩展后该点仍为MASK,则该点必为新盆地的一个起始点; curlabel = curlabel + 1; myqueue.push(ipos); flagarr[ipos] = curlabel; while ( myqueue.empty()==FALSE ) { INT ppei = myqueue.front(); myqueue.pop(); INT ppeiy = (INT) (ppei/imageWidth); INT ppeix = ppei - ppeiy*imageWidth; INT ppeileft = ppei - 1; if ( (ppeix-1>=0) && (flagarr[ppeileft]==MASK) ) { myqueue.push(ppeileft);//点位置压入fifo; flagarr[ppeileft] = curlabel; } INT ppeiright = ppei + 1; if ( (ppeix+1<imageWidth) && (flagarr[ppeiright]==MASK) ) { myqueue.push(ppeiright);//点位置压入fifo; flagarr[ppeiright] = curlabel; } INT ppeiup = ppei - imageWidth; if ( (ppeiy-1>=0) && (flagarr[ppeiup]==MASK) ) { myqueue.push(ppeiup);//点位置压入fifo; flagarr[ppeiup] = curlabel; } INT ppeidown = ppei + imageWidth; if ( (ppeiy+1<imageHeight) && (flagarr[ppeidown]==MASK) ) { myqueue.push(ppeidown);//点位置压入fifo; flagarr[ppeidown] = curlabel; } } } }//以上处理新发现的盆地; } outrgnumber = curlabel; delete [] imd; imd = NULL; } BOOL CWaterShedDoc::OnSaveDocument(LPCTSTR lpszPathName) { // TODO: Add your specialized code here and/or call the base class //return CDocument::OnSaveDocument(lpszPathName); if( myImageObject != NULL ) { // CString strPathName = lpszPathName; myImageObject->SaveToFile( lpszPathName ); SetModifiedFlag(FALSE); } return TRUE; } ////////////////////////////////////////////////////////////////////////// //1、建立各区的邻域数组; //2、依次扫描各区域,寻找极小区域; //3、对每个极小区(A),在相邻区中找到最相似者; //4、与相似区(B)合并(各种信息刷新),在极小区(A)的邻域中 // 删除相似区(B),在邻域数组中删除相似区(B)对应的项,将 // 相似区(B)的相邻区s加到极小区(A)的邻域中去; //5、记录合并信息,设一数组专门存放该信息,该数组的第A个元素值设为B; //6、判断是否仍为极小区,若是则返回3; //7、是否所有区域都已处理完毕,若非则返回2; // // 由于各区的相邻区不会太多,因此采用邻接数组作为存储结构; ////////////////////////////////////////////////////////////////////////// void CWaterShedDoc::MergeRgs(MyRgnInfo *rginfoarr, INT rgnumber, INT *flag, INT width, INT height, INT *outmerge, INT &rgnum) { CString* neiarr = new CString[rgnumber+1];//第一个不用; INT* mergearr = outmerge;//记录合并情况数组; //建立邻域数组; for (INT y=0; y<height; y++) { INT lstart = y * width; for (INT x=0; x<width; x++) { INT pos = lstart + x; INT left=-1, right=-1, up=-1, down=-1; myMath.GetNeiInt(x, y, pos, width, height , left, right, up, down);//找pos的四个邻域; //确定并刷新邻域区信息; INT curid = flag[pos]; AddNeiOfCur(curid, left, right , up, down, flag, neiarr); } }//建立邻域数组; //区域信息数组中的有效信息从1开始,第i个位置存放第i个区域的信息; for (INT rgi=1; rgi<=rgnumber; rgi++) { //扫描所有区域,找极小区; LONG allpoints = imageWidth * imageHeight; LONG nmin = (LONG) (allpoints / 400); INT curid = rgi; //rginfoarr[rgi].isflag初始为FALSE,在被合并到其它区后改为TRUE; while ( ( (rginfoarr[rgi].ptcount)<nmin ) && !rginfoarr[rgi].isflag ) { //该区为极小区,遍历所有相邻区,找最接近者; CString neistr = neiarr[curid]; INT nearid = FindNearestNei(curid, neistr, rginfoarr, mergearr); //合并curid与nearid; MergeTwoRgn(curid, nearid, neiarr , rginfoarr, mergearr); } } //以下再合并相似区域,(无论大小),如果不需要,直接将整个循环注释掉就行了; INT countjjj = 0; //区域信息数组中的有效信息从1开始,第i个位置存放第i个区域的信息; for (INT ii=1; ii<=rgnumber; ii++) { if (!rginfoarr[ii].isflag) { INT curid = ii; MergeNearest(curid, rginfoarr, neiarr, mergearr); } } INT counttemp = 0; for (INT i=0; i<rgnumber; i++) { if (!rginfoarr[i].isflag) { counttemp ++; } } rgnum = counttemp; delete [] neiarr; neiarr = NULL; } BOOL CWaterShedDoc::LuvToRgb(FLOAT *luvData, INT width, INT height, BYTE *rgbData) { if (NULL == rgbData) { CString tempstr; tempstr.Format("传入内存未分配,在MyColorSpace::RGBtoHSV"); AfxMessageBox(tempstr,NULL,MB_OK); return FALSE; } int i,j; INT r,g,b; FLOAT l, u, v; unsigned long pos; for(i=0;i<height;i++) { for (j=0;j<width;j++) { pos = (i*width+j) * 3; l = luvData[pos]; u = luvData[pos+1]; v = luvData[pos+2]; Luv2Rgb(l, u, v, r, g, b); rgbData[pos] = b; rgbData[pos+1] = g; rgbData[pos+2] = r; } } return TRUE; } BOOL CWaterShedDoc::Luv2Rgb(FLOAT l, FLOAT u, FLOAT v, INT &r, INT &g, INT &b) { if(l<0.1) { r = g = b =0; } else { float my_x, my_y, my_z; if(l < 8.0) my_y = (FLOAT) ( Yn * l / 903.3 ); else my_y = (FLOAT) ( Yn * pow((l + 16.0) / 116.0, 3) ); float u_prime = u / (13 * l) + Un_prime; float v_prime = v / (13 * l) + Vn_prime; my_x = 9 * u_prime * my_y / (4 * v_prime); my_z = (12 - 3 * u_prime - 20 * v_prime) * my_y / (4 * v_prime); r =int((RGB[0][0]*my_x + RGB[0][1]*my_y + RGB[0][2]*my_z)*255.0); g =int((RGB[1][0]*my_x + RGB[1][1]*my_y + RGB[1][2]*my_z)*255.0); b =int((RGB[2][0]*my_x + RGB[2][1]*my_y + RGB[2][2]*my_z)*255.0); if(r>255) r=255; else if(r<0) r=0; if(g>255) g=255; else if(g<0) g=0; if(b>255) b=255; else if(b<0) b=0; } return TRUE; } //刷新当前点的所有相邻区; void CWaterShedDoc::AddNeiOfCur(INT curid, INT left, INT right, INT up, INT down, INT *flag, CString *neiarr) { INT leftid, rightid, upid, downid; leftid = rightid = upid = downid = curid; if (left>=0) { leftid = flag[left]; if (leftid!=curid) { //邻点属于另一区, 加邻域点信息; AddNeiRgn(curid, leftid, neiarr); } } if (right>0) { rightid = flag[right]; if (rightid!=curid) { //邻点属于另一区, 加邻域点信息; AddNeiRgn(curid, rightid, neiarr); } } if (up>=0) { upid = flag[up]; if (upid!=curid) { //邻点属于另一区, 加邻域点信息; AddNeiRgn(curid, upid, neiarr); } } if (down>0) { downid = flag[down]; if (downid!=curid) { //邻点属于另一区, 加邻域点信息; AddNeiRgn(curid, downid, neiarr); } } } void CWaterShedDoc::AddNeiRgn(INT curid, INT neiid, CString *neiarr) //增加neiid为curid的相邻区 { CString tempneis = neiarr[curid];//当前的相邻区; CString toaddstr; toaddstr.Format("%d ", neiid); INT temppos = tempneis.Find(toaddstr, 0); while (temppos>0 && neiarr[curid].GetAt(temppos-1)!=' ') { temppos = neiarr[curid].Find(toaddstr, temppos+1); } if ( temppos<0 ) { //当前相邻区中没有tempneis,则加入 neiarr[curid] += toaddstr; } } //找到idint最终所合并到的区号; int CWaterShedDoc::FindMergedRgn(INT idint, INT *mergearr) { INT outid = idint; while ( mergearr[outid] > 0 ) { outid = mergearr[outid]; } return outid; } int CWaterShedDoc::FindNearestNei(INT curid, CString neistr, MyRgnInfo *rginfoarr, INT *mergearr) //寻找neistr中与curid最接近的区,返回该区id号; { INT outid = -1; DOUBLE mindis = 999999; FLOAT cl, cu, cv; cl = rginfoarr[curid].l;//当前区的LUV值; cu = rginfoarr[curid].u; cv = rginfoarr[curid].v; CString tempstr = neistr;//用于本函数内部处理; while (tempstr.GetLength()>0) { INT pos = tempstr.Find(" "); ASSERT(pos>=0); CString idstr = tempstr.Left(pos); tempstr.Delete(0, pos+1); INT idint = (INT) strtol(idstr, NULL, 10); //判断该区是否已被合并,若是,则一直找到该区当前的区号; idint = FindMergedRgn(idint, mergearr); if (idint==curid) { continue;//这个邻区已被合并到当前区,跳过; } FLOAT tl, tu, tv; tl = rginfoarr[idint].l;//当前处理的邻区的LUV值; tu = rginfoarr[idint].u; tv = rginfoarr[idint].v; DOUBLE tempdis = pow(tl-cl, 2) + pow(tu-cu, 2) + pow(tv-cv, 2); if (tempdis<mindis) { mindis = tempdis;//最大距离和对应的相邻区ID; outid = idint; } } return outid; } //将nearid合并到curid中去,更新合并后的区信息,并记录该合并; void CWaterShedDoc::MergeTwoRgn(INT curid, INT nearid, CString *neiarr, MyRgnInfo *rginfoarr, INT *mergearr) { //将区信息中nearid对应项的标记设为已被合并; rginfoarr[nearid].isflag = TRUE; //更新合并后的LUV信息; LONG ptincur = rginfoarr[curid].ptcount; LONG ptinnear = rginfoarr[nearid].ptcount; DOUBLE curpercent = (FLOAT)ptincur / (FLOAT)(ptincur+ptinnear); rginfoarr[curid].ptcount = ptincur + ptinnear; rginfoarr[curid].l = (FLOAT) ( curpercent * rginfoarr[curid].l + (1-curpercent) * rginfoarr[nearid].l ); rginfoarr[curid].u = (FLOAT) ( curpercent * rginfoarr[curid].u + (1-curpercent) * rginfoarr[nearid].u ); rginfoarr[curid].v = (FLOAT) ( curpercent * rginfoarr[curid].v + (1-curpercent) * rginfoarr[nearid].v ); //将nearid的邻域加到curid的邻域中去; AddBNeiToANei(curid, nearid, neiarr, mergearr); //记录该合并; mergearr[nearid] = curid; } //将nearid的邻域加到curid的邻域中去; void CWaterShedDoc::AddBNeiToANei(INT curid, INT nearid, CString *neiarr, INT *mergearr) { //先从curid的邻区中把nearid删去; /* CString tempstr; tempstr.Format("%d ", nearid); INT temppos = neiarr[curid].Find(tempstr, 0); while (temppos>0 && neiarr[curid].GetAt(temppos-1)!=' ') { temppos = neiarr[curid].Find(tempstr, temppos+1); } if (temppos>=0) { //否则邻近区为合并过来的区,忽略; neiarr[curid].Delete(temppos, tempstr.GetLength()); } */ //将nearid的邻区依次加到curid的邻区中去; CString neistr = neiarr[nearid]; CString curstr = neiarr[curid]; //一般说来,极小区的邻域应该较少,因此,为着提高合并速度,将 //curstr加到neistr中去,然后将结果赋给neiarr[curid]; while ( curstr.GetLength()>0 ) { INT pos = curstr.Find(" "); ASSERT(pos>=0); CString idstr = curstr.Left(pos); curstr.Delete(0, pos+1); INT idint = (INT) strtol(idstr, NULL, 10); idint = FindMergedRgn(idint, mergearr); idstr += " "; if ( (idint == curid) || (idint == nearid) ) { continue;//本区不与本区相邻; }else { if ( neistr.Find(idstr, 0) >= 0 ) { continue; }else { neistr += idstr;//加到邻区中去; } } } neiarr[curid] = neistr; /* CString toaddneis = neiarr[nearid]; while (toaddneis.GetLength()>0) { INT pos = toaddneis.Find(" "); ASSERT(pos>=0); CString idstr = toaddneis.Left(pos); toaddneis.Delete(0, pos+1); INT idint = (INT) strtol(idstr, NULL, 10); idint = FindMergedRgn(idint, mergearr); idstr += " "; if ( (idint == curid) || (idint == nearid) ) { continue;//本区不与本区相邻; }else { if ( neiarr[curid].Find(idstr, 0) >= 0 ) { continue; }else { neiarr[curid] += idstr;//加到邻区中去; } } } */ } #define NearMeasureBias 200.0//判定区域颜色相似的阈值; void CWaterShedDoc::MergeNearest(INT curid, MyRgnInfo *rginfoarr, CString *neiarr, INT *mergearr) //合并相似区域; { //依次处理各个邻域,若相似,则合并; //CString neistr = neiarr[curid]; FLOAT cl, cu, cv; cl = rginfoarr[curid].l;//当前区的LUV值; cu = rginfoarr[curid].u; cv = rginfoarr[curid].v; BOOL loopmerged = TRUE;//一次循环中是否有合并操作发生,若无,则退出循环; while (loopmerged) { loopmerged = FALSE; CString tempstr = neiarr[curid];//用于本函数内部处理; while (tempstr.GetLength()>0) { INT pos = tempstr.Find(" "); ASSERT(pos>=0); CString idstr = tempstr.Left(pos); tempstr.Delete(0, pos+1); INT idint = (INT) strtol(idstr, NULL, 10); //判断该区是否已被合并,若是,则一直找到该区当前的区号; idint = FindMergedRgn(idint, mergearr); if (idint==curid) { continue;//这个邻区已被合并到当前区,跳过; } FLOAT tl, tu, tv; tl = rginfoarr[idint].l;//当前处理的邻区的LUV值; tu = rginfoarr[idint].u; tv = rginfoarr[idint].v; DOUBLE tempdis = pow(tl-cl, 2) + pow(tu-cu, 2) + pow(tv-cv, 2); if (tempdis<NearMeasureBias) { MergeTwoRgn(curid, idint, neiarr, rginfoarr, mergearr); cl = rginfoarr[curid].l;//当前区的LUV值刷新; cu = rginfoarr[curid].u; cv = rginfoarr[curid].v; loopmerged = TRUE; } } } } //基于表转换,将位图图像数据转换为LUV数据, 修改自D. Comaniciu, P. Meer, //Robust Analysis of Feature Spaces: Color Image Segmentation 的相应代码 BOOL CWaterShedDoc::RgbtoLuvPcm(BYTE *inDatas, int width, int height, MyLUV *luvbuff) { int x, y, z, my_temp; float l_star, u_star, v_star; float u_prime, v_prime; //register int temp_col, temp_index, temp_ind; register int j;//,k; int a00=XYZ[0][0], a01=XYZ[0][1], a02=XYZ[0][2]; int a10=XYZ[1][0], a11=XYZ[1][1], a12=XYZ[1][2]; int a20=XYZ[2][0], a21=XYZ[2][1], a22=XYZ[2][2]; int *A00 = new int[MAXV]; int *A01 = new int[MAXV]; int *A02 = new int[MAXV]; int *A10 = new int[MAXV]; int *A11 = new int[MAXV]; int *A12 = new int[MAXV]; int *A20 = new int[MAXV]; int *A21 = new int[MAXV]; int *A22 = new int[MAXV]; for(j=0; j<MAXV; j++) { A00[j]=a00*j; A01[j]=a01*j; A02[j]=a02*j; A10[j]=a10*j; A11[j]=a11*j; A12[j]=a12*j; A20[j]=a20*j; A21[j]=a21*j; A22[j]=a22*j; } float *my_pow = new float[MAXV]; for(j=0; j<MAXV; j++) my_pow[j]= (FLOAT) ( 116.0 * pow(j/255.0, 0.3333333) - 16 ); for ( j = 0; j < width*height; j++) { INT R = inDatas[j*3+2]; INT G = inDatas[j*3+1]; INT B = inDatas[j*3]; x = A00[R] + A01[G] + A02[B]; y = A10[R] + A11[G] + A12[B]; z = A20[R] + A21[G] + A22[B]; float tval = (FLOAT) ( y / 2550000.0 ); //Yn==1 if ( tval > Lt) l_star = my_pow[(int)(tval*255+0.5)]; else l_star = (FLOAT) ( 903.3 * tval ); my_temp = x + 15 * y + 3 * z; if(my_temp) { u_prime = (float)(x << 2) / (float)(my_temp); v_prime = (float)(9 * y) / (float)(my_temp); } else { u_prime = 4.0; v_prime = (FLOAT) ( 9.0/15.0 ); } tval = 13*l_star; u_star = tval * (u_prime - Un_prime); // Un_prime = 0.1978 v_star = tval * (v_prime - Vn_prime); // Vn_prime = 0.4683 luvbuff[j].l = l_star; luvbuff[j].u = u_star; luvbuff[j].v = v_star; } delete [] my_pow; delete [] A22; delete [] A21; delete [] A20; delete [] A12; delete [] A11; delete [] A10; delete [] A02; delete [] A01; delete [] A00; return TRUE; }