欢迎关注 “小白玩转Python”,发现更多 “有趣”
引言
在之前的文章中,我们讨论了如何手动均衡每个通道的直方图。但是,直接操纵RGB通道只是增强图像质量的一种方法。在本文中我们将讨论下其他的方法。
一如既往,让我们首先导入所需的Python库。
import numpy as np
import matplotlib.pyplot as plt
from skimage.io import imshow, imread
from skimage.color import rgb2hsv, rgb2gray, rgb2yuv
from skimage import color, exposure, transform
from skimage.exposure import histogram, cumulative_distribution, equalize_hist
from skimage import img_as_ubyte, img_as_uint
加载我们需要处理的图像。
dark_image = imread('flea_market.png')
plt.figure(num=None, figsize=(8, 6), dpi=80)
imshow(dark_image);
这张照片显然存在光线问题。它不仅在某些地方非常黑暗,而且在其他地方非常明亮。让我们首先看看如果我们做一个简单的灰度直方图调整会发生什么。
dark_image_grey = img_as_ubyte(rgb2gray(dark_image))
freq, bins = cumulative_distribution(dark_image_grey, nbins =256)
target_bins = np.arange(255)
target_freq = np.linspace(0, 1, len(target_bins))
interpolation = np.interp(frequencies, target_freq, target_bins)
dark_image_eq = img_as_ubyte(interpolation[dark_image_grey].astype(int))
freq_adj, bins_adj = cumulative_distribution(dark_image_eq)
fig, axes = plt.subplots(1, 2, figsize=(15,7));
axes[0].imshow(dark_image_grey, cmap = 'gray');
axes[0].set_title(f'Original Greyscale', fontsize = 18)
axes[1].imshow(dark_image_eq, cmap = 'gray');
axes[1].set_title(f'Adjusted Greyscale', fontsize = 18)
axes[0].axis('off');
axes[1].axis('off');
我们可以看到图像有了显著的改善。然而,亮点仍然相当明显。让我们看看能不能补救这一点。下面是通过单独调整每个颜色通道将图像转换为直方图均衡图像的代码。
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', 'Greens', 'Blues']
line_color = ['red','green','blue']
adjusted_figures = []
f_size = 20
#Pad frequencies with min frequency
adj_freqs = []
for i in range(len(freq_bins)):
if len(freq_bins[i][0]) < 256:
frequencies = list(freq_bins[i][0])
min_pad = [min(frequencies)] * (256 - len(frequencies))
frequencies = min_pad + frequencies
else:
frequencies = freq_bins[i][0]
adj_freqs.append(np.array(frequencies))
#Plot RGB Images
fig, ax = plt.subplots(1,3, figsize=[15,5])
for n, ax in enumerate(ax.flatten()):
interpolation = np.interp(adj_freqs[n], 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()
#Plot Adjusted CDFs
fig, ax = plt.subplots(1,3, figsize=[15,3])
for n, ax in enumerate(ax.flatten()):
interpolation = np.interp(adj_freqs[n], 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()
adjusted_image = np.dstack((adjusted_figures[0][0],
adjusted_figures[1][0],
adjusted_figures[2][0]))
#Plot Original Image against Adjusted Image
fig, ax = plt.subplots(1,2, figsize=[17,7])
ax[0].imshow(image);
ax[0].set_title(f'Original Image', fontsize = f_size)
ax[1].imshow(adjusted_image);
ax[1].set_title(f'Adjusted Image', fontsize = f_size)
fig.tight_layout()
return adjusted_image
我们看到图像有了很大的改善。然而,这些灯泡的耀眼光芒仍然非常明显。为此,让我们探索另一种方法来调整图像的直方图。
通过 HSV 色彩空间进行调整
首先将RGB图像转换为HSV图像,然后均衡V通道的直方图。
hsv_image = color.rgb2hsv(dark_image[:,:,:-1])
hsv_image[:, :, 2] = equalize_hist(dark_image[:, :, 2])
hsv_adjusted = color.hsv2rgb(hsv_image)
fig, ax = plt.subplots(1,2, figsize=[15,10])
ax[0].imshow(dark_image);
ax[0].set_title(f'Original Image', fontsize = 18)
ax[1].imshow(hsv_adjusted);
ax[1].set_title(f'HSV Adjusted Image', fontsize = 18)
fig.tight_layout()
很明显,仅基于V通道调整图像会产生良好的效果。这些颜色不仅保留了其鲜艳度,而且整体图像看起来也更加清晰。
此外,图像的整体暖色调也得以保持。在某些情况下,这可能更可取。灯泡发出的光也不像RGB调整图像中的眩那样刺眼。下面的代码显示了另一张图片上RGB和HSV调整的并排比较。
rice_terraces = imread('rice_terraces.png')
plt.figure(num=None, figsize=(8, 6), dpi=80)
imshow(rice_terraces);
def rgb_vs_hsv(image):
f_size = 22
#Equalize Histogram
rgb_adjusted = image.copy()
rgb_adjusted = equalize_hist(rgb_adjusted)
#HSV Adjustment
new_image = color.rgb2hsv(image[:,:,:-1])
new_image[:, :, 2] = equalize_hist(new_image [:, :, 2])
hsv_adjusted = color.hsv2rgb(new_image)
images = [image, rgb_adjusted, hsv_adjusted]
names = ['Original', 'RGB Adjusted', 'HSV Adjusted']
fig, ax = plt.subplots(1,3, figsize=[19,14])
for n, ax in enumerate(ax.flatten()):
ax.imshow(images[n])
ax.set_title(f'{names[n]}', fontsize = f_size)
ax.set_axis_off()
fig.tight_layout()
rgb_vs_hsv(rice_terraces)
如我们所见,直接通过颜色通道调整图像与通过V通道调整图像之间有着明显的区别。后者产生的图像更清晰,但仍保持其颜色阴暗。
通过YUV色彩空间进行调整
最后,我们通过YUV颜色空间来调整图像。这与之前通过HSV颜色空间调整图像的方法没有太大区别。我们将把这个方法应用于下面的图像。
red_tree = imread('red_tree.png')
plt.figure(num=None, figsize=(8, 6), dpi=80)
imshow(red_tree);
#HSV Adjustment Manual
hsv_image = color.rgb2hsv(red_tree[:,:,:-1])
hsv_image[:, :, 2] = equalize_hist(hsv_image[:, :, 2])
hsv_adjusted = color.hsv2rgb(hsv_image)
#YUV Adjustment Manual
yuv = color.rgb2yuv(red_tree[:,:,:-1])
yuv[:, :, 0] = equalize_hist(yuv[:, :, 0])
yuv_adjusted = color.yuv2rgb(new_image)
fig, ax = plt.subplots(1,3, figsize=[15,10])
ax[0].imshow(red_tree);
ax[0].set_title(f'Original Image', fontsize = 18)
ax[1].imshow(hsv_adjusted);
ax[1].set_title(f'HSV Adjusted', fontsize = 18)
ax[2].imshow(yuv_adjusted);
ax[2].set_title(f'YUV Adjusted', fontsize = 18)
fig.tight_layout()
我们看到,YUV调整后的图像脱颖而出,因为它的整体色彩更明亮。与HSV调整后的图像不同,HSV调整后的图像颜色更清晰。YUV的照片看起来就像是在一个阳光明媚的日子里拍摄的。
总结
现在我们只是触及到了直方图均衡化的皮毛,如果你感兴趣可以继续探究下去~
· END ·
HAPPY LIFE