需要用Python和OpenCV制作一张卡通漫画版的图片

Eli*_*nko 8 python opencv image-processing python-3.x

我正在尝试制作一个能使任何图像看起来像卡通漫画的功能.到目前为止,这是我的代码:

import numpy
import cv2

__author__ = "Michael Beyeler"
__license__ = "GNU GPL 3.0 or later"

class Cartoonizer:

    def __init__(self):
        self.numDownSamples = 1
        self.numBilateralFilters = 7

    def render(self, img_rgb):

        # downsample image using Gaussian pyramid
        img_color = img_rgb
        for _ in range(self.numDownSamples):
            img_color = cv2.pyrDown(img_color)
        # repeatedly apply small bilateral filter instead of applying
        # one large filter
        for _ in range(self.numBilateralFilters):
            img_color = cv2.bilateralFilter(img_color, 9, 9, 7)
        # upsample image to original size
        for _ in range(self.numDownSamples):
            img_color = cv2.pyrUp(img_color)
        # convert to grayscale and apply bilateral blur
        img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2GRAY)
        for _ in range(self.numBilateralFilters):
            img_gray_blur = cv2.bilateralFilter(img_gray, 9, 9, 7)
        # detect and enhance edges
        img_edge = cv2.adaptiveThreshold(img_gray_blur, 255,
                                         cv2.ADAPTIVE_THRESH_GAUSSIAN_C,
                                         cv2.THRESH_BINARY, 9, 5)
        # convert back to color so that it can be bit-ANDed with color image
        img_edge = cv2.cvtColor(img_edge, cv2.COLOR_GRAY2RGB)
        #Ensure that img_color and img_edge are the same size, otherwise bitwise_and will not work
        height = min(len(img_color), len(img_edge))
        width = min(len(img_color[0]), len(img_edge[0]))
        img_color = img_color[0:height, 0:width]
        img_edge = img_edge[0:height, 0:width]
        return cv2.bitwise_and(img_color, img_edge)
Run Code Online (Sandbox Code Playgroud)

我从这里拿走了它,保存了许可证,稍加修改了它:http: //www.askaswiss.com/2016/01/how-to-create-cartoon-effect-opencv-python.html

我原来是这样的: 原始图像

这是我的脚本输出: 我的脚本输出

这就是我需要的: 我试图复制的图像

到目前为止我注意到的是:

  1. 我模糊图像的代码有太多的颜色,我需要从浅色到暗色的平滑过渡.
  2. 当我的代码产生大量噪音("孤独的"黑点)并分割线条时,目标图像具有平滑的边缘,即线条.我尝试过更改一些参数,添加了几个随机过滤器,但我真的不知道接下来要做什么.

任何帮助是极大的赞赏.

Cri*_*ngo 5

我没有Python代码,它是用MATLAB编写的(使用DIPimage 3).但我想你可能会从中得到一些想法.这是它的作用:

1- s是输入图像的略微平滑的版本img,将用于创建线条.为了平滑,我使用了一个平凡的非线性扩散.这样可以保留(甚至增强)边缘.它类似于双边滤波器.

2-使用s,我首先应用拉普拉斯算子(这个使用高斯导数,参数1.5是高斯的西格玛).这类似于高斯的差异.你的cv2.adaptiveThreshold电话相当于gaussf(img,2)-img.我的拉普拉斯算法做了类似的事gaussf(img,2)-gaussf(img,1)(高斯差异).也就是说,这个输出中的细节比来自的那个更少cv2.adaptiveThreshold.

3-拉普拉斯算子应用于彩色图像,因此产生颜色输出.我通过采用max color元素将其转换为灰度值.然后我剪辑并拉伸它,基本上做另外一半的cv2.adaptiveThreshold操作,除了输出不是二进制,但仍然是灰度值.也就是说,线条更暗更亮.更重要的是,线条看起来并不像素化,因为每条线的边缘都有从暗到亮的逐渐变化.我不得不稍微调整这些参数以获得良好的结果.l现在是一个图像,它是1,没有线条,下面(较暗),有线条.

4-现在我应用一条路径l.这是一个相当专业的形态运算符,您可能需要做一些努力才能找到实现.它消除了l很短的暗线.这基本上摆脱了你用点的问题.我确信还有其他方法可以解决点问题.

5-在我们希望平滑和量化原始图像的线条之间放置颜色.我s用更强烈平滑的版本覆盖img,我使用我在另一个答案中描述的算法应用颜色量化.该量化仅留下10种不同的颜色.我应用一点平滑来避免颜色之间过于尖锐的过渡.

6-最后,将彩色图像s和线图像l相乘.l1 在哪里,没有任何变化.l价值较低的地方s会变暗.这有效地绘制了图像上的线条.它比你使用的按位和运算符更好.

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
Run Code Online (Sandbox Code Playgroud)

代码输出