直方图匹配本质上是让两幅图像的累积直方图尽量相似,累积直方图相似了,直方图也就相似了。

把原图像img的直方图匹配到参考图像ref的直方图,包括以下几个步骤:

1. 求出原图像img的累积直方图img_accu;

2. 求出参考图像ref的累积直方图ref_accu;

3. 灰度级g在img_accu中对应的值记为img_accu_g,找出ref_accu中与ref_accu_g最接近的值,记为ref_accu_G,记该值对应的灰度级为G;

4. 根据g和G的对应关系,得到img经过匹配之后的直方图。

为了说明该过程,我们举一个简单的例子,并把计算过程列在表格中。该例子中图像只有10个灰度级,总共3289个像素,如下图所示。

直方图匹配原理与python、matlab实现-LMLPHP    直方图匹配原理与python、matlab实现-LMLPHP

(a) 原图像img的直方图                         (b) 参考图像ref的直方图

直方图匹配原理与python、matlab实现-LMLPHP    直方图匹配原理与python、matlab实现-LMLPHP

(c) 原图像img的累积直方图                (d) 参考图像ref的累积直方图

灰度级ref直方图ref累积直方图img直方图img累积直方图匹配之后的灰度级

匹配之后的img累积直方图

匹配之后的img直方图

100927927(匹配第三列第七行的1137)7 0 0
2006901617(匹配第三列第八行的1672)8 0 0
320205352152(匹配第三列第九行的2362)9 0 0
41121324502602(匹配第三列第九行的2362)9 0 0
52213533342936(匹配第三列第十行的3289)10 0 0
63346872213157(匹配第三列第十行的3289)10 0 0
745011371123269(匹配第三列第十行的3289)10 927 927
85351672203289(匹配第三列第十行的3289)10 1617 690
9690236203289(匹配第三列第十行的3289)10 2152 985
10927328903289(匹配第三列第十行的3289)10 3289 687

img在匹配之后的效果如下:

直方图匹配原理与python、matlab实现-LMLPHP  直方图匹配原理与python、matlab实现-LMLPHP

(a) img的经过匹配之后的累积直方图       (b) img的经过匹配之后的直方图

 1. OpenCV-Python实现直方图匹配

代码如下:

import cv2
import numpy as np
import matplotlib.pyplot as plt img = cv2.imread('C:\\Users\\admin\\Desktop\\original_img3\\testimg\\lena_300_500.jpg')
ref = cv2.imread('C:\\Users\\admin\\Desktop\\original_img3\\testimg\\messi_300_500.jpg') out = np.zeros_like(img)
_, _, colorChannel = img.shape
for i in range(colorChannel):
print(i)
hist_img, _ = np.histogram(img[:, :, i], 256) # get the histogram
hist_ref, _ = np.histogram(ref[:, :, i], 256)
cdf_img = np.cumsum(hist_img) # get the accumulative histogram
cdf_ref = np.cumsum(hist_ref) for j in range(256):
tmp = abs(cdf_img[j] - cdf_ref)
tmp = tmp.tolist()
idx = tmp.index(min(tmp)) # find the smallest number in tmp, get the index of this number
out[:, :, i][img[:, :, i] == j] = idx cv2.imwrite('C:\\Users\\admin\\Desktop\\lena.jpg', out)
print('Done')

效果如下:

直方图匹配原理与python、matlab实现-LMLPHP

2. matlab实现直方图匹配

程序如下:

clear;
% matching img's histogram to ref's histogram.
path = 'C:\\Users\\admin\\Desktop\\original_img3\\yijia0923_9\\';
ref = imread([path, '18.jpg']);
img = imread([path, '21.jpg']); [H, W, colorChannel] = size(ref);
out = zeros(H, W, colorChannel);
for k = 1:colorChannel
disp(k);
hist_ref = imhist(ref(:, :, k)); % ref的直方图
cumHist_ref = []; %ref的累积直方图
for i=1:256
cumHist_ref = [cumHist_ref sum(hist_ref(1:i))];
end img1 = img(:, :, k);
hist_img = imhist(img1); %img的直方图
cumHist_img = []; %img的累积直方图
for i=1:256
cumHist_img = [cumHist_img sum(hist_img(1:i))];
end for i=1:256
tmp{i} = cumHist_ref - cumHist_img(i);
tmp{i} = abs(tmp{i}); % 找到两个累积直方图距离最近的点
[a, index(i)] = min(tmp{i}); % a是tmp{i}中最小的值,index是该值对应的下标
end imgn = zeros(H,W);
for i = 1:H
for j = 1:W
imgn(i,j) = index(img1(i,j)+1)-1; % 由原图的灰度通过索引映射到新的灰度
end
end
out(:, :, k) = imgn;
end out=uint8(out);
% imwrite(out, [path, 'new3.jpg']);
figure; imshow(out); title('out')
disp('Done');
05-17 05:28