截图:
【检索前】
【检索后】
功能:
单击【查找目录】会随机显示当前目录下的6张图像,如果当前目录下小于6幅,则全部显示。
单击【选择】,会将测试图像显示在【选择】按钮上方。
单击【检索】,会将与当前图像颜色最接近的6幅图像显示在下方。
思路:
将图像的RGB空间映射到HSV空间,并将其H、S、V均划分为12个区间。这样图像得到3*12个属性。
对选取的测试图像和所有的待检索图像均进行上述处理。
计算测试图像与检索图像之间的距离,将得到的距离按照从小到大的顺序排序,将排序靠前的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章,图像检索系统。