MATLAB是数字图像处理的强有力的软件工具,很多情况下,我们借助MATLAB的内置函数,以很简便的方式就能实现直方图均衡化、灰度变换等图像处理。当然,其中大部分内置函数是不开源的。那么,我们如何不直接借助内置函数实现常见的数字图像处理方法呢?在这篇文章中,我们首先讨论的,是直方图均衡化与灰度变换的相关处理。后续,我们还将讨论图像的锐化、平滑等处理。
1.直方图均衡化
直方图均衡化是比较基本的一种图像处理方式。它的作用是通过减少像元数目来增加图像的对比度。在一般情况下,我们是通过histeq()函数来处理的,那么,不直接使用这个函数,我们怎样实现直方图均衡化呢?直方图均衡化,无非就是个先求原图像的灰度直方图,再求累积分布函数、取整,最后求出均衡化图像的直方图,做映射的过程。由此,我们可以这样编写程序:
clear;
clc;
% 均衡化
Image = imread('文件路径及文件名');
Image = rgb2gray(Image);
[Height, Width] = size(Image);
% 使用计数变量统计各灰度像元个数(简单处理的话可以直接histogram())
Count = zeros(1,256);
for i = 1 : Height*Width
% 因为Count数组的下标是从1开始的,但像素的取值范围是0~255,所以用Count(k+1)
Count(Image(i)+1) = Count(Image(i)+1) + 1;
end
% bar(Count);
ProbPixel = zeros(1,256); % 统计各灰度级出现的频率
for i = 1 : 256
ProbPixel(i) = Count(i) / (Height * Width);
end
% 用函数cumsum()来计算累积分布函数,并将频率(范围0~1)映射到0~255的无符号整数
CumPixel = cumsum(ProbPixel); % 这里的数组CumPixel大小也是1×256
CumPixel = uint8((256-1) .* CumPixel + 0.5);
OutImage = uint8(zeros(Height, Width)); % 预分配数组
for i = 1 : Height*Width
OutImage(i) = CumPixel(Image(i) + 1);
end
% 显示直方图均衡化前后的图像,与调用函数histeq()的效果一致
subplot(2,1,1);
imshowpair(Image, OutImage, 'montage');
subplot(2,1,2);
% 此处为方便起见直接使用histogram()了
histogram(Image);
hold on
grid on
histogram(OutImage);
以上就是直方图均衡化的代码,将文件路径修改后即可直接使用,如果出现错误很可能是插件在安装时没有安装完全或者是你使用的是盗版。
这里的确要声明一下:插件安装不完全,部分函数是无法使用的!在数字图像处理这方面尤其明显。
2.分段线性灰度变换
在拍摄图像时曝光度不足或过度的情况下,图像灰度就有可能会局限在一个很小的范围内,这时看到的将会是一个模糊不清、没有灰度层次的图像。用一个线性单值函数,对图像内的每一个像素作线性扩展,将有效地改善图像视觉效果。
假定原图像 的灰度范围为[a,b], 希望变换后图像 的灰度范围扩展至[c,d],则线性变换可表示为
由此可见,对输入图像灰度做线性扩张或压缩,映射函数为一个直线方程,该线性灰度变换函数是一个一维线性函数。式(2-1)可用图2-1表示。这种线性变换的前提是必须已知原图像的灰度范围[a,b],且变换后的范围[c,d]也不容易确定,人为因素影响较大。
分段线性变换是分段进行线性变换,将图像灰度区间分为两段或者多段,分别作不同的线性变换。分段线性变换的目的是为了突出感兴趣的目标或灰度区间,相对抑制那些不感兴趣的灰度区域。变换可公式表示为:
将上述代码MATLAB实现为:
clear;
clc;
% 分段线性变换
Image=imread('文件路径及文件名');
figure
subplot(1,2,1),imshow(Image);
title('原始图像')
f0=0;g0=0;
a=100;c=50;
b=150;d=200;
Mg=255;Mf=255;
a1=(c-g0)/(a-f0);
b1=0;
a2=(d-c)/(b-a);
b2=c-a*a2;
a3=(Mf-d)/(Mg-b);
b3=d-b*a3;
Image(Image>=f0&Image<=a)=a1*Image(Image>=f0&Image<=a);
Image(Image>a&Image<=b)=a2*(Image(Image>a&Image<=b)-a)+c;
Image(Image>b&Image<=Mg)=a3*(Image(Image>b&Image<=Mg)-b)+d;
subplot(1,2,2),imshow(Image);
title('分段变化后图像');
3.对数变换
除了线性变换,还存在非线性变换,比如指对数变换。首先我们看一下对数变换。
对数变换的基本思路也是将灰度按函数映射,凡事要注意的是,由于对数变换基本不可能做到完全整数映射,因此需要进行数据类型转换,这点要十分注意,很容易出错!!!!
一般对数变换的通用形式为:
代码实现为:
clear;
clc;
Image = imread('文件路径及文件名');
Image=double(rgb2gray(Image))/255;
a = log2(1+Image);
b = log2(1+Image)/log2(5);
c = log2(1+Image)/log2(15);
figure();
subplot(2,2,1);
imshow(Image);
xlabel('原始图像');
subplot(2,2,2);
imshow(a);
xlabel('以2为底对数变换后');
subplot(2,2,3);
imshow(b);
xlabel('以5为底对数变换后');
subplot(2,2,4);
imshow(c);
xlabel('以15为底对数变换后');
这里不难注意到,在编写程序时使用了换底公式,原因是什么呢?实际上,在实际的图像变换过程中,对数变换公式一般不能直接使用,否则会出现计算结果超过原图像灰度级的现象。为避免这种情况发生,在使用时可以进行换底公式处理,即将公式处理成为这个:g(x,y)= c/255*log【1+f(x,y)*a】/log(a)或者g(x,y)= c*log【1+f(x,y)*c】/log(a)。如此,便可以避免超出原灰度级。
4.指数变换
指数变换需要注意的问题上面基本上都囊括了,这里直接展示公式与代码。
公式:
代码:
clear;
clc;
% 指数变换
Image = imread('D:\绝密文件\数字图像处理\数字图像处理\car.jpg');
Image = double(rgb2gray(Image))/255;
c=255;
a = c/255*(Image.^2);
b = c/255*(Image.^4);
d = c/255*(Image.^0.5);
figure();
subplot(2,2,1);
imshow(Image,[0 1]);
xlabel('原始图像');
subplot(2,2,2);
imshow(a,[0 1]);
xlabel('d=2时的指数变换图像');
subplot(2,2,3);
imshow(b,[0 1]);
xlabel('d=4时的指数变换图像');
subplot(2,2,4);
imshow(d,[0 1]);
xlabel('d=0.5时的指数变换图像');
以上即为针对灰度图像的灰度变换处理。
5.彩图转灰度图像
一般彩色图像转灰度图像我们使用的是rgb2gray()函数,其实,我们可以查看此函数的文档,得到变换公式:ImageGray = 0.2989 * R + 0.5870 * G + 0.1140 * B。
如此,代码实现为:
clear;
clc;
% 彩色图像转灰度图像
Image = imread('文件路径及文件名');
figure(1)
imshow(Image);
% 转换
R = Image(:,:,1);
G = Image(:,:,2);
B = Image(:,:,3);
ImageGray = 0.2989 * R + 0.5870 * G + 0.1140 * B ;
figure(2);
imshow(ImageGray);
这就是本期全部内容,感谢观看!