- 直方图匹配又称为直方图规定化,是指将一幅图像的直方图变成规定形状的直方图而进行的图像增强方法。 即将某幅影像或某一区域的直方图匹配到另一幅影像上。使两幅影像的色调保持一致。
- 直方图规定化的实现步骤如下:
- 计算原图像的累积直方图
- 计算规定直方图的累积直方图
- 计算两累积直方图的差值的绝对值
- 根据累积直方图最小差值建立灰度级的映射
""""----------------------------------------
需求:
实现直方图匹配
流程:
1. 计算原图的累积直方图
2. 计算目标图的累积直方图
3. 比较两个直方图每一个灰度值的概率差(的绝对值)
4. 找出最小的绝对差,完成灰度值的映射
----------------------------------------"""
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
# 1. 获取图像宽高
# 2. 计算并绘制直方图
# 3. 计算并绘制直方图概率图
# 4. 计算并绘制累计概率直方图
def get_accumulative_hist(image, plot_enable=False):
"""
计算累积直方图概率图矩阵
:param image: 输入的图像矩阵
:param plot_enable: 是否开启绘制功能
:return: 累积概率直方图矩阵
"""
height, width = image.shape[0], image.shape[1]
hist = cv.calcHist([image], [0], None, [256], [0, 256])
ratio_hist = hist / (height * width)
accumulative_hist = np.zeros(256, np.float)
ratio_sum = 0
for i in range(256):
ratio_sum += ratio_hist[i]
accumulative_hist[i] = ratio_sum
if plot_enable:
plot_hist(accumulative_hist, hist, ratio_hist)
return accumulative_hist
# 1. 创建图表对象
# 2. 绘制直方图
# 3. 绘制直方概率图
# 4. 绘制累计直方概率图
def plot_hist(accumulative_hist, hist, ratio_hist):
"""
绘制图像直方图,直方概率图,累积直方概率图
:param accumulative_hist: 累积概率直方图矩阵
:param hist: 直方图矩阵
:param ratio_hist: 概率直方图矩阵
:return: None
"""
fig = plt.figure()
grid_rows = 1
grid_cols = 3
plt.subplot(grid_rows, grid_cols, 1)
plt.plot(hist)
plt.subplot(grid_rows, grid_cols, 2)
plt.plot(ratio_hist)
plt.subplot(grid_rows, grid_cols, 3)
plt.plot(accumulative_hist)
"""----------------------------------------
1. 读取图像
----------------------------------------"""
src_img = cv.imread("../img/yunduo.jpg", cv.IMREAD_COLOR)
src_gray = cv.cvtColor(src_img, cv.COLOR_BGR2GRAY)
ref_img = cv.imread("../img/fl4.jpg", cv.IMREAD_COLOR)
ref_gray = cv.cvtColor(ref_img, cv.COLOR_BGR2GRAY)
"""----------------------------------------
2. 计算累计累计直方概率图, src, ref
----------------------------------------"""
src_accumulative_hist = get_accumulative_hist(src_gray, True)
ref_accumulative_hist = get_accumulative_hist(ref_gray, True)
"""----------------------------------------
3. 比较两个直方概率图的差
----------------------------------------"""
# 创建一个0-255映射数组
# 遍历src的每一个灰度的累积概率(i:灰度值,src_hist_bin:累积概率)
# 预先定义一个最小绝对差, 最小绝对差对应的ref的索引
# 遍历ref的每一个灰度的累积概率(j:灰度值,ref_hist_bin:累积概率)
# 重置最小绝对差, 通过这个值找到其索引
# 重置最小绝对差索引,目标是 inde(abs(src_i - ref_j),并记录
# 找出当前灰度值的映射关系 src 的灰度值 匹配 ref 的灰度值
color_map = np.zeros(256, src_gray.dtype)
for i, src_hist_bin in enumerate(src_accumulative_hist):
min_diff_abs = 1000
min_diff_abs_index = 0
for j, ref_hist_bin in enumerate(ref_accumulative_hist):
diff_abs = np.abs(ref_hist_bin - src_hist_bin)
if (diff_abs < min_diff_abs):
min_diff_abs = diff_abs
min_diff_abs_index = j
color_map[i] = min_diff_abs_index
"""----------------------------------------
4. 修改原图的灰度值,通过直方图匹配
----------------------------------------"""
src_height = src_gray.shape[0]
src_width = src_gray.shape[1]
src_map = np.zeros(src_gray.shape, src_gray.dtype)
print(src_map.shape)
# 遍历src,通过 gray_map_array,用 ref 的灰度分布修改 src
# 获取 src 当前像素的灰度值
# 通过当前灰度值,得出映射灰度值
# 将 src 像素赋值映射灰度值
for row in range(src_height):
for col in range(src_width):
src_color = src_gray[row, col]
map_color = color_map[src_color]
src_map[row, col] = map_color
src_map_accumulative_hist = get_accumulative_hist(src_map, True)
"""----------------------------------------
5. 显示图像
----------------------------------------"""
cv.imshow("src", src_gray)
cv.imshow("ref", ref_gray)
cv.imshow("map", src_map)
cv.waitKey(1)
"""----------------------------------------
显示所有绘制得图像
----------------------------------------"""
plt.show()
原图 src 与 ref 图进行直方图匹配,得到结果图 map
""""----------------------------------------
需求:
实现直方图匹配_彩图
流程:
1. 计算原图的累积直方图
2. 计算目标图的累积直方图
3. 比较两个直方图每一个灰度值的概率差(的绝对值)
4. 找出最小的绝对差,完成灰度值的映射
----------------------------------------"""
import cv2 as cv
import numpy as np
import matplotlib.pyplot as plt
def plot_hist(accumulative_hist, hist, ratio_hist):
fig = plt.figure()
grid_rows = 1
grid_cols = 3
plt.subplot(grid_rows, grid_cols, 1)
plt.plot(hist)
plt.subplot(grid_rows, grid_cols, 2)
plt.plot(ratio_hist)
plt.subplot(grid_rows, grid_cols, 3)
plt.plot(accumulative_hist)
def get_accumulative_hist(image, plot_enable=False):
height, width = image.shape[0], image.shape[1]
hist = cv.calcHist([image], [0], None, [256], [0, 256])
ratio_hist = hist / (height * width)
accumulative_hist = np.zeros(256, np.float)
ratio_sum = 0
for i in range(256):
ratio_sum += ratio_hist[i]
accumulative_hist[i] = ratio_sum
if plot_enable:
plot_hist(accumulative_hist, hist, ratio_hist)
return accumulative_hist
def hist_match_channel_one(src, ref):
mapped_img = np.zeros(src.shape, src.dtype)
src_accumulative_hist = get_accumulative_hist(src, True)
ref_accumulative_hist = get_accumulative_hist(ref, True)
map_array_c1 = np.zeros(256, src.dtype)
for i, src_hist_bin in enumerate(src_accumulative_hist):
min_diff_abs = 1000
min_diff_abs_index = 0
for j, ref_hist_bin in enumerate(ref_accumulative_hist):
diff_abs = np.abs(ref_hist_bin - src_hist_bin)
if diff_abs < min_diff_abs:
min_diff_abs = diff_abs
min_diff_abs_index = j
map_array_c1[i] = min_diff_abs_index
src_height = src.shape[0]
src_width = src.shape[1]
for row in range(src_height):
for col in range(src_width):
src_color = src[row, col]
map_color = map_array_c1[src_color]
mapped_img[row, col] = map_color
return mapped_img
"""----------------------------------------
1. 读取图像
----------------------------------------"""
src_img = cv.imread("../img/yunduo.jpg", cv.IMREAD_COLOR)
ref_img = cv.imread("../img/fl4.jpg", cv.IMREAD_COLOR)
"""----------------------------------------
2. 三通道直方图匹配
----------------------------------------"""
# 拆分彩图,每一个通道进行直方图匹配,再融合
src_channels = cv.split(src_img)
ref_channels = cv.split(ref_img)
src_mapped_channels = []
for i in range(3):
src_mapped_channel = hist_match_channel_one(src_channels[i], ref_channels[i])
src_mapped_channels.append(src_mapped_channel)
src_mapped = cv.merge(src_mapped_channels)
# src_mapped = hist_match_channel_one(cv.cvtColor(src_img, cv.COLOR_BGR2GRAY),
# cv.cvtColor(ref_img, cv.COLOR_BGR2GRAY))
"""----------------------------------------
5. 显示图像
----------------------------------------"""
cv.imshow("src", src_img)
cv.imshow("ref", ref_img)
cv.imshow("map", src_mapped)
cv.waitKey(0)
for i in range(3):
plt.figure()
plt.hist(src_mapped_channels[i].ravel(), bins=256)
"""----------------------------------------
显示所有绘制得图像
----------------------------------------"""
plt.show()
原图 src,ref,与 src_mapped
链接:matplotlib 绘制多个图形,如何同时独立显示?(解决)
定义
完整代码