数字图像处理直方图,傅里叶变换,同态滤波的matlab实现

任务要求

对给定的第照度照片进行灰度化,计算并显示以上低照度图像的灰度直方图和离散傅里叶变换频谱幅度图;对以上低照度图像分别进行直方图均衡化和同态滤波操作,并对两种算法的最终效果

本文给出对于直方图、二维离散傅里叶变换、同态滤波、二维傅里叶变换逆变换的源码实现

虽然说matlab上有现成的函数,对于初学者而言,通过自己编写这些函数,可以对数字图像的处理过程以及实现具体步骤更加理解

首先是直方图以及均衡化

直方图说白了就是各个灰度值所占的个数,对于这部分程序的实现,就可以通过遍历数字图像,循环计数就可以了,代码如下

function hist=count_hist(picture) %计算直方图,输入变量为灰度值,返回矩阵为直方图
    Sum=zeros(2,256);%第一行表示的是出现的次数,第二行表示的是0~255供给256个灰度值
    for i=1:256
        Sum(2,i)=i-1;
    end   %第二行的初始化过程
    for i=1:size(picture,1)
        for j=1:size(picture,2)
            Sum(1,picture(i,j)+1)=Sum(1,picture(i,j)+1)+1;%由于灰度图像值是0~255,但索引为1~256,所以索引的时候需要编程X(i,j)+1
        end
    end  %对第一行进行赋值
    hist=Sum;
end

在这里插入图片描述
在这里插入图片描述
上图是自己编写程序实现的直方图,下图是matlab自带函数imhist所显示的直方图

直方图均衡化,顾名思义就是想让图像的直方图看起来更加均衡,不至于在某一个灰度值出现过高的情况
在这里插入图片描述

可能这样子还是不好理解,我们举一个实例来演示一下直方图均衡化
比如现在有图像
在这里插入图片描述
那我们可以得到他的直方图
在这里插入图片描述
由此可以算出每个灰度的概率
在这里插入图片描述
然后我们进行概率的累加,可以认为计算灰度值小于等于i(当前灰度值)的概率,我们得到概率累积分布
在这里插入图片描述
也就是
HS=[0.12, 0.20, 0.36, 0.52, 0.56, 0.60, 0.76, 0.80, 0.88, 1.00]

我们对其乘255得
HS=[30.6000 51.0000 91.8000 132.6000 142.8000 153.0000 193.8000 204.0000 224.4000 255.0000]

然后再四舍五入,可以得到
HS=[31 51 92 133 143 153 194 204 224 255]

原图[0 1 2 3 4 5 6 7 8 9]
原图和HS形成映射

得到映射后的图像为
在这里插入图片描述

代码的思路也是这样

function [new_picture,new_hist]=hist_equal(picture,hist)%直方图均衡化
    Y=hist(1,:)/(size(picture,1)*size(picture,2));%将得到的直方图求每个灰度值所对应的概率
    for i=2:length(hist(1,:))
        Y(i)=Y(i-1)+Y(i);      %这部分是变成概率密度函数,就是进行概率的累加
    end   
    Y=Y*255;%乘以灰度值255
    Y=round(Y);%取整
    new_picture=ones(size(picture,1),size(picture,2));%建立新的图像
    for i=1:size(picture,1)
        for j=1:size(picture,2)
            new_picture(i,j)=Y(picture(i,j)+1);   %同样,由于灰度图像值是0~255,但索引为1~256,所以索引的时候需要编程picture(i,j)+1
        end
    end
    new_picture=uint8(new_picture);%由于上面的到的类型是double行,imshow的时候需要unit8型的变量
    new_hist=count_hist(new_picture);%均衡化后的直方图
end

对题目中给出的图片,我们将其均衡化后得到
在这里插入图片描述

离散傅里叶变换

在这里我没有用到快速傅里叶变换,虽然这种耗时短
二维快速傅里叶变换的时间复杂度约为O(n2)
而普通的二维傅里叶变换就需要O(n4)
由于用的是matlab,我们可以通过进行矩阵操作来减少用时
我们可以由二维傅里叶表达式
在这里插入图片描述
将他换成矩阵
在这里插入图片描述
在这里插入图片描述
G3 G4分别为G1,G2的逆
同时,为了使得频谱图便于观察,我们将他进行中心化,也就是
f(x,y)*(-1)^(x+y)
代码如下

