3.2 灰度的线性变换
3.2.1 理论基础
线性灰度变换函数f(x)是一个一维线性函数。
式中,参数fA为线性函数的斜率,fB为线性函数在y轴的截距,DA表示输入图像的灰度,DB表示输出图像的灰度。
• 当fA>1时,输出图像的对比度将增大;当fA<1时,输出图像的对比度将减小。
• 当fA=1且fB≠0时,操作仅使所有的像素的灰度值上移或下移,其效果是使整个图像更暗或更亮;如fA<0,暗区域将变亮,亮区域将变暗。这种线性改变亮度的变换可能由于像素亮度达到饱和(小于0或超过255)从而丢失一部分细节。
• 特殊情况下,当fA=1, fB=0时,输出图像与输入图像相同;当fA=-1, fB=255时,输出图像的灰度正好反转。灰度反转处理适用于增强暗色图像中的亮度较大的细节部分,这也是由人的视觉特性决定的。
线性变换的示意图如图3.6所示。
图3.6 线性变换示意图
稍后的MATLAB实现中将分别给出对应于上述这些情况的变换实例。
3.2.2 MATLAB程序的实现
使用MATLAB对图像执行线性变换无需专门的函数,下面的程序对MATLAB示例图像coins.jpg进行了不同参数的线性变换操作。其编程代码如下。
I = imread('coins.png'); % 读入原图像 I = im2double(I); % 转换数据类型为double [M, N] = size(I); % 计算图像面积 figure(1); % 打开新窗口 imshow(I); % 显示原图像 title(’原图像’); figure(2); % 打开新窗口 [H, x] = imhist(I, 64); % 计算64个小区间的灰度直方图 stem(x, (H/M/N), '.'); % 显示原图像的直方图 title(’原图像’); % 增加对比度 Fa = 2; Fb = -55; O = Fa .* I + Fb/255; figure(3); subplot(2,2,1); imshow(O); title('Fa = 2 Fb = -55 增加对比度’); figure(4); subplot(2,2,1); [H, x] = imhist(O, 64); stem(x, (H/M/N), '.'); title('Fa = 2 Fb = -55 增加对比度’); % 减小对比度 Fa = 0.5; Fb = -55; O = Fa .* I + Fb/255; figure(3); subplot(2,2,2); imshow(O); title('Fa = 0.5 Fb = -55 减小对比度’); figure(4); subplot(2,2,2); [H, x] = imhist(O, 64); stem(x, (H/M/N), '.'); title('Fa = 0.5 Fb = -55 减小对比度’); % 线性增加亮度 Fa = 1; Fb = 55; O = Fa .* I + Fb/255; figure(3); subplot(2,2,3); imshow(O); title('Fa = 1 Fb = 55 线性平移增加亮度’); figure(4); subplot(2,2,3); [H, x] = imhist(O, 64); stem(x, (H/M/N), '.'); title('Fa = 1 Fb = 55 线性平移增加亮度’); % 反相显示 Fa = -1; Fb = 255; O = Fa .* I + Fb/255; figure(3); subplot(2,2,4); imshow(O); title('Fa = -1 Fb = 255 反相显示’); figure(4); subplot(2,2,4); [H, x] = imhist(O, 64); stem(x, (H/M/N), '.'); title('Fa = -1 Fb = 255 反相显示’);
上述程序存放在c3s1.m文件中,其运行结果如图3.7所示。
图3.7 线性变换实例说明
图3.7 线性变换实例说明(续)
从图3.7可以看出:改变图像的对比度是对直方图的缩放与平移,改变图像的亮度则只是平移直方图在横轴上的位置,而反相则是将直方图水平镜像。
单纯的线性灰度变换可以在一定程度上解决视觉上的图像整体对比度问题,但是对图像细节部分的增强则较为有限,结合后面将要介绍的非线性变换技术可以解决这一问题。
3.2.3 Visual C++实现
使用Visual C++实现线性变换的代码如下。
/************************************************** BOOL CImgProcess::LinTran(CImgProcess* pTo, double dFa, double dFb) 功能: 图像的线性变换方法 参数: CImgProcess * pTo:输出CImgProcess对象的指针 double dFa:线性变换斜率 double dFb:线性变换截距 返回值: BOOL类型,true为成功,false为失败 ***************************************************/ BOOL CImgProcess::LinTran(CImgProcess* pTo, double dFa, double dFb) { // 首先检查图像是否是8位灰度图像 if (m_pBMIH->biBitCount! =8) return false; BYTE gray; // 临时变量,存储当前光标像素的灰度值 int target; // 临时变量,存储当前光标像素的目标值 for (int i=0; i<m_pBMIH->biHeight; i++) { for (int j=0; j<m_pBMIH->biWidth; j++) { gray = GetGray(j, i); target = dFa * gray + dFb; if (target < 0) target = 0; if (target > 255) target = 255; // 写入目标图像 pTo->SetPixel(j, i, RGB(target, target, target)); } }; return true; }
利用LinTran()函数实现灰度线性变换的完整示例被封装在DIPDemo工程中的视图类函数void CDIPDemoView::OnPointLiner()中,其中调用LinTran()函数的代码片断如下所示。
// 输出的临时对象 CImgProcess imgOutput = imgInput; // 调用LinTran()函数进行线性变换 imgInput.LinTran(&imgOutput, fA, fB); // 其中fA和fB为线性变换的斜率和截距 // 将结果返回给文档类 pDoc->m_Image = imgOutput;
上述程序运行时会弹出对话框,要求用户设置线性变换参数。读者可以通过光盘中示例程序DIPDemo中的菜单命令“点运算→线性变换”来观察处理效果。