直方图均衡而不使用python中的内置直方图方法

Posted

技术标签:

【中文标题】直方图均衡而不使用python中的内置直方图方法【英文标题】:Histogram Equalization without using built-in histogram methods in python 【发布时间】:2021-06-06 04:38:11 【问题描述】:

我写了下面的代码,我得到的是下面的输出。我想做的是编写一个直方图均衡函数(没有内置方法)我没有收到错误,但是输出不是应该的。我的代码中没有任何逻辑错误。虽然,在编写计算 cdf 和/或映射的循环时,我无法准确了解它背后发生的事情,但问题可能就在那里,但我不确定。

def my_float2int(img):
    
    img = np.round(img * 255, 0)
    img = np.minimum(img, 255)
    img = np.maximum(img, 0)
    img = img.astype('uint8')
    
    return img

def equalizeHistogram(img):
    
    img_height = img.shape[0]
    img_width = img.shape[1]
    histogram = np.zeros([256], np.int32) 
    
    
    # calculate histogram 
    for i in range(0, img_height):
        for j in range(0, img_width):
            histogram[img[i, j]] +=1
            
    # calculate pdf of the image
    pdf_img = histogram / histogram.sum()
    
    ### calculate cdf 
    # cdf initialize . 
    cdf = np.zeros([256], np.int32) 

    # For loop for cdf
    for i in range(0, 256):
        for j in range(0, i+1):
            cdf[i] += pdf_img[j]
     
    cdf_eq = np.round(cdf * 255, 0) # mapping, transformation function T(x)
    
    imgEqualized = np.zeros((img_height, img_width))
    
    # for mapping input image to s.
    for i in range(0, img_height):
        for j in range(0, img_width):
            r = img[i, j] # feeding intensity levels of pixels into r. 
            s = cdf_eq[r] # finding value of s by finding r'th position in the cdf_eq list.
            imgEqualized[i, j] = s # mapping s thus creating new output image.
            
    # calculate histogram equalized image here
    # imgEqualized = s # change this
    
    return imgEqualized

# end of function


# 2.2 obtain the histogram equalized images using the above function
img_eq_low = equalizeHistogram(img_low)
img_eq_high = equalizeHistogram(img_high)

img_eq_low = my_float2int(img_eq_low)
img_eq_high = my_float2int(img_eq_high)

# 2.3 calculate the pdf's of the histogram equalized images
hist_img_eq_low = calcHistogram(img_eq_low)
hist_img_eq_high = calcHistogram(img_eq_high)

pdf_eq_low = hist_img_eq_low / hist_img_eq_low.sum()
pdf_eq_high = hist_img_eq_high / hist_img_eq_high.sum()

# 2.4 display the histogram equalized images and their pdf's
plt.figure(figsize=(14,8))
plt.subplot(121), plt.imshow(img_eq_low, cmap = 'gray', vmin=0, vmax=255)
plt.title('Hist. Equalized Low Exposure Image'), plt.xticks([]), plt.yticks([])
plt.subplot(122), plt.imshow(img_eq_high, cmap = 'gray', vmin=0, vmax=255)
plt.title('Hist. Equalized High Exposure Image'), plt.xticks([]), plt.yticks([])
plt.show()
plt.close()

我的输出:

预期输出:使用内置方法。

【问题讨论】:

【参考方案1】:

我发现了两个小错误和一个效率问题:

cdf = np.zeros([256], np.int32) 替换为cdf = np.zeros([256], float) 在循环中,您将float 元素放入cdf,因此类型应为float 而不是int32。 将img = np.round(img * 255, 0) 替换为img = np.round(img, 0)(在my_float2int 中)。 您将 img 缩放 255 两次(第一次在 cdf_eq = np.round(cdf * 255, 0) 中)。

您可以更高效地计算cdf。 您的实施:

for i in range(0, 256):
    for j in range(0, i+1):
        cdf[i] += pdf_img[j]

建议的实现方式(计算“累计和”的更有效方式):

cdf[0] = pdf_img[0]
for i in range(1, 256):
    cdf[i] = cdf[i-1] + pdf_img[i]

这不是错误,而是一种学术问题(关于复杂性)。


这是一个更正代码的示例(仅使用img_low):

import numpy as np
import cv2

def my_float2int(img):
    
    # Don't use *255 twice
    # img = np.round(img * 255, 0)
    img = np.round(img, 0)
    img = np.minimum(img, 255)
    img = np.maximum(img, 0)
    img = img.astype('uint8')
    
    return img

def equalizeHistogram(img):
    
    img_height = img.shape[0]
    img_width = img.shape[1]
    histogram = np.zeros([256], np.int32) 
    
    
    # calculate histogram 
    for i in range(0, img_height):
        for j in range(0, img_width):
            histogram[img[i, j]] +=1
            
    # calculate pdf of the image
    pdf_img = histogram / histogram.sum()
    
    ### calculate cdf 
    # cdf initialize . 
    # Why does the type np.int32?
    #cdf = np.zeros([256], np.int32)
    cdf = np.zeros([256], float)

    # For loop for cdf
    for i in range(0, 256):
        for j in range(0, i+1):
            cdf[i] += pdf_img[j]

    # You may implement the "accumulated sum" in a more efficient way:
    cdf = np.zeros(256, float)
    cdf[0] = pdf_img[0]
    for i in range(1, 256):
        cdf[i] = cdf[i-1] + pdf_img[i]
     
    cdf_eq = np.round(cdf * 255, 0) # mapping, transformation function T(x)
    
    imgEqualized = np.zeros((img_height, img_width))
    
    # for mapping input image to s.
    for i in range(0, img_height):
        for j in range(0, img_width):
            r = img[i, j] # feeding intensity levels of pixels into r. 
            s = cdf_eq[r] # finding value of s by finding r'th position in the cdf_eq list.
            imgEqualized[i, j] = s # mapping s thus creating new output image.
            
    # calculate histogram equalized image here
    # imgEqualized = s # change this
    
    return imgEqualized

# end of function


# Read input image as Grayscale
img_low = cv2.imread('img_low.png', cv2.IMREAD_GRAYSCALE)

# 2.2 obtain the histogram equalized images using the above function
img_eq_low = equalizeHistogram(img_low)
img_eq_low = my_float2int(img_eq_low)

# Use cv2.imshow (instead of plt.imshow) just for testing.
cv2.imshow('img_eq_low', img_eq_low)
cv2.waitKey()

结果:

【讨论】:

以上是关于直方图均衡而不使用python中的内置直方图方法的主要内容,如果未能解决你的问题,请参考以下文章

OpenCV使用python实现限制对比度的自适应直方图均衡化

OpenCV-Python自适应直方图均衡类CLAHE及方法详解

opencv图像直方图均衡化及其原理

matlab全局直方图均衡化和局部直方图均衡化的优缺点

数字图像处理:OpenCV-Python中的直方图均衡知识介绍及函数equalizeHist详解

OpenCV-Python实战——直方图均衡化(含大量示例,建议收藏)