图像直方图均衡化、空域滤波、图像锐化、图像傅里叶变换
一、图像直方图均衡化
直方图均衡化是图像增强的基本方法,可提高图像的对比度,即:将较窄的图像灰度范围以一定规则拉伸至较大(整个灰度级范围内)的范围。目的是在得到在整个灰度级范围内具有均匀分布的图像。直方图均衡化的目标是寻找一个灰度变换函数,使结果图像的直方图为一个常数。从数学角度,直方图均衡化处理是以累计分布函数变换法为基础的直方图修正法。
假设灰度级为归一化至范围[0,1]内的连续量,并令表示给定图像中灰度级的概率密度函数。对输入灰度级执行如下操作,得到输出灰度级:
S
=
T
(
r
)
=
∫
0
r
P
r
(
W
)
d
w
S=T(r)=\int_{0}^{r}P_{r}(W)dw
S=T(r)=∫0rPr(W)dw
得到的输出灰度级的概率密度函数是均匀的。
也就是通过对给定图像的灰度级概率密度函数进行一个积分处理,得到新的输出灰度级。通过这种变换得到的新图像灰度级在范围[0,1]比较均衡化。这个式子说明了,变换后的图像的灰度值时根据原图中该点的灰度值的概率分布函数得到的。
二维离散直方图变换:
在离散的图像中,假设图像总共有N个像素点,总共有L个像素级。图像中灰度级为k的像素点的数目为
n
k
n_{k}^{}
nk,则有如下关系:
P
r
(
r
k
)
=
n
k
N
P_{r}\left ( r_{k} \right )= \frac{n_{k}}{N}
Pr(rk)=Nnk
则灰度变换函数可以表示成以下式子:
T
(
r
k
)
=
∑
j
=
0
k
P
r
(
r
j
)
=
∑
j
=
0
k
n
k
N
;
0
≤
r
j
≤
1
,
k
=
0
,
1
,
.
.
.
L
−
1
T\left ( r^{k} \right )= \sum_{j=0}^{k}P_{r}\left ( r_{j} \right )= \sum_{j=0}^{k}\frac{n_{k}}{N};0\leq r_{j}\leq 1,k=0,1,...L-1
T(rk)=j=0∑kPr(rj)=j=0∑kNnk;0≤rj≤1,k=0,1,...L−1
r
k
=
k
L
−
1
r_{k}=\frac{k}{L-1}
rk=L−1k表示归一化后的灰度级;k表示归一化前的灰度级。在本实验中,L = 256,如果要求得指定灰度级数量图像的直方图分布以及前后效果对比,那么需要先通过遍历图像的像素,来统计图像中各灰度级的像素个数,再将频数值算为频,计算图像的累计分布函数,并将频率映射到0~255的无符号整数部分,最后通过向量化循环得到均衡之后的图像。值得注意的是,在本题中我默认了图像为灰度图像,所以没有经过RGB图像到灰度图像的转换。如果输入的图像为三通道,那么则需要调用matlab中的rgb2gray()函数。
function [img_2] = myHisteq(img_1, n)
% n表示输出图像的灰度级数量
% img_1表示读入的灰度图像(brigde/lenna/circuit/moon)
% 此处默认输入的图像为灰度图像
% img_1 = rgb2gray(img_1);
size_1 = size(img_1);
h = size_1(1); % 图像高度
w = size_1(2); % 图像宽度
img_2 = zeros(h, w);
% 建立一个256列的行向量,统计各灰度级的像素个数
NumPixel = zeros(1, 256);
for i = 1 : h
for j = 1 : w
k = img_1(i, j); % k是像素点(i, j)的灰度值
NumPixel(k + 1) = NumPixel(k + 1) + 1;
end
end
% 将频数值算为频,计算累计分布函数,并将频率映射到0~255的无符号整数部分
CumPixel = zeros(1, 256);
for i = 1 : 256
for j = 1 : i
CumPixel(i) = CumPixel(i) + NumPixel(j);
end
end
% 在下列用作直方图均衡化实现的赋值语句右端,img_2(i,j)被用来作为CumPixel的索引
% 例如,img_2(i,j)=120,则从CumPixel中取出第120个值作为img_2(i,j)的新像素值
% 向量化循环
i = 1 : h;
j = 1 : w;
img_2(i,j) = round( n * CumPixel(img_1(i , j) + 1)/(h * w));
img_2 = uint8(img_2 * 256 / n);
end
umPixel = zeros(1, 256);
for i = 1 : 256
for j = 1 : i
CumPixel(i) = CumPixel(i) + NumPixel(j);
end
end
% 在下列用作直方图均衡化实现的赋值语句右端,img_2(i,j)被用来作为CumPixel的索引
% 例如,img_2(i,j)=120,则从CumPixel中取出第120个值作为img_2(i,j)的新像素值
% 向量化循环
i = 1 : h;
j = 1 : w;
img_2(i,j) = round( n * CumPixel(img_1(i , j) + 1)/(h * w));
img_2 = uint8(img_2 * 256 / n);
end
输出的效果如下:
图1 直方图均衡化n=2,64,256和原图的对比效果
图2、3、4 从左到右分别代表_bridge_eq_2.jpg、_bridge_eq_64.jpg、_bridge_eq_256.jpg
为了直观的对比灰度图像均衡化前后的效果,我们调用matlab中的imhist()函数(该函数只能处理灰度图像,若图像原始为RGB图像格式,则需要进行转换,方法前期已有提及)来和原始进行对比。
从n=2到n=64再到n=256,可以很明显看出输入的灰度级数量对图像的均衡化存在不同的影响。n=2时图像对比度增强,图像噪声点多,所反映出来的直方图在一个固定的值上,效果不佳;而n=64和n=256所呈现出来的图像对比度增强适中,直方图在一定范围内呈均衡分布,效果较好。
n=2均衡化前后的直方图对比如下:
figure(1);
subplot(221); imshow(im); title('原图'); axis on
subplot(222); imhist(im);title('原图分布'); axis on
subplot(223); imshow(im_histeq_1); title('直方图均衡化, n=2'); axis on
subplot(224); imhist(im_histeq_1);title('直方图均衡化n=2分布'); axis on
图5 直方图均衡化n=2和原图的直方图对比效果
n=64均衡化前后的直方图对比如下:
figure(1);
subplot(221); imshow(im); title('原图'); axis on
subplot(222); imhist(im);title('原图分布'); axis on
subplot(223); imshow(im_histeq_2); title('直方图均衡化, n=64'); axis on
subplot(224); imhist(im_histeq_2);title('直方图均衡化n=64分布'); axis on
图6 直方图均衡化n=64和原图的直方图对比效果
n=256均衡化前后的直方图对比如下:
figure(1);
subplot(221); imshow(im); title('原图'); axis on
subplot(222); imhist(im);title('原图分布'); axis on
subplot(223); imshow(im_histeq_3); title('直方图均衡化, n=256'); axis on
subplot(224); imhist(im_histeq_3);title('直方图均衡化n=256分布'); axis on
图7 直方图均衡化n=256和原图的直方图对比效果
由于本实验是由我们自己编写均衡化函数,来对图像进行处理,而本身的效果我们无从得知。于是我们调用matlab中自带的histeq()函数对图像进行均衡化处理,再将其与自己编写的均衡化函数输入灰度级n=64时进行对比,得到的对比如下:
可以看出,自身编写的函数没有什么问题。
%% 使用matlab自带的histeq函数,对图像进行均衡化
histeq_1 = histeq(im);
%% 显示结果
figure(1);
subplot(221); imshow(histeq_1); title('matlab自带均衡化函数'); axis on
subplot(222); imhist(histeq_1); title('matlab自带均衡化函数直方图'); axis on
subplot(223); imshow(im_histeq_2); title('直方图均衡化, n=64'); axis on
subplot(224); imhist(im_histeq_2);title('直方图均衡化n=64分布'); axis on
图8 使用matlab自带均衡化函数和直方图均衡化n=64所输出的直方图对比效果
二、图像空域滤波
空域滤波是基于邻域处理的增强方法,直接在图像所在的二维空间进行处理,即对每一个像素的灰度值进行处理。它应用某一模版对每个像素与其周围邻域的所有像素进行某种数学运算得到该像素的灰度值,新的灰度值的大小不仅域该像素的灰度值有关,而且还与其领域内的像素值的灰度有关。
空域滤波是在图像空间通过邻域操作完成的,最常用的运算是模版运算,基本思路是将某个像素的值作为它本身的灰度值和其相邻像素灰度值的函数。模版可以看作是n*n的小图像,最基本的尺寸为3 * 3,更大的尺寸如5 * 5,7 * 7,最常用的是卷积模版,其基本步骤如下:
(1)将模板在图中漫游,并将模板中心与图中某个像素位置重合;
(2)将模板上的各个像素与模板下的各对应像素的灰度值相乘;
(3)将所有乘积相加(为保持图像的灰度范围,常常将灰度值除以模版中像素的个数)得到的结果赋给图中对应模板中心位置的像素。
空域滤波分为图像平滑(去噪声)和图像锐化(突出轮廓)。图像平滑的主要目的有两个:
1、模糊:在提取较大目标前,去除小的细节或将目标内的小间断连接起来的;
2、消除噪声:改善质量,降低干扰。平滑滤波对图像的低频分量增强,同时削弱高频分量,用于消除图像中的随机噪声,起到平滑作用。
1、均值滤波(滤波次数n→3)
均值滤波采用线性的方法,平均整个窗口范围内的像素值,均值滤波本身存在着固有的缺陷,即它不能很好地保护图像细节,在图像去噪的同时也破坏了图像的细节部分,从而使图像变得模糊,不能很好地去除噪声点。均值滤波对高斯噪声表现较多,对椒盐噪声表现较差。
均值滤波是指任意一点的像素值,都是周围个像素值的均值。在进行处理时,往往需要用到边界延拓。本实验将图像的边缘延拓到两行两列,形成矩阵,再根据图像像素点的值对该矩阵进行赋值。对于经过均值滤波处理后的图像,先初始化一个与原图像等高等宽的矩阵,再经过加权平均,舍掉结果中的小数,输出。
% 平滑滤波算法实现:均值滤波
function [img_2] = myAverage(img_1)
size_1 = size(img_1);
h = size_1(1); % 图像高度
w = size_1(2); % 图像宽度
img_2 = zeros(h, w);
% 边缘延拓两行两列
a = img_1(1,:);
b = img_1(h,:);
img_1 = [a;img_1;b];
c = img_1(:,1);
d = img_1(:,w);
img_1 = double([c,img_1,d]);
% 3X3均值
L = 1/9 *[1 1 1;
1 1 1;
1 1 1];
for i = 1:h
for j = 1:w
im = [img_1(i,j) img_1(i,j+1) img_1(i,j+2);...
img_1(i+1,j) img_1(i+1,j+1) img_1(i+1,j+2);...
img_1(i+2,j) img_1(i+2,j+1) img_1(i+2,j+2)];
img_2(i,j) = round(sum(sum(L.*im)));
end
end
img_2 = uint8(img_2);
end
2、中值滤波(滤波次数n→3)
中值滤波不同于均值滤波,它采用非线性的方法,用局部邻域(窗口)里的中值来代替上述局部平均法中的局部平均值。即将以该点为中心的某个窗口框住的各像素的中间值作为处理后图像中该点像素的值。它的平滑脉冲噪声方面非常有效,同时它可以保护图像尖锐的边缘,选择适当的点来替代污染点的值,所以处理效果好,对椒盐噪声表现较好,对高斯噪声表现较差。
该实验中同样需要用到边界延拓,和均值滤波处理时几乎接近的,是将图像的边缘延拓到两行两列,形成矩阵,但是需要对在模板区的值进行排序后选取中值,赋值给所需要输出的新图像。
![在这里插入图片描述](https://img-blog.csdnimg.cn/c8562c344a6c4008b1a75046634b41a2.png#pic_center](https://img-blog.csdnimg.cn/8e34c71a764940df81ae8f5c9e34091b.png)
图9 中值滤波示意图(转自CSDN)
% 平滑滤波算法实现:中值滤波
function [img_2] = myMedian(img_1)
size_1 = size(img_1);
h = size_1(1); % 图像高度
w = size_1(2); % 图像宽度
img_2 = zeros(h, w);
% 边缘延拓两行两列
a = img_1(1,:);
b = img_1(h,:);
img_1 = [a;img_1;b];
c = img_1(:,1);
d = img_1(:,w);
img_1 = double([c,img_1,d]);
for i = 1:h
for j = 1:w
% 获得模板区的值
% 对模板区的值进行排序
% 选取中值
img_2(i,j) = median([img_1(i,j) img_1(i,j+1) img_1(i,j+2)...
img_1(i+1,j) img_1(i+1,j+1) img_1(i+1,j+2)...
img_1(i+2,j) img_1(i+2,j+1) img_1(i+2,j+2)]);
end
end
img_2 = uint8(img_2);
end
输出的结果如下:
图10 均值滤波(n=3)和中值滤波(n=3)的处理效果图
图11、12 分别代表均值滤波_circuit_a.jpg和中值滤波_circuit_m.jpg效果图
3、图像锐化(Laplace算子)
图像锐化是针对常见的图像模糊、边缘不清晰所采取的处理方法,它能加强图像的轮廓,使图像看起来比较清楚。锐化处理处理的主要目的是突出灰度的过渡部分。
拉普拉斯算子是图像邻域内像素灰度差分计算的基础,通过二阶微分推导出的一种图像邻域增强算法。它的基本思想是当邻域的中心像素灰度低于它所在邻域内的其他像素的平均灰度时,此中心像素的灰度应该进一步降低;当高于时进一步提高中心像素的灰度,从而实现图像锐化处理。在算法实现过程中,通过对邻域中心像素的四方向或八方向求梯度,并将梯度和相加来判断中心像素灰度与邻域内其他像素灰度的关系,并用梯度运算的结果对像素灰度进行调整。通过模板可以发现,当邻域内像素灰度相同时,模板的卷积运算结果为0;当中心像素灰度高于邻域内其他像素的平均灰度时,模板的卷积运算结果为正数;当中心像素的灰度低于邻域内其他像素的平均灰度时,模板的卷积的负数。对卷积运算的结果用适当的衰弱因子处理并加在原中心像素上,就可以实现图像的锐化处理。
该实验使用边界延拓,将图像的边缘延拓到两行两列,形成矩阵,对于图像的每个像素点进行遍历,对图像矩阵进行赋值,之后对卷积运算的结果处理并加在原中心像素上。最后使用imuint8()函数将a转换成double型数据,并且进行归一化。
% 平滑滤波算法实现:图像锐化
function [img_2] = mySharpen(img_1)
size_1 = size(img_1);
h = size_1(1); % 图像高度
w = size_1(2); % 图像宽度
img_2 = zeros(h, w);
% 边缘延拓两行两列
a = img_1(1,:);
b = img_1(h,:);
img_1 = [a;img_1;b];
c = img_1(:,1);
d = img_1(:,w);
img_1 = double([c,img_1,d]);
% 拉普拉斯算子
L = [-1 -1 -1;
-1 8 -1;
-1 -1 -1];
for i = 1:h
for j = 1:w
im = [img_1(i,j) img_1(i,j+1) img_1(i,j+2);...
img_1(i+1,j) img_1(i+1,j+1) img_1(i+1,j+2);...
img_1(i+2,j) img_1(i+2,j+1) img_1(i+2,j+2)];
img_2(i,j) = round(sum(sum(L.*im)));
img_2(i,j) = img_2(i,j) + img_1(i+1,j+1);
end
end
img_2 = im2uint8(img_2/255);
end
输出的结果如下:
图13 使用拉普拉斯算子进行图像锐化的处理效果图
图14 拉普拉斯算子图像锐化的处理效果图_moon_s.jpg
三、图像傅里叶变换
傅里叶变换,表示能将满足一定条件的某个函数表示成三角函数(正弦和/或余弦函数)或者它们的积分的线性组合。
对于频谱图和相位图的输出,在读取图像后需要将图像灰度化(lenna是三通道的图像),再进行傅里叶变换操作即可。
%% 图像的傅里叶变换:输出频谱图和相位图
clc;
clear;
close all;
%% 读取图片
filename = 'lenna';
im = imread([filename, '.jpg']);
%% 图像灰度化
im = rgb2gray(im);
%% 对图像作快速傅里叶变换FFT
F = fft2(im2double(im)); % 对图像作二维离散傅里叶变换,再作快速傅里叶变换
F = fftshift(F); % 将直流分量平移到频谱中心
F = real(F); % 取实部
%% 做频谱对数变换,得到原图像的频谱图
im_t = log(abs(F)+1);
%% 做频谱对数变换,得到原图像的相位图
im_s = log(angle(F)*180/pi + 1);
%% 图像归一化(此步在此题可以省略)
ymax=255;ymin=0;
xmax = max(max(im_t)); %求得im_t中的最大值
xmin = min(min(im_t)); %求得im_t中的最小值
im_t = round((ymax-ymin)*(im_t-xmin)/(xmax-xmin) + ymin); %归一化并取整
%% 输出图像、频谱图和相位图
subplot(221);imshow(im);title('原图');axis on
subplot(222);imshow(im_t,[]);title('频谱图');axis on
subplot(223);imshow(im_s,[]);title('相位图');axis on
输出的结果如下:
图15 傅里叶变换处理lenna.jpg后输出的频谱图和相位图
问题及解决方案
1、均值滤波和中值滤波输出存在差异:在循环的时候,均值滤波对应的每个矩阵值需要进行分开,而中值滤波不是,且均值滤波是在赋值之后进行小数点的取舍,中值滤波是直接使用median()函数,否则会出现图18的错误示意图。
图16 均值滤波的矩阵
图17 中值滤波的计算操作
图18、19 中值滤波操作前后对比
2、在直方图均衡化中,向量化循环不是以for形式进行操作,而是直接使用i和j作为索引,它能够简化循环代码。
图20 向量化循环错误示范
图20、21 向量化循环操作改正前后对比
3、频谱图输出时是需要取复数的实部,而经过傅里叶变换之后,该实部是负数,所以进行取绝对值abs()操作。且对于输出为矩阵的图像,需要在imshow()里面规范输出格式。
图22 频谱图对数变换取绝对值操作
图23 频谱图输出时系统提示
图24 频谱图imshow()输出时格式规范
图25、26 频谱图输出格式规范前后对比
4、在进行图像锐化时,我们不能够单纯使用uint8()对图像进行转换,因为它只是将数据转换成uint8型,仅改变数据格式却不进行归一化。但是锐化需要将图像范围映射到0-255之间,所以需要使用im2uint8()函数。
图27 向量化循环操作改正前后对比
图28、29向量化循环操作改正前后对比
总结
本次实习中我学习到了使用Matlab进行直方图均衡化、空域滤波之图像平滑的应用、图像锐化以及傅里叶变换的应用。虽然对于有的操作我还不是很熟悉,中途也遇到了许多的困难,在不断查阅资料和调试之后还是获得了较为理想的结果。
对于本次实验,我还可以作出一定的改进,比如更改图像锐化时的算子,并进行比较;对于均衡化还可以尝试不同的灰度级数量输入,来对比不同数量级的效果。
参考链接
1、Matlab 直方图均衡化
2、【图像处理算法】直方图均衡化
3、数字图像处理2:不同灰度级的直方图均衡化
4、Matlab中函数histeq的使用方法及直方图均衡化
5、【图像处理】直方图均衡化(附带Matlab及OpenCV3自编程实现代码)
6、图像增强之三— —空域滤波
7、数字图像处理3:空域滤波(图像平滑:均值、中值、图像锐化)
8、图像处理入门:图像增强之空域滤波
9、【数字图像处理】图像锐化:拉普拉斯算子(Laplacian)、高通滤波、Sobel算子、Isotropic算子、Prewitt算子
10、matlab数字图像的傅立叶变换实验