標 題:位元影像八叉樹演算法
時 間:2008/11/08
源 碼:BmpConverter.rar
1.位元影像格式
位元影像檔案主要分為4個部分組成:檔案頭,資訊頭,調色盤,映像資料。
1.) 檔案頭
結構定義如下:
typedef struct tagBITMAPFILEHEADER
{
WORD bfType ; // 檔案類型,必須為 BM .
DWORD bfSize ; // 整個檔案的位元組大小
WORD bfReserved1 ; // 保留,為0
WORD bfReserved2 ; // 保留,為0
DWORD bfOffBits ; // 映像資料在檔案中相對頭結構的位移位元組數.
}BITMAPFILEHEADER ;
2.) 資訊頭 ;
結構定義如下:
typedef struct tagBITMAPINFOHEADER
{
DWORD biSize; // 結構大小
LONG biWidth; // 映像寬度(像素)
LONG biHeight; // 映像高度(像素)
WORD biPlanes; // 圖象位平面數目,必須為1
WORD biBitCount // 每像素的位元(1,4,8,24)
DWORD biCompression; // 壓縮類型
DWORD biSizeImage; // 壓縮圖象大小的位元組值
LONG biXPelsPerMeter; // 水平解析度
LONG biYPelsPerMeter; // 垂直解析度
DWORD biClrUsed; // 使用的顏色數目
DWORD biClrImportant; // 重要顏色數目
} BITMAPINFOHEADER;
3.) 調色盤
每個調色盤元素的結構體定義如下:
typedef struct tagRGBQUAD
{
BYTE rgbBlue;
BYTE rgbGreen;
BYTE rgbRed;
BYTE rgbReserved;
} RGBQUAD;
對於高位位元影像,將沒有調色盤存在.
4.) 映像資料
包含實際的映像資料,N位位元影像,每N Bits表示一個像素的值,按從下到上行優先儲存,同時每行按4位元組對齊.
5.) 讀取位元影像檔案
開啟檔案 :
FILE * fBmp = _tfopen(fileName,_T("rb"));
讀取檔案頭:
BITMAPFILEHEADER FileHeader;
fread(&FileHeader,sizeof(BITMAPFILEHEADER),1,fBmp);
讀取資訊頭:
BITMAPINFOHEADER InfoHeader;
fread(&InfoHeader,sizeof(BITMAPINFOHEADER),1,fBmp);
讀取調色盤(以256色為例,調色盤有256項):
RGBQUAD quard[256] ;
fread(quard,sizeof(RGBQUARD),256,fBmp);
讀取映像資料:
int nDataLen = (((InfoHeader.biWidth*InfoHeader.biBitCount/8) + 3) / 4) * 4 * InfoHeader.biHeight ;
BYTE * pbyDataBuf = new BYTE[ nDataLen ] ;
fseek(fBmp,FileHeader.bfOffBits,SEEK_SET);
fread(pbyDataBuf ,nDataLen ,1,fBmp);
2.八叉樹演算法
使用八叉樹演算法實現真彩色(24Bits)轉256色.要實現此功能,主要就是從真彩色中尋找出最能代表整張映像的256種顏色,建立調色盤.八叉樹就是為了找出這256種顏色.
1.) 建立八叉樹
八叉樹節點的特性就是每個節點最多有8個位元組點,編號為0~7 .
以RGB值建立八叉樹,首先建立根節點(Root),然後分別以RGB的每一位分別組成一個0~7的值,依次插入樹中。以RGB(123,54,78)為例,
以此類推,將所有的RGB值逐層插入到八叉樹中,在每個節點上,記錄所有經過的節點的RGB值的總和,已及RGB顏色個數。八叉樹節點結構如下:
typedef struct tagNode
{
DWORD dwCounter ; // 經過該節點的個數
DWORD dwRedSum ; // R分量的總和
DWORD dwGreenSum ; // G 分量的總和
DWORD dwBlueSum ; // B 分量的總和
BOOL bLeafNode ; // 是否為葉子節點.
tagNode * psChild[8]; // 分別指向該節點編號為0~7的8個子節點.
}SNode ;
插入的過程中,如果節點不存在,則需要建立新的節點,然後增加節點計數以及RGB各分量的總和.當在插入時,發現節點已經存在,且是葉子節點,則停止該顏色後續層數節點的插入。插入完一個顏色之後,如果葉子節點數超過了我們要得到的顏色數(256色需要得到256種顏色),這時候就需要合并一些呀位元組點了,使的葉子節點的個數不超過我們要得到的顏色數。
由于越底層的節點,資料的敏感度越低,所以,我們將從最底層的節點開始合并。按節點計數值小的優先合并策略,將其位元組點的所有RGB分量以及節點計數全部記錄到該節點中,並刪除其所有子節點。依此進行,直到合并後的葉子數符合要求為止。
2.) 提取調色盤
按照上述的步驟插入完所有的顏色之後,便建立起一顆葉子節點不超過256的八叉樹。此時,取出葉子節點中的RGB分量的平均值(分量總和 / 節點計數),即是得到的調色盤顏色值。
3.) 匹配調色盤索引
所謂匹配調色盤索引,就是根據原始的RGB值,在調色盤中尋找出最接近的顏色的索引。對每個RGB顏色,分別對調色盤資料求各分量的差值的平方和,求的的最小值對應的調色盤顏色的索引,即是該RGB顏色匹配到的調色盤索引。