截圖:函數
【檢索前】post
【檢索後】
code
功能:orm
單擊【查找文件夾】會隨機顯示當前文件夾下的6張圖像。假設當前文件夾下小於6幅。則全部顯示。排序
單擊【選擇】,會將測試圖像顯示在【選擇】button上方。圖片
單擊【檢索】,會將與當前圖像顏色最接近的6幅圖像顯示在下方。文檔
思路:it
將圖像的RGB空間映射到HSV空間,並將其H、S、V均劃分爲12個區間。這樣圖像獲得3*12個屬性。io
對選取的測試圖像和全部的待檢索圖像均進行上述處理。圖像處理
計算測試圖像與檢索圖像之間的距離。將獲得的距離依照從小到大的順序排序。將排序靠前的6張圖像顯示在檢索框中。
距離的計算可以採用典型的歐氏距離。
步驟:
1.將計算測試圖像的HSV屬性。
2.計算當前文件夾下每一個圖像的HSV屬性,並計算其與測試圖像HSV屬性之間的距離。
3.將獲得的距離進行排序。
4.依照排序結果顯示圖像。
部分代碼:
【查找文件夾】
void CCBIRLSDlg::OnBnClickedButton2() { // TODO: Add your control notification handler code here //使用BROWSEINFO結構,打開通用對話框,獲取用戶選中文件夾的信息 BROWSEINFO browse; ZeroMemory(&browse,sizeof(browse)); browse.hwndOwner = NULL; browse.pszDisplayName = SPath.GetBuffer(MAX_PATH); // browse.lpszTitle=s; //返回選擇文件夾的信息 LPITEMIDLIST lpItem = SHBrowseForFolder(&browse); if(lpItem == NULL) return ; SPath.ReleaseBuffer(); //SHGetPathFromIDList把項目標誌符列表轉換爲文檔系統路徑 if(SHGetPathFromIDList(lpItem,SPath.GetBuffer(MAX_PATH)) == false) return; SPath.ReleaseBuffer(); SPath.Trim(); ////////////////////待處理 int tempi=0; counts=0;//計數器清零 ////////////////////待處理 //AfxMessageBox(SPath); //檢索庫中圖像個數放入counts中,其路徑放入temp[100]中 BOOL flag; CFileFind find; char tempFileFind[200]; //sprintf_s(tempFileFind,"%s\\*.bmp",SPath); sprintf_s(tempFileFind,"%s\\*.bmp",SPath); flag = find.FindFile(tempFileFind); //在當前文件夾下查找BMP文件 LPWSTR myFileName; // path.SetWindowTextA(SPath); //path關聯文本框。 while(flag) { flag = find.FindNextFile(); char foundFileName[200];//暫時存儲查找到的圖像名 // strcpy_s(foundFileName,find.GetFileName().GetBuffer(200));//獲取圖像名 // strcpy(foundFileName,find.GetFileName().GetBuffer(200));//獲取圖像名 //strcpy_s //myFileName=find.GetFileName().GetBuffer(200); strcpy_s(foundFileName,find.GetFileName().GetBuffer(200)); //strcpy_s(foundFileName,find.GetFileName().GetBuffer(200)); //AfxMessageBox(foundFileName); //path.SetWindowTextW(foundFileName); //strcpy(foundFileName,&myFileName); if(!find.IsDots()) //過濾缺省文件夾 { char tempFileName[200]; sprintf_s(tempFileName,"%s\\%s",SPath,foundFileName); //CString strfilepath1; // strfilepath1.Format("%s",tempFileName);//獲取圖像完整路徑 ImageSource[counts] = new CString(tempFileName);//保存圖像完整路徑 counts++; //AfxMessageBox(ImageSource[counts],MB_ICONINFORMATION|MB_OK); //AfxMessageBox(ImageSource[counts]); //databaseImage.Load(ImageSource[counts]); // AfxMessageBox(*ImageSource[counts]); //path.SetWindowTextA(ImageSource[counts]); } } find.Close(); //CString temps; // temps.Format("該文件夾下共同擁有%d幅圖像!",counts); // AfxMessageBox(temps,MB_ICONINFORMATION|MB_OK); //AfxMessageBox("您選擇的文件夾爲:"+SPath,MB_ICONINFORMATION|MB_OK); //strcat("當前路徑爲:",SPath); //隨機顯示其如下的圖像,假設小於六幅。全部顯示;大於6幅,隨機顯示六幅 //CString result; /* pic[1]="Result1"; pic[2]="result2"; pic[3]="result3"; pic[4]= "result4"; pic[5]= "result5"; pic[6]="result6";*/ //將當前文件夾下的圖片顯示,顯示獲取的前6幅圖像,假設小於6幅,則僅顯示存在的圖像 if(counts<6) showCounts=counts; else showCounts=6; for(int i=0;i<counts;i++) { IS[i]=*ImageSource[i]; // AfxMessageBox(*ImageSource[i]); } id=1006; //這裏result2的id是1006,依次類推。result6的是1011 for(int i=0;i<showCounts;i++) { if(!databaseImage.IsNull())//推斷圖象是否爲空,假設不爲空則先釋放掉 databaseImage.Destroy(); // databaseImage.load(IS[i]); databaseImage.Load(IS[i]); CRect rect; CWnd *pWnd = GetDlgItem(id++); CDC *pDC = pWnd->GetDC(); //第1個控件 pWnd->GetClientRect(&rect); //取得客戶區尺寸 pDC->SetStretchBltMode(STRETCH_HALFTONE); //保持圖片不失真 databaseImage.Draw( pDC->m_hDC,rect); //已控件尺寸大小來畫圖 ReleaseDC( pDC ); } // path.SetWindowTextW(SPath); //path關聯文本框。此處在文本框內顯示設置的搜索路徑。
path.SetWindowTextA(SPath); //setWindowTextW爲單字符集下使用的函數 }
void CCBIRLSDlg::OnBnClickedButton1() { // TODO: Add your control notification handler code here CFileDialog fileDlg(TRUE,NULL,NULL,OFN_ALLOWMULTISELECT,_T("Picture Files (*.bmp *.jpg)|*bmp;;*jpg||"),AfxGetMainWnd()); CString pathName; if(fileDlg.DoModal () == IDOK) { POSITION mPos = fileDlg.GetStartPosition(); if(mPos!=NULL) { pathName = (LPCTSTR)fileDlg.GetPathName(); if(!myImage.IsNull())//推斷圖象是否爲空。假設不爲空則先釋放掉 myImage.Destroy(); myImage.Load(pathName); } } CRect rect; CWnd *pWnd = GetDlgItem(IDC_MY_PIC2); CDC *pDC = pWnd->GetDC(); //第1個控件 pWnd->GetClientRect(&rect); //取得客戶區尺寸 pDC->SetStretchBltMode(STRETCH_HALFTONE); //保持圖片不失真 myImage.Draw( pDC->m_hDC,rect); //已控件尺寸大小來畫圖 ReleaseDC( pDC ); //myImage.Destroy(); }
【檢索】
void CCBIRLSDlg::OnBnClickedButton3() { // TODO: Add your control notification handler code here /* if(myImage.IsNull()) { AfxMessageBox(_T("請先選擇要檢索的圖像")); return; } if(SPath.IsEmpty()) { AfxMessageBox(_T("請先選擇要檢索的路徑")); return ; } */ COLORREF color; double h=0,s=0,v=0; long myGraph[3][13]; //用於存儲HSV空間值 double sourceFeature[3][12];//待檢索圖像的顏色特徵 double tempFeature[3][12]; //用於存儲檢索文件夾下文件的特徵 int maxX,maxY; int totalNum; for(int i=0;i<3;i++) for(int j=0;j<13;j++) { myGraph[i][j]=0; } maxX=myImage.GetWidth(); maxY=myImage.GetHeight(); totalNum=maxX*maxY; for (int i=0; i<maxX-1; i++) { for (int j=0; j<maxY-1; j++) { color=myImage.GetPixel(i,j); RGB2HSV(GetRValue(color),GetGValue(color),GetBValue(color),&h,&s,&v); int result_h=(int)(6*h/3.1415926); int result_s=(int)(s*12); int result_v=(int)(v*12); myGraph[0][result_h]++; myGraph[1][result_s]++; myGraph[2][result_v]++; } } for(int i=0;i<3;i++) for(int j=0;j<12;j++) { sourceFeature[i][j]=((float)myGraph[i][j])/((float)totalNum); } //計算每幅圖像與待檢索圖像的距離。for(int i=0;i<counts;i++) distance[i]=0; for(int ch=0;ch<counts;ch++) { for(int i=0;i<3;i++) for(int j=0;j<13;j++) { myGraph[i][j]=0; } if(!databaseImage.IsNull())//推斷圖象是否爲空。假設不爲空則先釋放掉 databaseImage.Destroy(); // databaseImage.load(IS[i]); databaseImage.Load(IS[ch]); //測試。是否顯示了正確的圖像 AfxMessageBox(IS[ch]); maxX=databaseImage.GetWidth(); maxY=databaseImage.GetHeight(); totalNum=maxX*maxY; for (int i=0; i<maxX-1; i++) { for (int j=0; j<maxY-1; j++) { color=databaseImage.GetPixel(i,j); RGB2HSV(GetRValue(color),GetGValue(color),GetBValue(color),&h,&s,&v); int result_h=(int)(6*h/3.1415926); int result_s=(int)(s*12); int result_v=(int)(v*12); myGraph[0][result_h]++; myGraph[1][result_s]++; myGraph[2][result_v]++; //此處未對等於12的狀況進行處理,機率很是小,可是仍舊可能報錯。需要注意。 } } double distanceTemp=0; //此處。曾被定義爲int類型。錯錯!
。! for(int i=0;i<3;i++) { for(int j=0;j<12;j++) { tempFeature[i][j]=((float)myGraph[i][j])/((float)totalNum); distanceTemp+=(tempFeature[i][j]-sourceFeature[i][j])* (tempFeature[i][j]-sourceFeature[i][j]); } distance[ch]+=sqrt((double)distanceTemp); distanceTemp=0; } //開始對圖像進行置亂,而後顯示。
///////////////////測試位置 /* CString str; //double w=0.33; str.Format("%lf",distance[ch]); AfxMessageBox(str); */ ///////////////////測試位置 } //排序,讓距離較小的圖像顯示在較前的位置上。 //ImageSourceResult=ImageSource; for(int i=0;i<counts;i++) { ImageSourceResult[i]=*ImageSource[i]; // AfxMessageBox(*ImageSource[i]); } double tempDis; CString tempPic; ///////////測試 /* for(int i=0;i<counts-1;i++) if(distance[i]=distance[i+1]) { AfxMessageBox("game error"); } if(distance[0]==0) AfxMessageBox("game error"); // AfxMessageBox(distance[0]); CString str ; for(int i=0;i<counts;i++) { str.Format("%d",distance[i]); AfxMessageBox(str); }*/ ///////////測試 for(int i=0;i<counts;i++) { for(int j=i+1;j<counts;j++) { if(distance[i]>distance[j]) { //AfxMessageBox("game error"); tempPic=ImageSourceResult[i]; tempDis=distance[i]; ImageSourceResult[i]=ImageSourceResult[j]; distance[i]=distance[j]; ImageSourceResult[j]=tempPic; distance[j]=tempDis; }}} id=1006; // 設置顯示的picture control控件起始ID號 for(int i=0;i<showCounts;i++) { if(!databaseImage.IsNull())//推斷圖象是否爲空,假設不爲空則先釋放掉 databaseImage.Destroy(); // databaseImage.load(IS[i]); databaseImage.Load(ImageSourceResult[i]); CRect rect; CWnd *pWnd = GetDlgItem(id++); CDC *pDC = pWnd->GetDC(); //第1個控件 pWnd->GetClientRect(&rect); //取得客戶區尺寸 pDC->SetStretchBltMode(STRETCH_HALFTONE); //保持圖片不失真 databaseImage.Draw( pDC->m_hDC,rect); //已控件尺寸大小來畫圖 ReleaseDC( pDC ); } AfxMessageBox("檢索完畢!"); }
CImage CCBIRLSDlg::RGB2HSV(void) { return CImage(); } CImage CCBIRLSDlg::RGB2HSV(CImage * sourceImage) { return CImage(); } void CCBIRLSDlg::RGB2HSV(int r , int g , int b , double *h, double *s, double *v) { *h=acos((r-g+r-b)/(2.0*sqrtf((float)(r-g)*(r-g)+(float)(r-b)*(g-b)))); if(b>g) *h=2*3.1415926-*h; *s=(MAX(r,g,b)-MIN(r,g,b))/(float)MAX(r,g,b); *v=MAX(r,g,b)/255.0; } int CCBIRLSDlg::MAX(int a, int b, int c) { int m; if(a>b) m=a; else m=b; if(m<c) m=c; return m; } int CCBIRLSDlg::MIN(int a, int b, int c) { int m; if(a<b) m=a; else m=b; if(m>c) m=c; return m; } void CCBIRLSDlg::OnBnClickedButton4() { // TODO: Add your control notification handler code here CDialog::OnCancel(); }
實現環境:
VS2010
參考資料:
Visual C++數字圖像處理典型案例具體解釋。第8章,圖像檢索系統。