直方图匹配原理与python、matlab实现
直方图匹配本质上是让两幅图像的累积直方图尽量相似,累积直方图相似了,直方图也就相似了。
把原图像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个像素,如下图所示。
(a) 原图像img的直方图 (b) 参考图像ref的直方图
(c) 原图像img的累积直方图 (d) 参考图像ref的累积直方图
灰度级 | ref直方图 | ref累积直方图 | img直方图 |
img累积直方图 | 匹配之后的灰度级 |
匹配之后的img累积直方图 |
匹配之后的img直方图 |
1 | 0 | 0 | 927 | 927(匹配第三列第七行的1137) | 7 | 0 | 0 |
2 | 0 | 0 | 690 | 1617(匹配第三列第八行的1672) | 8 | 0 | 0 |
3 | 20 | 20 | 535 | 2152(匹配第三列第九行的2362) | 9 | 0 | 0 |
4 | 112 | 132 | 450 | 2602(匹配第三列第九行的2362) | 9 | 0 | 0 |
5 | 221 | 353 | 334 | 2936(匹配第三列第十行的3289) | 10 | 0 | 0 |
6 | 334 | 687 | 221 | 3157(匹配第三列第十行的3289) | 10 | 0 | 0 |
7 | 450 | 1137 | 112 | 3269(匹配第三列第十行的3289) | 10 | 927 | 927 |
8 | 535 | 1672 | 20 | 3289(匹配第三列第十行的3289) | 10 | 1617 | 690 |
9 | 690 | 2362 | 0 | 3289(匹配第三列第十行的3289) | 10 | 2152 | 985 |
10 | 927 | 3289 | 0 | 3289(匹配第三列第十行的3289) | 10 | 3289 | 687 |
img在匹配之后的效果如下:
(a) img的经过匹配之后的累积直方图 (b) img的经过匹配之后的直方图
1. OpenCV-Python实现直方图匹配
代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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' ) |
效果如下:
2. matlab实现直方图匹配
程序如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 | 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' ); |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 单元测试从入门到精通