Producing sketches from images is all about detecting edges in images. In this recipe, you will learn how to use different techniques, including the difference of **Gaussian** (and its extended version, **XDOG**), anisotropic diffusion, and dodging (applying Gaussian blur + invert + thresholding), to obtain sketches from images.

# Creating pencil sketches from images

# Getting ready

The following libraries need to be imported first:

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

# How to do it...

The following steps need to be performed:

- Define the
`normalize()`function to implement min-max normalization in an image:

def normalize(img):

return (img-np.min(img))/(np.max(img)-np.min(img))

- Implement the
`sketch()`function that takes an image and the extracted edges as input:

def sketch(img, edges):

output = np.multiply(img, edges)

output[output>1]=1

output[edges==1]=1

return output

- Implement a function to extract the edges from an image 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

- Implement a function to extract the edges from an image with the
`dodge`operation (there are two implementations):

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

- Implement a function to extract the edges from an image with a
**Difference of Gaussian**(**DOG**) operation:

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

- Implement a function to produce sketches from an image with an
**Extended Difference of Gaussian**(**XDOG**) operation:

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

If you run the preceding code and plot all of the input/output images, you will obtain an output like the following screenshot:

# How it works...

As you can see from the previous section, many of the sketching techniques work by blurring the edges (for example, with Gaussian filter or diffusion) in the image and removing details to some extent and then subtracting the original image to get the sketch outlines.

The `gaussian()` function from the scikit-image filters module was used to blur the images.

The `anisotropic_diffusion()` function from the `filter.smoothing` module of the `medpy` library was used to find edges with anisotropic diffusion (a variational method).

The dodge operation divides (using `np.divide()`) the image by the inverted blurred image. This highlights the boldest edges in the image.

# There's more...

There are a few more edge detection techniques, such as Canny (with hysteresis thresholds), that you can try to produce sketches from images. You can try them on your own and compare the sketches obtained using different algorithms. Also, by using OpenCV-Python's `pencilSketch()` and `sylization()` functions, you can produce black and white and color pencil sketches, as well as watercolor-like stylized images, with the following few lines of code:

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)

If you run this code and plot the images, you will get a diagram similar to the following screenshot:

# See also

For more details, refer to the following link: