├── inputs ├── 3--7.jpg ├── sjtu.jpg ├── 11--57.jpg ├── 12--73.jpg ├── 12--95.jpg ├── 16--85.jpg ├── 17--6.jpg ├── 17--8.jpg ├── 18--28.jpg ├── 2--31.jpg ├── 2--32.jpg ├── 2--43.jpg ├── 2--46.jpg ├── 2--58.jpg ├── 2--59.jpg ├── 2--73.jpg ├── 2--83.jpg ├── 3--17.jpg ├── 4--24.jpg ├── 5--26.jpg ├── 5--32.jpg ├── 6--267.jpg ├── 6--336.jpg ├── 7--128.jpg ├── 7--129.jpg ├── 7--136.jpg ├── 7--165.jpg ├── 7--88.jpg ├── flower.png ├── 11--128.jpg ├── 15--198.jpg ├── 15--298.jpg ├── 15--306.jpg ├── 15--313.jpg ├── 15--324.jpg ├── wuda--0.jpg ├── wuda--1.jpg ├── wuda--2.jpg ├── wuda--3.jpg └── sjtu_xuhui.JPG ├── images ├── h_beta.JPG ├── Workflow.JPG ├── LineShaping.JPG ├── dp_compare.JPG ├── jl_compare.JPG └── ExampleResult.JPG ├── pencils ├── pencil0.jpg ├── pencil1.jpg ├── pencil2.png ├── pencil3.jpg └── pencil4.jpg ├── README.md └── PencilDrawingBySketchAndTone.py /inputs/3--7.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/3--7.jpg -------------------------------------------------------------------------------- /inputs/sjtu.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/sjtu.jpg -------------------------------------------------------------------------------- /images/h_beta.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/images/h_beta.JPG -------------------------------------------------------------------------------- /inputs/11--57.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/11--57.jpg -------------------------------------------------------------------------------- /inputs/12--73.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/12--73.jpg -------------------------------------------------------------------------------- /inputs/12--95.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/12--95.jpg -------------------------------------------------------------------------------- /inputs/16--85.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/16--85.jpg -------------------------------------------------------------------------------- /inputs/17--6.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/17--6.jpg -------------------------------------------------------------------------------- /inputs/17--8.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/17--8.jpg -------------------------------------------------------------------------------- /inputs/18--28.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/18--28.jpg -------------------------------------------------------------------------------- /inputs/2--31.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/2--31.jpg -------------------------------------------------------------------------------- /inputs/2--32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/2--32.jpg -------------------------------------------------------------------------------- /inputs/2--43.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/2--43.jpg -------------------------------------------------------------------------------- /inputs/2--46.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/2--46.jpg -------------------------------------------------------------------------------- /inputs/2--58.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/2--58.jpg -------------------------------------------------------------------------------- /inputs/2--59.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/2--59.jpg -------------------------------------------------------------------------------- /inputs/2--73.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/2--73.jpg -------------------------------------------------------------------------------- /inputs/2--83.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/2--83.jpg -------------------------------------------------------------------------------- /inputs/3--17.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/3--17.jpg -------------------------------------------------------------------------------- /inputs/4--24.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/4--24.jpg -------------------------------------------------------------------------------- /inputs/5--26.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/5--26.jpg -------------------------------------------------------------------------------- /inputs/5--32.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/5--32.jpg -------------------------------------------------------------------------------- /inputs/6--267.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/6--267.jpg -------------------------------------------------------------------------------- /inputs/6--336.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/6--336.jpg -------------------------------------------------------------------------------- /inputs/7--128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/7--128.jpg -------------------------------------------------------------------------------- /inputs/7--129.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/7--129.jpg -------------------------------------------------------------------------------- /inputs/7--136.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/7--136.jpg -------------------------------------------------------------------------------- /inputs/7--165.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/7--165.jpg -------------------------------------------------------------------------------- /inputs/7--88.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/7--88.jpg -------------------------------------------------------------------------------- /inputs/flower.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/flower.png -------------------------------------------------------------------------------- /images/Workflow.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/images/Workflow.JPG -------------------------------------------------------------------------------- /inputs/11--128.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/11--128.jpg -------------------------------------------------------------------------------- /inputs/15--198.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/15--198.jpg -------------------------------------------------------------------------------- /inputs/15--298.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/15--298.jpg -------------------------------------------------------------------------------- /inputs/15--306.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/15--306.jpg -------------------------------------------------------------------------------- /inputs/15--313.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/15--313.jpg -------------------------------------------------------------------------------- /inputs/15--324.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/15--324.jpg -------------------------------------------------------------------------------- /inputs/wuda--0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/wuda--0.jpg -------------------------------------------------------------------------------- /inputs/wuda--1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/wuda--1.jpg -------------------------------------------------------------------------------- /inputs/wuda--2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/wuda--2.jpg -------------------------------------------------------------------------------- /inputs/wuda--3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/wuda--3.jpg -------------------------------------------------------------------------------- /pencils/pencil0.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/pencils/pencil0.jpg -------------------------------------------------------------------------------- /pencils/pencil1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/pencils/pencil1.jpg -------------------------------------------------------------------------------- /pencils/pencil2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/pencils/pencil2.png -------------------------------------------------------------------------------- /pencils/pencil3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/pencils/pencil3.jpg -------------------------------------------------------------------------------- /pencils/pencil4.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/pencils/pencil4.jpg -------------------------------------------------------------------------------- /images/LineShaping.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/images/LineShaping.JPG -------------------------------------------------------------------------------- /images/dp_compare.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/images/dp_compare.JPG -------------------------------------------------------------------------------- /images/jl_compare.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/images/jl_compare.JPG -------------------------------------------------------------------------------- /inputs/sjtu_xuhui.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/inputs/sjtu_xuhui.JPG -------------------------------------------------------------------------------- /images/ExampleResult.JPG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/taldatech/image2pencil-drawing/master/images/ExampleResult.JPG -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # image2pencil-drawing 2 | Python implementation of the Pencil Drawing by Sketch and Tone algorithm 3 | ![alt text](https://github.com/taldatech/image2pencil-drawing/blob/master/images/dp_compare.JPG) 4 | ### Based on the paper "Combining Sketch and Tone for Pencil Drawing Production" by Cewu Lu, Li Xu, Jiaya Jia 5 | #### International Symposium on Non-Photorealistic Animation and Rendering (NPAR 2012), June 2012 6 | Project site can be found here: 7 | http://www.cse.cuhk.edu.hk/leojia/projects/pencilsketch/pencil_drawing.htm 8 | 9 | Paper PDF - http://www.cse.cuhk.edu.hk/leojia/projects/pencilsketch/npar12_pencil.pdf 10 | 11 | Draws inspiration from the Matlab implementation by "candtcat1992" - https://github.com/candycat1992/PencilDrawing 12 | 13 | In this notebook, we will explain and implement the algorithm described in the paper. This is what we are trying to achieve: 14 | ![alt text](https://github.com/taldatech/image2pencil-drawing/blob/master/images/ExampleResult.JPG) 15 | 16 | We can divide the workflow into 2 main steps: 17 | 1. Pencil stroke generation (captures the general strucure of the scene) 18 | 2. Pencil tone drawing (captures shapes shadows and shading) 19 | 20 | Combining the results from these steps should yield the desired result. The workflow can be depicted as follows: 21 | ![alt text](https://github.com/taldatech/image2pencil-drawing/blob/master/images/Workflow.JPG) 22 | 23 | * Both figures were taken from the original paper 24 | 25 | Another example: 26 | ![alt text](https://github.com/taldatech/image2pencil-drawing/blob/master/images/jl_compare.JPG) 27 | 28 | # Usage 29 | ```python 30 | from PencilDrawingBySketchAndTone import * 31 | import matplotlib.pyplot as plt 32 | ex_img = io.imread('./inputs/11--128.jpg') 33 | pencil_tex = './pencils/pencil1.jpg' 34 | ex_im_pen = gen_pencil_drawing(ex_img, kernel_size=8, stroke_width=0, num_of_directions=8, smooth_kernel="gauss", 35 | gradient_method=0, rgb=True, w_group=2, pencil_texture_path=pencil_tex, 36 | stroke_darkness= 2,tone_darkness=1.5) 37 | plt.rcParams['figure.figsize'] = [16,10] 38 | plt.imshow(ex_im_pen) 39 | plt.axis("off") 40 | ``` 41 | # Parameters 42 | * kernel_size = size of the line segement kernel (usually 1/30 of the height/width of the original image) 43 | * stroke_width = thickness of the strokes in the Stroke Map (0, 1, 2) 44 | * num_of_directions = stroke directions in the Stroke Map (used for the kernels) 45 | * smooth_kernel = how the image is smoothed (Gaussian Kernel - "gauss", Median Filter - "median") 46 | * gradient_method = how the gradients for the Stroke Map are calculated (0 - forward gradient, 1 - Sobel) 47 | * rgb = True if the original image has 3 channels, False if grayscale 48 | * w_group = 3 possible weight groups (0, 1, 2) for the histogram distribution, according to the paper (brighter to darker) 49 | * pencil_texture_path = path to the Pencil Texture Map to use (4 options in "./pencils", you can add your own) 50 | * stroke_darkness = 1 is the same, up is darker. 51 | * tone_darkness = as above 52 | 53 | # Folders 54 | * inputs: test images from the publishers' website: http://www.cse.cuhk.edu.hk/leojia/projects/pencilsketch/pencil_drawing.htm 55 | * pencils: pencil textures for generating the Pencil Texture Map 56 | 57 | # Reference 58 | [1] Lu C, Xu L, Jia J. Combining sketch and tone for pencil drawing production[C]//Proceedings of the Symposium on Non-Photorealistic Animation and Rendering. Eurographics Association, 2012: 65-73. 59 | 60 | [2] Matlab implementation by "candtcat1992" - https://github.com/candycat1992/PencilDrawing 61 | -------------------------------------------------------------------------------- /PencilDrawingBySketchAndTone.py: -------------------------------------------------------------------------------- 1 | 2 | # # Combining Sketch & Tone for Pencil Drawing Production 3 | # ## Python Implementation 4 | # ### Based on the paper "Combining Sketch and Tone for Pencil Drawing Production" by Cewu Lu, Li Xu, Jiaya Jia 5 | # #### International Symposium on Non-Photorealistic Animation and Rendering (NPAR 2012), June 2012 6 | # Project site can be found here: 7 | # http://www.cse.cuhk.edu.hk/leojia/projects/pencilsketch/pencil_drawing.htm 8 | # 9 | # Paper PDF - http://www.cse.cuhk.edu.hk/leojia/projects/pencilsketch/npar12_pencil.pdf 10 | # 11 | # Draws inspiration from the Matlab implementation by "candtcat1992" - https://github.com/candycat1992/PencilDrawing 12 | 13 | 14 | 15 | # imports 16 | import numpy as np 17 | import cv2 18 | from skimage import io, color, filters, transform, exposure 19 | from scipy import signal, sparse 20 | 21 | 22 | # Generate Stroke Map 23 | def gen_stroke_map(img, kernel_size, stroke_width=0, num_of_directions=8, smooth_kernel="gauss", gradient_method=0): 24 | height = img.shape[0] # number of rows, height of the image 25 | width = img.shape[1] # number of columns, width of the image 26 | # Let's start with smoothing 27 | if (smooth_kernel == "gauss"): 28 | smooth_im = filters.gaussian(img, sigma=np.sqrt(2)) 29 | else: 30 | smooth_im = filters.median(img) # default is 3x3 kernel size 31 | # Let's calculate the gradients: 32 | if not gradient_method: 33 | # forward gradient: (we pad with zeros) 34 | imX = np.zeros_like(img) 35 | diffX = img[: , 1:width] - img[: , 0:width - 1] 36 | imX[:, 0:width - 1] = diffX 37 | imY = np.zeros_like(img) 38 | diffY = img[1:height , :] - img[0:height - 1 , :] 39 | imY[0:height - 1, :] = diffY 40 | G = np.sqrt(np.square(imX) + np.square(imY)) 41 | else: 42 | # Sobel 43 | sobelx = cv2.Sobel(img,cv2.CV_64F,1,0,ksize=5) 44 | sobely = cv2.Sobel(img,cv2.CV_64F,0,1,ksize=5) 45 | G = np.sqrt(np.square(sobelx) + np.square(sobely)) 46 | # Let's create the basic line segement (horizontal) 47 | # make sure it is an odd number, so the lines are at the middle 48 | basic_ker = np.zeros((kernel_size * 2 + 1, kernel_size * 2 + 1)) 49 | basic_ker[kernel_size + 1,:] = 1 # ------- (horizontal line) 50 | # Let's rotate the lines in the given directions and perform the classification: 51 | res_map = np.zeros((height, width, num_of_directions)) 52 | for d in range(num_of_directions): 53 | ker = transform.rotate(basic_ker, (d * 180) / num_of_directions) 54 | res_map[:,:, d] = signal.convolve2d(G, ker, mode='same') 55 | max_pixel_indices_map = np.argmax(res_map, axis=2) 56 | # What does it compute? every direction has a (height X width) matrix. For every pixel in the matrix, 57 | # np.argmax returns the index of the direction that holds the pixel with the maximum value 58 | # and thus we get the max_pixel_indices map is a (height X width) matrix with direction numbers. 59 | # Now we compute the Classification map: 60 | C = np.zeros_like(res_map) 61 | for d in range(num_of_directions): 62 | C[:,:,d] = G * (max_pixel_indices_map == d) # (max_pixel_indices_map == d) is a binary matrix 63 | # We should now consider the stroke width before we create S' 64 | if not stroke_width: 65 | for w in range(1, stroke_width + 1): 66 | if (kernel_size + 1 - w) >= 0: 67 | basic_ker[kernel_size + 1 - w, :] = 1 68 | if (kernel_size + 1 + w) < (kernel_size * 2 + 1): 69 | basic_ker[kernel_size + 1 + w, :] = 1 70 | # It's time to compute S': 71 | S_tag_sep = np.zeros_like(C) 72 | for d in range(num_of_directions): 73 | ker = transform.rotate(basic_ker, (d * 180) / num_of_directions) 74 | S_tag_sep[:,:,d] = signal.convolve2d(C[:,:,d], ker, mode='same') 75 | S_tag = np.sum(S_tag_sep, axis=2) 76 | # Remember that S shpuld be an image, thus we need to make sure the values are in [0,1] 77 | S_tag_normalized = (S_tag - np.min(S_tag.ravel())) / (np.max(S_tag.ravel()) - np.min(S_tag.ravel())) 78 | # The last step is to invert it (b->w, w->b) 79 | S = 1 - S_tag_normalized 80 | return S 81 | 82 | 83 | # Generate Tone Map 84 | # Make sure input image is in [0,1] 85 | def gen_tone_map(img, w_group=0): 86 | # The first thing we need to do is to calculate the parameters and define weight groups 87 | w_mat = np.array([[11, 37, 52], 88 | [29, 29, 42], 89 | [2, 22, 76]]) 90 | w = w_mat[w_group,:] 91 | # We can now define tone levels like: 92 | # dark: [0-85] 93 | # mild: [86-170] 94 | # bright: [171-255] 95 | # Assign each pixel a tone level, make 3 lists where each list holds the pixels (indices) of every tone. 96 | # Use these lists to calculate the parameters for each image. 97 | 98 | # For simplicity, we will use the parameters from the paper: 99 | # for the mild layer: 100 | u_b = 225 101 | u_a = 105 102 | # for the bright layer: 103 | sigma_b = 9 104 | # for the dark layer: 105 | mu_d = 90 106 | sigma_d = 11 107 | 108 | # Let's calculate the new histogram (p(v)): 109 | num_pixel_vals = 256 110 | p = np.zeros(num_pixel_vals) 111 | for v in range(num_pixel_vals): 112 | p1 = (1 / sigma_b) * np.exp(-(255 - v) / sigma_b) 113 | if (u_a <= v <= u_b): 114 | p2 = 1 / (u_b - u_a) 115 | else: 116 | p2 = 0 117 | p3 = (1 / np.sqrt(2 * np.pi * sigma_d)) * np.exp( (-np.square(v - mu_d)) / (2 * np.square(sigma_d)) ) 118 | p[v] = w[0] * p1 + w[1] * p2 + w[2] * p3 * 0.01 119 | # normalize the histogram: 120 | p_normalized = p / np.sum(p) 121 | # calculate the CDF of the desired histogram: 122 | P = np.cumsum(p_normalized) 123 | # calculate the original histogram: 124 | h = exposure.histogram(img, nbins=256) 125 | # CDF of original: 126 | H = np.cumsum(h / np.sum(h)) 127 | # histogram matching: 128 | lut = np.zeros_like(p) 129 | for v in range(num_pixel_vals): 130 | # find the closest value: 131 | dist = np.abs(P - H[v]) 132 | argmin_dist = np.argmin(dist) 133 | lut[v] = argmin_dist 134 | lut_normalized = lut / num_pixel_vals 135 | J = lut_normalized[(255 * img).astype(np.int)] 136 | # smooth: 137 | J_smoothed = filters.gaussian(J, sigma=np.sqrt(2)) 138 | return J_smoothed 139 | 140 | 141 | 142 | # Generate Pencil Texture: 143 | def gen_pencil_texture(img, H, J): 144 | # define the regularization parameter: 145 | lamda = 0.2 146 | height = img.shape[0] 147 | width = img.shape[1] 148 | # Adjust the input to correspond 149 | # H_res = transform.resize(H,(height, width)) 150 | H_res = cv2.resize(H, (width, height), interpolation=cv2.INTER_CUBIC) 151 | H_res_reshaped = np.reshape(H_res, (height * width, 1)) 152 | logH = np.log(H_res_reshaped) 153 | 154 | # J_res = transform.resize(J,(height, width)) 155 | J_res = cv2.resize(J, (width, height), interpolation=cv2.INTER_CUBIC) 156 | J_res_reshaped = np.reshape(J_res, (height * width, 1)) 157 | logJ = np.log(J_res_reshaped) 158 | 159 | # In order to use Conjugate Gradient method we need to prepare some sparse matrices: 160 | logH_sparse = sparse.spdiags(logH.ravel(), 0, height*width, height*width) # 0 - from main diagonal 161 | e = np.ones((height * width, 1)) 162 | ee = np.concatenate((-e,e), axis=1) 163 | diags_x = [0, height*width] 164 | diags_y = [0, 1] 165 | dx = sparse.spdiags(ee.T, diags_x, height*width, height*width) 166 | dy = sparse.spdiags(ee.T, diags_y, height*width, height*width) 167 | 168 | # Compute matrix X and b: (to solve Ax = b) 169 | A = lamda * ((dx @ dx.T) + (dy @ dy.T)) + logH_sparse.T @ logH_sparse 170 | b = logH_sparse.T @ logJ 171 | 172 | # Conjugate Gradient 173 | beta = sparse.linalg.cg(A, b, tol=1e-6, maxiter=60) 174 | 175 | # Adjust the result 176 | beta_reshaped = np.reshape(beta[0], (height, width)) 177 | 178 | # The final pencil texture map T 179 | T = np.power(H_res, beta_reshaped) 180 | 181 | return T 182 | 183 | 184 | # It's time to pack it all up (WOOHOOO!) 185 | def gen_pencil_drawing(img, kernel_size, stroke_width=0, num_of_directions=8, smooth_kernel="gauss", 186 | gradient_method=0, rgb=False, w_group=0, pencil_texture_path="", stroke_darkness=1, tone_darkness=1): 187 | if not rgb: 188 | # Grayscale image: 189 | im = img 190 | else: 191 | # RGB image: 192 | yuv_img = color.rgb2yuv(img) 193 | im = yuv_img[:,:,0] 194 | # Generate the Stroke Map: 195 | S = gen_stroke_map(im, kernel_size, stroke_width=stroke_width, num_of_directions=num_of_directions, 196 | smooth_kernel=smooth_kernel, gradient_method=gradient_method) 197 | S = np.power(S, stroke_darkness) 198 | # Generate the Tone Map: 199 | J = gen_tone_map(im, w_group=w_group) 200 | 201 | # Read the pencil texture: 202 | if not pencil_texture_path: 203 | pencil_texture = io.imread('./pencils/pencil0.jpg', as_gray=True) 204 | else: 205 | pencil_texture = io.imread(pencil_texture_path, as_gray=True) 206 | # Generate the Pencil Texture Map: 207 | T = gen_pencil_texture(im, pencil_texture, J) 208 | T = np.power(T, tone_darkness) 209 | # The final Y channel: 210 | R = np.multiply(S, T) 211 | 212 | if not rgb: 213 | return R 214 | else: 215 | yuv_img[:,:,0] = R 216 | return exposure.rescale_intensity(color.yuv2rgb(yuv_img), in_range=(0, 1)) 217 | 218 | --------------------------------------------------------------------------------