一. 理論和方法介紹
a) 采用顏色檢索方法的目的:
對多媒體數據的檢索,早期的方法是用文本將多媒體數據進行標識,這顯然不是基于多媒體信息本身內容的檢索,對多媒體數據中包含的信息是一中及大的浪費;
基于內容的檢索是多媒體數據庫的關鍵技術,如何實現這塊技術,是值得商榷的,而最好的方法是使用無需領域知識的檢索方法,因此,基于顏色的方法就是實現的關鍵;
本文介紹了顏色直方圖和顏色對方法在基于內容檢索時的實現思路和理論;
其實顏色直方圖簡單來說,就是統計圖像中具有某一特定顏色的象素點數目而形成的各顏色的直方圖表示,不同的直方圖代表不同圖片的特征。
b) 利用顏色直方圖進行檢索:
該方法也可以應用于視頻數據庫的查詢中,有以下三種方式:
(1)指明顏色組成--該法需要用戶對圖像中的顏色非常敏感,而且使用起來也不方便,檢索的查準率和查全率并不高,因此文章中并未介紹該法的實現思路
(2)指明一幅示例圖像--通過與用戶確定的圖像的顏色直方圖的相似性匹配得到查詢結果,這是文章介紹的兩種方法的根本
(3)指明圖像中一個子圖--分割圖像為各個小塊,然后利用選擇小塊來確定圖像中感興趣的對象的輪廓,通過建立更復雜的顏色關系(如顏色對方法)來查詢圖像,該方法是文章的重心所在
c) 顏色直方圖實現思路的介紹:
兩圖片是否相似可以采用歐氏距離來描述:
Ed=(G,S)=(Ed越小相似度就越大)
檢索后,全圖直方圖的相似度的定量度量可以用如下公式表示:
Sim(G,S)=?
(N為顏色級數,Sim越靠近1兩幅圖片越相似)
可以對上面2中的公式加改進對某些相對重要的顏色乘上一個權重,就可以做尋找某一前景或組合的查詢。
全圖的顏色直方圖算法過于簡單,因此帶來很多問題,如:可能會有兩幅根本不同的圖像具有完全一樣的顏色直方圖,不反映顏色位置信息,這樣導致查準率和查全率都不高,因此問文章提出了一個改進,即將圖像進行了分割,形成若干子塊,這樣就提供了一定程度的位置信息,而且可以對含用戶感興趣的子塊加大權重,提高檢索的查詢智能性和查準查全率,相應的公式有,子塊Gij與Sij的相似性度量為:
?
(P為所選顏色空間的樣點數)
再引入子塊權重Wij,選取L個最大的Sim值作Simk(Gk,Sk),就有:
?
(Wk 的選取應根據圖像的特點決定,可以使圖像中間或用戶指定的區域權重大,以反映圖像的位置信息)
d) 顏色對實現思路介紹:
主要目的:借助圖像中相鄰子塊之間的顏色直方圖的配對建模,實現對圖像中的具體對象的查詢,支持對象的移位、旋轉和部分變形;
顏色對方法特別適合于對邊界明顯的對象的查詢;
實現思路:計算用戶輸入圖像的子塊直方圖片à用戶選定包含查詢對象的子塊à計算這些子塊與周圍相鄰的子塊的顏色對表à將這些顏色對中差值小于某一域值的顏色對刪除以消除顏色噪聲à選取顏色對表中數值最大的幾個顏色對做為圖片的代表特征à搜索目標圖像的每一子塊的顏色對表尋找與這寫代表顏色對的匹配à統計單一匹配次數à若有某一比例以上的顏色對匹配到,圖像即被檢索到。
相似性度量:
?
(N為所用查詢顏色對數目)
qj、gj:顏色對j在查詢圖像Q和目標圖像G中出現的次數
查詢時顏色對的匹配應該是不精確的,應該允許的誤差為2%以內?
二. 具體程序實現
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子塊的兩幅圖像的各子塊的相似度。
對于用戶選定的塊其實是代表查詢對象的,因此應該加大權重,相對來說就是減小其他塊的權重,然后可以將乘過對應權重的塊的相似度相加,得到最終的相似度,然后將所有目標圖像與用戶輸入的圖像的相似度從大到小排序,選出值最大的幾張作為最后的查詢結果顯示出來返回。
以上是具體實現設想,程序實現如下:
1 //基于顏色直方圖的方法
2 pDC->TextOut(
10,
168,
"檢索結果:");
3 CBmpProc *
pDestBmp;
4 CString comp_pic_path;
5 double fsim[
15]; file:
//15張待比較的目標圖片與用戶輸入圖片的相似度存放的數組
6 int psim[
15]; file:
//與fsim想對應的圖片編號數組,以便顯示
7 for(
int comp_pic=
1;comp_pic<=
15;comp_pic++
){
8 comp_pic_path.Format(
"image%d.bmp",comp_pic);
9 bmp.LoadFromFile(comp_pic_path);
// 從庫中讀入位圖
10 pDestBmp = (CBmpProc*)
new(CBmpProc);
// 用new分配類目標
11 pDestBmp->LoadFromObject(bmp, &CRect(
0,
0,
128,
128));
12 // 從bmp中的指定區域讀入圖像,以便圖片匹配的進行
13 pDestBmp->CalculateColor(*pDC); file:
//計算目標圖片的顏色直方圖
14 int x1,x2,y1,y2,x3,x4,y3,y4;
15 x1=obj_set.m_x1;x2=obj_set.m_x2;x3=obj_set.m_x3;x4=
obj_set.m_x4;
16 y1=obj_set.m_y1;y2=obj_set.m_y2;y3=obj_set.m_y3;y4=
obj_set.m_y4;
17 file:
//用戶輸入的對象所在子塊(既用戶選定的4個子塊)的坐標
18 double sim[
4][
4]; file:
//子塊之間的相似度數組
19 int ccount[
4][
4]; file:
//有過統計的顏色數目記錄數組
20 for(
int i=
0;i<
4;i++
)
21 for(
int j=
0;j<
4;j++
){
22 sim[i][j]=
0;
23 ccount[i][j]=
0;
24 }
25 file:
//以下兩個for按公式計算兩幅圖像的各對應子塊之間的相似度
26 for(i=
0;i<
4;i++
)
27 for(
int j=
0;j<
4;j++
)
28 for(
int k=
0;k<
256;k++
){
29 if((pDestBmp->Color[i][j][k]>=pBmp->Color[i][j][k])&&pDestBmp->Color[i][j][k]!=
0){
30 sim[i][j]+=(
1-((fabs(pDestBmp->Color[i][j][k]-pBmp->Color[i][j][k]))/(pDestBmp->
Color[i][j][k])));
31 ccount[i][j]++
;
32 }
33 if((pDestBmp->Color[i][j][k]Color[i][j][k])&&pBmp->Color[i][j][k]!=
0){
34 sim[i][j]+=(
1-((fabs(pDestBmp->Colori][j][k]-pBmp->Color[i][j][k]))/(pBmp->
Color[i][j][k])));
35 ccount[i][j]++
;
36 }
37 }
38 for(i=
0;i<
4;i++
)
39 for(
int j=
0;j<
4;j++
){
40 sim[i][j]=sim[i][j]/
ccount[i][j];
41 }
42 file:
//計算兩圖像最終的相似度結果
43 double final_sim=
0;
44 for(i=
0;i<
4;i++
)
45 for(
int j=
0;j<
4;j++
){
46 file:
//對用戶指定的塊設置權重為1
47 if((i==x1&&j==y1)||(i==x2&&j==y2)||(i==x3&&j==y3)||(i==x4&&j==
y4))
48 final_sim+=
sim[i][j];
49 else
50 file:
//其他塊降低權重為0.7,提高對對象匹配的精確度
51 final_sim+=(sim[i][j]*
0.7);
52 }
53 file:
//將15幅被比較圖像與用戶輸入源圖像的最后計算出來的相似度結果記錄在數組中
54 fsim[comp_pic-
1]=
final_sim;
55 delete (CBmpProc*
)pDestBmp;
56 }
57 int count=
15;
double tempf;
int tempp;
58 for(
int l=
0;l<
15;l++
){
59 psim[l]=l+
1; file:
//設定編號數組
60 }
61 file:
//將15個相似度從大到小排列,并且改變次序的時候編號數組和跟著改變
62 for(
int i=count;i>
0;i--
){
63 for(
int j=
0;jif(fsim[j]tempf=
fsim[j];
64 tempp=
psim[j];
65 fsim[j]=fsim[j+
1];
66 psim[j]=psim[j+
1];
67 fsim[j+
1]=
tempf;
68 psim[j+
1]=
tempp;
69 }
70 }
71 int disp=
0;
72 int space=-
128;
73 file:
//將相似度最大的的兩張圖片顯示出來
74 for(
int disp_pic=
1;disp_pic<=
2;disp_pic++
){
75 comp_pic_path.Format(
"image%d.bmp",psim[disp_pic]);
76 bmp.LoadFromFile(comp_pic_path);
// 從庫中讀入位圖
77 pDestBmp = (CBmpProc*)
new(CBmpProc);
// 用new分配類目標
78 pDestBmp->LoadFromObject(bmp, &CRect(
0,
0,
128,
128));
// 從bmp中的指定區域讀入圖像
79 disp++
;
80 space+=
128;
81 pDC->Rectangle(
10+space-
1,
190-
1,
138+space+
1,
318+
1);
82 pDestBmp->Draw(*pDC, &CRect(
10+space,
190,
138+space,
318));
83 // 將pBmp中的圖像繪入DC的指定區域
84 space+=
6;
85 }
86 delete (CBmpProc*)pBmp;
// 刪除類目標,delete會自動調用類的析構函數。
87 AfxMessageBox(
"檢索完成");
88 }
?
b) 基于顏色對的方法的程序實現
該方法也需要分成4×4子塊,計算顏色直方圖,具體計算顏色直方圖的方法上面已經有過詳細的解釋。
該方法主要在于對顏色對表示結構的實現,顏色對是某一圖片的代表特征,因此在程序中必須有定量表示,現在采取用兩個子塊顏色直方圖的歐氏距離表示,因此計算某一子塊的顏色對表就是按八方向計算其與周圍的子塊之間的歐氏距離,將結果存放于一個double o_dis[8]的數組中,然后將這個數組從大到小排序,排序完成后再將數組中相互之間值的差小于某一域值(取8個顏色對的平均值的2%)的顏色對祛除(按序兩兩比較再移動數組里的變量實現),最后將結果先填入圖像的特征顏色對表(有4×8=32個變量,是一個結構數組,結構記錄用戶選定子塊的坐標和與其相對應的被選中的顏色對值)。
最后,對4個用戶選定的子塊依次計算完畢,就可以調用SortColorPair()函數,對特征顏色對表做出處理(先從大到小排序,然后祛除差值小于總平均值的2%的特征顏色對)。
在比較的時候,按順序計算出目標圖像的子塊顏色對表,和以上的特征顏色對表匹配,如果匹配到,則標記該顏色對(設定另一標記0數組),并且將匹配數變量加一,如果最后匹配到的數目是60%以上,就算目標圖像被搜索到。
具體程序實現如下:
//計算子塊(x,y)的顏色對表,采取"八方向鄰接技術"
int CBmpProc::CalculateColorPair(
int x,
int y)
{
file://顏色對采取歐氏距離來描述
double o_dis[
8];
for(
int k=
0;k<
8;k++
){
o_dis[k]=
0;
}
file://計算(x,y)與周圍所有子塊的顏色直方圖的歐氏距離
file:
//---------------------------------------------
for(
int i=
0;i<
256;i++
){
if((x-
1)>=
0&&(y-
1)>=
0)
o_dis[0]=o_dis[
0]+(Color[x-
1][y-
1][i]-Color[x][y][i])*(Color[x-
1][y-
1][i]-
Color[x][y][i]);
else
o_dis[0]=-
1;
if((y-
1)>=
0)
o_dis[1]=o_dis[
1]+(Color[x][y-
1][i]-Color[x][y][i])*(Color[x][y-
1][i]-
Color[x][y][i]);
else
o_dis[1]=-
1;
if((x+
1)<=
3&&(y-
1)>=
0)
o_dis[2]=o_dis[
2]+(Color[x+
1][y-
1][i]-Color[x][y][i])*(Color[x+
1][y-
1][i]-
Color[x][y][i]);
else
o_dis[2]=-
1;
if((x-
1)>=
0)
o_dis[3]=o_dis[
3]+(Color[x-
1][y][i]-Color[x][y][i])*(Color[x-
1][y][i]-
Color[x][y][i]);
else
o_dis[3]=-
1;
if((x+
1)<=
3)
o_dis[4]=o_dis[
4]+(Color[x+
1][y][i]-Color[x][y][i])*(Color[x+
1][y][i]-
Color[x][y][i]);
else
o_dis[4]=-
1;
if((x-
1)>=
0&&(y+
1)<=
3)
o_dis[5]=o_dis[
5]+(Color[x-
1][y+
1][i]-Color[x][y][i])*(Color[x-
1][y+
1][i]-
Color[x][y][i]);
else
o_dis[5]=-
1;
if((y+
1)<=
3)
o_dis[6]=o_dis[
6]+(Color[x][y+
1][i]-Color[x][y][i])*(Color[x][y+
1][i]-
Color[x][y][i]);
else
o_dis[6]=-
1;
if((x+
1)<=
3&&(y+
1)<=
3)
o_dis[7]=o_dis[
7]+(Color[x+
1][y+
1][i]-Color[x][y][i])*(Color[x+
1][y+
1][i]-
Color[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]);
}
file://------------------------------------------------
file:
//歐氏距離計算結束
int flag=
0;
int num=
0;
for(
int pairnum=
0;pairnum<
32;pairnum++
){
if(pair[pairnum].x!=-
1){
num++
;
}
}//因為在計算子塊的顏色對表的時候已經寫了特征顏色對數組,因此要先統計一下特征顏色對數組里已經//有多少有數值了,以便下次的寫入可以接在后面,而不至于覆蓋了前面的數值
file:
//計算顏色對差值小于某個"域值"的這個域值
double ave=
0;
for(
int e=
0;e<
8;e++
){
ave+=
o_dis[e];
}
ave=ave/
8;ave=ave*
0.02; file:
//采取與子塊周圍顏色對的平均值的2%計為域值
file:
//對該子塊的顏色對表進行從大到小的排序,采取冒泡排序
int count=
8;
double temp;
for(i=count;i>
0;i--
){
for(
int j=
0;jif(o_dis[j]temp=
o_dis[j];
o_dis[j]=o_dis[j+
1];
o_dis[j+
1]=
temp;
}
}
file://消除那些顏色對差值小于某個"域值"的顏色對,以消除那些沒有意義的小對象
for(k=
0;kif(fabs(o_dis[k]-o_dis[k+
1])
for(
int l=k+
1;lo_dis[l]=o_dis[l+
1];
}
count--
;
k--
;
o_dis[count]=-
1;
}
}
file://將該字塊計算得到的顏色對表填入該圖像的特征顏色對表
for(
int scan=
0;scan<
8;scan++
){
if(o_dis[scan]>
0){
pair[num].x=
x;
pair[num].y=
y;
pair[num].o_dis=
o_dis[scan];
num++
;
}
}
return 1;
} //計算該圖像的最終確定的特征顏色對表
BOOL CBmpProc::SortColorPair()
{
file://32個數據項中有count個有實際數值
for(
int count=
0;count<
32;count++
){
if(pair[count].x==-
1)
break;
}
struct color_pair temp;
file://對顏色對表從大到小排列序(冒泡排序法)
for(
int i=count;i>
0;i--
){
for(
int j=
0;jif(pair[j].o_distemp=
pair[j];
pair[j]=pair[j+
1];
pair[j+
1]=
temp;
}
}
file://計算域值以消除差值小于這個值的顏色對
double ave=
0;
for(
int e=
0;eave+=
pair[e].o_dis;
}
ave=ave/
count;
ave=ave*
0.02;
file://消除差值小于域值的顏色對
for(
int k=
0;kif(fabs(pair[k].o_dis-pair[k+
1].o_dis)
for(
int l=k+
1;lpair[l]=pair[l+
1];
}
count--
;
k--
;
}
}
file://置特征顏色對數目變量
pair_count=
count;
return true;
}
將計算顏色直方圖的代碼表達如下:
file://以下函數計算顏色直方圖
BOOL CBmpProc::CalculateColor(CDC &
dc)
{
if (!
IsValid())
return FALSE;
ASSERT(m_pInfo);
ASSERT(m_pInfo->bmiHeader.biSize ==
sizeof(BITMAPINFOHEADER));
// 復制源圖
CDC compDC;
// 創建與當前顯示設備兼容的內存設備描述表
compDC.CreateCompatibleDC(&
dc);
compDC.SelectObject(this);
COLORREF clr; file://定義一個COLORREF結構,因為提取的象素點的顏色是以RGB形式表示的
int pix_color;
int red,green,blue;
int x,y;
for(
int fd=
0;fd<
4;fd++
)
for(
int sd=
0;sd<
4;sd++
)
for(
int td=
0;td<
256;td++
){
Color[fd][sd][td]=
0;
}
file://計算顏色直方圖
for(
int i=
0;i<
4;i++
)
for(
int j=
0;j<
4;j++
)
for(
int k=
0;k<
32;k++
)
for(
int l=
0;l<
32;l++
){
x=j*
32+
l;
y=i*
32+
k;
clr=
compDC.GetPixel(x,y);
red=
GetRValue(clr);
green=
GetGValue(clr);
blue=
GetBValue(clr);
file://因為RGB顏色共256^3種,不可能都保存到數組中,因此要先進行一定的提取工作,因為人對亮度的感
file:
//覺是最明顯的,所以可以先將RGB顏色值轉成亮度值,這個公式即轉換公司,剛好亮度數值是256級的,//就可以統計顏色直方圖了
pix_color=red*
0.299+green*
0.587+blue*
0.114;
Color[i][j][pix_color]++
;
file://對該象素點的顏色直方圖數組中的相信位置加一,是直方圖的物理實現
}
return true;
}
?
以上三個函數實現對某一圖像內部的具體計算,而對于基于顏色對方法的外部計算如下:
1 //計算用戶確定的4塊位置與其周圍位置的顏色對(顏色對現采取用相鄰兩塊的直方圖的歐氏距離表示)
2 pBmp->
CalculateColorPair(obj_set.m_x1,obj_set.m_y1);
3 pBmp->
CalculateColorPair(obj_set.m_x2,obj_set.m_y2);
4 pBmp->
CalculateColorPair(obj_set.m_x3,obj_set.m_y3);
5 pBmp->
CalculateColorPair(obj_set.m_x4,obj_set.m_y4);
6 file:
//其實在以上的4部計算中,已經形成了初步的顏色對表,在此只不過是將表中的數據從大到小排列出來//并且祛除差值小于某一域值的顏色對
7 file:
//計算顏色對結束,形成顏色對表
8 pBmp->
SortColorPair();
9 file:
//顏色對表計算出來,表中的數據既是用戶輸入的該圖像的代表特征
10 pDC->TextOut(
10,
168,
"檢索結果:");
11 CBmpProc *
pDestBmp;
12 CString comp_pic_path;
13 int disp=
0;
14 int space=-
128;
15 file:
//讀取帶比較的圖像(在此初定15幅--現定義這15幅圖像即圖片數據庫)
16 for(
int comp_pic=
1;comp_pic<=
15;comp_pic++
){
17 comp_pic_path.Format(
"image%d.bmp",comp_pic);
18 bmp.LoadFromFile(comp_pic_path);
// 從庫中讀入位圖
19 pDestBmp = (CBmpProc*)
new(CBmpProc);
// 用new分配類目標
20 pDestBmp->LoadFromObject(bmp, &CRect(
0,
0,
128,
128));
// 從bmp中的指定區域讀入圖像
21 file:
//計算當前被比較的圖像的顏色直方圖
22 pDestBmp->CalculateColor(*
pDC);
23 int match=
0; file:
//顏色對匹配數目
24 double ave=
0; file:
//確定匹配時候不能使用精確匹配,所以需要一個差值小于某一域值時的域值
25 for(
int s=
0;spair_count;s++
){
26 ave+=pBmp->
pair[s].o_dis;
27 }
28 ave=ave/pBmp->pair_count; file:
//這個域值的基數即是用戶輸入的圖片的顏色對表中顏色對的平均值
29 ave=ave*
0.02; file:
//確定誤差小于2%的顏色對均屬于這個域值
30
31 int pairflag[
32]; file:
//顏色對匹配標志數組,即某一顏色對如果在目標圖像中找到,下一次就不能再匹配
32 for(
int t=
0;t<
32;t++
){
33 pairflag[t]=-
1;
34 }
35 for(
int i=
0;i<
4;i++
){
36 for(
int j=
0;j<
4;j++
){
37 file:
//按順序計算目標圖像中一子塊與其周圍子塊的顏色對,然后在用戶輸入的圖像的顏色對表中查詢計算出//來的顏色對
38 pDestBmp->
CalculateColorPair(i,j);
39 for(
int scan=
0;scan<
8;scan++
){
40 if(pDestBmp->pair[scan].x==-
1)
41 break;
42 }
43 for(
int comp=
0;compfor(
int count=
0;countpair_count;count++
){
44 if((fabs(pBmp->pair[count].o_dis-pDestBmp->pair[comp].o_dis))file:
//差值小于某域值,則匹配到
45 pairflag[count]=
0; file:
//置顏色對匹配標志位
46 match++; file:
//匹配數加一
47 break;
48 }
49 }
50 }
51 file:
//重新置目標圖像的顏色對表為空,因為現在的實現方式是在計算某一子塊的顏色對時已經寫過了顏色對//表,為保證顏色對表的真確性,必須在查詢下一子塊的時候重新置顏色對表為空
52 for(
int re=
0;repDestBmp->pair[re].x=-
1;
53 }
54 }
55 file:
//如果有60%以上的特征顏色對匹配到,就說明該圖像已經被檢索到
56 if(match>=(pBmp->pair_count*
0.60)){
57 file:
//以下是對檢索到的圖像的界面上的排版顯示
58 disp++
;
59 space+=
128;
60 file:
//畫圖像邊框
61 pDC->Rectangle(
10+space-
1,
190-
1,
138+space+
1,
318+
1);
62 pDestBmp->Draw(*pDC, &CRect(
10+space,
190,
138+space,
318));
// 將pBmp中的圖像繪入DC的指定區域
63 space+=
6;
64 }
65 delete (CBmpProc*)pDestBmp;
// 刪除類目標,delete會自動調用CBmpProc類的析構函數。
66 }
67 delete (CBmpProc*)pBmp;
// 刪除類目標,delete會自動調用類的CBmpProc析構函數。
68 AfxMessageBox(
"檢索完成");
from: http://www.cnblogs.com/wengzilin/archive/2013/03/12/2956374.html
總結
以上是生活随笔為你收集整理的vc++基于颜色直方图的图像检索,含代码的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。