MATLAB--数字图像处理 图像的灰度变换与直方图修正

一、实验名称

图像的灰度变换与直方图修正

二、实验目的

1.熟悉MATLAB软件的使用。
2.掌握灰度变换、直方图修正的原理及数学运算。
3.于MATLAB环境下编程实现对图片的灰度变换和直方图修正。

三、实验内容

1.对于给定图片,在MATLAB软件下编程实现对图片的不同程度的灰度变换。
2.对于给定图片,在MATLAB软件下编程实现对图片的不同程度的直方图修正。

四、实验仪器与设备

Win10 64位电脑
MATLAB2017a

五、实验原理

灰度变换
线性变换:fa>1时,输出图像的对比度将增大;fa<1时,输出图像对比度将减小。Fa=1且fb非零时,所有像素的灰度值上移或者下移,使得整个图像更暗或者更亮。Fa<0,暗区变亮,亮区变暗。
对数变换:可以增强一副图像中较暗部分的细节,用来拓展被压缩的高值图像中的较暗像素。
指数变换:可以增强一副图像中较亮部分的细节。
取反:亮变暗,暗变亮。
直方图均衡化
步骤
1、 计算出每个灰度级的概率
2、计算出灰度累加概率
3、累加概率乘以length-1再取整
4、更新灰度级
具体解法:
利用循环,算出累积概率,灰度级为0时,累积概率为0.02,灰度级为1时,为0.02+0.05=0.07 。。。。。
再分别乘以7,取整,
得到最后的灰度

在这里插入图片描述

直方图SML、GML映射

步骤
1.分别计算出原图直方图、规定直方图的累加概率
2.分别用GML、SML映射
3.获取更新后的数据

具体解题
分别利用循环计算出原图和规定图的累积概率,
SML映射规则下,先看原图累积直方图中的0.1,然后在规定直方图累积找最靠近的那个值,是0.3,所以灰度级由0变成1,依次类推
GML映射规则下,先看规定累积直方图中的0.3,然后在原图累积直方图中找到最靠近的那个,是0.3,对应的灰度是2,所以2,2以前的灰度值都变成1,依次类推


在这里插入图片描述

六、实验过程及代码

灰度变换
1)线性变换

t=imread('t1.jpg')
t1=im2double(t)
figure(1)
subplot(2,2,1),imshow(t1),title('原图')
figure(2),subplot(2,2,1),imhist(t1),title('原图')
fa=1.25,fb=0
t2=fa.*t1+fb/255
figure(1)
subplot(2,2,2),imshow(t2),title('fa=1.25 fb=0')
figure(2),subplot(2,2,2),imhist(t2),title('fa=1.25 fb=0')
fa=0.5,fb=0
t2=fa.*t1+fb/255
figure(1)
subplot(2,2,3),imshow(t2),title('fa=0.5 fb=0')
figure(2),subplot(2,2,3),imhist(t2),title('fa=0.5 fb=0')
fa=-1,fb=255
t2=fa.*t1+fb/255
figure(1)
subplot(2,2,4),imshow(t2),title('fa=-1 fb=255')
figure(2),subplot(2,2,4),imhist(t2),title('fa=-1,fb=255')
2)对数变换
 t=imread('t1.jpg')
t1=double(rgb2gray(t))
t2=log(1+t1)/0.033
t3=log(1+t1)/0.092
t2=uint8(t2)
t3=uint8(t3)
subplot(2,3,1),imshow(t),title('原图')
subplot(2,3,4),imhist(t),title('原图')
subplot(2,3,2),imshow(t2),title('r=0.033')
subplot(2,3,5),imhist(t2),title('r=0.032')
subplot(2,3,3),imshow(t3),title('r=0.092')
subplot(2,3,6),imhist(t3),title('r=0.092')
3)指数变换
 t=imread('t1.jpg')
t1=double(rgb2gray(t))
t2=1.4.^(t1*0.09)-1
t3=1.4.^(t1*0.03)-1
t2=uint8(t2)
t3=uint8(t3)
subplot(2,3,1),imshow(t),title('原图')
subplot(2,3,4),imhist(t),title('原图')
subplot(2,3,2),imshow(t2),
subplot(2,3,5),imhist(t2),
subplot(2,3,3),imshow(t3),
subplot(2,3,6),imhist(t3)
4)取反
 t=imread('a1.jpg')
t1=im2double(rgb2gray(t))
fa=-1,fb=255
t2=fa.*t1+fb/255
subplot(2,2,1),imshow(t1),title('原图')
subplot(2,2,2),imhist(t1),title('原图')
subplot(2,2,3),imshow(t2),title('取反')
subplot(2,2,4),imhist(t2),title('取反')

