灰度位图的定义和转换

    袁智勇 刘文林

    摘? 要:该文首先介绍了灰度位图的背景知识,包括灰度位图的定义、特点、应用范围。接着介绍了全彩色和灰度色彩转换的算法。最后演示了基于GDI+的,将全彩色位图转换为灰度位图的核心代码。该代码使用了GDI+的Bitmap类,并通过其成员函数ConvertFormat进行位图格式转换。特点是代码高度简单,程序员无须了解位图格式转换,颜色转换等的细节,大大降低了编码难度和复杂度。

    关键词:灰度位图;转换;GDI+

    中图分类号:TP391? ? ? ? ? ? ? 文献标志码:A

    0 引言

    网上关于灰度位图(grayscale bitmap)的介绍虽然不少,但大多数都只是触及点皮毛,没有交代清楚其原理,使初学者一知半解。该文对灰度位图做了一个原理性的介绍,使初学者彻底弄明白灰度图像的原理。同样的,网上关于彩色图像转换为灰度图像的代码也很多,但过于烦琐,该文也介绍了1种简便的转换方法。

    1 灰度位图的定义

    顾名思义,灰度位图的所有像素都是灰色的。灰色是一类特殊的颜色,其R(红色),G(绿色),B(蓝色)三原色分量的值都是一样的。如果以(R,G,B)的格式表示颜色,那么(0,0,0),(1,1,1),(2,2,2),……,(254,254,254),(255,255,255),总共256种颜色都是灰色。全0的黑色和全255的白色都是灰色的特例,其中黑色最暗,白色最亮。R,G,B三原色分量的大小代表了三原色的亮度,因此各种灰色的差别在于其亮度不同。

    因为颜色仅限于256种灰色(这256种灰色构成灰度位图的颜色表),为了减少存储空间,灰度位图统一使用索引位图的格式来存储。也就是说,灰度位图的像素值不是直接存储为24 bit的(R,G,B)颜色,而是存储为颜色表的索引号。例如如果某个灰度位图的像素值是1,那么它对应的实际颜色是颜色表中编号为1的颜色,也就是(1,1,1)。可以看出,索引号同时代表了对应灰度颜色的亮度。例如,当索引号为0时,对应的颜色是黑色(0,0,0),亮度为0;当索引号为255时,对应的颜色时白色(255,255,255),亮度为255。表达256种索引号只需8 bit(1字节)数据,而直接表达(R,G,B)颜色需要24 bit(3字节)数据,所以使用索引位图格式能大大节省存储空间。

    将有16 777 216(224)种颜色的24 bit全彩色位图转换为只有256(28)种灰色的灰度位图无疑会丢失图像的细节,尽管如此,灰度位图的应用却非常广泛。

    首先,这种转换能将彩色图像转换为黑白图像,这是一种非常有用的特效。

    其次,这种转换在丢失细节的同时,往往能使图像中物体的轮廓变得更明显。就像黑白证件照的底片,虽然细节很模糊,但人物的轮廓却很明显。这使得灰度位图在文字识别、图像识别中得到了广泛的应用。

    2 颜色转换

    将24bit全彩色位图转换为8bit灰色位图的原则是将彩色转换为与之最接近的灰色。关于什么是最接近,在不同的场合下,解读是不同的。对于灰度图像转换,我们是依据全彩色图像的亮度,将其转换为同等亮度的灰度颜色。其公式为:

    I= R× 0.299 + G×0.587 + B×0.114 ? ? ? ? ? ? ? (1)

    I代表索引号。前面提到过,索引号同时代表了对应灰度颜色的亮度。所以上面的公式实际上按照全彩色R、G、B颜色分量的亮度,将其映射到对应亮度的灰度颜色。0.299、0.587 、0.114分别代表了R、G、B颜色分量的权重。可以看出,绿色分量的权重最大,这是因为人类对绿色亮度的变化更敏感。

    3 关于GDI+

    GDI+是微软针对传统的GDI(Graphic Device Interface,图形设备界面)技术的改进。和GDI不同,GDI+的编程接口是面向对象的,将底层代码封装于各种类中,这使得编程难度大大降低。其次,在图像格式转换、图像变换等方面引入了很多新的类成员函数,程序员简单调用这些函数就可以完成以前通过GDI无法直接完成的工作。

    举个例子,在GDI+中位图被封装为Bitmap类,以下C++代码可以读取硬盘上的位图文件test.bmp(假定其为24 bit全彩色位图),轻松构造一个Bitmap类:

    Bitmap bmp=new Bitmap(L”C:\\test.bmp”);

    下一步,我们可以通过Bitmap的类成员函数操作test.bmp,例如将其转换为灰度位图。对应的函数如下:

    ConvertFormat(PixelFormat format,

    DitherType dithertype,PaletteType palettetype,

    ColorPalette *palette,REAL alphaThresholdPercent);

    format参数指定转换后的位图的格式,须设置为PixelFormat8bppIndexed(8bit索引位图)。

    dithertype参数指定抖动颜色采用的方法,须设置为DitherTypeSolid(抖动到实体颜色)。

    palettetype参数指定灰度位图使用的颜色表(在GDI+中称为调色板)的类型,须设置为PaletteTypeCustom(自定义调色板)。

    palette为指向灰度位图的颜色表数据结构指针,调用这个函数的关键一步是构造颜色表。如何构造灰度图像的颜色表请参考下一节中的核心代码。

    alphaThresholdPercent参数和像素透明化处理有关,一般转换不涉及像素透明化处理,须设置为0。

    4 核心代码

    代码使用visual C++开发,因为仅为演示代码,其他不重要的代码都已经略去。

    void GrayScale(Bitmap* bmp){

    void* p=malloc(sizeof(Gdiplus::ColorPalette)+255*sizeof(ARGB));

    Gdiplus::ColorPalette*cpal=(Gdiplus::ColorPalette*)p;

    for(int i=0;iEntries[i]=Color::MakeARGB(0,i,i,i);//構造颜色表

    cpal->Flags=PaletteFlagsGrayScale;

    cpal->Count=256;

    bmp->ConvertFormat(PixelFormat8bppIndexed,DitherTypeSolid,PaletteTypeCustom,cpal,0);

    free(p);}

    颜色表数据结构包含2个部分:头和数据。头部有2个字段Flags和Count。Flags设置为PaletteFlagsGrayScale,表示颜色表是灰度位图颜色表。Count设置为256,表示有256中灰度颜色。数据部分是256种灰度颜色,从(0,0,0)一直到(255,255,255)。要注意的是,在标准颜色表中,每种颜色占用32 bit空间,所以要通过宏MakeARGB扩充到32 bit。

    5 结语

    通过GDI+将全彩色图像转化为灰度图像是非常简单的,无须和位图格式细节打交道,也无须直接用公式进行色彩转换,非常简便高效。

    参考文献

    [1]周鸣扬,赵景亮.精通GDI+编程[M].北京:清华大学出版社,2004.

    [2]Ivor Horton.Visual C++2010入门经典(第5版)[M].北京:清华大学出版社,2010.