数字图像处理与机器视觉:Visual C++与Matlab实现(第2版)
上QQ阅读APP看书,第一时间看更新

3.3 灰度对数变换

本节介绍一种灰度的非线性变换——对数变换,并介绍它在傅里叶频谱显示中的应用。

3.3.1 理论基础

对数变换的一般表达式如下。

其中,c为尺度比例常数,s为源灰度值,t为变换后的目标灰度值。

在如图3.8所示的对数曲线上,函数自变量为低值时,曲线的斜率很高;自变量为高值时,曲线斜率变小。

图3.8 对数变换示意图

由对数函数曲线可知,这种变换可以增强一幅图像中较暗部分的细节,从而可用来扩展被压缩的高值图像中的较暗像素,因此对数变换被广泛地应用于频谱图像的显示中。一个典型的应用是傅里叶频谱(参见第6章),其动态范围可能宽达0~106。直接显示频谱时,图像显示设备的动态范围往往不能满足要求,从而丢失了大量的暗部细节。而在使用对数变换之后,图像的动态范围被合理地非线性压缩,从而可以清晰地显示。本节的MATLAB实现中就提供了一个这样的示例。

3.3.2 MATLAB实现

对数变换不需要专门的图像处理函数,可以使用如下数学函数实现对图像I的对数变换。

      T = log(I + 1);

注意

log函数会对输入图像矩阵I中的每个元素进行操作,但是却仅能处理double类型的矩阵。从图像文件中得到的图像矩阵则大多数是uint8类型的,因此需要首先使用im2double函数来执行数据类型的转换。

下面的程序比较了对傅里叶频谱图像进行对数变换前后的效果(不必关注代码中生成傅里叶频谱的部分)。结果如图3.9所示。

      I=imread('coins.png');          % 读取图像
      F = fft2(im2double(I));         % 计算频谱
      F = fftshift(F);
      F = abs(F);
      T  = log(F + 1);                % 对数变换

      subplot(1,2,1);
      imshow(F, []);
      title(’未经变换的频谱’);

      subplot(1,2,2);
      imshow(T, []);
      title(’对数变换后’);          % 显示原图和变换结果

图3.9 对数变换效果示意图

在图3.5(a)中未经变换的频谱可见,图像中心绝对高灰度值的存在压缩了低灰度部分的动态范围,从而无法在显示时表现出细节;而经过对数灰度处理的图像,其低灰度区域对比度将会增加,暗部细节被增强。

3.3.3 Visual C++实现

利用Visual C++实现灰度对数变换的代码如下。

      /**************************************************
      BOOL CImgProcess::LogTran(CImgProcess* pTo, double dC)
      功能:      图像的灰度对数变换
      参数:     CImgProcess * pTo:输出CImgProcess对象的指针
                double dC:灰度对数变换所需的参数
      返回值:    BOOL类型,0为成功,其他值为失败
      ***************************************************/
      BOOL CImgProcess::LogTran(CImgProcess* pTo, double dC)
      {
        // 首先检查图像是否是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 = dC * log( (double)(gray + 1) );

                if (target < 0) target = 0;
                if (target > 255) target = 255;

                // 写入目标图像
                pTo->SetPixel(j, i, RGB(target, target, target));
            }
        };

        return 0;
      }

利用LogTran()函数实现对数变换的完整示例被封装在DIPDemo工程中的视图类函数void CDIPDemoView::OnPointLog()中,其中调用LogTran()函数的代码片断如下所示。

      // 输出的临时对象
        CImgProcess imgOutput = imgInput;

        // 使用对数变换方法
        imgInput.LogTran(&imgOutput, dlg.m_dC);
      // 其中dlg.m_dC是对数变换的系数

        // 将结果返回给文档类
        pDoc->m_Image = imgOutput;

上述程序运行时会弹出对话框要求用户设置对数变换参数。读者可以通过光盘中示例程序DIPDemo中的菜单命令“点运算→对数变换”来观察处理效果。