第 3 章 数字图像的运算 .. 3.1 点 运 算 点运算(PointOperation)是指对一幅图像中部分像素点的灰度值进行计 算。它将输入图像映射为输出图像,输出图像中每个像素点的灰度值仅由对应 的输入像素点的灰度值决定,运算结果不会改变图像内像素点之间的空间关 系。设输入图像在坐标(x,y)处的灰度值为f(x,y),输出图像在坐标(x,y)处 的灰度值为g(x,y),则点运算为 g(x,y)=T[f(x,y)] (3-1) 其中,T 是对f(x,y)的一种数学运算,即点运算是一种像素的逐点运算, 是灰度到灰度的映射过程,通常称T 为灰度变换函数。 点运算又称为“对比度增强”“对比度拉伸”“灰度变换”等。按灰度变换函 数T 的性质,可将点运算分为以下两类。 (1)灰度变换增强,又包括线性灰度变换(线性点运算)、分段线性灰度变换 (分段线性点运算)、非线性灰度变换(非线性点运算)。 (2)直方图增强。 灰度变换是图像增强的重要手段之一,用于改善图像显示效果,属于空间 域处理方法,它可以使图像的动态范围加大,图像的对比度扩展,图像更加清 晰,特征更加明显。灰度变换的实质是按一定的规则修改图像每个像素的灰 度,从而改变图像的灰度范围。 下面给出了灰度值增加的C++代码,点运算示例如图3-1所示,其中,显示 的示例图为每个像素增加给定的灰度值的效果。 C++示例代码3-1:灰度值增加 /* 将图像中的每个像素的蓝、绿、红3 个分量的灰度值分别加上blue、green、red,以增 强图像的亮度。注意:若灰度值增加后超过255,则直接取255。 */ void CFgImage::Add(int blue,int green,int red){ for (int row = 0; row < m_height; row++){ for (int col = 0; col < m_width; col++){ 第3章 数字图像的运算 65 BYTE* p = m_pBmpBuf + (m_height-row-1)*m_widthStep + col * 3; BGR bgr; bgr.Blue = *p; bgr.Green = *(p + 1); bgr.Red = *(p + 2); if (bgr.Blue + blue>=255) *p = 255; else *p = (bgr.Blue + blue); if (bgr.Green + green >= 255) *(p + 1) = 255; else *(p + 1) = (bgr.Green + green); if (bgr.Red + red >= 255) *(p + 2) = 255; else *(p + 2) = (bgr.Red + red); } } } 图3-1 点运算示例 3.1.1 线性灰度变换 线性灰度变换又称为线性点运算,主要有对比度增强等。假定原图像f(x,y)的灰 度范围为[a,b],若希望变换后的图像g(x,y)的灰度范围扩展为[c,d],则其函数表现形 式如式(3-2)所示。线性灰度变换如图3-2所示。 66 数字图像处理系列教程———基础知识篇 g(x,y)=d -c b-a[f(x,y)-a]+c (3-2) 图3-2 线性灰度变换 下面给出了线性灰度变换的C++代码实现,图3-3为线性灰度变换示例。 C++示例代码3-2:线性灰度变换 void CFgImage::GrayTrans1(double a, double b, double c, double d) { struct TranFunc{ double a, b, c, d; TranFunc(double a, double b, double c, double d) :a(a), b(b), c(c), d(d){ } BYTE func(int gray){ double val = (d - c) * (gray - a) / (b - a) + c; return saturate_cast(val); } BGR operator()(BYTE Blue, BYTE Green, BYTE Red){ BGR bgr; bgr.Blue = func(Blue); bgr.Green = func(Green); bgr.Red = func(Red); return bgr; } }; GrayTrans(TranFunc(a, b, c, d)); } template void CFgImage::GrayTrans(Func& func) { for (int row = 0; row < m_height; row++){ for (int col = 0; col < m_width; col++){ BYTE* p = m_pBmpBuf + row * m_widthStep + col * 3; 第3章 数字图像的运算 67 BGR bgr = func(*p, *(p + 1), *(p + 2)); *p = bgr.Blue; *(p + 1) = bgr.Green; *(p + 2) = bgr.Red; } } } 图3-3 线性灰度变换示例 3.1.2 分段线性灰度变换 为了突出图像中用户感兴趣的目标或者灰度区间,相对抑制那些用户不感兴趣的灰 度区域而不牺牲其他灰度级上的细节,可以采用分段线性灰度变换,它可将需要的图像细 节灰度拉伸,增强对比度,而将不需要的细节灰度级压缩。 分段线性灰度变换是将输入图像f(x,y)的灰度级区间分成两段乃至多段,然后分 别对每一段做线性灰度变换,以获得增强图像g(x,y)。典型的3段线性灰度变换如 图3-4所示,其函数表达形式如下。 g(x,y)= c af(x,y) 01时,幂次变换可以扩展原始图像的中、高灰度级,压缩低灰度级,从而使 得图像变暗,增强原始图像中亮区的细节。 幂次变换常用于图像获取、打印和显示的各种转换设备的伽马校正中,这些设备的光 电转换特性都是非线性的,是根据幂次规律产生响应。幂次变换的指数即伽马值,因此幂 次变换也称为伽马变换。 下面给出了幂次变换的C++代码实现,图3-11为幂次变换示例。 C++示例代码3-6:幂次变换 void CFgImage::GrayTrans5(double c, double gamma) { struct TranFunc{ double c, gamma; TranFunc(double c, double gamma) :c(c), gamma(gamma){ } BYTE func(int gray){ double val = c * std::pow(gray, gamma); return saturate_cast(val); } BGR operator()(BYTE Blue, BYTE Green, BYTE Red){ BGR bgr; bgr.Blue = func(Blue); bgr.Green = func(Green); bgr.Red = func(Red); return bgr; } };