直方图均衡化

H= imread('a1.jpg'); 

%判断是否为三通道彩色图片 若是 则将其灰度化
if length(size(H))>2
    H=rgb2gray(H);  
end

%获取图片的尺寸 便于计算总像素数 即m*n 
[m,n]=size(H);  

%生成一个一行256列的矩阵
p=zeros(1,256);  

% 统计各灰度的像素个数 
%find(H==i) 是在图像矩阵里面寻找灰度为i的点坐标 
% 因为矩阵是从1开始的 所以为p(i+1)
for i=0:255  
   p(i+1)=length(find(H==i))/(m*n);  
end  

subplot(2,2,1);  
imshow(H);  
title('原图');  
subplot(2,2,2);  
% 显示原图的直方图
bar(0:255,p,'b');  
title('原图直方图');  

 % 利用循环 累加概率值
s=zeros(1,256);  
for i=1:256  
     for j=1:i  
         s(i)=p(j)+s(i);                  
     end  
end  

%对s中的数先乘以255,再取整   
a=round(s*255);  
b=H;  
%更新原图像的灰度
for i=0:255  
     b(find(H==i))=a(i+1);                
end

subplot(2,2,3);  
imshow(b)                            
title('均衡化后图像');  
 %统计更新后的概率
for i=0:255  
    GPeq(i+1)=sum(p(find(a==i)));            
end  
subplot(2,2,4);  
bar(0:255,GPeq,'b'); title('均衡化后的直方图');

GML、SML映射
t=imread('a1.jpg')
%获取图片的长和宽,用于计算总像素,即m*n
[m,n]=size(t);

%n_1 这里是先统计各灰度的像素数,后面会变换为概率
n_1=zeros(1,256);

%统计各灰度的像素数
for i=1:m
for j=1:n
n_1(t(i,j)+1)=n_1(t(i,j)+1)+1;
end
end

%转换为概率
n_1=n_1/m/n; %计算各个灰度级的概率

%p_1  记录原图的累积直方图概率
p_1=zeros(1,256);

%p_1 计算原始累积直方图的概率
for i=1:256
for j=1:i
p_1(i)=p_1(i)+n_1(j);
end
end

%n_2  规定直方图的灰度概率分布
n_2=[zeros(1,50),0.1,zeros(1,50),0.2,zeros(1,50),0.3,zeros(1,50),0.2,zeros(1,20),0.1,zeros(1,30),0.1];

%p_2 记录规定直方图的累积概率
p_2=zeros(1,256);

% 计算规定直方图累积概率
for i=1:256
for j=1:i
p_2(i)=p_2(i)+n_2(j);
end
end

%SML映射算法
data_1=zeros(1,256);%data_1 SML映射表

for i=1:256
min=abs(p_1(i)-p_2(1));
for j=2:256
if  abs(p_1(i)-p_2(j))<min
min=abs(p_1(i)-p_2(j));
data_1(i)=j-1;
end
end
end

%GML
 data_2=zeros(1,256); %data_2记录GML映射表

for i=1:256
if n_2(i)~=0
tem=1;
min=abs(p_2(i)-p_1(1));
for j=2:256
if abs(p_2(i)-p_1(j))<min
min=abs(p_2(i)-p_1(j));
tem=j;
end
end
data_2(tem)=i-1;
end
end

%将上面得到的data_2 转换为目标数组(原理解释有c++算法)
for i=1:256
if data_2(i)==0
for j=i:256
if data_2(j)~=0
tem=data_2(j);
break;
end
end
data_2(i)=tem;
end
end

%利用SML、GML映射表,转换原图像
t2=t;
t3=t;

%转换算法
for i=1:m
for j=1:n
t2(i,j)=data_1(t(i,j)+1);
end
end
for i=1:m
for j=1:n
t3(i,j)=data_2(t(i,j)+1);
end
end

%显示
subplot(3,2,1),imshow(t),title('原图')
subplot(3,2,2),imhist(t),title('原图')
subplot(3,2,3),imshow(t2),title('SML')
subplot(3,2,4),imhist(t2),title('SML')
subplot(3,2,5),imshow(t3),title('GML')
subplot(3,2,6),imhist(t3),title('GML')

七、实验结果与分析

图 1原图


在这里插入图片描述

灰度变换

图 2线性变换


在这里插入图片描述

图 3线性变换直方图


在这里插入图片描述

图 4对数变换


在这里插入图片描述

图 5指数变换


在这里插入图片描述

图 6取反


