上一篇博文中讲到的直方图均衡技术,可以自动地确定变换函数,而产生具有均匀直方图的输出图像。对于需要自动增强时,该算法仅需简单的操作就能扩展灰度级,且结果可以预知,因此是一种好方法。但是,不同图像出现的问题不尽相同,有时我们需要根据图像的某种缺陷,得出处理后的图像需要具有某种形状的直方图。因此,均衡化这样单一的方法显然不能成为万能钥匙。这时,就轮到直方图规定化技术登场了。规定化,顾名思义,就是规定好输出图像应该具有什么样形状的直方图。那么,这个“形状”该怎么规定呢?通常,我们指定一个规定的概率函数来表示所需的直方图,常用的有均匀分布函数、指数分布函数、双曲分布函数、高斯分布函数……
接着讨论如何实现直方图的规定化,以下是书中的推导(由于仍存在不理解的部分,暂且放弃自己推导)。注意,r和z分别表示输入图像和输出(已处理)图像的灰度级。
令s为一个具有如下特性的随记变量:
不难发现,这个式子就是前面推导的直方图均衡化的连续形式。
接着,我们定义一个有如下特性的随记变量z:
(重点来了,画圈圈的地方我不是很懂,为什么令s等于G(z),推出来的结果就能使z的pdf等于r的pdf?)为了继续下去,我只有先假装认同这个任何书上都一笔带过的步骤(可能是我太笨了)。
由这两个等式可得G(z)=T(r),因此就可以求出z:
总结来说,按照下列步骤,就可由一幅给定图像得到一幅灰度级具有指定概率密度函数的图像:
1. 由输入图像得到p(r),并求出s.
2. 由指定的概率密度函数求出G(z).
3. 求得反变换函数,并对所有输入像素应用第三个公式,即可求出输出图像.
实现的时候,需要利用上述公式的离散形式。重写如下:
其中符号与直方图均衡化中相同。
对一个q值,有:
与前面一样,利用反变换找到期望的z值:
实现上述公式的重点在于:该操作对每一个s值给出一个z值。这样,就形成了从s到z的一个映射。因此,实际中,我们并不需要计算G的反变换。计算q=0,1,2,…,L-1时的所有可能的G值是一件简单的事情。标定这些值,并取整。将这些值存储在一个表中,然后,给定一个特殊的Sk值后,我们可以查找存储在表中的最匹配值(离散情况下,不一定能找到相等的值,此时就要找最接近的值,即最匹配!)。重复该过程,我们将找到所有s值到z值的映射(当满足给定s值的z值多于一个时,即映射不唯一时,按惯例选择最小的值),他们就是最接近的解。
目前来说,在上述说到的查找最匹配的映射过程中,存在两种映射方法:单映射规则(SML)和组映射规则(GML)。具体区别很值得琢磨,以后另写一篇博文再研究,下面先用单映射规则编码实现。
% ***************************Copyright 2016[c]**************************
% ************************Declaration************************************
% File name: histogram_specification
% Author: 靖Harry
% Date: 22-Jul-2016 22:10:28
% Version Number: 1.0
% Abstract:
% Transforms the original intensity image so that the histogram
% of the output image with length bins approximately matches
% the specified histogram.
% *********************************end*********************************
clear
clc
I1=imread('0.tif');
[m,n]=size(I1);
L=256; % 灰度级
%对输入图像均衡化
nk=zeros(1,256);
for i1=1:m
for j1=1:n
nk(I1(i1,j1)+1)=nk(I1(i1,j1)+1) + 1 ;
end
end
pk=nk/(m*n);
sk=zeros(1,256);
for i2=1:L
for j2=1:i2
sk(i2)=sk(i2)+pk(j2);
end
end
sk=fix((L-1)*sk); % 取整数部分.
%规定化直方图
counts=[zeros(1,49),0.1,zeros(1,49),0.2,zeros(1,49),0.3,zeros(1,49),0.1,zeros(1,49),0.2,zeros(1,49),0.1];
%对规定直方图进行均衡化
gk=zeros(1,256);
for i3=1:256
for j3=1:i3
gk(i3)=counts(j3)+gk(i3);
end
end
gk=fix((L-1)*gk); % 取整数部分.
%SML映射规则
for i=1:256
minvalue=abs(sk(i)-gk(1)); %先假设与第一个G值为最小间距
T(i)=0;
for j=2:256
if abs(sk(i)-gk(j))abs(sk(i)-gk(j)); %求出最小距离值,即最匹配值
T(i)=j-1; %建立映射关系
end
end
end
%将映射的结果组合成输出图像
I2=I1;
for i5=1:m
for j5=1:n
I2(i5,j5)=T(I2(i5,j5)+1);
end
end
subplot(2,2,1),imshow(I1),title('原图像');
subplot(2,2,2),bar(1:300,counts,'r'),title('规定直方图');
subplot(2,2,3),histeq(I1,counts),title('histeq函数处理结果');
subplot(2,2,4),imshow(I2),title('我的函数处理结果');
很明显可以看到,我写的函数处理的结果与matlab自带函数处理的结果仍有区别,我没看histeq函数内部的实现,在此做一个猜想:histeq函数采用的是组映射(GML)规则,而我的函数采用的是单映射(SML)规则。从前人的经验来看,采用SML映射方式,所得结果与规定直方图差距较大,而GML映射的结果,基本与规定直方图一致。两者相比较,GML映射规则的优势十分明显。具体映射规则的内容及差异下回再好好研究,在此先不做讨论。