最接近色.docx
《最接近色.docx》由会员分享,可在线阅读,更多相关《最接近色.docx(28页珍藏版)》请在冰豆网上搜索。
![最接近色.docx](https://file1.bdocx.com/fileroot1/2022-12/14/d9b9adbb-ecc1-4bc6-9af2-30aa73b40a7a/d9b9adbb-ecc1-4bc6-9af2-30aa73b40a7a1.gif)
最接近色
◇最接近色
*最接近色搜尋方法研究-球殼範圍逼近法*
*作者:
邱奕南(Chi'uI-Nan)*
*版權聲明:
以下文章內容本人僅同意供BBS站上流傳學習,但必須完整流傳*
*(含版權聲明及程式),其餘權利一概保留。
任何未經本人同意*
*,將本文販賣、刊登、節錄、或其他一切侵害本人著作權之行為*
*者,皆需負擔刑事責任及民事賠償責任。
*
**********************************************************************
對於彩色影像的處理上,不管是處理抖色、更換色盤資料、或是全彩影像
轉色盤影像時,最接近色搜尋的速度往往決定這些影像處理的速度。
因此本文
的目的,便是要探討如何快速搜尋到最接近色。
首先將問題定義如下:
對於一個在RGB色彩空間、具有N個顏色的集合S={Ci},i=0~N-1,現給
定任一顏色C,請找出集合S中的一個顏色C',使得C與C'在RGB色彩空間上
的距離最接近。
由於RGB色彩空間可視為一個立方體的三度空間,因此我們可將整個問題轉換成
三度空間幾何上的問題:
假設三度空間上有N個點Pi,i=0~N-1。
現給定任一點P,請在這N個點中找
出另一點P',使得P與P'的距離最小。
解決這個問題最簡單的方法,便是循序搜尋法(SequentialSearch),也就是
算出每一個點Pi和點P的距離,然後一個點一個點的比較,自然便可找出和點P
距離最接近的點P'。
但是可想而知的是,這種方法的效率必然很差,因此我們
必須想辦法略去一些不必比較的點。
而要略去不必比較的點,首先便必須從目
前已算出最接近點的資訊上著手,由該點已算得的資訊略去一些必定較遠的點。
至於目前已算出最接近點中,有那些與距離相關的資訊可用來判斷某些未比較
點較遠呢?
我們先看下面的定理:
對於空間上點P和點Q,若其與原點O的距離為Rp和Rq,且點P和點Q的距離為
D,則D>=│Rp-Rq│。
證明:
三點O、P、Q成一三角形。
現已知OP=Rp,OQ=Rq,假設OP與OQ夾角為θ,則:
PQ=Sqrt(Rp^2+Rq^2-2RpRq*cosθ)
因此當θ=0(也就是OP與OQ重疊)時,PQ值最小,故
PQ>=Sqrt(Rp^2+Rq^2-2RpRq*cos0)=│Rp-Rq│
現在我們先假設已存在的N個點Pi,若其與原點距離為Ri,而給定點P,其與原
點距離為R,與點Pi距離為Di。
則當目前最接近點P'與點P的距離為D'時,任何
一點Pj,只要符合Dj>=D'時,由於其距離不會比較近,因此便不需去比較這
個點Pj了。
然而我們並未算出Dj的值呀?
這時候便可用上面的定理了。
當下式
成立時:
D'<=abs(R-Rj)
由於abs(R-Rj)<=Dj,因此D'<=Dj。
也就是說,只要任何一點Pj,其與原點
距離Rj代入上式成立時,便不需去比較了。
從另外一個角度來看,若我們已算
出目前最接近點與點P的距離D'時,則所有與原點相距在(R-D',R+D')範圍以外
的其他點都不必再去比較了。
接下來我們再考慮距離的計算方式。
一般距離的定義為sqrt(x^2+y^2+z^2),
但由於必須有三個乘法且必須開根號,其速度會慢很多。
因此,我們可以將色
彩距離的定義改為:
D'=│R-Rj│+│G-Gj│+│B-Bj│
由於
│R-Rj│+│G-Gj│+│B-Bj│>=│(R-Rj)+(G-Gj)+(B-Bj)│
因此D'<=abs(R-Rj)的式子依然成立。
如此在距離的計算上速度會比較快些。
至於採用這種距離定義,效果是否會變得太差?
這點倒不用擔心。
因為不管是
在影像處理或地貌比對上,絕對誤差和常用來取代平方誤差和,其效果雖較差
些,但差異並不大。
這點作者也實際驗證過。
最後我們將整個搜尋最接近色的
演算法列出如下:
1.算出顏色集合S中,每個顏色Ci與原點的距離Ri,並依Ri值大小排序好。
這個部份可事先算好。
2.算出給定顏色C與原點的距離R。
3.取出顏色集合中與原點距離亦為R(或附近)的顏色C',並計算與顏色C
的距離為D',得到搜尋範圍(R-D',R+D')。
4.取出搜尋範圍(R-D',R+D')中尚未比較過的點C",並計算與顏色C的距離
為D"。
若D"5.重複步驟4,直到搜尋範圍(R-D',R+D')中已無尚未比較過的點。
此時,
C'即為所要搜尋的最接近色。
現在我們已得到一種快速搜尋最接近色的方法了,但是我們要如何寫成程
式呢?
對於搜尋範圍的逼近,以及已比較點的略去,我們可以從已排序好的色
盤資料中,由初始計算(距離R)的顏色索引值開始往兩方向逐點計算,直到兩
方向所計算的顏色原點距均超出搜尋範圍為止。
至於顏色索引值的更新方式有
兩種,一種是依目前比較的顏色索引值漸增及漸減,一種是對目前搜尋距離值
漸增及漸減(利用距離區間的方式記錄應比較的顏色索引值)。
直覺上,前者
的速度應比後者快。
以下是這兩種方法的程式部份:
(一)顏色索引值增減逼近法
staticintColor_No;/*顏色數*/
staticunsignedcharUse_Palette[3][256];/*改變索引方式,以加速取值*/
staticunsignedcharPalette_Index[256];/*與原調色盤對應之索引值*/
staticunsignedintRGB_Distance[256];/*各顏色與原點距離*/
staticunsignedcharDistance_Index[765+1];/*相同原點距離索引值*/
voidSetPalette(intcolor_no,unsignedchar*palette)
{
/*------------------------------------------------------------
作用:
設定使用的調色盤資料
參數:
color_no=色彩數,1~256。
palette=色盤資料,依次為RGB,每色3byte。
------------------------------------------------------------*/
inti,j,min_index,min_distance,cur_distance,temp;
/*計算與原點距離*/
Color_No=color_no;
for(i=0;i{
Palette_Index[i]=i;
RGB_Distance[i]=palette[i*3]+palette[i*3+1]+palette[i*3+2];
}
/*依原點距離排序-使用MinimaxSort*/
cur_distance=0;
Distance_Index[0]=0;
for(i=0;i{
/*找出最小原點距離者*/
min_distance=RGB_Distance[i];
min_index=i;
for(j=i+1;jif(RGB_Distance[j]{
min_distance=RGB_Distance[j];
min_index=j;
}
/*將最小者調上來*/
j=Palette_Index[min_index];
Palette_Index[min_index]=Palette_Index[i];
Palette_Index[i]=j;
temp=RGB_Distance[min_index];
RGB_Distance[min_index]=RGB_Distance[i];
RGB_Distance[i]=temp;
/*記錄調色盤資料*/
Use_Palette[0][i]=palette[j*3];
Use_Palette[1][i]=palette[j*3+1];
Use_Palette[2][i]=palette[j*3+2];
/*更新距離索引範圍*/
for(j=cur_distance+1;j<=min_distance;j++)Distance_Index[j]=i;
cur_distance=min_distance;
}
for(j=cur_distance+1;j<=765;j++)Distance_Index[j]=color_no-1;
}
intGetNearestColor(intr,intg,intb)
{
/*------------------------------------------------------------
作用:
取得最接近色之索引值
參數:
r,g,b=RGB三色分量值
傳回:
最接近色在色盤資料上的索引值
限制:
呼叫前必須呼叫SetPalette設定使用之調色盤資料
------------------------------------------------------------*/
intmin_index,min_distance,distance,left_bound,right_bound;
intcur_distance,left_index,right_index;
intleft_distance,right_distance,left_ok,right_ok;
/*初始化:
先比較相同距離之色彩
色彩索引值可由Distance_Index中直接取得*/
distance=r+g+b;
left_index=right_index=min_index=Distance_Index[distance];
min_distance=abs(r-Use_Palette[0][min_index])+
abs(g-Use_Palette[1][min_index])+
abs(b-Use_Palette[2][min_index]);
/*搜尋至超出範圍為止
搜尋範圍:
distance-min_distance~distance+min_distance
left_index,right_index:
兩方向目前比較的顏色索引值
left_distance,right_distance:
兩方向目前已搜尋到的原點距
left_bound,right_bound:
兩方向的搜尋範圍
left_ok,right_ok:
兩方向是否已超出搜尋範圍旗標*/
left_ok=right_ok=false;
left_distance=right_distance=distance;
left_bound=distance-min_distance;
right_bound=distance+min_distance;
for(;;)
{
/*往右搜尋*/
if(!
right_ok)
if((++right_index>Color_No)||
((right_distance=RGB_Distance[right_index])>right_bound))
right_ok=true;
else
{
cur_distance=abs(r-Use_Palette[0][right_index])+
abs(g-Use_Palette[1][right_index])+
abs(b-Use_Palette[2][right_index]);
if(cur_distance{
min_distance=cur_distance;
min_index=right_index;
left_bound=distance-min_distance;
right_bound=distance+min_distance;
if(left_distance}
}
/*往左搜尋*/
if(!
left_ok)
if((--left_index<0)||
((left_distance=RGB_Distance[left_index])left_ok=true;
else
{
cur_distance=abs(r-Use_Palette[0][left_index])+
abs(g-Use_Palette[1][left_index])+
abs(b-Use_Palette[2][left_index]);
if(cur_distance{
min_distance=cur_distance;
min_index=left_index;
left_bound=distance-min_distance;
right_bound=distance+min_distance;
if(right_distance>right_bound)right_ok=true;
}
}
/*兩邊都超出範圍時,即結束搜尋*/
if(left_ok&&right_ok)break;
}
returnPalette_Index[min_index];
}
(二)搜尋距離值增減逼近法
staticunsignedcharUse_Palette[3][256];/*改變索引方式,以加速取值*/
staticunsignedcharPalette_Index[256];/*與原調色盤對應之索引值*/
staticunsignedcharDistance_Index[765/9+2];/*相同原點距離索引值*/
staticunsignedintDistance_Divide;/*區間分割距離*/
staticunsignedintMax_Divide;/*最大的區間索引值*/
voidSetPalette(intcolor_no,unsignedchar*palette)
{
/*------------------------------------------------------------
作用:
設定使用的調色盤資料
參數:
color_no=色彩數,1~256。
palette=色盤資料,依次為RGB,每色3byte。
------------------------------------------------------------*/
inti,j,min_index,min_distance,cur_distance;
unsignedchardistance[256];
/*決定分割區間數,目前儘量使得每個區間約有3個顏色
除數:
16色=144,256色=9*/
Distance_Divide=2304/color_no;
Max_Divide=765/Distance_Divide;
/*計算與原點距離*/
for(i=0;i{
Palette_Index[i]=i;
distance[i]=(palette[i*3]+palette[i*3+1]+palette[i*3+2])/
Distance_Divide;
}
/*依原點距離排序-使用MinimaxSort*/
cur_distance=0;
Distance_Index[0]=0;
for(i=0;i{
/*找出最小原點距離者*/
min_distance=distance[i];
min_index=i;
for(j=i+1;jif(distance[j]{
min_distance=distance[j];
min_index=j;
}
/*將最小者調上來*/
j=Palette_Index[min_index];
Palette_Index[min_index]=Palette_Index[i];
Palette_Index[i]=j;
distance[min_index]=distance[i];
/*記錄調色盤資料*/
Use_Palette[0][i]=palette[j*3];
Use_Palette[1][i]=palette[j*3+1];
Use_Palette[2][i]=palette[j*3+2];
/*更新距離索引範圍*/
for(j=cur_distance+1;j<=min_distance;j++)Distance_Index[j]=i;
cur_distance=min_distance;
}
for(j=cur_distance+1;j<=Max_Divide+1;j++)Distance_Index[j]=color_no;
}
intGetNearestColor(intr,intg,intb)
{
/*------------------------------------------------------------
作用:
取得最接近色之索引值
參數:
r,g,b=RGB三色分量值
傳回:
最接近色在色盤資料上的索引值
限制:
呼叫前必須呼叫SetPalette設定使用之調色盤資料
------------------------------------------------------------*/
inti,min_index,min_distance,cur_range,distance,end_index;
intcur_distance,search_range;
/*初始化:
搜尋相同距離區間之色彩*/
distance=(r+g+b)/Distance_Divide;
end_index=Distance_Index[distance+1];
min_distance=768;
for(i=Distance_Index[distance];i{
cur_distance=abs(r-Use_Palette[0][i])+abs(g-Use_Palette[1][i])+
abs(b-Use_Palette[2][i]);
if(cur_distance{
min_distance=cur_distance;
min_index=i;
}
}
/*搜尋至超出範圍為止
搜尋範圍:
distance-search_range~distance+search_range*/
cur_range=1;
search_range=min_distance/Distance_Divide+1;
while(cur_range<=search_range)
{
/*往左搜尋一個區間*/
if(distance-cur_range>=0)
{
end_index=Distance_Index[distance-cur_range+1];
for(i=Distance_Index[distance-cur_range];i{
cur_distance=abs(r-Use_Palette[0][i])+
abs(g-Use_Palette[1][i])+
abs(b-Use_Palette[2][i]);
if(cur_distance{
min_distance=cur_distance;
min_index=i;
search_range=min_distance/Distance_Divide+1;
}
}
}
/*往右搜尋一個區間*/
if(distance+cur_range<=Max_Divide)
{
end_index=Distance_Index[distance+cur_range+1];
for(i=Distance_Index[distance+cur_range];i{
cur_distance=abs(r-Use_Palette[0][i])+
abs(g-Use_Palette[1][i])+
abs(b-Use_Palette[2][i]);
if(cur_distance{
min_distance=cur_distance;
min_index=i;
search_range=min_distance/Distance_Divide+1;
}
}
}
cur_range++;
}
returnPalette_Index[min_index];
}
上面兩個程式,我們以標準調色盤資料為準,R、G、B各以4倍增,全部呼叫次
數為262144次來做分析。
首先測得兩種方法的平均比較次數:
│循序搜尋法│程式一│倍差│程式二│倍差
───┼─────┼─────┼───┼─────┼───
16色│16次│5.5次│2.9│10.0次│1.6
256色│256次│39.9次│6.4│48.1次│5.3
因此在理論上來講,程式一的速度應較快。
但是實際在486DX2-66測試而得的速
度如下:
│循序搜尋法│程式一│倍差│程式二│倍差
───┼──