在这里插入图片描述

灰度变换分析
线性变换:fa>1时,输出图像的对比度将增大;fa<1时,输出图像对比度将减小。Fa=1且fb非零时,所有像素的灰度值上移或者下移,使得整个图像更暗或者更亮。Fa<0,暗区变亮,亮区变暗。
对数变换:可以增强一副图像中较暗部分的细节,用来拓展被压缩的高值图像中的较暗像素。
指数变换:可以增强一副图像中较亮部分的细节,用来拓展被压缩的高值图像中的较亮像素。
取反:与原来的图像成鲜明的对比,暗区变亮区,亮区变暗区。

直方图均衡化

GML、SML映射

八、实验总结及心得体会

在这次实验中,自己学到了利用一些简单数学函数对数字图像进行处理,比如简单的线性变换、对数、指数变换等,利用这些简单操作,可以对图像进行一些处理,达到一定的效果。刚开始的时候,对图像处理的概念不是很强,通过这次的学习,了解到对图像进行处理,其实无非就是对图片中的一些像素点进行处理,而像素点代表的值就是图像的灰度值。在直方图的均衡化和GML、SML映射中,发现可以利用已学C++的知识来进行解题。在两种映射方法中,最难的还是GML,这里还是下了一定的功夫的。

附:SML-GML算法验证

直方图规定化

原理
所谓直方图规定化,就是通过一个灰度映像函数,将原灰度直方图改造成所希望的直方图。说的通俗一点就是,原图像的灰度是从0~255的,其分布是随机的,在一些情况下,我们可能需要一些特定的灰度值,比如我们只需要灰度值为0 3 40 240 255 这些值,除此之外的灰度值我们不需要,那么从原图像到我们需要的图像就可以理解成图像的规定化。

具体事例
左图是原图像的灰度直方图,右图是我们需要的图(这里的需要是指需要灰度由原来的0~7变成规定的1 3 6,规定化后图像的纵坐标是会变的,这里只需要横坐标吻合就行!)
规定化后的图像(横坐标和规定一样,纵坐标是会变化的):
实现步骤:

  1. 分别计算出原图像和规定图像的累加直方图
  2. 利用SML或者GML映射灰度值
  3. 利用更新后的映射表转换原图像的灰度值

看完之后,应该还是不懂?那么直接实战一题!题目见下图:
解题步骤:

  1. 这里是直接给出的原图像各灰度的像素个数,为了得到我们需要的直方累加图(其实是概率累加值,当然也可以不用概率,直接用像素点数也行,就是看起来数字比较大),需要先算出原图像各灰度的概率(占总像素个数的比例),然后在计算累加值 2. 根据给出的规定直方图,同样的方法计算累加直方图,见下图 3. 利用SML映射规则得出结果
  2. 利用映射变化表,更新原图像

提示

这里可能不懂SML映射规则,我说说自己简单的理解(自己也可以自行百度):
SML就是单映射,这里我们关注原图累加直方图和规定累加直方图,所谓SML,就是从原图累加直方图开始,在规定累加直方图寻找和自己最接近的值,然后把它的灰度值变成自己的。具体来说,原图第一个累加概率是0.19,在规定累加直方图中,最接近它的就是0.15,那么原图的灰度0变成规定的3,第二个累加概率是0.44,最接近规定累加直方图的0.35,所以由1变成4,同理,依次遍历完原图累加直方图的概率就行,在规定累加直方图找到最靠近自己的值,最后进行灰度变化。

SML规则懂了,GML规则也就好理解了(GML规则其实编程更难):

SML中,我们是依次遍历原图累加直方图,在规定累加直方图寻找最靠近自己的。在GML(组映射)中,就变成了依次从规定累加直方图中,对比原图累加直方图,也是找到最靠近的值,进行灰度变换,只是这里的变换规则变了。
具体举例来说,从上图看,这里我们这里从规定累加直方图的0.15看,前面的0其实不用看,再从原始累加直方图找到最接近0.15的值,是0.19,那么0.19对应和它对应灰度值前面的灰度变成规定累加直方图中0.15所对应的灰度值:3;第二个看规定累加直方图的0.35,靠近原图的0.44,那么原图的1变成4(假设这里0.44对应的原图灰度值为4,那么在前一个不为0和4之间变成4)
这里有的不好理解,举个例子:
原数组:1 0 0 2 0 3 0 0 0 4 0 0 6
GML映射变化规则的目标数组就是:1 2 2 2 3 3 4 4 4 4 6 6 6
解释:1前面的数变为1,1和2之间变成2,2和3之间变成3,3和4之间变成4,4和6之间变成6,简单的说就是变0变成后面最靠近的一个不为0的数。(这里算法自己需要掌握,即如何从原数组变成目标数组,这里先给个C++的验证算法)

