【转】彩色图像转换成灰度图像

图像处理中,大部分的处理方法都需要事先把彩色图像转换成灰度图像才能进行相关的计算、识别。
彩色图转换灰度图的原理如下:
我们知道彩色位图是由R/G/B三个分量组成,其文件存储格式为
BITMAPFILEHEADER+BITMAPINFOHEADER,紧跟后面的可能是:
如果是24位真彩图,则每个点是由三个字节分别表示R/G/B,所以这里直接跟着图像的色彩信息;
如果是8位(256色),4位(16色),1位(单色)图,则紧跟后面的是调色板数据,一个RGBQUAD类型的数组,其长度由BITMAPINFOHEADER.biClrUsed来决定。
然后后面紧跟的才是图像数据(24位图是真实的图像数据,其他的则是调色板的索引数据)。
灰度图是指只含亮度信息,不含色彩信息的图象,就象我们平时看到的黑白照片:亮度由暗到明,变化是连续的。因此,要表示灰度图,就需要把亮度值进行 量化。通常划分成0到255共256个级别,其中0最暗(全黑),255最亮(全白)。在表示颜色的方法中,除了RGB外,还有一种叫YUV的表示方法, 应用也很多。电视信号中用的就是一种类似于YUV的颜色表示方法。在这种表示方法中,Y分量的物理含义就是亮度,Y分量包含了灰度图的所有信息,只用Y分 量就能完全能够表示出一幅灰度图来。
从 RGB 到 YUV 空间的 Y 转换公式为:
Y = 0.299R+0.587G+0.114B
在 WINDOWS 中,表示 16 位以上的图和以下的图有点不同; 16 位以下的图使用一个调色板来表示选择具体的颜色,调色板的每个单元是 4 个字节,其中一个透明度;而具体的像素值存储的是索引,分别是 1 、 2 、 4 、 8 位。 16 位以上的图直接使用像素表示颜色。
那么如何将彩色图转换为灰度图呢?
灰度图中有调色板,首先需要确定调色板的具体颜色取值。我们前面提到了,灰度图的三个分量相等。
当转换为 8 位的时候,调色板中有 256 个颜色,每个正好从 0 到 255 个,三个分量都相等。
当转换为 4 位的时候,调色板中 16 个颜色,等间隔平分 255 个颜色值,三个分量都相等。
当转换为 2 位的时候,调色板中 4 个颜色,等间隔平分 255 个颜色,三个分量相等。
当转换为 1 位的时候,调色板中两个颜色,是 0 和 255 ,表示黑和白。
将彩色转换为灰度时候,按照公式计算出对应的值,该值实际上是亮度的级别;亮度从 0 到 255 ;由于不同的位有不同的亮度级别,所以 Y 的具体取值如下:
Y = Y/ (1<<(8- 转换的位数 ));
所以,我们要转化成灰度图,并且存储成一幅可以看到的图像,需要做如下转换:
16位以上的图像不带调色板,只需要把图像数据按每个点的位数都转换成相同的灰度值即可
16位以下的图像,则需要修改调色板的数值,并且按照每个点所占位数修改灰度值索引即可。

 

这个程序实现将彩色图像转换为灰度图像。

彩色转换为灰度使用如下公式:

Gray = R * 0.299 + G * 0.587 + B * 0.114
为了提高运算速度,将这个公式转换为整数运算:
Gray = (R * 229 + G * 587 + B * 114 + 500) / 1000
为了提高运算速度的方法还有很多,这里作为演示,不再详述。 完整代码如下:
/////////////////////////////////////////////////////////
// 程序名称:彩色图片转换为灰阶图片
// 编译环境:Visual C++ 6.0 / 2010,EasyX 20130322(beta)
// 作    者:krissi <zh@easyx.cn>
// 最后修改:2013-1-19
//
#include <graphics.h>
#include <conio.h>

// 彩色图像转换为灰度图像
void  ColorToGray(IMAGE *pimg)
{
    DWORD *p = GetImageBuffer(pimg);
    COLORREF c;

    // 逐个像素点读取计算
    for(int i = pimg->getwidth() * pimg->getheight() - 1; i >= 0; i--)
    {
        c = BGR(p[i]);
        c = (GetRValue(c) * 299 + GetGValue(c) * 587 + GetBValue(c) * 114 + 500) / 1000;
        p[i] = RGB(c, c, c);    // 由于是灰度值,无需再执行 BGR 转换
    }
}

// 主函数
void main()
{
    // 初始化绘图环境
    initgraph(640, 480);

    // 获取图像
    IMAGE img;
    loadimage(&img, _T("c:\\test.jpg"));

    // 显示原始图像
    putimage(0, 0, &img);

    // 按任意键转换为灰度图像
    getch();

    // 处理图像为灰度
    ColorToGray(&img);

    // 显示处理后的图像
    putimage(0, 0, &img);

    // 关闭绘图环境
    getch();
    closegraph();
}