Need to make a cartoon comic version of a picture with Python and OpenCV

前端 未结 1 1076
你的背包
你的背包 2021-02-14 22:45

I\'m trying to make a function which will make any image look like a cartooney comic strip. Here is my code so far:

import numpy
import cv2

__author__ = \"Micha         


        
1条回答
  •  死守一世寂寞
    2021-02-14 22:59

    I don't have Python code, it's written in MATLAB (using DIPimage 3). But I think you might get some ideas from it. Here is what it does:

    1- s is a slightly smoothed version of the input image img, and will be used for creating the lines. For the smoothing I use a trivial non-linear diffusion. This preserves (even enhances) edges. It is similar to the bilateral filter.

    2- Using s, I first apply the Laplacian operator (this one uses Gaussian derivatives, the parameter 1.5 is the sigma for the Gaussian). This is similar to a difference of Gaussians. Your cv2.adaptiveThreshold call does the equivalent to gaussf(img,2)-img. My Laplacian does something similar to gaussf(img,2)-gaussf(img,1) (a difference of Gaussians). That is, there is somewhat less detail in this output than in the one from cv2.adaptiveThreshold.

    3- The Laplacian was applied to a color image, so it yields a color output. I convert this to grey-value by taking the max color element. Then I clip and stretch this, essentially doing the other half of what cv2.adaptiveThreshold does, except the output is not binary, but still grey-value. That is, there are darker and lighter lines. More importantly, the lines don't look pixelated because there is a gradual change from dark to light at the edges of each line. I had to tweak these parameters a bit to get a good result. l is now an image that is 1 where there will be no lines, and lower (darker) where there will be lines.

    4- Now I apply a path closing to l. This is a rather specialized morphological operator, you might have to do some effort to find an implementation. It removes dark lines in l that are very short. This basically gets rid of the problem you had with the dots. I'm sure there are other ways to solve the dot problem.

    5- To put color in between the lines we want to both smooth and quantize the original image. I overwrite s with a more strongly smoothed version of img, to which I apply color quantization using an algorithm I described in another answer. This quantization leaves only 10 distinct colors. I apply a little bit of smoothing to avoid the too-sharp transition between colors.

    6- Finally, the color image s and the lines image l are multiplied together. Where l was 1, nothing changes. Where l had lower values, s will become darker. This effectively draws the lines on the image. It's a nicer effect than the bitwise and operator that you use.

    img = readim('https://i.stack.imgur.com/Zq1f4.jpg');
    % Simplify using non-linear diffusion
    s = colordiffusion(img,2);
    % Find lines -- the positive response of the Laplace operator
    l = laplace(s,1.5);
    l = tensorfun('immax',l);
    l = stretch(clip(l,0.4,4),0,100,1,0);
    % Remove short lines
    l = pathopening(l,8,'closing','constrained');
    % Simplify color image using diffusion and k-means clustering
    s = colordiffusion(gaussf(img),5);
    s = quantize(s,10,'minvariance');
    s = gaussf(s);
    % Paint lines on simplified image
    out = s * l;
    
    % Color diffusion:
    function out = colordiffusion(out,iterations)
       sigma = 0.8;
       K = 10;
       for ii = 1:iterations
          grey = colorspace(out,'grey');
          nabla_out = gradientvector(grey,sigma);
          D = exp(-(norm(nabla_out)/K)^2);
          out = out + divergence(D * nabla_out);
       end
    end
    

    0 讨论(0)
提交回复
热议问题