www.pudn.com > WaterShed.rar > WaterShedDoc.cpp
// WaterShedDoc.cpp : implementation of the CWaterShedDoc class // #include "stdafx.h" #include "WaterShed.h" #include "WaterShedDoc.h" #includeusing 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 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 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 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 myqueue; INT curlabel = 0;//各盆地标记; for (h=minh; h<=maxh; h++) { INT stpos = graddarr[h]; INT edpos = graddarr[h+1]; for (INT ini=stpos; ini =0) { if (flagarr[left]>=0) { imd[ipos] = 1; myqueue.push(ipos);//点位置压入fifo; continue; } } INT right = ipos + 1; if (x+1 =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 =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] 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 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] 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 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 =0) && (flagarr[ppeileft]==MASK) ) { myqueue.push(ppeileft);//点位置压入fifo; flagarr[ppeileft] = curlabel; } INT ppeiright = ppei + 1; if ( (ppeix+1 =0) && (flagarr[ppeiup]==MASK) ) { myqueue.push(ppeiup);//点位置压入fifo; flagarr[ppeiup] = curlabel; } INT ppeidown = ppei + imageWidth; if ( (ppeiy+1 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 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 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 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; }