function FFT_picture=FFT(picture)  %变换并且中心化
    G1=zeros(size(picture,1),size(picture,1));   %前变换矩阵
    G2=zeros(size(picture,2),size(picture,2));   %后变换矩阵
    picture1=double(picture);   %将图像uint8格式转换成double型,便于进行复数相乘
    for i=1:size(picture,1)
        for j=1:size(picture,2)
            picture1(i,j)=picture1(i,j)*exp(complex(0,1)*2*pi*(i+j)/2);%对原图像进行中心化预处理
        end
    end
    for i=1:size(picture,1)   %前变换矩阵的赋值
        for j=1:size(picture,1)
            G1(i,j)=exp(-complex(0,1)*2*pi*(i-1)*(j-1)/size(picture,1));
        end
    end
    for i=1:size(picture,2)   %后变换矩阵的赋值
        for j=1:size(picture,2)
            G2(i,j)=exp(-complex(0,1)*pi*2*(i-1)*(j-1)/size(picture,2));
        end
    end
    FFT_picture=G1*picture1*G2;   %二维傅里叶变换并且进行了中心化,返回的是复数型矩阵,要是想进行显示...
                                  %需要在程序中运行   imshow(log(abs(FFT_picture)+1),[])
end

逆变换:

function IFFT_picture=IFFT(f_picture)  %逆变换并且退中心化
    G1=zeros(size(f_picture,1),size(f_picture,1));%前变换矩阵
    G2=zeros(size(f_picture,2),size(f_picture,2));%后变换矩阵
    for i=1:size(f_picture,1)   %前变换矩阵赋初值
        for j=1:size(f_picture,1)
            G1(i,j)=exp(complex(0,1)*2*pi*(i-1)*(j-1)/size(f_picture,1))/size(f_picture,1);
        end
    end
    for i=1:size(f_picture,2)  %后变换矩阵赋初值
        for j=1:size(f_picture,2)
            G2(i,j)=exp(complex(0,1)*pi*2*(i-1)*(j-1)/size(f_picture,2))/size(f_picture,2);
        end
    end
    IFFT_picture=G1*f_picture*G2;   %进行逆变换
    for i=1:size(f_picture,1)  %退中心化,但是这个时候的到的矩阵还是复数矩阵
        for j=1:size(f_picture,2)
            IFFT_picture(i,j)=IFFT_picture(i,j)/exp(complex(0,1)*2*pi*(i+j)/2);
        end
    end
%     IFFT_picture=uint8(IFFT_picture);  %变换成uint8格式,便于之间输出逆变换的图像
end

频谱图如下
在这里插入图片描述
再进行逆变换
在这里插入图片描述
其实这张图片就是A图的图像

同态滤波

直方图均衡化是在空域上进行的操作,对于人的视觉对比度不够强烈
我们希望能够增强对比度,进而我们寻求了一种在频域上进行增强的滤波方法
人之所以可以看到某个景物,是因为有光辐射能照在该景物上,经过景物的反射或透射作用之后,在人的视网膜上产生感知信号,该感知信号传送到大脑后形成对景物的理解。
按照光图像的成像原理,可以对一幅图像进行如下的简单建模:
在这里插入图片描述
即把图像亮度?(?,?)看成是由入射分量(入射到景物上的光强度)?(?,?)和反射分量(景物反射的光强度)?(?,?)组成

当灰度动态范围太大时,由于人眼可以分辨的亮度变化范围是有限的,往往会因为很高的灰度值区域的信号掩盖暗区的信号,使得目标区域的细节,特别是暗区的细节难以辨认。

一幅图像所表示的灰度变化的最大可能范围(即画面的动态范围)主要取决于入射光的强度,画面的对比度则主要取决于图像中的景物特性。

