作者 | 小白

来源 | 小白学视觉

在这篇文章中,我们将探讨如何使用直方图处理技术来校正图像中的颜色。

像往常一样,我们导入库,如numpy和matplotlib。此外,我们还从skimage 和scipy.stats库中导入特定函数。

import numpy as np
import matplotlib.pyplot as plt
from skimage.io import imread, imshow
from skimage import img_as_ubyte
from skimage.color import rgb2gray
from skimage.exposure import histogram, cumulative_distribution
from scipy.stats import cauchy, logistic

让我们使用马尼拉内穆罗斯马尼拉大教堂的夜间图像。

cathedral = imread('cathedral.jpg')
plt.imshow(cathedral)
plt.title('Manila Cathedral')

首先,让我们将图像转换为灰度。

fig, ax = plt.subplots(1,2, figsize=(15,5))
cathedral_gray = rgb2gray(cathedral)
ax[0].imshow(cathedral_gray, cmap='gray')
ax[0].set_title('Grayscale Image')
ax1 = ax[1]
ax2 = ax1.twinx()
freq_h, bins_h = histogram(cathedral_gray)
freq_c, bins_c = cumulative_distribution(cathedral_gray)
ax1.step(bins_h, freq_h*1.0/freq_h.sum(), c='b', label='PDF')
ax2.step(bins_c, freq_c, c='r',  label='CDF')
ax1.set_ylabel('PDF', color='b')
ax2.set_ylabel('CDF', color='r')
ax[1].set_xlabel('Intensity value')
ax[1].set_title('Histogram of Pixel Intensity');

由于图像是在夜间拍摄的,因此图像的特征比较模糊,这也在像素强度值的直方图上观察到,其中 PDF 在较低的光谱上偏斜。

由于图像的强度值是倾斜的,因此可以应用直方图处理来重新分布图像的强度值。直方图处理的目的是将图像的实际 CDF 拉伸到新的目标 CDF 中。通过这样做,倾斜到较低光谱的强度值将转换为较高的强度值,从而使图像变亮。

让我们尝试在灰度图像上实现这一点,我们假设 PDF 是均匀分布,CDF 是线性分布。

image_intensity = img_as_ubyte(cathedral_gray)
freq, bins = cumulative_distribution(image_intensity)
target_bins = np.arange(255)
target_freq = np.linspace(0, 1, len(target_bins))
new_vals = np.interp(freq, target_freq, target_bins)
fig, ax = plt.subplots(1,2, figsize=(15,5))
ax[0].step(bins, freq, c='b', label='Actual CDF')
ax[0].plot(target_bins, target_freq, c='r', label='Target CDF')
ax[0].legend()
ax[0].set_title('Grayscale: Actual vs. ''Target Cumulative Distribution')
ax[1].imshow(new_vals[image_intensity].astype(np.uint8), cmap='gray')
ax[1].set_title('Corrected Image in Grayscale');

通过将实际 CDF 转换为目标 CDF,我们可以在保持图像关键特征的同时使图像变亮。请注意,这与仅应用亮度过滤器完全不同,因为亮度过滤器只是将图像中所有像素的强度值增加相等的量。在直方图处理中,像素强度值可以根据目标 CDF 增加或减少。

现在,让我们尝试在彩色图像中实现直方图处理。这些过程可以从灰度图像中复制——然而,不同之处在于我们需要对图像的每个通道应用直方图处理。为了简化实现,我们创建一个函数来对图像执行此过程。

def show_linear_cdf(image, channel, name, ax):image_intensity = img_as_ubyte(image[:,:,channel])freq, bins = cumulative_distribution(image_intensity)target_bins = np.arange(255)target_freq = np.linspace(0, 1, len(target_bins))ax.step(bins, freq, c='b', label='Actual CDF')ax.plot(target_bins, target_freq, c='r', label='Target CDF')ax.legend()ax.set_title('{} Channel: Actual vs. ''Target Cumulative Distribution'.format(name))
def linear_distribution(image, channel):image_intensity = img_as_ubyte(image[:,:,channel])freq, bins = cumulative_distribution(image_intensity)target_bins = np.arange(255)target_freq = np.linspace(0, 1, len(target_bins))new_vals = np.interp(freq, target_freq, target_bins)return new_vals[image_intensity].astype(np.uint8)

现在,我们将这些函数应用于原始图像的每个通道。

fig, ax = plt.subplots(3,2, figsize=(12,14))
red_channel = linear_distribution(cathedral, 0)
green_channel = linear_distribution(cathedral, 1)
blue_channel = linear_distribution(cathedral, 2)
show_linear_cdf(cathedral, 0, ‘Red’, ax[0,0])
ax[0,1].imshow(red_channel, cmap=’Reds’)
ax[0,1].set_title(‘Corrected Image in Red Channel’)
show_linear_cdf(cathedral, 1, ‘Green’, ax[1,0])
ax[1,1].imshow(green_channel, cmap=’Greens’)
ax[1,1].set_title(‘Corrected Image in Green Channel’)
show_linear_cdf(cathedral, 2, ‘Blue’, ax[2,0])
ax[2,1].imshow(blue_channel, cmap=’Blues’)
ax[2,1].set_title(‘Corrected Image in Blue Channel’)

请注意,所有通道几乎都具有相同的 CDF,这显示了图像中颜色的良好分布——只是颜色集中在较低的强度值光谱上。就像我们在灰度图像中所做的一样,我们还将每个通道的实际 CDF 转换为目标 CDF。

校正每个通道的直方图后,我们需要使用 numpy stack函数将这些通道堆叠在一起。请注意,RGB 通道在堆叠时需要按顺序排列。

fig, ax = plt.subplots(1,2, figsize=(15,5))
ax[0].imshow(cathedral);
ax[0].set_title('Original Image')
ax[1].imshow(np.dstack([red_channel, green_channel, blue_channel]));
ax[1].set_title('Transformed Image');

堆叠所有通道后,我们可以看到转换后的图像颜色与原始图像的显着差异。直方图处理最有趣的地方在于,图像的不同部分会有不同程度的像素强度转换。请注意,马尼拉大教堂墙壁的像素强度发生了巨大变化,而马尼拉大教堂钟楼的像素强度却保持相对不变。

现在,让我们尝试使用其他函数作为目标 CDF 来改进这一点。为此,我们将使用该scipy.stats库导入各种分布,还创建了一个函数来简化我们的分析。

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

让我们使用 Cauchy 函数来试试这个。

distribution(cathedral, cauchy, 90, 30);

使用不同的分布似乎会产生更令人愉悦的配色方案。事实上,大教堂正门的弧线在逻辑分布中比线性分布更好,这是因为在逻辑分布中像素值强度的平移比线性分布要小,这可以从实际 CDF 线到目标 CDF 线的距离看出。

让我们看看我们是否可以使用逻辑分布进一步改进这一点。

distribution(cathedral, logistic, 90, 30);

请注意,门中的灯光如何从线性和Cauchy分布改进为逻辑分布的。这是因为逻辑函数的上谱几乎与原始 CDF 一致。因此,图像中的所有暗物体(低像素强度值)都被平移,而灯光(高像素强度值)几乎保持不变。

结论

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

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

Github代码连接:

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

技术

基于聚类的图像分割(Python)

资讯

人工智能监考VS传统方式监考

资讯

Meta研发触觉手套助力元宇宙

图像

深度学习视频理解之图像分类

分享

点收藏

点点赞

点在看

新技能 Get,使用直方图处理进行颜色校正相关推荐

  1. AI时代,产品经理需要掌握的5项新技能

    不同于传统的产品经理,AI时代的产品经理更加注重的如何将技术应用在业务问题上.AI时代,产品经理最重要的职责就是提供数据规范,所以这也要求产品经理对数据有足够的认识.文章对AI时代产品经理需要掌握的新 ...

  2. 学习新技能时,大脑在如何发生改变?

    来源:中国生物技术网 众所周知,无论是一项运动.一种乐器还是一门手艺,掌握一项新技能都是需要花费时间并进行训练的.虽然我们都知道健康的大脑能够应付的来,但是为了开发出新行为大脑如何发生改变科学家们对此 ...

  3. 开课吧python学费-分享一个小白也能月赚2万的新技能

    原标题:分享一个小白也能月赚2万的新技能 这两年,每天都听身边人吐槽:"最近太累了,加班多.事情杂.离家远......可到手的工资却少得可怜." 辞职.跳槽,已然成为一种常态. 这 ...

  4. 谷歌 Daydream 实验室:VR中学习新技能是一种怎样的体验?

    谷歌 Daydream 实验室:VR中学习新技能是一种怎样的体验? 本文作者:逸炫 编辑:田苗 2017-07-26 10:56 导语:要学做一桌满汉全席,还是得撸起袖子下厨房. 雷锋网按:在VR中, ...

  5. 2030年,逾1亿中国人需要学习新技能并转换岗位,这就是摩擦性失业

    在自动化的浪潮中,全社会需要解决好四个问题:一是需要保持积极的稳健增长,以保证工作岗位的增加:二是提供工作培训机会,帮助个人学习适应市场需求的新技能:三是提高商业社会乃至劳动力市场的活力和流动性:四是 ...

  6. 云开发数据库又增新技能!

    开篇彩蛋 由于近期小程序·云开发将上线付费功能(付费功能针对非基础资源配额,基础资源配额仍可免费使用).为了给开发者更充足的时间进行调整,对于截止 2019-06-21 日前通过邮件申请调整的配额(非 ...

  7. 学习一项新技能的公式

    **学习一项新技能的公式** 一项新技能=(得核心技巧)+(入门)+(固定.持续.大量的训练)一项新技能=(得核心技巧) +(入门)+(固定.持续.大量的训练) 一项新技能=(得核心技巧)+(入门)+ ...

  8. 高效掌握新技能的「树型思维」

    大家好,我是Z哥. 不知道你有没有过这样的困惑,想学习某项新技能,但是很容失败.比如,出于职业发展的考虑,想学习一门新的编程语言,或者想了解一个新的技术框架:又或者看了某些综艺节目后想玩一玩滑板.练一 ...

  9. android l 电池,DIY新技能--M1L换电池

    DIY新技能--M1L换电池 2019-10-23 16:48:52 6点赞 6收藏 10评论 更换理由 M1L是好几年前买的了,具体几年前我都懒得购买记录了.前前后后买了4台锤子手机了,这是我支持老 ...

  10. linux通讯录软件带头像,小程序新技能 Get!保存微信好友头像到手机通讯录

    原标题:小程序新技能 Get!保存微信好友头像到手机通讯录 亲爱的朋友,你知道来电时能看到好友的头像是一种怎样的体验吗? 你是否注意过这样一件事:每当打开自己的微博.微信等社交软件,除了扑面而来的信息 ...

最新文章

  1. java unsafe获取指针_【实战Java高并发程序设计 1】Java中的指针:Unsafe类
  2. MySQL两主多从,且故障转移配置
  3. 用gulp构建你的前端项目
  4. 2013-12-7 在超市给思杨买东西-思杨踢球
  5. 【最后一天倒计时】你离¥399网易黑猪肉券就差一步
  6. 问题 E: 序列操作Ⅰ(01背包)
  7. CentOS7 安装 webgoat 7.1 简介
  8. UVA 10588—— Queuing at the doctors
  9. keras提取模型中的某一层_Tensorflow笔记:高级封装——Keras
  10. 前端分页插件pagination
  11. libevent 源码学习五 —— 事件 event
  12. matlab---之imcrop
  13. 联想本装系统stop:0X000007B错误[转]
  14. 给排水科学与工程和计算机选哪个,2021中国给排水科学与工程专业大学排名 最好的高校排行榜...
  15. asp版 vbscript RSA公钥加密 / 私钥解密 / 私钥签名 / 公钥验签(支持中文)分段加密解密
  16. Github标星25K+超火的Android实战项目,2022BTAJ面试真题详解
  17. 怎么把线稿提取出来_99%的人不知道!教你怎么提取绘画作品的线稿!
  18. mathtype免费版下载及序列号获取地址
  19. 文明重启怎么找回之前的服务器,文明重启房子消失怎么找回 详尽攻略助你一臂之力...
  20. VS2019中,解决“错误CS0006:未能找到元数据文件”

热门文章

  1. windows下安装mysql8.0压缩版
  2. 使用工作集(Working Set)整理项目
  3. linux发行版的用户交互
  4. Codeforces 862B - Mahmoud and Ehab and the bipartiteness
  5. Selenium2+python自动化25-js处理日历控件(修改readonly属性)
  6. 第 十 天 : 添 加 硬 盘 和 分 区 挂 载 等
  7. Android程序完全退出的三种方法
  8. linux下使profile和.bash_profile立即生效的方法
  9. 神器与经典--sp_helpIndex
  10. 使用Photoshop制作网页模板