欢迎关注 “小白玩转Python”,发现更多 “有趣”
引言
在之前的文章中,我们讨论了边缘检测内核。在本文我们将讨论如何在图像上应用模糊与锐化内核,将这些内核应用到彩色图像上,同时保留核心图像。
一如既往,我们从导入所需的python库开始。
import numpy as np
import matplotlib.pyplot as plt
from skimage.io import imshow, imread
from skimage.color import rgb2yuv, rgb2hsv, rgb2gray, yuv2rgb, hsv2rgb
from scipy.signal import convolve2d
读取本文将使用的图像。
dog = imread('fire_dog.png')
plt.figure(num=None, figsize=(8, 6), dpi=80)
imshow(dog);
现在我们应用于图像的内核是高斯模糊内核和锐化内核。
# Sharpen
sharpen = np.array([[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]])
# Gaussian Blur
gaussian = (1 / 16.0) * np.array([[1., 2., 1.],
[2., 4., 2.],
[1., 2., 1.]])
fig, ax = plt.subplots(1,2, figsize = (17,10))
ax[0].imshow(sharpen, cmap='gray')
ax[0].set_title(f'Sharpen', fontsize = 18)
ax[1].imshow(gaussian, cmap='gray')
ax[1].set_title(f'Gaussian Blur', fontsize = 18)
[axi.set_axis_off() for axi in ax.ravel()];
但我们如何将这些内核应用到我们的图像中呢?那么,让我们直接通过卷积来试试。
def multi_convolver(image, kernel, iterations):
for i in range(iterations):
image = convolve2d(image, kernel, 'same', boundary = 'fill',
fillvalue = 0)
return image
multi_convolver(dog, gaussian, 2)
很显然,我们出现了维数错误。当我们将一个矩阵与另一个矩阵卷积时,它们的维数应该是相同的。因此,我们必须先将图像转化为灰度。
dog_grey = rgb2gray(dog)
plt.figure(num=None, figsize=(8, 6), dpi=80)
imshow(dog_grey);
现在我们可以运行上面的卷积函数并得到预期的效果。
convolved_image = multi_convolver(dog_grey, gaussian, 2)
plt.figure(num=None, figsize=(8, 6), dpi=80)
imshow(convolved_image);
我们可以清楚的看到,图像已经模糊了。下面的代码将告诉我们如果继续运行高斯模糊卷积图像会发生什么。
def convolution_plotter(image, kernel):
iterations = [1,10,20,30]
f_size = 20
fig, ax = plt.subplots(1,4, figsize = (15,7))
for n, ax in enumerate(ax.flatten()):
ax.set_title(f'Iteration : {iterations[n]}', fontsize =
f_size)
ax.imshow(multi_convolver(image, kernel, iterations[n]),
cmap='gray')
ax.set_axis_off()
fig.tight_layout()
convolution_plotter(dog_grey, gaussian)
可以看到图像变得越来越模糊了。
如果需要使图像模糊并保留颜色怎么办?让我们首先尝试对每个颜色通道应用卷积。
def convolver_rgb(image, kernel, iterations = 1):
convolved_image_r = multi_convolver(image[:,:,0], kernel,
iterations)
convolved_image_g = multi_convolver(image[:,:,1], kernel,
iterations)
convolved_image_b = multi_convolver(image[:,:,2], kernel,
iterations)
reformed_image = np.dstack((np.rint(abs(convolved_image_r)),
np.rint(abs(convolved_image_g)),
np.rint(abs(convolved_image_b)))) /
255
fig, ax = plt.subplots(1,3, figsize = (17,10))
ax[0].imshow(abs(convolved_image_r), cmap='Reds')
ax[0].set_title(f'Red', fontsize = 15)
ax[1].imshow(abs(convolved_image_g), cmap='Greens')
ax[1].set_title(f'Green', fontsize = 15)
ax[2].imshow(abs(convolved_image_b), cmap='Blues')
ax[2].set_title(f'Blue', fontsize = 15)
[axi.set_axis_off() for axi in ax.ravel()]
return np.array(reformed_image).astype(np.uint8)
convolved_rgb_gauss = convolver_rgb(dog, gaussian, 2)
上面这个函数实际上将给我们返回重新生成的图像,我们只需要将其插入到imshow函数中即可。
plt.figure(num=None, figsize=(8, 6), dpi=80)
imshow(convolved_rgb_gauss);
让我们看看卷积十次后图像会变成什么样。
现在让我们尝试下更换锐化内核会发生什么。
convolved_rgb_sharpen = convolver_rgb(dog, sharpen, 1)
处理后的图像有一些轻微的扭曲,为什么会这样呢?
请记住,RGB颜色空间隐式地将像素的光照与颜色混合。这意味着在不改变颜色的情况下对图像的光照应用卷积几乎是不可能的。那么我们如何处理这个问题呢?
解决此问题的一种方法是更改图像的色彩空间。除了使用RGB颜色空间外,我们还可以使用YUV颜色空间。因为YUV空间中的光照通道实际上是与颜色分开的。
现在我们编写一个函数,它首先将图像转换为YUV色彩空间,然后对图像进行卷积。
def convolver_rgb(image, kernel, iterations = 1):
img_yuv = rgb2yuv(image)
img_yuv[:,:,0] = multi_convolver(img_yuv[:,:,0], kernel,
iterations)
final_image = yuv2rgb(img_yuv)
fig, ax = plt.subplots(1,2, figsize = (17,10))
ax[0].imshow(image)
ax[0].set_title(f'Original', fontsize = 20)
ax[1].imshow(final_image);
ax[1].set_title(f'YUV Adjusted, Iterations = {iterations}',
fontsize = 20)
[axi.set_axis_off() for axi in ax.ravel()]
fig.tight_layout()
return final_image
final_image = convolver_rgb(dog, sharpen, iterations = 1)
现在可以看到,处理后的图像是明显锐化且没有任何颜色扭曲的。还有许多其他的方法来解决这个问题,YUV转换只是其中之一,我们还可以使用HSV来解决这个问题。
def convolver_comparison(image, kernel, iterations = 1):
img_yuv = rgb2yuv(image)
img_yuv[:,:,0] = multi_convolver(img_yuv[:,:,0], kernel,
iterations)
final_image_yuv = yuv2rgb(img_yuv)
img_hsv = rgb2hsv(image)
img_hsv[:,:,2] = multi_convolver(img_hsv[:,:,2], kernel,
iterations)
final_image_hsv = hsv2rgb(img_hsv)
convolved_image_r = multi_convolver(image[:,:,0], kernel,
iterations)
convolved_image_g = multi_convolver(image[:,:,1], kernel,
iterations)
convolved_image_b = multi_convolver(image[:,:,2], kernel,
iterations)
final_image_rgb = np.dstack((np.rint(abs(convolved_image_r)),
np.rint(abs(convolved_image_g)),
np.rint(abs(convolved_image_b)))) /
255
fig, ax = plt.subplots(2,2, figsize = (17,17))
ax[0][0].imshow(image)
ax[0][0].set_title(f'Original', fontsize = 30)
ax[0][1].imshow(final_image_rgb);
ax[0][1].set_title(f'RGB Adjusted, Iterations = {iterations}',
fontsize = 30)
fig.tight_layout()
ax[1][0].imshow(final_image_yuv)
ax[1][0].set_title(f'YUV Adjusted, Iterations = {iterations}',
fontsize = 30)
ax[1][1].imshow(final_image_hsv)
ax[1][1].set_title(f'HSV Adjusted, Iterations = {iterations}',
fontsize = 30)
[axi.set_axis_off() for axi in ax.ravel()]
fig.tight_layout()
convolver_comparison(dog, sharpen, iterations = 1)
我们看到,与原始RGB方法相比,HSV和YUV有了一些改进。为了更好地说明,我们可以将迭代次数从1增加到2。
在2次迭代后,失真变得更加明显。但是也很清楚,HSV和Y'UV调整后的图像比原始RGB调整后的图像要好得多。在选择将卷积内核应用于图像的最佳方法时,应当牢记这些特性。
总结
在本文中,我们已经学会了如何对图像进行模糊和锐化卷积。这些技术对于任何从事图像处理和计算机视觉领域的人员都是至关重要的。非常重要的是,我们了解到,简单地将卷积应用到各个RGB通道可能不是最好的方法。在处理图像时,我们应该始终意识到有大量不同类型的色彩空间可以使用。
· END ·
HAPPY LIFE