数字图像处理的Matlab实现(3)—灰度变换与空间滤波
第3章 灰度变换与空间滤波(1)
3.1 简介
空间域指的是图像平面本身,这类方法是以对图像像素直接处理为基础的。本章主要讨论两种空间域处理方法:亮度(灰度)变换与空间滤波。后一种方法有时涉及到邻域处理或空间卷积。
本章讨论的空间域处理由下列表达式表示:
\[g(x,y)=T[f(x,y)]
\]
其中,\(f(x,y)\)为输入图像,\(g(x,y)\)为输出图像, \(T\)是对图像\(f\)的算子,作用于点\((x,y)\)定义的邻域。此外,\(T\)还可以对一组图像进行处理,例如为了降低噪声而叠加\(K\)幅图像。
为了定义点\((x,y)\)的空间邻域,主要方法是利用一块中心位于\((x,y)\)的正方形或矩形区域。此区域的中心由起始点开始逐个像素移动,比如从左上角,在移动的同时包含不同的邻域。算子\(T\)作用于每个位置\((x,y)\),从而得到相应位置的输出图像\(g\)。只有中心点在\((x,y)\)处的邻域内的像素被用来计算\((x,y)\)处\(g\)的值。
3.2 灰度变换函数
变换函数\(T\)的最简单形式是邻域大小为1*1(单个像素)的情况。在此情况下,在\((x,y)\)处,\(g\)的值仅由\(f\)在这一点处的灰度决定,\(T\)也就成为亮度或灰度变换函数。当处理单色(也就是灰度)图像时,这两个术语是可以相互换用的。当处理彩色图像时,亮度用来表示在特定色彩空间里的彩色图像成分。
由于输出值仅取决于点的灰度值,而不是取决于点的邻域,因此灰度变换函数通常写成:$$s=T(r)$$其中,\(r\)表示图像\(f\)的灰度,\(s\)表示\(g\)的灰度。两者在图像中处于相同的坐标\((x,y)\)处。
3.2.1 imadjust和stretchlim函数
imadjust函数是针对灰度图像进行灰度变换的基本图像处理工具箱函数,一般的语法格式为:
g=imadjust(f,[low_in high_in],[low_out high_out],gamma)
如上图所示,此函数将\(f\)的灰度值映射到\(g\)中的新值,将low_in与high_in之间的值映射到low_out和high_out之间。low_in以下与high_in以上的值被截去。其实就是将 low_in以下的值映射为low_out;将high_in以上的值映射为high_out。输入图像应属于uint8、uint16或double类。输出图像应和输入图像属于同一类。对于函数imadjust来说,所有输入中除了图像\(f\)和gamma,不论\(f\)属于什么类,都将输入值限定在0和1之间。例如,如果\(f\)属于uint8类,imadjust函数将乘以255来决定应用中的实际值。利用空矩阵([])得到[low_in high_in]或[low_out high_out],将导致结果默认为[0 1]。如果high_out小于low_out,输出灰度将反转。
参数gamma指明了由\(f\)映射生成图像\(g\)时曲线的形状。如果gamma的值小于1,映射被加权至较高的输出值,如图3.2a。如果gamma的值大于1,映射加权至较低的输出值,如图3.2c。如果省略函数参量,gamma默认为1(线性映射)
案例3.1 使用imadjust函数
f=imread('Fig0203(a).tif');
g1=imadjust(f,[0 1],[1 0]);
g2=imadjust(f,[0.5 0.75],[0 1]);
g3=imadjust(f,[],[],2);
g4=imadjust(f,stretchlim(f),[]);
g5=imadjust(f,stretchlim(f),[1 0]);
subplot(231);imshow(f);xlabel('(a)');
subplot(232);imshow(g1);xlabel('(b)');
subplot(233);imshow(g2);xlabel('(c)');
subplot(234);imshow(g3);xlabel('(d)');
subplot(235);imshow(g4);xlabel('(e)');
subplot(236);imshow(g5);xlabel('(f)');
上图中,(a)是一幅数字乳房X射线图像f,显示出一处病灶;(b)是负片图像,可以通过下列命令得到:
g1=imadjust(f,[0 1],[1 0]);
获得照片负片图像的这一过程对于增强在一大片主要的黑色区域中嵌入白色及灰色细节是非常有用的,图(b)非常容易分析胸部的组织,图像的负片也可以使用工具箱函数imcomplement得到: g=imcomplement(f);图(c)是下列命令得到的结果:
g2=imadjust(f,[0.5 0.75],[0 1]);
此命令是将0.5到0.75之间的灰度扩展到[0,1]整个范围。这种类型的处理对于处理强调图像中感兴趣的灰度区非常有用;最后利用:
g3=imadjust(f,[],[],2);
通过压缩灰度图像的低端和扩展高端,得到类似于图(d)的结果;有时能够用imadjust函数自动地而不必关心上面讨论的低高参数的处理。stretchlim函数在这个方面非常有用,基本语法如下:
Low_high=stretchlim(f)
其中,Low_high是低和高均受限的两元素向量,可用于完成对比度拉伸。默认情况下,Low_high的值指定灰度图像f中所有像素值底部和顶部饱和度的1%。结果以向量[low_in high_in]的形式应用于imadjust函数:
g4=imadjust(f,stretchlim(f),[]);
图(e)显示了上述命令得到的结果,观察对比度的提升。与此类似,使用如下命令得到图(f):
g5=imadjust(f,stretchlim(f),[1 0]);
可以看到,增强了负片图像的对比度。
stretchlim函数的通用语法如下:
Low_high=stretchlim(f,tol)
其中,tol是两元素向量[low_frac high_frac],指定了图像低和高像素值饱和度的百分比。
如果tol是标量,那么low_fac=tol,并且high_frac=1-low_frac;饱和度等于低像素值和高像素值的百分比。如果在参数中忽略tol,那么饱和度水平为2%,tol的默认值为[0.01 0.99]。如果选择tol=0,那么Low_high=[min(f(😃) max(f(😃)]。
3.2.2 对数及对比度扩展变换
对数及对比度扩展变换是动态范围处理的基本工具,对数变换通过下列表达式实现:
g=c*log(1+(f))
其中,c是常数,f是浮点数。这个变换的形状与图3.2(a)中的gamma曲线蕾丝。在两个标量值中,低值置为0,高值置为1。然而,gamma曲线是可变的,对数函数的形状是固定的。
对数变换的一项主要应用是压缩动态范围,例如,傅立叶频谱的范围在[0,10^6] 或更高范围是常见的,当监视器显示范围线性地显示为8位时,高值部分较占优势,从而导致频谱中低灰度值的细节部分丢失。而通过计算对数,假设动态范围是\(10^6\),而后大约被降至\(log_e(10^6)=13.8\),这样就更易于处理。
当执行对数变换时,通常期望将导致的压缩值还原为显示的全范围。对8比特而言,在MATLAB中最简易的办法是:
gs=im2uint8(mat2gray(g));
使用mat2gray将值限定在[0,1]范围内,使用im2uint8将值限定在[0,255]范围内,图像也转化为uint8类。
案例3.2 利用对数变换减小动态范围
f=imread('Fig0205(a).tif');
g=im2uint8(mat2gray(log(1+double(f))));
subplot(1,2,1);imshow(f);xlabel('(a)');
subplot(1,2,2);imshow(g);xlabel('(b)');
3.2.3 针对灰度变换的某些公用M函数
1.处理可变数目的输入和输出
为检测输入到M函数的参量数目,利用nargin函数:
n=nargin
该函数将返回输入到M函数的参量的实际数目。类似的,函数nargout用于M函数的输出:
n=nargout
例如,假设我们在提示符处执行如下M函数:
>>T=testhv(4,5)
该函数体使用nargin返回2,使用nargout返回1。
函数nargchk可用于一个M函数体中,以检测传递的参量数目是否正确。语法为:
msg=nargchk(low,high,number)
该函数在number小于low时,返回消息Not enough input parameters;在number大于high时,返回消息Too many input parameters。若number 介于low与high之间,则函数nargchk返回一个空矩阵。若输入参量的数目不正确,则频繁使用函数nargchk可通过函数error来终止程序的执行。实际输入参量的数目由函数nargin决定。
function G=testhv2(x,y,z)
.
.
.
error(nargchk(2,3,nargin));
.
.
.
键入仅有一个输入变量的语句:
>>testhv2(6)
将产生错误消息:
Not enough input arguments
同时执行终止。
通常,写出具有可变数目的输入变量和输出变量的函数是十分有用的。这里,使用变量varargin和变量varargout。varargin和varargout必须使用小写形式:
function [m,n]=testhv3(varargin)
将输入的变量数读取到函数testhv3中,而
function [varargout]=testhv4(m,n,p)
则通过函数 testhv4返回输出的变量数。若函数testhv3有一个固定的输入变量x,后跟输入变量的可变数目,则调用
function [m,n]=testhv3(x,varargin)
函数时,会导致varargin由用户提供的第二个输入变量开始运行。
当varargin用作一个函数的输入变量时,MATLAB会将其置入一个单元数组中,该数组接受由用户输入的变量数。由于varargin是一个单元数组,所以此类配置的一个钟涛方面是对函数的调用可包括输入的混合集。例如,我们要使用假设函数testhv3的代码来处理此项操作,则它能很好地接受输入的混合集:
>>[m,n]=testhv3(f,[0 0.5 1.5],A,'label');
其中,f是一幅图像,下一个变量时是一个长度为3的行向量,A是一个矩阵,'label'是一个字符串。
2. 亮度变换的另一个M函数
在这一节中,我们将开发一个计算如下变换功能的函数:负片变换、对数变换、gamma变换和对比度拉伸变换。选用这些变换是因为随后要用到他们。此外,我们将进一步说明编写亮度变换M函数所涉及的机理。在编写该函数时,我们将用到函数tofloat,其语法为:
[g,revertclass]=tofloat(f)
该函数将Logical、uint8、uint16或int16类的图像转换成single(单精度类),同时应用适当的比例因子。如果f属于double(双精度)或单精度,那么g=f;revertclass是函数句柄,可用于把输出转换为与f相同的类。
在下面名为intrans2的M函数中,要注意函数的选项是如何在代码的帮助中格式化的,输入的变量数是如何处理的,错误检验是如何插入代码的,以及输入图像的类是如何与输出图像的类相匹配的。varavgin是单元数组,因而其中的元素应使用花括号进行选择。
function g=intrans2(f,method,varargin)
%Intras performs intensity (gray-level) transformations
% G=INTRANS(F,'neg') computes the negative of input image F.
% G=INTRANS(F,'log',C,CLASS) computes log(1+F) and multiplies the result
% by constant C. If the last two parameters are ommitted, C defaults to 1.
% Because the log is used frequently to display Fourier spectra, parameter
% CLASS offers the option to specify the class of the output as 'uint8' or
% 'uint16'. If parameter CLASS is ommitted, the output is of thr same class
% as the input
%G=INTRANS(F,'gamma',GAM) performs a gamma transformation on the input
%image using parameter GAM
%G+INTRANS(F,'stretch',M,E) computes a constrast-stretching transformation
%using the expression 1./(1+(M./(F+eps).^E)). Parameter M Must be in the
%range [0,1], The default value for M is mean2(tofloat(F)), and the
%default value for E is 4
%G=INTRANS(F,'specified',TXFUN) performances the intensity transformation
%s=TXFUN(r) where r are input intensities, s are output intensities, and
%TXFUN is an intensity transformation function, expressed as a vector with
%values in the range [0,1]. TXFUN must have at least two values.
%For the 'neg', 'gamma', and 'stretch' transformations, floating-point input images
%whose values are outside the range [0,1] are scaled first using mat2gray.
%Other images are converted to floating point using tofloat. For the 'log'
%transformation, floating-point images are transformed without being scaled;other
%images are converted to floating point first using tofloat
%Verify the correct number of inputs
narginchk(2,4);
if strcmp(method,'log');
%The log transform handles image classes differently than the other
%trnasforms, so let the logTransform function handle that and then
%return.
g=logTransform(f,varargin(:));
return;
end
%if f is floating point, check to see if it is in the range [0 1].
%If it is not, force it to be using function mat2gray.
if isfloat(f) && (max(f(:))>1 || min(f(:))<0)
f=mat2gray(f);
end
[f,revertclass]=tofloat(f);%store class of f for use later.
%Perfor the intensity transformation specified.
switch method
case 'neg'
g=imcomplement(f);
case 'gamma'
g=gammaTransform(f,varargin{:});
case 'stretch'
g=stretchTransform(f,varargin{:});
case 'specified'
g=spcfiedTransform(f,varargin{:});
otherwise
error('unknown enhancement method.')
end
%Convert to the class of the input image.
g=revertclass(g);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [out,revertclass]=tofloat(in)
%Tofloat Convert image to floating point
%[OUT,REVERTCLASS]=TOFLOAT(IN) converts the input image IN to
%floating-point. if IN is a double or single image, then OUT equals IN.
%Othereise, OUT equals im2single(IN). Revertcalss is a function handle that
%can be used to convert back to the class of IN
identity=@(x)x;
tosingle=@im2single;
table={'uint8',tosingle,@im2uint8
'uint16',tosingle,@im2uint16
'int16',tosingle,@im2int16
'logical',tosingle,@logical
'double',identity,identity
'single',identity,identity};
classIndex=find(strcmp(class(in),table(:,1)));
if isempty(classIndex)
error('Unsupported input image calss.');
end
out=table{classIndex,2}(in);
revertclass=table{classIndex,3};
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function g=gammaTransform(f,gamma)
g=imadjust(f,[],[],gamma);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function g=stretchTransform(f,varargin)
if isempty(varargin)
%Use defaults
m=mean2(f);
E=4.0;
elseif length(varargin) == 2
m=varargin{1};
E=varargin{2};
else
error('Incorrect number of inputs for the stretch method.');
end
g=1./(1+(m./f).^E);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function g=spcfiedTransform(f,txfun)
%f is floating point with values in the range [0 1]
txfun=txfun(:);%Force it to be a column vector.
if any(txfun)>1 || any(txfun)<=0
error('All elements of txfun must be in the range [0 1].')
end
T=txfun;
X=Linspace(0,1,numel(T))';
g=interpl(X,T,f);
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function g=logTransform(f,varargin)
[f,revertclass]=tofloat(f);
if numel(varargin)>=2
if strcmp(varargin{2},'uint8')
revertclass=@im2uint8;
elseif strcmp(varargin{2},'uint16')
revertclass=@im2uint16;
else
error('Unsupported CLASS option for ''log'' method.')
end
end
if numel(varargin)<1
% Set default for C.
C=1;
else
C=varargin{1};
end
g=C*(log(1+f));
g=revertclass(g);
案例3.3 函数intrans2的说明
要说明函数intrans2,我们可首先考虑下图(a)中的图像,这是一幅利用对比度拉伸方法增强骨骼结构后的理想图像。利用对intrans2的调用得到增强后的图像,如图(b)所示。
>> f=imread('Fig0306(a).tif');
>> g=intrans2(f,'stretch',mean2(im2double(f)),0.9);
>> subplot(121);imshow(f);subplot(122);imshow(g);
3. 亮度标度的M函数
当处理图像时,像素值域由负到正的现象是很普遍的。尽管在中间计算过程中没有问题,但当我们想利用8比特或16比特格式保存或查看一幅图像时,就会出现问题。在这种情况下,我们通常希望把图像标度在全尺度,即最大范围[0,255]或[0,65535]。下列名为gscale的M函数能实现此项功能。此外,此函数能将输出映射到一个特定的范围。
function g=gscale(f,varargin)
%GSCALE Scales the intensity of the input image
% G=GSCALE(F,'full8') scales the intensity of F to the full 8-bit intensity
% range [0,255]. This is the default if there is only one input argument.
%
% G=GSCALE(F,'full16') scales the intensities of F to the full 16-bit
% intensity range [0,65535].
%
% G=GSCALE(F,'minmax',LOW,HIGH) scales the intensities of F to the range
% [LOW,HIGH]. These values must be provided, and they must be in the range
% [0,1], independently of the class of the input. GSCALE performs any
% necessary scaling. If the input is of class double, and its values are
% not in the range [0,1], then GSCALE scales it to this range before
% processing.
%
% The class of the output is the same as the class of the input.
if length(varargin)==0 % If only one argument it must be f.
method='full8';
else
method=varargin{1};
end
if strcmp(class(f),'double') & (max(f(:))>1 | min(f(:))<0)
f=mat2gray(f);
end
% Perform the specified scaling.
switch method
case 'full8'
g=im2uint8(mat2gray(double(f)));
case 'full19'
g=im2uint16(mat2gray(double(f)));
case 'minmax'
low=varargin{2};high=varargin{3};
if low >1 | low<0 | high>1 | high<0
error('Parameters low and high must be in the range [0,1].')
end
if strcmp(class(f),'double')
low_in=min(f(:));
hign_in=max(f(:));
elseif strcmp(class(f),'uint8')
low_in=double(min(f(:)))./255;
high_in=double(max(f(:)))./255;
elseif strcmp(class(f),'uint16')
low_in=double(min(f(:)))./65535;
high_in=double(max(f(:)))./65535;
end
% imadjust automatically matches the class of the input.
g=imadjust(f,[low_in high_in],[low high]);
otherwise
error('Unknown method.')
end
函数gscale的语法为:
g=gscale(f,method,low,high)