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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131 | import cv2 as cv
import matplotlib.pyplot as plt;
import numpy as np
"""
直方图匹配: 让一张图参考另一张图, 让他们的色调保持一致
步骤:
计算原图累计直方图
计算参考图的累计直方图
计算两个累计直方图的差异
生成原图和参考图之间的颜色映射
"""
# 计算单通道图像 累计概率
def getAccumulateRatios(img):
height = img.shape[0]
width = img.shape[1]
# 1.计算直方图
hist = cv.calcHist([img],[0],None,[256],[0,255])
# print(hist)
# plt.plot(hist)
# plt.show()
# 2.计算每个灰度值出现的概率
ratios = hist/(height*width);
# 3. 计算累计概率
sumRatios = np.zeros(256,np.float)
sum1=0;
for i,r in enumerate(ratios):
sum1 = sum1 + r;
sumRatios[i] = sum1;
# 4. 绘制累计概率直方图
# x = np.linspace(0,255,256);
# plt.bar(x,sumRatios)
# plt.show()
return sumRatios;
"""
传入进来的数据仍然上单通道数据
1. 计算累计直方图的差异
找到最小的差异
2. 获取颜色映射
"""
def map_color(src_channel,refer_channel):
# src 单通道累计直方图
src_sumRatios = getAccumulateRatios(src_channel);
# refer 单通道累计直方图
refer_sumRatios = getAccumulateRatios(refer_channel);
colorMaps = np.zeros(256,np.uint8);
# 遍历原图每一个灰度的累计概率
for i,srcRatio in enumerate(src_sumRatios):
# 得到 i: 灰度值 ratio :累计概率 0 0.19
min = 100;
referColor = 0;
for j,referRatio in enumerate(refer_sumRatios):
# j: 表示参考图的灰度值, referRatio累计概率
diff = np.abs(srcRatio - referRatio)
if diff < min:
# 更新最小值
min = diff;
referColor = j;
# 0 ---> referColor
colorMaps[i] = referColor;
# print(colorMaps)
return colorMaps;
""" 完成单通道直方图匹配 """
def oneChannelMatch(src_channel,refer_channel):
# 单通道颜色值映射
colorMaps = map_color(src_channel, refer_channel);
# 绘制原图直方图
# cv.imshow("src",src_channel)
# plt.hist(src_channel.ravel(),bins=256,color="blue")
# plt.show()
# 绘制参考图直方图
# cv.imshow("refer", refer_channel)
# plt.hist(refer_channel.ravel(), bins=256,color="green")
# plt.show()
one_channel = src_channel
height = one_channel.shape[0]
width = one_channel.shape[1]
for row in range(height):
for col in range(width):
# 获取原来的灰度值
gray = one_channel[row, col];
# 去颜色映射表中查找新的颜色值
referColor = colorMaps[gray];
# 替换为新的颜色值
one_channel[row, col] = referColor;
# 绘制生成之后的直方图
# cv.imshow("dst", one_channel)
# plt.hist(refer_channel.ravel(), bins=256, color="red")
# plt.show()
return one_channel
if __name__ == '__main__':
src = cv.imread("../img/1.jpg",cv.IMREAD_COLOR);
cv.imshow("src",src)
refer = cv.imread("../img/2.jpg",cv.IMREAD_COLOR);
cv.imshow("refer",refer)
# 先计算src的累计直方图 , 计算单通道
src_channels = cv.split(src);
# 先计算refer的累计直方图 , 计算单通道
refer_channels = cv.split(refer);
dst_channel0 = oneChannelMatch(src_channels[0],refer_channels[0])
dst_channel1 = oneChannelMatch(src_channels[1],refer_channels[1])
dst_channel2 = oneChannelMatch(src_channels[2],refer_channels[2])
dst = cv.merge([dst_channel0,dst_channel1,dst_channel2])
cv.imshow("dst",dst);
cv.waitKey(0)
cv.destroyAllWindows()
|