关闭

BMP真彩色转256色

415人阅读 评论(0) 收藏 举报
分类:

原文链接:http://pyhcx.blog.51cto.com/713166/144126/


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         //
每像素的位数(14824

       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~78个子节点.

   }SNode ;
  
插入的过程中,如果节点不存在,则需要创建新的节点,然后增加节点计数以及RGB各分量的总和.当在插入时,发现节点已经存在,且是叶子节点,则停止该颜色后续层数节点的插入。插入完一个颜色之后,如果叶子节点数超过了我们要得到的颜色数(256色需要得到256种颜色),这时候就需要合并一些呀字节点了,使的叶子节点的个数不超过我们要得到的颜色数。

  
由于越底层的节点,数据的敏感度越低,所以,我们将从最底层的节点开始合并。按节点计数值小的优先合并策略,将其字节点的所有RGB分量以及节点计数全部记录到该节点中,并删除其所有子节点。依此进行,直到合并后的叶子数符合要求为止。

2.)
提取调色板

  
按照上述的步骤插入完所有的颜色之后,便建立起一颗叶子节点不超过256的八叉树。此时,取出叶子节点中的RGB分量的平均值(分量总和 / 节点计数),即是得到的调色板颜色值。
3.)
匹配调色板索引

  
所谓匹配调色板索引,就是根据原始的RGB值,在调色板中查找出最接近的颜色的索引。对每个RGB颜色,分别对调色板数据求各分量的差值的平方和,求的的最小值对应的调色板颜色的索引,即是该RGB颜色匹配到的调色板索引

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:96041次
    • 积分:1313
    • 等级:
    • 排名:千里之外
    • 原创:19篇
    • 转载:122篇
    • 译文:0篇
    • 评论:5条
    最新评论