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

2024-10-01 17:34:16 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试做一个函数,使任何图像看起来像一个卡通漫画。 以下是我目前为止的代码:

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)

我从这里取下来,保留了许可证,并对其进行了轻微修改: http://www.askaswiss.com/2016/01/how-to-create-cartoon-effect-opencv-python.html

我最初的想法是: Original image

以下是我的脚本输出: My script output

我需要的是: The image I'm trying to replicate

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

  1. 我需要太多的颜色从暗色过渡到较暗的颜色。在
  2. 当我的代码产生大量噪音(“孤独的”黑点)并分割线条时,目标图像的边缘是平滑的,即线条。 我试着改变一些参数,添加了几个随机过滤器,但我真的不知道下一步该怎么做。在

非常感谢任何帮助。在


Tags: andtoinselfimgforlenrange
1条回答
网友
1楼 · 发布于 2024-10-01 17:34:16

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

1-s是输入图像img的稍微平滑的版本,将用于创建行。对于平滑,我使用了一个简单的非线性扩散。这样可以保留(甚至增强)边。它类似于双边滤波器。在

2-使用s,我首先应用拉普拉斯算子(这个算子使用高斯导数,参数1.5是高斯的sigma)。这类似于高斯函数的区别。您的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-为了在线条之间添加颜色,我们需要平滑和量化原始图像。我用更平滑的img覆盖s,我使用an algorithm I described in another answer对其应用颜色量化。这种量化只剩下10种不同的颜色。我应用了一点平滑,以避免太尖锐的过渡之间的颜色。在

6-最后,彩色图像s和线条图像l相乘在一起。其中l为1,没有任何变化。如果l的值较低,s将变暗。这样可以有效地在图像上绘制线条。它比您使用的按位and运算符效果更好。在

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

output of code

相关问题 更多 >

    热门问题