基于颜色的图像检索学习系统

截图:

【检索前】


【检索后】


功能:

单击【查找目录】会随机显示当前目录下的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章,图像检索系统。


你可能感兴趣的:(基于颜色的图像检索学习系统)