Python图像处理经典实例
上QQ阅读APP看书,第一时间看更新

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