基于内容的图像检索(CBIR)
所谓基于内容图像的检索是指由图像分析软件对输入的图像先进行图像分析,根据图像中物体或区域的颜色(color)、形状(shape)或纹理(texture)等特征以及这些特征的组合,自动抽取特征,在将输入图像存入图像库的同时将其相应的特征向量也存入与图像库相连的特征库。在进行检索图像时,对每一幅给定的查询图,进行图像分析,并提取图像特征向量。将该图像的特征向量和特征库中的特征向量进行匹配,根据匹配的结果到图像库中搜索就可以提取出所需要的检索图。这是一种基于图像固有属性的机械匹配,特别适用于检索目标明确的查询要求(例如对商标的检索),产生的结果也比较准确。目前这种较成熟的检索技术主要应用于图像数据库的检索。在基于Web的图像搜索引擎中应用这种检索技术虽还具有一定的困难,但已有部分图像搜索引擎进行了尝试,如、yahoo, WebSEEK就提供了基于图像的形状或颜色直方图的粗陋的可视检索功能。
基于内容的图像检索是一个逐步求精的过程,大致可以经过以下几个步骤:
(1).特征提取
对图像数据进行自动或半自动的特征提取,提取用户感兴趣的、适合检索要求的特征。特征提取可以是全局性的,如整幅图像,也可能是针对某个目标,如图像中的子区域等。
(2).图像匹配
在选取了特征之后,需要选择或寻找适当的判别准则,从而判断出待识别的图像的特征与数据库中的哪些图像的特征最接近。常用的度量准则是距离度量法。
(3).结果输出,将满足一定相似性条件的一组候选结果按相似度大小排列后返回给用户。
(4).特征调整,对系统返回的结果可通过浏览来挑选,直至找到满意的结果,或从候选结果中选择一个示例,经过特征调整,形成一个新的查询。
图像特征的提取的方法
图像特征提取的好坏,将直接影响着图像检索系统的性能,特征提取是基于内容的图像检索的基础。特征的提取可以分为手工提取、半自动提取和自动提取。这在很大程度上依赖于图像处理技术的发展。
从图像中提取出来的图像特征,主要分为三个层次:低层次、中层次和高层次。低层次的图像特征是形状、纹理、颜色、轮廓等图像某一方面的特征。高层次的图像特征是在图像中层次特征基础上的再一次抽象,它赋予图像一定的语义信息,是图像所包含内容的一种抽象概括,也是基于内容的图像检索所要达到的最终目标。本文主要是针对颜色特征的提取进行研究。
基于颜色特征的图像检索
在图像的形状、颜色、纹理等特征中,颜色特征是最显著、最可靠、最稳定的视觉特征,是人识别图像的主要感知特征。相对于几何特征而言,颜色对图像中子对象的大小和方向的变化都不敏感,具有相当强的鲁棒性。同时,在许多情况下,颜色又是描述一幅图像最简便而有效的特征。人们对于一幅图像的印象,往往从图像中颜色的空间分布开始。所有这些都促使颜色成为基于内容的图像检索所采取的主要手段之一。
对于基于颜色特征的图像检索,科学工作者们提出了多种方案。譬如颜色直方图、主色调、颜色矩(Color Moments),颜色集(Color sets)、聚类、扫描线投影等检索算法,颜色直方图是目前较常使用的检索方法。
特征提取与图像子块的划分
特征提取是图像分析和识别的基础。特征提取的方法是决定图像检索系统效率的关键。一般情况下,图像的目标形状可以通过图像分割获得。但是,图像分割是图像分析中公开的难题,尤其对于场景复杂的图像,通过分割直接提取有意义的形状特征几乎是不可能的。为了避免图像分割的困难,文中采用几何划分的方法对图像进行局部特征提取,并用特征组合描述整幅图像。本文将图像划分成大小相等的栅格状区域,提取每块的颜色直方图作为特征矢量。用具有视觉一致性的HSV 颜色空间模型分析图像颜色信息。为了减少计算复杂性,将HSV 空间的每一维分量都均匀量化为10 份。因为光照强度不影响图像的内容表示,所以V分量可以忽略不计。这样计算颜色直方图时,通过划分后,每一个块的特征包含了颜色的局部分布信息,而所有块的空间分布,又反映了图像内容的颜色模式结构。因此,对于一幅场景复杂的图像,可以从结构分布的角度,用特征组合的方式描述。
在基于划分的特征表示方法中,划分尺度的选择直接影响图像内容描述的有效性[6] 。全局颜色直方图虽然具有计算简单,对平移和旋转不敏感的优点,但无法捕捉颜色组成之间的空间关系,丢失了图像的空间信息。这无疑是不够准确的。两幅颜色直方图非常相似的图像其内容可能丝毫无相似之处。因此,在基于颜色的图像检索中引入空域的信息对于确保检索精度是十分重要的。事实上,颜色的不同空间分布极大地影响了人们对图像的相似性判断。鉴于此,解决方法之一就是基于图像空间的固定划分,即人为地将图像划分成适当的分块,然后为每个分块提取相应的局部颜色特征。我们知道分块太大则失去分块的意义,若分块太小则会增加检索过程的计算量[3]。图3.1 显示了分别划分成4 块和16 块的情形,当然我们可以划分更多的子块,划分的子块越多,图像的距离矩阵携带的空间信息越完备,检索精度也越高,计算复杂度也越高。
距离度量
图像检索的性能不仅依赖于所抽取的图像特征, 而且也与所采用的距离度量或相似度量函数密切相关. 所谓相似度量函数, 就是根据某些预先设定的准则来计算并返回两个图像之间的相似度. 为了确定合适的相似度量函数, 我们对不同的距离度量进行了实验, 例如, L p 距离、余弦距离等. 我们在实验中发现, 使用不同的L p 距离度量均能得到较满意的检索结果, 并且不同的L p 距离度量几乎均给出相同的检索结果. 因此, 我们就选取最简单的欧氏距离作为距离度量[7].
设x= (x1,x2,……,xk) , y= (y1,y2, ……,yk ) 为两个图像, 则它们之间的距离定义为:
d2hist(x,y)=(x1- y1)2+(x2-y2)2+ ……+(xn- yn)2(①)
(②)
3.3.4相似性度量
设G和S 表示要进行比较的两幅图像, N 表示图片中出现的颜色级数, gk 和sk 分别表示图G和S中k级色出现的频数,则两幅图像的相似度可用如下公式表示:
(③)
. Sim 值越接近1,两幅图像越相似。
设图像G分割成(m ×n) 个子块,用颜色对来表示图像G的特征,如果颜色对的值用两个子块颜色直方图的欧氏距离表示,则图G中子块Gij ( i = 1, 2, ?, m; j = 1, 2, ?, n) 的颜色对表就是该子块与周围子块欧氏距离的颜色对。为了消除颜色噪声, 若图像G中子块Gij 的颜色对表中任意两个颜色对值之差小于某一阈值,则删除其中一个颜色对。
算法的描述
颜色直方图的实现算法描述
1.从图像库中读入关键图;
2.计算目标图片的直方图;
3.定位子块,即指定用户输入的图征对象所在子块坐标位置;
4.按式(①)计算两幅图像的各对应子块的相似度;
5.对用户指定的块设置权重为1,其他块降低权重为0.7,;
6.将N幅被比较的图像与用户输入的源图像的最后计算出来的相似度结果记录放入数组中。
7.将N个相似度从大到小排列;
8.根据相似度的排列显示检索到的图像。
改进的颜色直方图实现算法描述
结合前面颜色直方图的实现思路,提出了些改进,其具体实现过程如下:
1.从图像库中读入关键图;
2.定位图像中的子块,并计算子块直方图,即用户选定包含查询图像的子块;
3.计算子块(x,y)的颜色对表,采取“八方向邻接技术”计算这些子块与周围相邻子块的颜色对表,用calcuatecolorpair()函数实现;
4.将这些颜色对中差值小于某一域值的颜色对删除,以消除颜色澡声;
5.将该子块计算得到的颜色对表填入该图像的特征颜色对表,并对其从大到小排列,给定一个域值,选取颜色对表中最大的几个颜色对做为图像的代表特征;
6.颜色匹配,读取待比较的N幅图像,计算当前被比较的图像的颜色直方图,搜索目标图像的每一子块的颜色对表,匹配时不能使用精确匹配,因此颜色对误差小于2%也属于该匹配值;
7.统计单一匹配次数,按顺序计算目标图像中一子块与其同周围子块的颜色对,然后在用户输入的图像颜色对表中查询计算出来的颜色对,差值小于某域值,则匹配到,并置颜色匹配对标志;
8.如果有60%以上的特征颜色匹配到,就说明该图像被检索到;
9.显示检索结果。
基于颜色直方图的图像检索系统的实现
开发工具的选取
本文的系统实现选用的开发工具为 Microsoft 公司的 Visual C++ 6.0。C++是最流行的面向对象语言之一,支持对象、类、方法、消息等概念,同时也支持面向对象方法的封装机制和继承、多态性机制。1998 年,C++由 ISO(InternationalStandards Organization)完成了标准化,C++标准提供了统一的 C++标准库,为用户提供了最为广泛的编程基础设施。Visual C++ 6.0 是 Microsoft 公司推出的基于Windows 的可视化集成开发环境,将编辑、编译、链接和执行集成为一体,能用它来开发 32 位程序。Visual C++经历了从 1.0 到 6.0 版本的发展,软件系统逐渐庞大,功能日益完善。
系统结构
系统结构图
图像查询流程
图4.2图像查询流程图
主要类方法和数据结构
位图类
该系统的实现,没有采用数据库的形式,直接以文件夹的形式调用图像库。
class CPicture
{
public:
CPicture();
virtual ~CPicture();
private:
IPicture *m_pic;
HGLOBAL hGlobal;
public:
HBITMAP LoadPicture(char * FileName);
HBITMAP LoadPicture(char * FileName, HDC hdc);
VOID FreePicture( VOID );
HDC _GetDC ( VOID );
HBITMAP _GetHandle ( VOID );
DWORD _GetWidth ( VOID );
DWORD _GetHeight ( VOID );
BOOL DrawPicture(HDC hdc,long x,long y,long cx,long cy);
};
CImageRetrievalDlg类
class CImageRetrievalDlg
{
public:
void ShowPic(CString pathfile,int idc);// picture中显示图片
void StartDir(const CString& strfile1); //对所有目录查找,取得图像目录下文件路径
void RunDir(const CString& strfile2); //对*.bmp文件查找
void CalculateColor(CString pathfile); //计算颜色直方图
void HistogramShow(int idc);// 绘置直方图
void CalculateColorPair(int x, int y); //计算子块的颜色对表
void SortColorPair();//对四个子块的颜色对表排序
void SeekImage();
//部分方法略
protected:
//部分变量定义略
struct pairs
{
int x1;
int y1;
double o_dis1;
}pair[32];
struct obj_sets
{
int x;
int y;
}obj_set[4];//定义子块位置结构
};
主要程序界面
打开关键图:
指定关键图子块位置
显示关键图直方图
选择图像库
实验结果
以蓝天白云为例
关键图:路径为\2006519\样本\cloud.bmp
图像库:路径为\2006519\图像库\clouds
检索结果:
用户指定一个检索图像, 系统从图像库中自动检索与检索图像最相似的图像,检索结果按距离的降序排列。特别是对于轮廓或边界分明的图像,该算法的检索结果比全局图像的颜色直方图算法明显要好。
附录
主要函数:
// picture中显示图片
void CImageRetrievalDlg::ShowPic(CString pathfile,int idc)
{
CBitmap hbmp;
HBITMAP hbitmap;
//将pStatic指向要显示的地方
CStatic *pStaic;
pStaic=(CStatic*)GetDlgItem(idc);
//装载资源
hbitmap=(HBITMAP)::LoadImage (::AfxGetInstanceHandle(),pathfile, IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
hbmp.Attach(hbitmap);
//获取图片格式
BITMAP bm;
hbmp.GetBitmap(&bm);
//创建临时的内存DC对象
CDC dcMem;
dcMem.CreateCompatibleDC(GetDC());
CBitmap *poldBitmap=(CBitmap*)dcMem.SelectObject(hbmp);
CRect lRect;
pStaic->GetClientRect(&lRect);
lRect.NormalizeRect();
//显示位图
pStaic->GetDC()->StretchBlt(lRect.left ,lRect.top ,lRect.Width(),lRect.Height(),
&dcMem,0 ,0,bm.bmWidth,bm.bmHeight,SRCCOPY);
dcMem.SelectObject(&poldBitmap);
pStaic->ReleaseDC(&dcMem);
}
//打开关键图
void CImageRetrievalDlg::OnOpenImage()
{
CFileOpen fileOpenDlg(TRUE);
if (fileOpenDlg.DoModal () != IDOK) return;
//使菜单可用
CMenu* mmenu = GetMenu();
mmenu->EnableMenuItem(ID_START_RETRIEVAL, 0);
mmenu->EnableMenuItem(ID_STOP_RETRIEVAL, 0 );
mmenu->EnableMenuItem(ID_SHOW_IM, 0 );
mmenu->EnableMenuItem(ID_SHOW_IM2, 0 );
mmenu->EnableMenuItem(ID_SHOW_INFO, 0 );
// 画格子
CWnd* pWnd = GetDlgItem(IDC_VIEW1);
CDC* pDC = pWnd->GetDC();
pWnd->Invalidate();
pWnd->UpdateWindow();
CPen* pPenRed = new CPen;
pPenRed->CreatePen(PS_SOLID, 1, RGB(255,0,0));
CPen* pOldPen = pDC->SelectObject(pPenRed);
/* pDC->MoveTo(1,1); //PictureBox 宽194高172
pDC->LineTo(1, 172);
pDC->MoveTo(1,86);
pDC->LineTo(211,86);
pDC->MoveTo(97,1);
pDC->LineTo(97,190);
pDC->MoveTo(48,1);
pDC->LineTo(48,190);
pDC->MoveTo(145,1);
pDC->LineTo(145,190);
pDC->MoveTo(1,43);
pDC->LineTo(211,43);
pDC->MoveTo(1,129);
pDC->LineTo(211,129);*/
//取得文件路径
POSITION pos = fileOpenDlg.GetStartPosition();
strfile = fileOpenDlg.GetNextPathName(pos);
ShowPic(strfile,IDC_VIEW1);
}
//选择图像库目录
void CImageRetrievalDlg::OnMutiImageIndb()
{
CString m_strPath;
tempi=0;
//打开通用对话框
BROWSEINFO browse;
ZeroMemory(&browse,sizeof(browse));//fills a block of memory with zeros.
browse.hwndOwner = NULL;
browse.pszDisplayName = m_strPath.GetBuffer(MAX_PATH);
browse.lpszTitle = "请选择一个图像目录";
LPITEMIDLIST lpItem = SHBrowseForFolder(&browse);
if(lpItem == NULL) return ;
m_strPath.ReleaseBuffer();
if(SHGetPathFromIDList(lpItem,m_strPath.GetBuffer(MAX_PATH)) == false) return;
m_strPath.ReleaseBuffer();
AfxMessageBox("您选择的目录为:"+m_strPath,MB_ICONINFORMATION|MB_OK);
//得到图像目录下文件的路径
CString tempath;
CString temps;
tempath=m_strPath;
tempath.TrimRight();tempath.TrimLeft(); //去除前后多余
CString strfilepath=tempath;
counts=0;
StartDir(strfilepath);
temps.Format("该目录下共有%d幅图像!",counts);
AfxMessageBox(temps,MB_ICONINFORMATION|MB_OK);
//for (int i = 0; i<counts; i++)
//{
// AfxMessageBox(temp[i],MB_ICONINFORMATION|MB_OK);
//}
}
//对所有目录查找,取得图像目录下文件路径
void CImageRetrievalDlg::StartDir(const CString& strfile1)
{
BOOL yesno;
CFileFind find;
char tempFileFind[200];
sprintf(tempFileFind,"%s\\*.*",strfile1);
RunDir(strfile1);
yesno = (BOOL)find.FindFile(tempFileFind);
//查找下级目录
while(yesno)
{
yesno = find.FindNextFile();
if (find.IsDots() != TRUE)
{
char foundFileName[200];
strcpy(foundFileName,find.GetFileName().GetBuffer(200));
if((find.IsDirectory() == TRUE))
{
char tempDir[200];
sprintf(tempDir,"%s\\%s",strfile1,foundFileName);
// 递归调用
StartDir(tempDir);
}
}
}
find.Close();
return;
}
//对*.bmp文件查找
void CImageRetrievalDlg::RunDir(const CString& strfile2)
{
BOOL yesno;
CFileFind find;
char tempFileFind[200];
sprintf(tempFileFind,"%s\\*.bmp",strfile2);
yesno = find.FindFile(tempFileFind);
while(yesno)
{
yesno = find.FindNextFile();
char foundFileName[200];
strcpy(foundFileName,find.GetFileName().GetBuffer(200));
if(!find.IsDots())
{
char tempFileName[200];
sprintf(tempFileName,"%s\\%s",strfile2,foundFileName);
CString strfilepath1;
strfilepath1.Format("%s",tempFileName);
counts++;
temp[tempi] = new CString(strfilepath1);
tempi++;
}
}
find.Close();
return;
}
//单个图像特征向量
void CImageRetrievalDlg::OnSingleImageIndb()
{
CFileOpen fileOpenDlg1(TRUE);
if (fileOpenDlg1.DoModal () != IDOK) return;
//取得文件路径
POSITION pos = fileOpenDlg1.GetStartPosition();
strfile = fileOpenDlg1.GetNextPathName(pos);
AfxMessageBox(strfile);
}
//显示关键图的直方图
void CImageRetrievalDlg::OnShowIm()
{
CString imagefilepath = strfile;
//if (imagefilepath = ' ') {AfxMessageBox("请选择一幅关键图");return;}
CalculateColor(imagefilepath);
HistogramShow(IDC_DLG_HIST_SHOW);
}
//计算颜色直方图
void CImageRetrievalDlg::CalculateColor(CString pathfile)
{
CBitmap hbmp;
HBITMAP hbitmap;
int R,G,B,H,S,V;
int i,j;
hbitmap=(HBITMAP)::LoadImage (::AfxGetInstanceHandle(),pathfile, IMAGE_BITMAP,0,0,LR_LOADFROMFILE|LR_CREATEDIBSECTION);
hbmp.Attach(hbitmap);
BITMAP bm;
hbmp.GetBitmap(&bm);
CDC dcMem;
dcMem.CreateCompatibleDC(GetDC());
dcMem.SelectObject(hbmp);
int width=bm.bmWidth/4;
int height=bm.bmHeight/4;
COLORREF clr; //定义一个COLORREF结构,因为提取的象素点的颜色是以RGB形式表示的
int x,y;
for(int fda=0;fda<4;fda++)
for(int sda=0;sda<4;sda++)
for(int tda=0;tda<256;tda++){
Ha[fda][sda][tda]=0;
}
for(int fdb=0;fdb<4;fdb++)
for(int sdb=0;sdb<4;sdb++)
for(int tdb=0;tdb<256;tdb++){
Sa[fdb][sdb][tdb]=0;
}
for(int fdc=0;fdc<4;fdc++)
for(int sdc=0;sdc<4;sdc++)
for(int tdc=0;tdc<256;tdc++){
Va[fdc][sdc][tdc]=0;
}
for( i=0;i<4;i++)
for( j=0;j<4;j++)
for(int k=0;k<width;k++)
for(int l=0;l<height;l++){
x=j*width+l;
y=i*height+k;
clr=dcMem.GetPixel(x,y);
R=GetRValue(clr);
G=GetGValue(clr);
B=GetBValue(clr);
//RGB转HSV
int maxp=max(R,G);
int max=max(maxp,B);
int minp=min(R,G);
int min=min(minp,B);
if(max!=0) {S=(max-min)/max;} else {S=0;H=-1;break;} //饱和度
if(max==min) {break;}
if (R == max)
H = (G-B)/(max-min);
else if (G == max)
H = 2 + (B-R)/(max-min); else
H = 4 + (R-G)/(max-min);
H = H * 60 ;
if (H < 0)
H = H + 360 ; //色彩度
V=max; //亮度
Ha[i][j][H]++;
Sa[i][j][S]++;
Va[i][j][V]++;
}
}
//绘置直方图
void CImageRetrievalDlg::HistogramShow(int idc)
{
int m;
CWnd* pWnd = GetDlgItem(idc);// 获取绘制直方图文本框的标签
// 获取设备上下文
CDC* pDC = pWnd->GetDC();
pWnd->Invalidate();
pWnd->UpdateWindow();
pDC->Rectangle(0, 0, 367,338);
CPen* pPenRed = new CPen;// 创建画笔对象
pPenRed->CreatePen(PS_SOLID, 1, RGB(255,0,0));// 创建红色画笔(用于绘制坐标轴)
CPen* pOldPen = pDC->SelectObject(pPenRed);// 选入红色画笔,并保存以前的画笔
pDC->MoveTo(40,40);// 绘制坐标轴
pDC->LineTo(40, 300);// 绘制垂直轴
pDC->LineTo(340, 300);// 绘制水平轴
// 绘制X轴刻度值
CString strTemp;
strTemp.Format("0");
pDC->TextOut(40, 303, strTemp);
strTemp.Format("50");
pDC->TextOut(90, 303, strTemp);
strTemp.Format("100");
pDC->TextOut(140, 303, strTemp);
strTemp.Format("150");
pDC->TextOut(190, 303, strTemp);
strTemp.Format("200");
pDC->TextOut(240, 303, strTemp);
strTemp.Format("255");
pDC->TextOut(295, 303, strTemp);
// 绘制X轴刻度
for (m = 0; m < 256; m += 5)
{
if ((m & 1) == 0)
{
// 10的倍数
pDC->MoveTo(m + 40, 303);
pDC->LineTo(m + 40, 307);
}
else
{
// 5的奇数倍数
pDC->MoveTo(m + 40, 303);
pDC->LineTo(m + 40, 310);
}
}
// 绘制X轴箭头
pDC->MoveTo(335,295);
pDC->LineTo(340,300);
pDC->LineTo(335,305);
// 绘制Y轴箭头
pDC->MoveTo(40,40);
pDC->LineTo(35,45);
pDC->MoveTo(40,40);
pDC->LineTo(45,45);
LONG lMaxCount = 0;// 直方图中最大计数值
// 计算最大计数值
for (m = 0; m <= 255; m ++)
{
// 判断是否大于当前最大值
if (Ha[1][1][m] > lMaxCount)
{
// 更新最大值
lMaxCount = Ha[1][1][m];
}
}
pDC->TextOut(10, 150, "hue");
CPen* pPenBlue = new CPen;// 声名画笔对象
pPenBlue->CreatePen(PS_SOLID, 1, RGB(0,0,255));// 创建蓝色画笔(用于绘制直方图)
pDC->SelectObject(pPenBlue);// 选入蓝色画笔
// 判断是否存在计数值
if(lMaxCount > 0){
// 绘制直方图
for (m = 0; m <= 255; m++)
{
if (Ha[1][1][m]>=1040)
{
pDC->MoveTo(m+40, 300);
pDC->LineTo(m+40, 40);
}else if(Ha[1][1][m]>0 && Ha[1][1][m]<1040){
pDC->MoveTo(m+40, 300);
pDC->LineTo(m+40, 300-Ha[1][1][m]/4);}
if (Ha[1][1][m]>0)
{
strTemp.Format("%d", Ha[1][1][m]);
pDC->TextOut( m+40, 20, strTemp);
}
}
}
pDC->SelectObject(pOldPen); // 恢复以前的画笔
// 删除新的画笔
delete pPenRed;
delete pPenBlue;
}
//显示匹配图的直方图
void CImageRetrievalDlg::OnShowIm2()
{
CDlgHistShow dlgShow;
dlgShow.DoModal();
}
//计算子块的颜色对表
void CImageRetrievalDlg::CalculateColorPair(int x, int y)
{
//采用欧氏距离表示颜色对
for(int ka=0; ka<8; ka++)
{
o_dis[ka]=0;
}
for(int numb=0; numb<32; numb++)
{
pair[numb].x1=-1;
pair[numb].y1=-1;
pair[numb].o_dis1=-1;
}
//计算(x,y)与周围所有子块的颜色直方图的欧氏距离
for(int i=0; i<256; i++)
{
if((x-1)>=0 && (y-1)>=0)
o_dis[0]=o_dis[0]+(Ha[x-1][y-1][i]-Ha[x][y][i])*(Ha[x-1][y-1][i]-Ha[x][y][i]);
else
o_dis[0]=-1;
if((y-1)>=0)
o_dis[1]=o_dis[1]+(Ha[x][y-1][i]-Ha[x][y][i])*(Ha[x][y-1][i]-Ha[x][y][i]);
else
o_dis[1]=-1;
if((x+1)<=3 && (y-1)>=0)
o_dis[2]=o_dis[2]+(Ha[x+1][y-1][i]-Ha[x][y][i])*(Ha[x+1][y-1][i]-Ha[x][y][i]);
else
o_dis[2]=-1;
if((x-1)>=0)
o_dis[3]=o_dis[3]+(Ha[x-1][y][i]-Ha[x][y][i])*(Ha[x-1][y][i]-Ha[x][y][i]);
else
o_dis[3]=-1;
if((x+1)<=3)
o_dis[4]=o_dis[4]+(Ha[x+1][y][i]-Ha[x][y][i])*(Ha[x+1][y][i]-Ha[x][y][i]);
else
o_dis[4]=-1;
if((x-1)>=0 && (y+1)<=3)
o_dis[5]=o_dis[5]+(Ha[x-1][y+1][i]-Ha[x][y][i])*(Ha[x-1][y+1][i]-Ha[x][y][i]);
else
o_dis[5]=-1;
if((y+1)<=3)
o_dis[6]=o_dis[6]+(Ha[x][y+1][i]-Ha[x][y][i])*(Ha[x][y+1][i]-Ha[x][y][i]);
else
o_dis[6]=-1;
if((x+1)<=3 && (y+1)<=3)
o_dis[7]=o_dis[7]+(Ha[x+1][y+1][i]-Ha[x][y][i])*(Ha[x+1][y+1][i]-Ha[x][y][i]);
else
o_dis[7]=-1;
}
//取平方根
for(int j=0; j<8; j++)
{
if(o_dis[j]>=0) o_dis[j]=sqrt(o_dis[j]);
}
//取得颜色已有数目
int num=0;
for(int pairnum=0; pairnum<32; pairnum++)
{
if(pair[pairnum].x1!=-1) num++;
}
//计算域值
double ave=0;
for(int e=0; e<8; e++)
{
ave+=o_dis[e];
}
ave=ave/8; ave=ave*0.02;
//对该子块的颜色对表进行从大到小的排序(冒泡排序)
int count=8; double temp;
for(int i1=count; i1>0; i1--)
{
for(int j1=0;j1<i1-1;j1++)
{
if(o_dis[j1]<o_dis[j1+1])
{
temp=o_dis[j1];
o_dis[j1]=o_dis[j1+1];
o_dis[j1+1]=temp;
}
}
}
//消除那些颜色对差值小于域值的颜色对,以消除那些没有意义的小对象
for(int k1=0; k1<count-1; k1++)
{
if(fabs(o_dis[k1]-o_dis[k1+1])<ave)
{
for(int l=k1+1;l<count-1;l++)
{
o_dis[l]=o_dis[l+1];
}
count--;
o_dis[count]=-1;
k1--;
}
}
//将该字块计算得到的颜色对表填入该图像的特征颜色对表
for(int scan=0; scan<8; scan++)
{
if(o_dis[scan]>0)
{
pair[num].x1=x;
pair[num].y1=y;
pair[num].o_dis1=o_dis[scan];
num++;
}
}
}
//对四个子块的颜色对表排序
void CImageRetrievalDlg::SortColorPair()
{
//32个数据项中有count个实际数值
for(int count=0; count<32; count++)
{
if(pair[count].x1 == -1)
break;
}
//对颜色对表从大到小排列序
struct pairs temp;
for(int i=count; i>0; i--)
{
for(int j=0; j<i; j++)
{
if(pair[j].o_dis1<pair[j+1].o_dis1)
{
temp = pair[j];
pair[j] = pair[j+1];
pair[j+1] = temp;
}
}
}
//计算域值
double ave=0;
for(int e=0; e<count; e++)
{
ave += pair[e].o_dis1;
}
ave=ave/count; ave=ave*0.02;
//消除差值小于域值的颜色对
for(int k=0; k<count-1; k++)
{
if(fabs(pair[k].o_dis1-pair[k+1].o_dis1)<ave)
{
for(int l=k+1; l<count-1; l++)
{
pair[l] = pair[l+1];
}
pair[count-1].x1 = -1;
count--;
k--;
}
}
//置特征颜色对数目变量
pair_count=count;
}
//显示关键图(1,1)块颜色对信息
void CImageRetrievalDlg::OnShowInfo()
{
CWnd* pWnd = GetDlgItem(IDC_STATIC_SHOWINFO);
CDC* pDC = pWnd->GetDC();
pDC->Rectangle(0, 0, 120,160);
int t1=0;
CString imagefilepath = strfile;
CalculateColor(imagefilepath);
CalculateColorPair(1, 1);
for(int ka1=0; ka1<8; ka1++)
{
CString sd1;
sd1.Format("%d",o_dis[ka1]);
pDC->TextOut(0,t1,sd1);
t1+=20;
}
}
//开始检索
void CImageRetrievalDlg::OnStartRetrieval()
{
UpdateData(TRUE);
for (int objset=0; objset<4; objset++)
{
obj_set[objset].x=0;
obj_set[objset].y=0;
}
int m1=0;
if (m_00 == TRUE)
{obj_set[m1].x=0; obj_set[m1].y=0; m1++;}
if (m_01 == TRUE)
{obj_set[m1].x=0; obj_set[m1].y=1; m1++;}
if (m_02 == TRUE)
{obj_set[m1].x=0; obj_set[m1].y=2; m1++;}
if (m_03 == TRUE)
{obj_set[m1].x=0; obj_set[m1].y=3; m1++;}
if (m_10 == TRUE)
{obj_set[m1].x=1; obj_set[m1].y=0; m1++;}
if (m_11 == TRUE)
{obj_set[m1].x=1; obj_set[m1].y=1; m1++;}
if (m_12 == TRUE)
{obj_set[m1].x=1; obj_set[m1].y=2; m1++;}
if (m_13 == TRUE)
{obj_set[m1].x=1; obj_set[m1].y=3; m1++;}
if (m_20 == TRUE)
{obj_set[m1].x=2; obj_set[m1].y=0; m1++;}
if (m_21 == TRUE)
{obj_set[m1].x=2; obj_set[m1].y=1; m1++;}
if (m_22 == TRUE)
{obj_set[m1].x=2; obj_set[m1].y=2; m1++;}
if (m_23 == TRUE)
{obj_set[m1].x=2; obj_set[m1].y=3; m1++;}
if (m_30 == TRUE)
{obj_set[m1].x=3; obj_set[m1].y=0; m1++;}
if (m_31 == TRUE)
{obj_set[m1].x=3; obj_set[m1].y=1; m1++;}
if (m_32 == TRUE)
{obj_set[m1].x=3; obj_set[m1].y=2; m1++;}
if (m_33 == TRUE)
{obj_set[m1].x=3; obj_set[m1].y=3; m1++;}
if (m1 != 4) {AfxMessageBox("请选择四个小方块"); return;}
SeekImage();
}
void CImageRetrievalDlg::SeekImage()
{
CString imagefilepath = strfile;
CalculateColor(imagefilepath);
CalculateColorPair(obj_set[0].x, obj_set[0].y);
CalculateColorPair(obj_set[1].x, obj_set[1].y);
CalculateColorPair(obj_set[2].x, obj_set[2].y);
CalculateColorPair(obj_set[3].x, obj_set[3].y);
SortColorPair();
struct pairs temps[32];
for(int count1=0; count1<32; count1++)
{
temps[count1].x1 = pair[count1].x1;
temps[count1].y1 = pair[count1].y1;
temps[count1].o_dis1 = pair[count1].o_dis1;
}
CString temp_1[1000];
for(int count2=0; count2<counts; count2++)
{
temp_1[count2] = *temp[count2];
}
int match=0;
double ave=0;
int scan=0,picnum=1002,piccount=0,pic1=0;
CString picn;
for(int s=0;s<pair_count;s++)
{
ave+=pair[s].o_dis1;
}
ave=ave/pair_count; ave=ave*0.02;
CWnd* pWnd = GetDlgItem(IDC_STATIC_NUM);// 获取绘制直方图文本框的标签
CDC* pDC = pWnd->GetDC();// 获取设备上下文
for(int pic=0; pic<counts; pic++)
{
CalculateColor(temp_1[pic]);
//显示正在检索的第N幅图
ShowPic(temp_1[pic],IDC_VIEW14);
picn.Format("%d",pic+1);
pDC->TextOut(0,0,picn);
int pairflag[32];
for(int t=0; t<32; t++)
{
pairflag[t]=-1;
}
for(int i=0; i<4; i++)
for(int j=0;j<4;j++)
{
CalculateColorPair(i,j);
for( scan=0; scan<8; scan++)
{
if(pair[scan].x1==-1)
break;
}
for(int comp=0; comp<scan; comp++)
for(int count=0; count<pair_count; count++)
{
if(fabs(temps[count].o_dis1-pair[comp].o_dis1)<ave && pairflag[count]!=0)
{
pairflag[count]=0;
match++;
break;
}
}
}
for(int re=0;re<scan;re++)
{
pair[re].x1=-1;
}
if(match>=pair_count*0.60) piccount++;
if(match>=pair_count*0.60 && picnum<=1013)
{
ShowPic(temp_1[pic],picnum);
picnum++;
}
} //显示相似匹配数
CWnd* pWnd1 = GetDlgItem(IDC_STATIC_TOTAL);
CDC* pDC1 = pWnd1->GetDC();
picn.Format("%d",piccount);
pDC1->TextOut(0,0,picn);
}