1.5 基于图像创建铅笔草图
基于图像生成草图,实际上就是检测图像的边缘。在本实例中,我们将学习如何使用不同的技术从图像中获取草图,这类技术包括高斯差分(及其扩展版本XDOG)、各向异性扩散和局部遮光(应用高斯模糊+反转+阈值)。
1.5.1 准备工作
让我们先导入以下Python库:
import numpy as np from skimage.io import imread from skimage.color import rgb2gray from skimage import util from skimage import img_as_float import matplotlib.pylab as plt from medpy.filter.smoothing import anisotropic_diffusion from skimage.filters import gaussian, threshold_otsu
1.5.2 执行步骤
要从图像中创建铅笔草图,我们需要执行以下步骤。
1.定义normalize()函数来实现图像的最小值、最大值归一化:
def normalize(img): return (img-np.min(img))/(np.max(img)-np.min(img))
2.实现sketch()函数。该函数以图像及其所提取的图像的边缘作为输入参数:
def sketch(img, edges): output = np.multiply(img, edges) output[output>1]=1 output[edges==1]=1 return output
3.实现edges_with_anisotropic_diffusion()函数。该函数通过各向异性扩散从图像中提取边缘:
def edges_with_anisotropic_diffusion(img, niter=100, kappa=10, gamma=0.1): output = img - anisotropic_diffusion(img, niter=niter, \ kappa=kappa, gamma=gamma, voxelspacing=None, \ option=1) output[output > 0] = 1 output[output < 0] = 0 return output
4.实现sketch_with_dodge()函数和edges_with_dodge2()函数。所实现的函数通过局部遮光操作从图像中提取边缘(代码提供了函数的两个实现版本):
def sketch_with_dodge(img): orig = img blur = gaussian(util.invert(img), sigma=20) result = blur / util.invert(orig) result[result>1] = 1 result[orig==1] = 1 return result def edges_with_dodge2(img): img_blurred = gaussian(util.invert(img), sigma=5) output = np.divide(img, util.invert(img_blurred) + 0.001) output = normalize(output) thresh = threshold_otsu(output) output = output > thresh return output
5.实现edges_with_DOG()函数。利用该函数,使用高斯差分(DOG)运算来从图像中提取边缘:
def edges_with_DOG(img, k = 200, gamma = 1): sigma = 0.5 output = gaussian(img, sigma=sigma) - gamma*gaussian(img, \ sigma=k*sigma) output[output > 0] = 1 output[output < 0] = 0 return output
6.实现sketch_with_XDOG()函数。利用该函数,使用扩展高斯差分(XDOG)运算从图像中生成草图:
def sketch_with_XDOG(image, epsilon=0.01): phi = 10 difference = edges_with_DOG(image, 200, 0.98).astype(np.uint8) for i in range(0, len(difference)): for j in range(0, len(difference[0])): if difference[i][j] >= epsilon: difference[i][j] = 1 else: ht = np.tanh(phi*(difference[i][j] - epsilon)) difference[i][j] = 1 + ht difference = normalize(difference) return difference
运行上述代码并绘制输入及输出的图像,将得到图1-10所示的输出。
图1-10
1.5.3 工作原理
从前文中可以看到,许多草图绘制技术都是通过模糊图像的边缘(例如,使用高斯滤波器或扩散)并在一定程度上去除细节,然后减去原始图像来得到草图轮廓。
通过调用scikit-image库filter模块中的gaussian()函数来模糊图像。通过调用medpy 库中filter.smoothing模块的anisotropic_diffusion()函数来查找具有各向异性扩散(一种变分方法)的图像边缘。
局部遮光操作(使用np.divide()函数)会将反转的模糊图像从图像中分割出来,通过该操作,将突出显示图像中最醒目的边缘。
1.5.4 更多实践
还有一些其他边缘检测技术可供选择,如通过Canny边缘检测(带有滞后阈值),读者可以尝试从图像中生成草图。读者可以尝试各种算法,并对比使用不同算法所获得的草图有何区别。此外,通过使用以下代码——调用OpenCV-Python库函数,如pencilSketch()和sylization()函数,可以生成黑白的和彩色的铅笔草图,以及类似水彩效果的图像:
import cv2 import matplotlib.pylab as plt src = cv2.imread('images/bird.png') #dst = cv2.detailEnhance(src, sigma_s=10, sigma_r=0.15) dst_sketch, dst_color_sketch = cv2.pencilSketch(src, sigma_s=50, sigma_r=0.05, shade_factor=0.05) dst_water_color = cv2.stylization(src, sigma_s=50, sigma_r=0.05)
运行上述代码并绘制图像,将得到图1-11所示的输出。
图1-11