完整内容 见 参考资料;

本文只是对代码略微进行了改动;

 

原图是一张 夜间 拍摄的教堂照片,见下图

from skimage.exposure import histogram, cumulative_distribution
from skimage import img_as_ubyte
from skimage.color import rgb2gray
from scipy.stats import cauchy, logistic


def plot(gray, pltimg, title1='', title2=''):
    '''灰度图 画 直方图,pdf,cdf'''
    fig, ax = plt.subplots(1, 3, figsize=(15, 5))

    ## 手动计算后 画图
    ax0 = ax[0]
    ax0.imshow(pltimg)             # 图像
    ax0.set_title(title1)

    ax1 = ax[1]
    ax1.set_title(title2)
    ax11 = ax1.twinx()   # 二图合一,双坐标
    hist, bins = np.histogram(gray, bins=255)
    cumsum = np.cumsum(hist) / np.sum(hist)
    ax1.bar(bins[1:], hist / np.sum(hist), width=0.5)    # 概率密度函数
    ax11.plot(bins[1:], cumsum, 'r*-')                   # 累计概率分布

    ## skimage 计算后 画图
    ax2 = ax[2]
    ax22 = ax2.twinx()
    skhist_pdf, skbins_pdf = histogram(gray)
    skhist_cdf, skbins_cdf = cumulative_distribution(gray)
    ax2.bar(skbins_pdf, skhist_pdf / skhist_pdf.sum())
    ax22.plot(skbins_cdf, skhist_cdf, 'r*-')

    plt.show()

# 原始图像 - 灰度图
img = cv.imread('imgs/jiaotang.png')
gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
# 灰度图的直方图
plot(gray, img)

输出原图 和 灰度图的直方图

源图像明显偏暗,其直方图 左侧明显占比过高,也证明了这点

 

把原始直方图 转换成 均匀分布 的直方图,对应的图像变成

# 灰度图 经过 直方图均衡化,转换成 均匀分布
image_intensity = img_as_ubyte(gray)
freq, bins = cumulative_distribution(image_intensity)

target_bins = np.arange(255)
target_freq = np.linspace(0, 1, len(target_bins))           # 一条直线,从0到1的累加
new_vals = np.interp(freq, target_freq, target_bins)        # 把原累加 插值成 上面的直线,x为 range(255)
gray2 = new_vals[image_intensity]
plot(gray2, gray2)

输出

图像整体亮度增加,因为把 大量的低区间像素转换到高区间像素了;对比度也增强了

均匀分布的 累计概率分布 就是一条直线 

 

直方图均衡不仅可以转换成 均匀分布,也可以转换成其他分布;

本文实现 柯西分布cauchy、逻辑分布logistic,其效果更优于 均匀分布,仅对本图而言

def individual_channel(image, dist, channel):
    im_channel = img_as_ubyte(image[:, :, channel])
    freq, bins = cumulative_distribution(im_channel)
    new_vals = np.interp(freq, dist.cdf(np.arange(0, 256)),
                         np.arange(0, 256))
    return new_vals[im_channel].astype(np.uint8)


def distribution(image, function, mean, std):
    dist = function(mean, std)
    fig, ax = plt.subplots(1, 2, figsize=(15, 5))

    image_intensity = img_as_ubyte(rgb2gray(image))
    freq, bins = cumulative_distribution(image_intensity)
    ax[0].step(bins, freq, c='b', label='Actual CDF')
    ax[0].plot(dist.cdf(np.arange(0, 256)),
               c='r', label='Target CDF')
    ax[0].legend()
    ax[0].set_title('Actual vs. Target Cumulative Distribution')

    red = individual_channel(image, dist, 0)
    green = individual_channel(image, dist, 1)
    blue = individual_channel(image, dist, 2)
    ax[1].imshow(np.dstack((red, green, blue)))
    ax[1].set_title('Transformed Image')
    return ax

distribution(img, cauchy, 90, 30)
plt.show()

distribution(img, logistic, 90, 30)
plt.show()

输出

 

 

 

我们已经探索了如何使用直方图处理来校正图像中的颜色,实现了各种分布函数,以了解它如何影响结果图像中的颜色分布。

同样,我们可以得出结论,在固定图像的颜色强度方面没有“一体适用”的解决方案,数据科学家的主观决定是确定哪个是最适合他们的图像处理需求的解决方案

 

 

 

参考资料:

https://mp.weixin.qq.com/s/T1ziuMkMhqIc0NDHmgm19A  使用直方图处理进行颜色校正

https://github.com/jephraim-manansala/histogram-manipulation  github 代码

https://blog.51cto.com/u_14411234/3113945  使用OpenCV实现图像增强      这里面的例子效果特别好,处理 灯光不亮 的图片