图像直方图均衡化
首先,我们要理解什么是图像直方图均衡化:
把原始图像的灰度直方图从比较集中的某个灰度区间变成在全部灰度范围内的均匀分布。直方图均衡化就是对图像进行非线性拉伸,重新分配图像像素值,使一定灰度范围内的像素数量大致相同。直方图均衡化就是把给定图像的直方图分布改变成“均匀”分布直方图分布,具体见下图(说的简单点,就是把原来的图像的灰度分配均匀,使得0-255都有一定的取值,这样对比度相对大一些,视觉上更好看一点):
这里我们可以直接利用histeq()、adapthisteq()函数对图像进行均衡化
H= imread('a1.jpg');
if length(size(H))>2
H=rgb2gray(H);
end
subplot(3,2,1);
imshow(H); title('原图');
subplot(3,2,2);
imhist(H); title('原图直方图');
subplot(3,2,3);
H1=adapthisteq(H);
imshow(H1); title('adapthisteq均衡后图');
subplot(3,2,4);
imhist(H1);title('adapthisteq均衡后直方图');
subplot(3,2,5);
H2=histeq(H);
imshow(H2); title('histeq均衡后图');
subplot(3,2,6);
imhist(H1); title('histeq均衡后直方图');
效果图:
当然,我们也可以自己编写均衡化函数,首先就要了解均衡化的算法步骤(这里我就不多说了)
上代码:
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('均衡化后的直方图');
效果图:
方法二(从大佬那里copy的)
Img= imread('a1.jpg');
if length(size(Img))>2
Img=rgb2gray(Img);
end
%绘制原始图像的直方图
[height,width]=size(Img);
[counts1, x] = imhist(Img,256);
counts2 = counts1/height/width;
figure(1),
subplot(1,2,1),
imshow(Img);title('原始图像');
subplot(1,2,2),
stem(x, counts2); title('原始图像直方图');
%统计每个灰度的像素值累计数目
NumPixel = zeros(1,256);%统计各灰度数目,共256个灰度级
for i = 1:height
for j = 1: width
%对应灰度值像素点数量+1
%NumPixel的下标是从1开始,而图像像素的取值范围是0~255,所以用NumPixel(Img(i,j) + 1)
NumPixel(Img(i,j) + 1) = NumPixel(Img(i,j) + 1) + 1;
end
end
%将频数值算为频率
ProbPixel = zeros(1,256);
for i = 1:256
ProbPixel(i) = NumPixel(i) / (height * width * 1.0);
end
%函数cumsum来计算cdf,并将频率(取值范围是0.0~1.0)映射到0~255的无符号整数
CumuPixel = cumsum(ProbPixel);
CumuPixel = uint8(255 .* CumuPixel + 0.5);
%直方图均衡。赋值语句右端,Img(i,j)被用来作为CumuPixel的索引
for i = 1:height
for j = 1: width
Img(i,j) = CumuPixel(Img(i,j)+1);
end
end
%显示更新后的直方图
figure(2),
subplot(1,2,1),
imshow(Img); title('直方图均衡化图像');
[counts1, x] = imhist(Img,256);
counts2 = counts1/height/width;
subplot(1,2,2),
stem(x, counts2); title('直方图均衡化后图像的直方图');
上面都是对灰度图片进行均衡化,那么对彩色图片怎么均衡化呢?办法肯定是有的。我们知道,彩色图片无非就是RGB三通道组成的,只要我们分别对三个通道进行均衡化,再合成,得到的图片就是彩色的,均衡化后的。
上代码:
Img= imread('a1.jpg');
OutImg=Img;
%分别提取三通道的信息
R = Img(:,:,1);
G = Img(:,:,2);
B = Img(:,:,3);
%分别对三通道的图片进行均衡化
R = histeq(R, 256);
G = histeq(G, 256);
B = histeq(B, 256);
%最后合成为一张图片
OutImg(:,:,1) = R;
OutImg(:,:,2) = G;
OutImg(:,:,3) = B;
figure,
subplot(1,2,1),
imshow(Img);title('原始图像');
subplot(1,2,2),
imshow(OutImg); title('均衡化后结果');
效果图(感觉颜色更加丰富了,哈哈):
这里其实还有一种方法,就是先把RGB转换为HSV,再均衡化
上代码:
mg= imread('a1.jpg');
hsvImg = rgb2hsv(Img);
V=hsvImg(:,:,3);
[height,width]=size(V);
V = uint8(V*255);
NumPixel = zeros(1,256);
for i = 1:height
for j = 1: width
NumPixel(V(i,j) + 1) = NumPixel(V(i,j) + 1) + 1;
end
end
ProbPixel = zeros(1,256);
for i = 1:256
ProbPixel(i) = NumPixel(i) / (height * width * 1.0);
end
CumuPixel = cumsum(ProbPixel);
CumuPixel = uint8(255 .* CumuPixel + 0.5);
for i = 1:height
for j = 1: width
V(i,j) = CumuPixel(V(i,j)+1); %注意,这里需要+1,要不然会出问题
end
end
V = im2double(V);
hsvImg(:,:,3) = V;
outputImg = hsv2rgb(hsvImg);
figure,
subplot(1,2,1),
imshow(Img);title('原始图像');
subplot(1,2,2),
imshow(outputImg); title('在HSV空间均衡化后结果');
效果图(感觉没有上一种方法好看,这个其实是要分图片的):