同态滤波是一种在频域中同时进行图像对比度增强和压缩图像亮度范围的滤波方法;
其基本思想是减少入射分量?(?,?),并同时增加反射分量?(?,?)来改善图像?(?,?)的显示效果;
?(?,?)在空间上变化缓慢,其频谱集中在低频段,?(?,?)反映图像的细节和边缘,其频谱集中在高频段。
在这里插入图片描述
对成像模型两边取对数:???(?,?)=???(?,?)+???(?,?)
两边取傅里叶变换:?(?,?)=?(?,?)+?(?,?)
用一频域函数?(?,?)处理?(?,?):
?(?,?)?(?,?)=?(?,?)?(?,?)+?(?,?)?(?,?)
反变换到空域:?_? (?,?)=?_? (?,?)+?_? (?,?)
两边取指数:
?(?,?)=???|?_? (?,?)|=???|?_? (?,?)|∙???|?_? (?,?)|

但是这种方法需要给定滤波器,而且滤波器要有高通性质,还要保存一些低频成分,需要不断地调节参数来改善视觉效果
本文给出的是高斯型滤波器,当然也可以采用巴特沃斯滤波器

function HF_picture=HF(picture)
    picture=double(picture);%对于原图像进行double化,方便后面进行复数运算
    LN_picture=log(picture+1);%取对数
    LNF_picture=FFT(LN_picture);%进行傅里叶正变换
    m=size(picture,1);
    n=size(picture,2);
    H=zeros(m,n);
    D0=10;
    rh=1.95;
    rl=0.5;
    c=1.5;
    for i=1:m
        for j=1:n
            H(i,j)=(rh-rl)*(1-exp(-c*((i-m/2)^2+(j-n/2)^2))/D0^2)+rl;  %同态滤波器的实现
        end
    end
    HFLNF_picture=LNF_picture.*H;  %频域滤波
    IFFTHFLNF_picture=IFFT(HFLNF_picture);%傅里叶逆变化
    HF_picture=exp(IFFTHFLNF_picture)-1;%在时域取指数,由于最初取对数的时候+1,取指数的时候需要进行减一操作
    HF_picture=uint8(HF_picture);%类型转换为八位无符号整数uint8
end

经过一系列的实验可以得到一组比较好的参数,结果如下图
在这里插入图片描述
整个任务也就完成了
下面是全部代码,已用matlab 2018a测试成功

clc,clear;
picture=imread('I:\A.jpg');%读取图像的信息
picture=rgb2gray(picture);%将图像信息进行灰度化
hist=count_hist(picture);%计算直方图
% stem(H(2,:),H(1,:),'.');%打印直方图
% ylim([0 2*10^4])%限制直方图的Y值的上界限
% imhist(Y)%matlab自带的直方图显示图
[new_picture,new_hist]=hist_equal(picture,hist);
% stem(new_hist(2,:),new_hist(1,:),'.');
% ylim([0 2*10^4])
FFT_picture=FFT(picture);
% imshow(log(abs(FFT_picture)+1),[])
IFFT_picture=IFFT(FFT_picture);

% F1=fft2(picture);
% F1=fftshift(F1);
HF_picture=HF(picture);
imshow(HF_picture)
function hist=count_hist(picture) %计算直方图,输入变量为灰度值,返回矩阵为直方图
    Sum=zeros(2,256);%第一行表示的是出现的次数,第二行表示的是0~255供给256个灰度值
    for i=1:256
        Sum(2,i)=i-1;
    end   %第二行的初始化过程
    for i=1:size(picture,1)
        for j=1:size(picture,2)
            Sum(1,picture(i,j)+1)=Sum(1,picture(i,j)+1)+1;%由于灰度图像值是0~255,但索引为1~256,所以索引的时候需要编程X(i,j)+1
        end
    end  %对第一行进行赋值
    hist=Sum;
end

function [new_picture,new_hist]=hist_equal(picture,hist)%直方图均衡化
    Y=hist(1,:)/(size(picture,1)*size(picture,2));%将得到的直方图求每个灰度值所对应的概率
    for i=2:length(hist(1,:))
        Y(i)=Y(i-1)+Y(i);      %这部分是变成概率密度函数,就是进行概率的累加
    end   
    Y=Y*255;%乘以灰度值255
    Y=round(Y);%取整
    new_picture=ones(size(picture,1),size(picture,2));%建立新的图像
    for i=1:size(picture,1)
        for j=1:size(picture,2)
            new_picture(i,j)=Y(picture(i,j)+1);   %同样,由于灰度图像值是0~255,但索引为1~256,所以索引的时候需要编程picture(i,j)+1
        end
    end
    new_picture=uint8(new_picture);%由于上面的到的类型是double行,imshow的时候需要unit8型的变量
    new_hist=count_hist(new_picture);%均衡化后的直方图