#include<iostream>
using namespace std;
int main()
{
    int t[8]={2,0,1,0,3,0,0,6};
    int i,j;
    int tem;
    int flag=0;
    for (i=0;i<8;i++)
    {
    if(t[i]==0)
    {

    for(j=i;j<8;j++)
    {
    if(t[j]!=0)
    {
    tem=t[j];
    break;}
    }
     t[i]=tem;

    }
    }
for(i=0;i<8;i++)
cout<<t[i]<<" ";
return 0;
}

如果还是不懂SML和GML规则的话?那自己根据下面两种图片再理解理解吧。
MATLAB实战
原理懂了,肯定就是要开始实战了啊!
这里我先上全部代码:

 t=imread('a1.jpg')
%获取图片的长和宽,用于计算总像素,即m*n
[m,n]=size(t);

%n_1 这里是先统计各灰度的像素数,后面会变换为概率
n_1=zeros(1,256);

%统计各灰度的像素数
for i=1:m
for j=1:n
n_1(t(i,j)+1)=n_1(t(i,j)+1)+1;
end
end

%转换为概率
n_1=n_1/m/n; %计算各个灰度级的概率

%p_1  记录原图的累积直方图概率
p_1=zeros(1,256);

%p_1 计算原始累积直方图的概率
for i=1:256
for j=1:i
p_1(i)=p_1(i)+n_1(j);
end
end

%n_2  规定直方图的灰度概率分布
n_2=[zeros(1,50),0.1,zeros(1,50),0.2,zeros(1,50),0.3,zeros(1,50),0.2,zeros(1,20),0.1,zeros(1,30),0.1];

%p_2 记录规定直方图的累积概率
p_2=zeros(1,256);

% 计算规定直方图累积概率
for i=1:256
for j=1:i
p_2(i)=p_2(i)+n_2(j);
end
end

%SML映射算法
data_1=zeros(1,256);%data_1 SML映射表

for i=1:256
min=abs(p_1(i)-p_2(1));
for j=2:256
if  abs(p_1(i)-p_2(j))<min
min=abs(p_1(i)-p_2(j));
data_1(i)=j-1;
end
end
end

%GML
 data_2=zeros(1,256); %data_2记录GML映射表

for i=1:256
if n_2(i)~=0
tem=1;
min=abs(p_2(i)-p_1(1));
for j=2:256
if abs(p_2(i)-p_1(j))<min
min=abs(p_2(i)-p_1(j));
tem=j;
end
end
data_2(tem)=i-1;
end
end

%将上面得到的data_2 转换为目标数组(原理解释有c++算法)
for i=1:256
if data_2(i)==0
for j=i:256
if data_2(j)~=0
tem=data_2(j);
break;
end
end
data_2(i)=tem;
end
end

%利用SML、GML映射表,转换原图像
t2=t;
t3=t;

%转换算法
for i=1:m
for j=1:n
t2(i,j)=data_1(t(i,j)+1);
end
end
for i=1:m
for j=1:n
t3(i,j)=data_2(t(i,j)+1);
end
end

%显示
subplot(3,2,1),imshow(t),title('原图')
subplot(3,2,2),imhist(t),title('原图')
subplot(3,2,3),imshow(t2),title('SML')
subplot(3,2,4),imhist(t2),title('SML')
subplot(3,2,5),imshow(t3),title('GML')
subplot(3,2,6),imhist(t3),title('GML')

效果图:

总结

SML、GML两个算法用来一天才搞清楚原理,书上的公式开始看真的是好难啊,看不进去,网上的方法,真的是,没有自己想要的。算法其实一天就搞定了,当时由于MATLAB语法还不是很熟,走了很多弯路。下面总结下自己的踩坑吧:

  • MATLAB里面的循环写法 for i=1:256 c++:for(i=1;i<=256;i++)
  • for、if等用end结束,end个数必须和if、for配对,比如,3个for,2个if,就必须有5个end结束,不然程序会一直执行下去
  • 程序语句最后有无 ; 的区别:写了 ; 本地代码区不会显示具体数据,反之不写,则会显示,建议还是写吧,和c++语法类似。
  • 多打印数据,一步一步调试,便于寻找bug
x.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,293评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,604评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,958评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,729评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,719评论 5 366
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,630评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,000评论 3 397
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,665评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,909评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,646评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,726评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,400评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,986评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,959评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 44,996评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,481评论 2 342