Repository: candycat1992/PencilDrawing Branch: master Commit: bca965d1c92a Files: 6 Total size: 8.2 KB Directory structure: gitextract__zisyvfe/ ├── GenPencil.m ├── GenStroke.m ├── GenToneMap.m ├── PencilDrawing.m ├── README.md └── demo.m ================================================ FILE CONTENTS ================================================ ================================================ FILE: GenPencil.m ================================================ function T = GenPencil(im, P, J) % ============================================== % Compute the pencil map 'T' % % Paras: % @im : input image ranging value from 0 to 1. % @P : the pencil texture. % @J : the tone map. % %% Parameters theta = 0.2; [H, W, ~] = size(im); %% Initialization P = imresize(P, [H, W]); P = reshape(P, H*W, 1); logP = log(P); logP = spdiags(logP, 0, H*W, H*W); J = imresize(J, [H, W]); J = reshape(J, H*W, 1); logJ = log(J); e = ones(H*W, 1); Dx = spdiags([-e, e], [0, H], H*W, H*W); Dy = spdiags([-e, e], [0, 1], H*W, H*W); %% Compute matrix A and b A = theta * (Dx * Dx' + Dy * Dy') + (logP)' * logP; b = (logP)' * logJ; %% Conjugate gradient beta = pcg(A, b, 1e-6, 60); %% Compute the result beta = reshape(beta, H, W); P = reshape(P, H, W); T = P .^ beta; end ================================================ FILE: GenStroke.m ================================================ function S = GenStroke(im, ks, width, dirNum) % ============================================== % Compute the stroke structure 'S' % % Paras: % @im : input image ranging value from 0 to 1. % @ks : kernel size. % @width : width of the strocke % @dirNum : number of directions. % %% Initialization [H, W, ~] = size(im); %% Smoothing im = medfilt2(im, [3 3]); %% Image gradient imX = [abs(im(:,1:(end-1)) - im(:,2:end)),zeros(H,1)]; imY = [abs(im(1:(end-1),:) - im(2:end,:));zeros(1,W)]; imEdge = imX + imY; %% Convolution kernel with horizontal direction kerRef = zeros(ks*2+1); kerRef(ks+1,:) = 1; %% Classification response = zeros(H,W,dirNum); for n = 1 : dirNum ker = imrotate(kerRef, (n-1)*180/dirNum, 'bilinear', 'crop'); response(:,:,n) = conv2(imEdge, ker, 'same'); end [~, index] = max(response,[], 3); %% Create the stroke C = zeros(H, W, dirNum); for n = 1 : dirNum C(:,:,n) = imEdge .* (index == n); end kerRef = zeros(ks*2+1); kerRef(ks+1,:) = 1; for n = 1 : width if (ks+1-n) > 0 kerRef(ks+1-n,:) = 1; end if (ks+1+n) < (ks*2+1) kerRef(ks+1+n,:) = 1; end end Spn = zeros(H, W, dirNum); for n = 1 : dirNum ker = imrotate(kerRef, (n-1)*180/dirNum, 'bilinear', 'crop'); Spn(:,:,n) = conv2(C(:,:,n), ker, 'same'); end Sp = sum(Spn, 3); Sp = (Sp - min(Sp(:))) / (max(Sp(:)) - min(Sp(:))); S = 1 - Sp; end ================================================ FILE: GenToneMap.m ================================================ function J = GenToneMap(im) % ============================================== % Compute the tone map 'T' % % Paras: % @im : input image ranging value from 0 to 1. % %% Parameters Ub = 225; Ua = 105; Mud = 90; DeltaB = 9; DeltaD = 11; % groups from dark to light % 1st group Omega1 = 42; Omega2 = 29; Omega3 = 29; % 2nd group Omega1 = 52; Omega2 = 37; Omega3 = 11; % 3rd group Omega1 = 76; Omega2 = 22; Omega3 = 2; %% Compute the target histgram histgramTarget = zeros(256, 1); total = 0; for ii = 0 : 255 if ii < Ua || ii > Ub p = 0; else p = 1 / (Ub - Ua); end histgramTarget(ii+1, 1) = (... Omega1 * 1/DeltaB * exp(-(255-ii)/DeltaB) + ... Omega2 * p + ... Omega3 * 1/sqrt(2 * pi * DeltaD) * exp(-(ii-Mud)^2/(2*DeltaD^2))) * 0.01; total = total + histgramTarget(ii+1, 1); end histgramTarget(:, 1) = histgramTarget(:, 1)/total; % %% Smoothing % im = medfilt2(im, [5 5]); %% Histgram matching J = histeq(im, histgramTarget); %% Smoothing G = fspecial('average', 10); J = imfilter(J, G,'same'); end ================================================ FILE: PencilDrawing.m ================================================ function I = PencilDrawing(im, ks, width, dirNum, gammaS, gammaI) % ============================================== % Generate the pencil drawing I based on the method described in % "Combining Sketch and Tone for Pencil Drawing Production" Cewu Lu, Li Xu, Jiaya Jia % International Symposium on Non-Photorealistic Animation and Rendering (NPAR 2012), June, 2012 % % Paras: % @im : the input image. % @ks : the length of convolution line. % @width : the width of the stroke. % @dirNum : the number of directions. % @gammaS : the darkness of the stroke. % @gammaI : the darkness of the resulted image. % %% Read the image im = im2double(im); [H, W, sc] = size(im); %% Convert from rgb to yuv when nessesary if (sc == 3) yuvIm = rgb2ycbcr(im); lumIm = yuvIm(:,:,1); else lumIm = im; end %% Generate the stroke map S = GenStroke(lumIm, ks, width, dirNum) .^ gammaS; % darken the result by gamma % figure, imshow(S) %% Generate the tone map J = GenToneMap(lumIm) .^ gammaI; % darken the result by gamma % figure, imshow(J) %% Read the pencil texture P = im2double(imread('pencils/pencil0.jpg')); P = rgb2gray(P); %% Generate the pencil map T = GenPencil(lumIm, P, J); % figure, imshow(T) %% Compute the result lumIm = S .* T; if (sc == 3) yuvIm(:,:,1) = lumIm; % resultIm = lumIm; I = ycbcr2rgb(yuvIm); else I = lumIm; end end ================================================ FILE: README.md ================================================ # Introduction Implement the algorithm presented in [1]. You can use the code like below to get a pencil drawing production: ```C++ I = PencilDrawing(im, ks, width, dirNum, gammaS, gammaI); ``` See demo.m for example. # Parameters I added some more parameters for better control of the final image. * **width** Control the width of the strokes. See Figure 1 for example. ![alt text](https://github.com/candycat1992/PencilDrawing/blob/master/results/width0.png) ![alt text](https://github.com/candycat1992/PencilDrawing/blob/master/results/width1.png) **Figure 1**: Width of the strokes. left: width = 0; right: width = 2. * **gammaS** Control the darkness of the strokes. See Figure 2 for example. ![alt text](https://github.com/candycat1992/PencilDrawing/blob/master/results/stroke_dark0.png) ![alt text](https://github.com/candycat1992/PencilDrawing/blob/master/results/stroke_dark1.png) **Figure 2**: Gamma of the strokes. left: gammaS = 1.0; right: gammaS = 2.0. * **gammaI** Control the darkness of the final image. See Figure 3 for example. ![alt text](https://github.com/candycat1992/PencilDrawing/blob/master/results/image_dark0.png) ![alt text](https://github.com/candycat1992/PencilDrawing/blob/master/results/image_dark1.png) **Figure 3**: Gamma of the final image. left: gammaI = 1.0; right: gammaI = 0.4. ## Tone Transfer Weights The paper presented three groups of weights for tone map generation. 1. ![alt text](https://github.com/candycat1992/PencilDrawing/blob/master/project_images/Tex2Img_1448535264.jpg) 2. ![alt text](https://github.com/candycat1992/PencilDrawing/blob/master/project_images/Tex2Img_1448535306.jpg) 3. ![alt text](https://github.com/candycat1992/PencilDrawing/blob/master/project_images/Tex2Img_1448535007.jpg) These weights will determine the histogram of the tone map. I use the third group by default, which makes the final image lighter. You can change to other groups in GenToneMap.m. # Folder Organization * **inputs** Include some test images from the website of the publishers and other images. * **pencils** Include 5 pencil textures for demonstration. I use “pencils/pencil0.jpg” by default. You can change it in PencilDrawing.m. * **results** Include the results generated by my code. Each image may use different parameters. * **resultsFromPaper** Include the results of the paper for comparison. I grabbed them in their website. # Reference [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. ================================================ FILE: demo.m ================================================ im = imread('inputs/15--298.jpg'); I = PencilDrawing(im, 8, 1, 8, 1.0, 1.0); figure, imshow(I)