Python 直方图均衡化:未获得所需的输出图像
我试图实现直方图均衡功能自己,但没有得到所需的输出图像Python 直方图均衡化:未获得所需的输出图像,python,opencv,image-processing,Python,Opencv,Image Processing,我试图实现直方图均衡功能自己,但没有得到所需的输出图像 import numpy as np import cv2 import matplotlib.pyplot as plt import math %matplotlib inline def freq(lst): d = {} for i in lst: for j in i: if d.get(j): d[j] += 1 e
import numpy as np
import cv2
import matplotlib.pyplot as plt
import math
%matplotlib inline
def freq(lst):
d = {}
for i in lst:
for j in i:
if d.get(j):
d[j] += 1
else:
d[j] = 1
return d
def probability(d,total_pixels):
l = {}
for i in range(256):
value = d.get(i)
if value != None:
l[i] = value/total_pixels
return l
def equalizer(d, l):
f_dic = {}
last_sum = 0
for i in range(l):
if d.get(i):
prob = d.get(i)
last_sum = last_sum+((l-1)*prob)
f_dic[i] = math.floor(last_sum)
return f_dic
def replace_values(f_dic, img):
print(f_dic)
for i in range(len(img)):
for j in range(len(img)):
vv = f_dic.get(img[i][j])
if vv != None:
img[i][j] = vv
return img
def histogramEqualization(img):
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
freqq = freq(img)
area = img.shape
total_pixels = area[0]*area[1]
prob = probability(freqq, total_pixels)
f_dic = equalizer(prob,len(img))
new_img = replace_values(f_dic,img)
return new_img
pollen_dark = cv2.imread("/home/ahmed/Downloads/dip/DIP_A1_Fall2019/pollen_dark.tif")
new = histogramEqualization(pollen_dark)
plt.imshow(new, cmap='gray')
我得到了这个图像:
输入图像如下:
所需的输出图像是:
.
解决这一问题的公式实现
使用NumPy执行此操作的一种方法是使用
np.unique()
查找要修改的值,以及它们的概率分布函数(pdf),基本上是直方图。这可用于根据从pdf上的np.cumsum()
获得的累积分布函数(cdf),使用以下公式生成相应的规范化值:
round((cdf-min\u cdf)/(num\u体素-min\u cdf)*(depth-1))
整个想法(以及公式)在中以图形的方式进行了很好的描述
这通常是一种比在阵列中循环更干净的方法:
DEPTH = 2 ** 8
def hist_equalization(arr, depth=DEPTH):
vals, pdf = np.unique(arr, return_counts=True)
cdf = np.cumsum(pdf)
min_cdf = min(cdf)
new_vals = (
np.round((cdf - min_cdf) / (arr.size - min_cdf) * (depth - 1))
.astype(int))
result = np.empty_like(arr)
for i, val in enumerate(vals):
result[np.nonzero(arr == val)] = new_vals[i]
return result
plt.imshow(arr, cmap='gray', vmin=0, vmax=DEPTH - 1)
plt.imshow(hist_equalization(arr), cmap='gray', vmin=0, vmax=DEPTH - 1)
输入:
输出:
(完整的脚本是可用的。请注意,为了方便I/O,我使用了PIL
而不是cv
,但这与问题无关。)
编辑 代码中到处都有一些小故障(有些不太严重,有些更严重),但妨碍您获得正确结果的是
equalizer()
根本错误
如果将您的均衡器()
版本替换为:
def equalizer(pdf, l, depth=2 ** 8):
min_cdf = pdf[min(pdf)]
result = {}
accumulator = 0
for k, v in sorted(pdf.items()):
accumulator += v
result[k] = int(round((accumulator - min_cdf) / (l - min_cdf) * (depth - 1)))
return result
被称为:
f_dic = equalizer(freqq, total_pixels)
那么剩下的代码就可以工作了。
请注意,probability()
完全没有必要,您确实需要total_pixels
(或img.size
),因为应用于N维数组的len(img)
将为您提供沿第0维的长度,而不是像素总数
(这也包括在内。)您在某处的计算太多了。将中间值z设置为更大的类型以避免出现这种情况(使用8位整数进行计算是不好的)。@CrisLuengo我同意使用8位整数进行计算是危险的,但这在大多数情况下都使用Python
int
s,并且没有溢出。有趣的结果来自均衡器()
中的一个错误参数/公式。这很有效。但是我对找出我的代码的错误很感兴趣。你能帮我吗?@Mrcreamio看到编辑,但请注意,上面建议的矢量化版本比修复代码所需的最小编辑要快得多,更干净。非常感谢。:)我用f_dic=均衡器(prob,len(img))
更改了f_dic=均衡器(prob,2**8)
,它工作了。请参见上面的编辑。我添加了公式,我正在尝试实施。@Creamio先生,很好,你发现了这个问题。如果能够立即在原始代码中实现您试图实现的数学,这将是非常有帮助的。不过,我看不到立即以矢量化形式编写这个新公式的方法。