end

function FFT_picture=FFT(picture)  %变换并且中心化
    G1=zeros(size(picture,1),size(picture,1));   %前变换矩阵
    G2=zeros(size(picture,2),size(picture,2));   %后变换矩阵
    picture1=double(picture);   %将图像uint8格式转换成double型,便于进行复数相乘
    for i=1:size(picture,1)
        for j=1:size(picture,2)
            picture1(i,j)=picture1(i,j)*exp(complex(0,1)*2*pi*(i+j)/2);%对原图像进行中心化预处理
        end
    end
    for i=1:size(picture,1)   %前变换矩阵的赋值
        for j=1:size(picture,1)
            G1(i,j)=exp(-complex(0,1)*2*pi*(i-1)*(j-1)/size(picture,1));
        end
    end
    for i=1:size(picture,2)   %后变换矩阵的赋值
        for j=1:size(picture,2)
            G2(i,j)=exp(-complex(0,1)*pi*2*(i-1)*(j-1)/size(picture,2));
        end
    end
    FFT_picture=G1*picture1*G2;   %二维傅里叶变换并且进行了中心化,返回的是复数型矩阵,要是想进行显示...
                                  %需要在程序中运行   imshow(log(abs(FFT_picture)+1),[])
end

function IFFT_picture=IFFT(f_picture)  %逆变换并且退中心化
    G1=zeros(size(f_picture,1),size(f_picture,1));%前变换矩阵
    G2=zeros(size(f_picture,2),size(f_picture,2));%后变换矩阵
    for i=1:size(f_picture,1)   %前变换矩阵赋初值
        for j=1:size(f_picture,1)
            G1(i,j)=exp(complex(0,1)*2*pi*(i-1)*(j-1)/size(f_picture,1))/size(f_picture,1);
        end
    end
    for i=1:size(f_picture,2)  %后变换矩阵赋初值
        for j=1:size(f_picture,2)
            G2(i,j)=exp(complex(0,1)*pi*2*(i-1)*(j-1)/size(f_picture,2))/size(f_picture,2);
        end
    end
    IFFT_picture=G1*f_picture*G2;   %进行逆变换
    for i=1:size(f_picture,1)  %退中心化,但是这个时候的到的矩阵还是复数矩阵
        for j=1:size(f_picture,2)
            IFFT_picture(i,j)=IFFT_picture(i,j)/exp(complex(0,1)*2*pi*(i+j)/2);
        end
    end
%     IFFT_picture=uint8(IFFT_picture);  %变换成uint8格式,便于之间输出逆变换的图像
end

function HF_picture=HF(picture)
    picture=double(picture);%对于原图像进行double化,方便后面进行复数运算
    LN_picture=log(picture+1);%取对数
    LNF_picture=FFT(LN_picture);%进行傅里叶正变换
    m=size(picture,1);
    n=size(picture,2);
    H=zeros(m,n);
    D0=10;
    rh=1.95;
    rl=0.5;
    c=1.5;
    for i=1:m
        for j=1:n
            H(i,j)=(rh-rl)*(1-exp(-c*((i-m/2)^2+(j-n/2)^2))/D0^2)+rl;  %高斯滤波器的实现
        end
    end
    HFLNF_picture=LNF_picture.*H;  %频域滤波
    IFFTHFLNF_picture=IFFT(HFLNF_picture);%傅里叶逆变化
    HF_picture=exp(IFFTHFLNF_picture)-1;%在时域取指数,由于最初取对数的时候+1,取指数的时候需要进行减一操作
    HF_picture=uint8(HF_picture);%类型转换为八位无符号整数uint8
end


发布了10 篇原创文章 · 获赞 7 · 访问量 1195

猜你喜欢

转载自blog.csdn.net/qq_43294951/article/details/101617954