基于直方图修正的图像增强:是一种常见的图像处理方法。该方法通过对图像的像素值分布进行调整,以改善图像的对比度和亮度等视觉效果。具体地,直方图校正方法将图像的像素值转换为一个新的值域范围,使得像素值的分布更加均匀,从而增强图像的细节和对比度。这种方法通常包括以下步骤
直方图校正方法可以有效地改善图像的视觉质量,但也可能会导致一些问题,比如增强后的图像可能出现过度增强或者噪声增加等情况。因此,在实际应用中需要根据具体情况选择适当的直方图校正方法和参数
灰度直方图:表示的是数字图像中每一灰度级与其出现频数(即该灰度上出现像素的数目)间的统计关系。具体来说,它将灰度级的像素值与其在图像中出现的频次(或概率)作为纵轴和横轴上的坐标,形成一个直方图
p ( r k ) = n k N p(r_{k})=\frac{n_{k}}{N} p(rk)=Nnk
例如下图这张图像,可以得到其灰度直方图
MATLAB实现:相关函数如下,具体解释可看MATLAB帮助手册
imhist(I,N)
Image=rgb2gray(imread('couple.bmp'));
histgram=zeros(256);
[h w]=size(Image);
for x=1:w
for y=1:h %循环扫描
histgram(Image(y,x)+1)=histgram(Image(y,x)+1)+1; %统计并累加
end
end
imwrite(Image,'Gcouple.bmp');
imshow(Image);title('couple灰度图像');
figure;stem(histgram(),'.');
axis tight;
colormap(gray)
figure;imhist(Image);
axis tight;
colormap(gray)
Python实现:
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
import cv2
import matplotlib.pyplot as plt
import numpy as np
# 读入图像并转换为灰度图
Image = cv2.imread('couple.bmp')
Image = cv2.cvtColor(Image, cv2.COLOR_BGR2GRAY)
# 初始化直方图
histogram = np.zeros(256)
# 统计每个像素值的数量
h, w = Image.shape[:2]
for x in range(w):
for y in range(h):
histogram[Image[y, x]] += 1
# 保存图像
cv2.imwrite('Gcouple.bmp', Image)
# 显示图像和直方图
plt.subplot(121)
plt.imshow(Image, cmap='gray')
plt.title('couple灰度图像')
plt.subplot(122)
plt.stem(histogram, use_line_collection=True)
plt.axis('tight')
plt.title('灰度直方图')
plt.show()
灰度直方图性质:
总的来说,不同直方图引起不同的视觉效果,同一直方图可以对应不同的图像
直方图修正法理论:图像的灰度动态范围太小或者说其直方图集中在某一个灰度区间,视觉效果不理想;当图像直方图占满所有灰度级区间,且所有灰度级的概率分布相接近,即直方图均匀分布的图像其视觉效果会最理想。另一方面,从随机信号及信息量的角度来看,各个灰度级的概率分布等概率时,信息量最大,熵最大。因此,需要寻找这一个变换,使得变换后图像直方图均匀,这就是直方图均衡化
设 0 ≤ r ≤ 1 0\leq r \leq 1 0≤r≤1为要增强像素灰度级, 0 ≤ s ≤ 1 0 \leq s \leq 1 0≤s≤1为增强后新灰度级,直方图修正公式为 s = T ( r ) s=T(r) s=T(r)(或 r = T − 1 ( s ) r=T^{-1}(s) r=T−1(s)),式中 T ( r ) T(r) T(r)为变换函数,需要满足以下两个条件
直方图均衡化:又叫做直方图均匀化。其目的是使所有灰度级出现的相对频数(概率)相同,此时图像所包含的信息量最大。也就是使得原图像的灰度直方图修正为均匀分布的直方图,实现图像的全局整体均匀化
设 p r ( r ) p_{r}(r) pr(r)和 p s ( s ) p_{s}(s) ps(s)分别表示 r r r和 s s s的灰度概率密度函数,则变换前后有
p s ( s ) d s = p r ( r ) d r ∫ 0 s p s ( s ) d s = ∫ 0 r p r ( r ) d r \begin{array}{l}p_{s}(s) d s=p_{r}(r) d r \\\int_{0}^{s} p_{s}(s) d s=\int_{0}^{r} p_{r}(r) d r\end{array} ps(s)ds=pr(r)dr∫0sps(s)ds=∫0rpr(r)dr
因为均衡化后有 p s ( s ) = 1 p_{s}(s)=1 ps(s)=1,因此直方图均衡化变化函数为 s = T ( r ) = ∫ 0 r p r ( ω ) d ω s=T(r)=\int_{0}^{r} p_{r}(\omega) d \omega s=T(r)=∫0rpr(ω)dω
数字图像的直方图均衡化:一幅离散数字图像,共 L L L个灰度等级,其中第 k k k个灰度级 r k r_{k} rk出现的像素个数为 n k n_{k} nk,图像总像素个数为 N N N。则第 k k k个灰度级出现的概率为
P ( r k ) = n k N 0 ≤ r k ≤ 1 , k = 0 , 1 , … , L − 1 P\left(r_{k}\right)=\frac{n_{k}}{N} \quad 0 \leq r_{k} \leq 1, k=0,1, \ldots, L-1 P(rk)=Nnk0≤rk≤1,k=0,1,…,L−1
进行均衡化处理的变换函数 T ( r ) T(r) T(r)为
s k = T ( r k ) = ∑ j = 0 k p r ( r j ) = ∑ j = 0 k n j N s_{k}=\boldsymbol{T}\left(r_{k}\right)=\sum_{j=0}^{k} p_{r}\left(r_{j}\right)=\sum_{j=0}^{k} \frac{n_{j}}{N} sk=T(rk)=j=0∑kpr(rj)=j=0∑kNnj
数字图像的直方图均衡化算法步骤为
如下,给定一幅64×64的8级灰度图像,其灰度级分布如表中所示,对其进行直方图均衡化
首先计算新灰度级
接着修正 s k s_{k} sk为合理的灰度级 s k ′ s^{\prime}_{k} sk′
则新图像对应只有5个不同的灰度级别
然后计算新的直方图
最后生成新图像
新旧直方图对比
MATLAB实现:相关函数如下,具体解释可看MATLAB帮助手册
histeq(I,N)
Image=rgb2gray(imread('couple.bmp'));
histgram =imhist(Image); %统计图像直方图
[h w]=size(Image);
NewImage1=zeros(h,w);
NewImage2=zeros(h,w);
s=zeros(256);
s(1)=histgram(1);
for t=2:256
s(t)=s(t-1)+histgram(t); %计算新的灰度值
end
for x=1:w
for y=1:h
NewImage1(y,x)=s(Image(y,x)+1)/(w*h); %生成新图像
end
end
NewImage2=histeq(Image,256);%调用Matlab函数
imshow(Image);title('couple灰度图像');
figure;imhist(Image);title('couple灰度图像的直方图');
axis tight;
figure;imshow(NewImage1);title('全局直方图均衡化处理后图像');
figure;imhist(NewImage1);title('全局直方图均衡化处理后图像的直方图');
axis tight;
figure;imshow(NewImage2);title('Matlab函数全局均衡化处理后图像');
figure;imhist(NewImage2);title('Matlab函数全局均衡化处理后图像的直方图');
axis tight;
Python实现:
import cv2
import numpy as np
import matplotlib.pyplot as plt
plt.rcParams['font.sans-serif'] = ['SimHei']
# 读取图像
img = cv2.imread('couple.bmp')
# 转换为灰度图像
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 统计图像直方图
histogram = cv2.calcHist([gray_img], [0], None, [256], [0, 256])
# 计算新的灰度值
s = np.zeros((256,))
s[0] = histogram[0]
for t in range(1, 256):
s[t] = s[t-1] + histogram[t]
# 生成新图像
new_img1 = np.zeros_like(gray_img)
h, w = gray_img.shape[:2]
for y in range(h):
for x in range(w):
new_img1[y, x] = s[gray_img[y, x]] / (w * h)
# 调用OpenCV自带的全局均衡化函数
new_img2 = cv2.equalizeHist(gray_img)
# 显示图像和直方图
plt.subplot(2, 2, 1)
plt.imshow(gray_img, cmap='gray')
plt.title('couple灰度图像')
plt.subplot(2, 2, 2)
plt.hist(gray_img.ravel(), 256, [0, 256])
plt.title('couple灰度图像的直方图')
plt.axis('tight')
plt.subplot(2, 2, 3)
plt.imshow(new_img1, cmap='gray')
plt.title('全局直方图均衡化处理后图像')
plt.subplot(2, 2, 4)
plt.hist(new_img1.ravel(), 256, [0, 256])
plt.title('全局直方图均衡化处理后图像的直方图')
plt.axis('tight')
plt.show()
# 显示OpenCV自带函数处理后的图像和直方图
cv2.imshow('Matlab函数全局均衡化处理后图像', new_img2)
cv2.waitKey(0)
cv2.destroyAllWindows()
plt.figure()
plt.hist(new_img2.ravel(), 256, [0, 256])
plt.title('Matlab函数全局均衡化处理后图像的直方图')
plt.axis('tight')
plt.show()
局部直方图均衡化:根据区域的局部直方图统计特性来定义灰度级变换函数,进行均衡化处理,这就是局部直方图均衡化。给出一幅数字图像,选定大小为 w × h w×h w×h的矩形子块 S S S,子块 S S S内进行直方图均衡化处理,有
s k = T ( r k ) = ∑ j = 0 k p S ( r j ) = ∑ j = 0 k n j w × h s_{k}=\boldsymbol{T}\left(r_{k}\right)=\sum_{j=0}^{k} p_{S}\left(r_{j}\right)=\sum_{j=0}^{k} \frac{n_{j}}{w \times h} sk=T(rk)=j=0∑kpS(rj)=j=0∑kw×hnj
可以分为如下三类
MATLAB实现:
Image=(rgb2gray(imread('couple.bmp')));
imshow(Image);title('原始图像');
result1=blkproc(Image,[32 32],@histeq);
figure,imshow(result1);title('无重叠的局部直方图均衡化图像');
imwrite(result1,'NLHE.bmp');
[height,width]=size(Image);
result2=zeros(height,width);
n=16;%邻域模板半径
hh=height+2*n; ww=width+2*n;
ff=zeros(hh,ww);%图像对外边缘扩充ff
ff(n+1:hh-n,n+1:ww-n)=Image;
ff(1:n,n+1:ww-n)=Image(1:n,:);
ff(hh-n+1:hh,n+1:ww-n)=Image(height-n+1:height,:);
ff(:,1:n)=ff(:,n+1:n*2);
ff(:,ww-n+1:ww)=ff(:,ww+1-n*2:ww-n);
ff=uint8(ff);
for i=n+1:hh-n
for j=n+1:ww-n
lwc=histeq(ff(i-n:i+n,j-n:j+n),256);
result2(i-n,j-n)=lwc(n+1,n+1);%实现对子块中心像素点的均衡化处理
end
end
figure,imshow(uint8(result2));title('重叠的局部直方图均衡化图像');
imwrite(uint8(result2),'LHE.bmp');
sumf=int16(zeros(hh,ww));%%转化成int16型数据
num=zeros(hh,ww);
for i=n+1:8:hh-n
for j=n+1:8:ww-n
lwc=int16(histeq(ff(i-n:i+n,j-n:j+n),256));%计算子块的局部直方图均衡化
sumf(i-n:i+n,j-n:j+n)=sumf(i-n:i+n,j-n:j+n)+lwc;%像素的均衡化结果进行累加
num(i-n:i+n,j-n:j+n)=num(i-n:i+n,j-n:j+n)+1;%像素被均衡化的累加次数
end
end
result3(:,:)=double(sumf(n+1:hh-n,n+1:ww-n));
result3(:,:)=result3(:,:)./num(n+1:hh-n,n+1:ww-n);%像素的均衡化结果取平均值
rr(:,:)=uint8(result3(:,:));
figure,imshow(uint8(result3(:,:)));title('部分重叠的局部直方图均衡化图像');
imwrite(uint8(result3(:,:)),'POSHE.bmp');
Python实现:
import cv2
import numpy as np
from matplotlib import pyplot as plt
# 读入图像
Image = cv2.imread('couple.bmp')
Image = cv2.cvtColor(Image, cv2.COLOR_BGR2GRAY)
# 显示原始图像
plt.imshow(Image, cmap='gray')
plt.title('原始图像')
plt.show()
# 无重叠的局部直方图均衡化
result1 = cv2.normalize(cv2.boxFilter(Image, -1, (32, 32)), None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
plt.imshow(result1, cmap='gray')
plt.title('无重叠的局部直方图均衡化图像')
plt.show()
cv2.imwrite('NLHE.bmp', result1)
# 重叠的局部直方图均衡化
n = 16
hh, ww = Image.shape[0] + 2 * n, Image.shape[1] + 2 * n
ff = np.zeros((hh, ww), dtype=np.uint8)
ff[n:hh-n, n:ww-n] = Image
ff[0:n, n:ww-n] = Image[0:n, :]
ff[hh-n:hh, n:ww-n] = Image[Image.shape[0]-n:Image.shape[0], :]
ff[:, 0:n] = ff[:, n:2*n]
ff[:, ww-n:ww] = ff[:, ww-2*n:ww-n]
result2 = np.zeros_like(Image, dtype=np.uint8)
for i in range(n, hh-n):
for j in range(n, ww-n):
lwc = cv2.equalizeHist(ff[i-n:i+n+1, j-n:j+n+1])
result2[i-n, j-n] = lwc[n, n]
plt.imshow(result2, cmap='gray')
plt.title('重叠的局部直方图均衡化图像')
plt.show()
cv2.imwrite('LHE.bmp', result2)
# 部分重叠的局部直方图均衡化
result3 = np.zeros_like(Image, dtype=np.float32)
num = np.zeros((hh, ww), dtype=np.uint8)
for i in range(n, hh-n, 8):
for j in range(n, ww-n, 8):
lwc = cv2.equalizeHist(ff[i-n:i+n+1, j-n:j+n+1]).astype(np.float32)
result3[i-n:i+n+1, j-n:j+n+1] += lwc
num[i-n:i+n+1, j-n:j+n+1] += 1
result3 /= num[n:hh-n, n:ww-n]
result3 = result3.astype(np.uint8)
plt.imshow(result3, cmap='gray')
plt.title('部分重叠的局部直方图均衡化图像')
plt.show()
cv2.imwrite('POSHE.bmp', result3)