二. 具体程序实现
a) 基于子块颜色直方图方法的程序实现:
将图片分成4×4格局,按从左到右、从上到下的顺序,分别计算各子块的颜色直方图,因此需要设定一个三维数组,前两维为子块的坐标,最后一维为颜色级,但现在采样得到的象素点的颜色值是RGB形式的,因此,需要将RGB形式转换为可以用比较合理的有限数表示的颜色级,而人眼对亮度是最为敏感的,因此可以将RGB转换为亮度值Y,公式为:
Y=R×0.299+G×0.587+B×0.114
这样就确定的一个256级的颜色级别,而统计颜色直方图的三维数组就可以定义为:int Color[4][4][256],当采样到某一颜色级时候,将相应的位置加一即可。
根据以上的子块间的相似公式:
,知道某一颜色级对应的数有可能是分母,当两个颜色级的数都为0的时候,显然是不能统计的,因此需要一个数组记录实际统计过的颜色级数,也需要一个数组记录4×4子块的两幅图像的各子块的相似度。
对于用户选定的块其实是代表查询对象的,因此应该加大权重,相对来说就是减小其他块的权重,然后可以将乘过对应权重的块的相似度相加,得到最终的相似度,然后将所有目标图像与用户输入的图像的相似度从大到小排序,选出值最大的几张作为最后的查询结果显示出来返回。
以上是具体实现设想,程序实现如下:
//基于颜色直方图的方法 pDC->TextOut(10,168,"检索结果:"); CBmpProc *pDestBmp; CString comp_pic_path; double fsim[15]; file://15张待比较的目标图片与用户输入图片的相似度存放的数组 int psim[15]; file://与fsim想对应的图片编号数组,以便显示 for(int comp_pic=1;comp_pic<=15;comp_pic++){ comp_pic_path.Format("image%d.bmp",comp_pic); bmp.LoadFromFile(comp_pic_path); // 从库中读入位图 pDestBmp = (CBmpProc*)new(CBmpProc); // 用new分配类目标 pDestBmp->LoadFromObject(bmp, &CRect(0,0,128,128)); // 从bmp中的指定区域读入图像,以便图片匹配的进行 pDestBmp->CalculateColor(*pDC); file://计算目标图片的颜色直方图 int x1,x2,y1,y2,x3,x4,y3,y4; x1=obj_set.m_x1;x2=obj_set.m_x2;x3=obj_set.m_x3;x4=obj_set.m_x4; y1=obj_set.m_y1;y2=obj_set.m_y2;y3=obj_set.m_y3;y4=obj_set.m_y4; file://用户输入的对象所在子块(既用户选定的4个子块)的坐标 double sim[4][4]; file://子块之间的相似度数组 int ccount[4][4]; file://有过统计的颜色数目记录数组 for(int i=0;i<4;i++) for(int j=0;j<4;j++){ sim[i][j]=0; ccount[i][j]=0; } file://以下两个for按公式计算两幅图像的各对应子块之间的相似度 for(i=0;i<4;i++) for(int j=0;j<4;j++) for(int k=0;k<256;k++){ if((pDestBmp->Color[i][j][k]>=pBmp->Color[i][j][k])&&pDestBmp->Color[i][j][k]!=0){ sim[i][j]+=(1-((fabs(pDestBmp->Color[i][j][k]-pBmp->Color[i][j][k]))/(pDestBmp->Color[i][j][k]))); ccount[i][j]++; } if((pDestBmp->Color[i][j][k]
Color[i][j][k])&&pBmp->Color[i][j][k]!=0){ sim[i][j]+=(1-((fabs(pDestBmp->Colori][j][k]-pBmp->Color[i][j][k]))/(pBmp->Color[i][j][k]))); ccount[i][j]++; } } for(i=0;i<4;i++) for(int j=0;j<4;j++){ sim[i][j]=sim[i][j]/ccount[i][j]; } file://计算两图像最终的相似度结果 double final_sim=0; for(i=0;i<4;i++) for(int j=0;j<4;j++){ file://对用户指定的块设置权重为1 if((i==x1&&j==y1)||(i==x2&&j==y2)||(i==x3&&j==y3)||(i==x4&&j==y4)) final_sim+=sim[i][j]; else file://其他块降低权重为0.7,提高对对象匹配的精确度 final_sim+=(sim[i][j]*0.7); } file://将15幅被比较图像与用户输入源图像的最后计算出来的相似度结果记录在数组中 fsim[comp_pic-1]=final_sim; delete (CBmpProc*)pDestBmp; } int count=15;double tempf;int tempp; for(int l=0;l<15;l++){ psim[l]=l+1; file://设定编号数组 } file://将15个相似度从大到小排列,并且改变次序的时候编号数组和跟着改变 for(int i=count;i>0;i--){ for(int j=0;jif(fsim[j]tempf=fsim[j]; tempp=psim[j]; fsim[j]=fsim[j+1]; psim[j]=psim[j+1]; fsim[j+1]=tempf; psim[j+1]=tempp; } } int disp=0; int space=-128; file://将相似度最大的的两张图片显示出来 for(int disp_pic=1;disp_pic<=2;disp_pic++){ comp_pic_path.Format("image%d.bmp",psim[disp_pic]); bmp.LoadFromFile(comp_pic_path); // 从库中读入位图 pDestBmp = (CBmpProc*)new(CBmpProc); // 用new分配类目标 pDestBmp->LoadFromObject(bmp, &CRect(0,0,128,128)); // 从bmp中的指定区域读入图像 disp++; space+=128; pDC->Rectangle(10+space-1,190-1,138+space+1,318+1); pDestBmp->Draw(*pDC, &CRect(10+space,190,138+space,318)); // 将pBmp中的图像绘入DC的指定区域 space+=6; } delete (CBmpProc*)pBmp; // 删除类目标,delete会自动调用类的析构函数。 AfxMessageBox("检索完成"); } |