编程语言
首页 > 编程语言> > 如何使用Python(NumPy和OpenCV)对图像进行 Funkify

如何使用Python(NumPy和OpenCV)对图像进行 Funkify

作者:互联网

工作方式

代码的主要功能将图像作为输入,并将funkified图像作为输出返回。主要功能如下所示:

def funkify(self,img):
    
edges = self.edge_mask(img)
模糊 = cv2。GaussianBlur(img,(self.color_blur_val,self.color_blur_val),
sigmaX=0,sigmaY=0)
指数 = self.pick_color(blur.reshape((-1, 3)),
self.lightness,self.n_colors)
重新着色 = np.uint8(self.colors[indices].reshape(blur.shape))
卡通= cv2.bitwise_and(重新着色,重新着色,面具=边缘)

    返回卡通

现在,我将以这张图片为例,逐行细分。

第1步:thiccc边缘

这个项目基于这个博客。我想重新使用代码,以便在网络摄像头上实时运行。事实证明,用他们的方法是不可能的,但他们的一些代码仍然非常好。特别是找到图像中边缘并使其变厚的功能。

加厚边缘的目的是让它看起来像卡通或动漫中的墨水线。获取边缘由代码中的第一行完成。

edges = self.edge_mask(img)

edge_mask()函数调用以下代码。

def edge_mask(self,img):
        # 获取图像的边缘
灰色 = cv2.cvtColor(img,cv2。颜色_BGR2灰色)
gray_blur = cv2。GaussianBlur(灰色,
(self.edge_blur_val,self.edge_blur_val),
-1)
edges = cv2.adaptiveThreshold(gray_blur,255,
cv2。ADAPTIVE_THRESH_MEAN_C,
cv2。THRESH_BINARY,
self.block_size,
                                      2)
        返回边缘

前两行是预处理图像,为自适应阈值函数做准备。图像从颜色转换为灰度,然后使用高斯内核进行模糊,因此自适应阈值函数将产生更少的噪声输出。

第三行是主要部分。自适应阈值是一种二进制阈值函数。这意味着它将图像中的每个像素归类为黑色(0)或白色(1)。有许多二进制阈值算法。自适应阈值的独特之处在于,它根据相邻像素的强度而不是整个图像对每个像素进行分类。这使得它在不同的照明条件下表现得更好。

使用此功能,可以快速找到图像的边缘,这使得它非常适合我们实时运行的版本。这是应用于我们示例图像的这个函数。

 

第2步:重新着色图像

下一步是重新着色图像。使某些东西看起来卡通化的原因之一是图像中的颜色较少。例如,由于照明,真实图像将有数千种不同的颜色和色调,但卡通只有几种颜色。这可以使用卡通着色器来完成,这在电子游戏中很常见。

 

在我基于这个项目的代码中,他们使用K-均值将像素聚类为一定数量的颜色。然后,每个像素都更改为其组的平均颜色。虽然这效果很好,但它太慢了,无法实时使用。此外,这有点无聊。

相反,颜色是手动选择的,然后所有像素都根据它们在亮度上最接近的颜色被覆盖为这些颜色。这消除了寻找颜色的需要,老实说,它看起来就像你想要的一样酷。选择亮度——对亮度的定量测量)——是因为它保留了原始图像的照明效果。

主函数中重新着色的代码由以下三行组成:

模糊 = cv2。GaussianBlur(img,(self.color_blur_val,self.color_blur_val),
sigmaX=0,sigmaY=0)
指数 = self.pick_color(blur.reshape((-1, 3)),
self.luminance,self.n_colors)
重新着色 = np.uint8(self.colors[indices].reshape(blur.shape))

第一行只是模糊图像,就像边缘变模糊一样。这样做的目的是使最终图像中的颜色看起来更光滑。

第二行是最重要的。pick_color()函数是计算图像中每个像素的颜色。它运行以下代码:

def pick_color(self,img,color_lums,n_colors):
    #根据亮度重新分配像素颜色
    
    # 获取像素的亮度
lum_mult = [0.114, 0.587, 0.299]
img_lum = np.sum(np.multiply(img, lum_mult), axis=1)
    
    #为每种颜色创建条件列表
condlist = []
选择列表 = []
    对于范围(n_colors)的i:
choicelist.append(i)
        如果我<n_colors-1:
condlist.append(img_lum < (color_lums[i]+color_lums[i+1])/2)
        其他:
condlist.append(img_lum > (color_lums[i]+color_lums[i-1])/2)
    
    #获取每个像素的新颜色索引
inds = np.select(condlist,choicelist)
    
    返回ins

首先,该函数使用此堆栈溢出帖子的公式从RGB值中计算每个像素的亮度。

然后,创建一个条件列表,用于根据亮度确定选择哪种颜色。制作此条件列表允许该功能适应用户想要使用的任何数量的颜色,而不是硬编码一组数字。np.select()函数用于实际从该列表中进行选择。它本质上是每个像素的一系列“if语句”,像这样:

#例如3种颜色
如果 pix_lum < (color_lums[0] + color_lums[1])/2:
pix_ind = 0
else if pix_lum < (color_lums[1] + color_lums[2])/2:
pix_ind = 1
其他:
pix_ind = 2

第三行根据我们从thepick_color()函数获得的索引重新着色图像。它只需通过切片图像数组,然后将其转换为uint_8来做到这一点,以便可以正确显示。

这个过程的输出看起来像这样。

 

第3步:合并

主要功能的最后一部分是将重新着色的图像和厚边缘结合起来。

卡通= cv2.bitwise_and(重新着色,重新着色,面具=边缘)

标签:Python,Funkify,
来源: