本文将讨论调整彩色图像的累积分布函数的最好方法。
我们开始吧!
像往常一样,我们首先导入所有必需的库。
import numpy as np
import matplotlib.pyplot as plt
from skimage.io import imread, imshow
import matplotlib.pyplot as plt
from skimage.exposure import histogram, cumulative_distribution
from scipy.stats import norm
现在加载图像。
dark_image = imread('dark_books.png');
plt.figure(num=None, figsize=(8, 6), dpi=80)
imshow(dark_image);
为了帮助我们更好地了解图像中的RGB层,让我们分离每个单独的通道。下面函数实现此操作,并且可以对任何图像执行此操作。
def rgb_splitter(image):
rgb_list = ['Reds','Greens','Blues']
fig, ax = plt.subplots(1, 3, figsize=(17,7), sharey = True)
for i in range(3):
ax[i].imshow(image[:,:,i], cmap = rgb_list[i])
ax[i].set_title(rgb_list[i], fontsize = 22)
ax[i].axis('off')
fig.tight_layout()
rgb_splitter(dark_image)
很好!我们已经大致了解了各个颜色通道的外观。现在我们检查他们的CDF,下面函数实现此操作:
def df_plotter(image):
freq_bins = [cumulative_distribution(image[:,:,i]) for i in
range(3)]
target_bins = np.arange(255)
target_freq = np.linspace(0, 1, len(target_bins))
names = ['Red', 'Green', 'Blue']
line_color = ['red','green','blue']
f_size = 20
fig, ax = plt.subplots(1, 3, figsize=(17,5))
for n, ax in enumerate(ax.flatten()):
ax.set_title(f'{names[n]}', fontsize = f_size)
ax.step(freq_bins[n][1], freq_bins[n][0], c=line_color[n],
label='Actual CDF')
ax.plot(target_bins,
target_freq,
c='gray',
label='Target CDF',
linestyle = '--')
df_plotter(dark_image)
可以看到,这三个通道都离理想的直线距离很远。为了解决这个问题,我们只需插入他们的cdf。同样,下面的函数,它可以为我们实现这一点。
def rgb_adjuster_lin(image):
target_bins = np.arange(255)
target_freq = np.linspace(0, 1, len(target_bins))
freq_bins = [cumulative_distribution(image[:,:,i]) for i in
range(3)]
names = ['Reds', 'Blues', 'Greens']
line_color = ['red','green','blue']
adjusted_figures = []
f_size = 20
fig, ax = plt.subplots(1,3, figsize=[15,5])
for n, ax in enumerate(ax.flatten()):
interpolation = np.interp(freq_bins[n][0], target_freq,
target_bins)
adjusted_image = img_as_ubyte(interpolation[image[:,:,
n]].astype(int))
ax.set_title(f'{names[n]}', fontsize = f_size)
ax.imshow(adjusted_image, cmap = names[n])
adjusted_figures.append([adjusted_image])
fig.tight_layout()
fig, ax = plt.subplots(1,3, figsize=[15,5])
for n, ax in enumerate(ax.flatten()):
interpolation = np.interp(freq_bins[n][0], target_freq,
target_bins)
adjusted_image = img_as_ubyte(interpolation[image[:,:,
n]].astype(int))
freq_adj, bins_adj = cumulative_distribution(adjusted_image)
ax.set_title(f'{names[n]}', fontsize = f_size)
ax.step(bins_adj, freq_adj, c=line_color[n], label='Actual
CDF')
ax.plot(target_bins,
target_freq,
c='gray',
label='Target CDF',
linestyle = '--')
fig.tight_layout()
return adjusted_figures
channel_figures = return adjusted_figures
我们看到每个颜色通道都有显著的改进,所有这些几乎都像一条直线。
另外,请注意此函数如何以列表的形式返回所有这些值。这将很好地服务于最后一步,也就是把它放回到一个单一的画面。为了让我们更好地了解如何做到这一点,检查一下列表。
print(channel_figures)
print(f'Total Inner Lists : {len(channel_figures)}')
我们可以看到,有三个列表。这些列表表示RGB通道的值。在这种情况下,我们有可能将所有这些值组合在一起。下面的代码实现了这一操作:
plt.figure(num=None, figsize=(10, 8), dpi=80)
imshow(np.dstack((channel_figures[0][0],
channel_figures[1][0],
channel_figures[2][0])));
注意差异有多大。这张照片不仅看起来更加明亮,黄色的阴影也被去除了。让我们在不同的图像上尝试同样的技术。幸运的是我们已经通过设置函数奠定了大部分基础。
dark_street = imread('dark_street.png');
plt.figure(num=None, figsize=(8, 6), dpi=80)
imshow(dark_street);
现在已经加载了新图片,我们简单地通过函数来运行它。
channel_figures_street = adjusted_image_data = rgb_adjuster_lin(dark_street)
plt.figure(num=None, figsize=(10, 8), dpi=80)
imshow(np.dstack((channel_figures_street [0][0],
channel_figures_street [1][0],
channel_figures_street [2][0])));
我们可以看到惊人的进步。尽管这张照片曝光过度了。这可能是因为后面的霓虹灯非常明亮。
总结
在本文中,我们学习了如何调整每个RGB通道以保留图像的颜色信息。这种方法比以前的灰度调整方法有了很大的改进。