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

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

作者|Luke Tambakis

编译|Flin

来源|medium

在这篇博客中,我将解释如何制作一个 Python 脚本来使用 Python 代码“funkify”图像。该程序速度足够快,甚至可以处理实时视频(无需 GPU)!像这样:

be6a3c964ed3a75d49e4c6e636dd276f.jpeg

如果你对枯燥的代码解释不感兴趣,只想自己尝试一下,最简单的方法是使用FunkyCam存储库。它会向你展示如何在几行代码中安装和运行它:https://github.com/LTambam/FunkyCam

怎么运行

代码的主要功能是将图像作为输入并返回 funkified 图像作为输出:

def funkify(self, img):

    edges = self.edge_mask(img)
    blur = cv2.GaussianBlur(img, (self.color_blur_val, self.color_blur_val), 
                            sigmaX=0, sigmaY=0)
    indices = self.pick_color(blur.reshape((-1, 3)), 
                              self.lightness, self.n_colors)
    recolored = np.uint8(self.colors[indices].reshape(blur.shape))
    cartoon = cv2.bitwise_and(recolored, recolored, mask=edges)

    return cartoon

现在,我将以此图为例将其逐行分解。

6aeffc2121e3d0292c21f750dc815a99.jpeg

示例图片

第1步:增加边缘宽度

该项目基于此博客(https://github.com/Sudarshana2000/cartoonization)。我想重新利用这些代码,以便它可以在网络摄像头上实时运行。但他们的方法证明是不可能的,但他们的一些代码仍然非常出色。特别是用于查找图像边缘并增加边缘宽度的函数。

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

edges = self.edge_mask(img)

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

def edge_mask(self, img):
        # get the edges of the image
        gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        gray_blur = cv2.GaussianBlur(gray, 
                                    (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)
        return edges

第一和第二行对图像进行预处理,为自适应阈值函数做准备。图像首先从彩色转换为灰度,然后使用高斯核进行模糊处理,以使自适应阈值函数生成噪音较少的输出。

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

d5916121ff54befce531630e436b2204.jpeg

自适应阈值和全局阈值比较

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

12670b3327275f2a5ba3cf25a86e46f5.jpeg

第 2 步:对图像重新着色

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

5c2559e9329b31a7cef87e43a8618251.jpeg

在我基于该项目的代码(https://github.com/Sudarshana2000/cartoonization)中,他们使用 K-means 将像素聚类为一定数量的颜色。然后每个像素都更改为其组的平均颜色。虽然这种方法效果很好,但对于实时使用来说太慢了。此外,这有点无聊。

相反,颜色是手动选择的,然后根据它们在亮度上最接近的颜色,将所有像素都覆盖为这些颜色。这消除了查找颜色的需求,而且实际上可以根据需要使图像看起来很酷。之所以选择亮度(亮度的定量测量)是因为它保留了原始图像的光照效果。

在主函数中重新着色的代码包括以下三行:

blur = cv2.GaussianBlur(img, (self.color_blur_val, self.color_blur_val), 
                         sigmaX=0, sigmaY=0)
indices = self.pick_color(blur.reshape((-1, 3)), 
                          self.luminance, self.n_colors)
recolored = np.uint8(self.colors[indices].reshape(blur.shape))

第一行只是对图像进行模糊处理,就像在边缘增宽时一样。其目的是使最终图像中的颜色看起来更平滑。

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

def pick_color(self, img, color_lums, n_colors):
    # reassign pixel colors based on luminance

    # get luminance of pixels
    lum_mult = [0.114, 0.587, 0.299]
    img_lum = np.sum(np.multiply(img, lum_mult), axis=1)

    # create list of conditions for each color
    condlist = []
    choicelist = []
    for i in range(n_colors):
        choicelist.append(i)
        if i < n_colors-1:
            condlist.append(img_lum < (color_lums[i]+color_lums[i+1])/2)
        else:
            condlist.append(img_lum > (color_lums[i]+color_lums[i-1])/2)

    # get index of new color for each pixel
    inds = np.select(condlist, choicelist)

    return inds

首先,该函数使用此帖(https://stackoverflow.com/questions/596216/formula-to-determine-perceived-brightness-of-rgb-color)中的公式根据 RGB 值计算每个像素的亮度。

然后,创建了一个条件列表,用于根据亮度确定选择哪种颜色。通过创建这个条件列表,该函数可以适应用户想要使用的任何颜色数量,而不是硬编码一个固定数量。np.select() 函数用于实际从这个列表中进行选择。它实际上是一系列像这样的“if语句”:

# e.g. for 3 colors
if 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
else:
    pix_ind = 2

第三行根据我们从pick_color()函数获得的索引对图像重新着色。它只是通过对图像数组进行切片,然后将其转换为 uint_8 来实现此目的,以便可以正确显示。

该过程的输出如下所示。

a0ea869c02016eb74487a7098b05b20d.jpeg

第 3 步:合并

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

cartoon = cv2.bitwise_and(recolored, recolored, mask=edges)

最终结果:

2b84d367bc9241011f6b2804906da2f1.jpeg

看起来很酷,对吧?

它的运行速度非常快,你可以将其与网络摄像头实时结合使用,甚至不使用 GPU 处理。你还可以转换视频,如下所示:

adbed7099e347d2d2dfdddf00ef89604.jpeg

☆ END ☆

如果看到这里,说明你喜欢这篇文章,请转发、点赞。微信搜索「uncle_pn」,欢迎添加小编微信「 woshicver」,每日朋友圈更新一篇高质量博文。

扫描二维码添加小编↓

34b70f9fa26a0bfcd7a040219329988b.jpeg

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/199486.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【Java Spring】Spring MVC基础

文章目录 1、Spring MVC 简介2、Spring MVC 功能1.1 Spring MVC 连接功能2.2 Spring MVC 获取参数2.2.1 获取变量2.2.2 获取对象2.2.3 RequestParam重命名后端参数2.2.4 RequestBody 接收Json对象2.2.5 PathVariable从URL中获取参数 1、Spring MVC 简介 Spring Web MVC是构建于…

低压三相无刷直流驱动芯片GC5958,无感,正弦,低压,PWM调速可替代APX9358/茂达

GC5958提供了无传感器的三相无刷直流电机的速度控制的所有电路。正弦波驱动器的方法将是更好的低噪声。控制器功能包括启动电路、反电动势换向控制、脉宽调制 (PWM) 速度控制锁定保护和热关断电路GC5958适用于需要静音驱动程序的游戏机和CPU散热器。它以DFN3x3-10封装形式展现。…

深入理解虚拟 DOM:提升前端性能的关键技术

&#x1f90d; 前端开发工程师&#xff08;主业&#xff09;、技术博主&#xff08;副业&#xff09;、已过CET6 &#x1f368; 阿珊和她的猫_CSDN个人主页 &#x1f560; 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 &#x1f35a; 蓝桥云课签约作者、已在蓝桥云…

Maven 介绍

文章目录 什么是 maven为什么要选择mavenmaven 仓库什么是maven中央仓库什么是maven本地仓库 idea如何创建出maven项目如何引入第三方库依赖配置国内源 下载 Maven Helper 插件查看各个项目之间的依赖关系 什么是 maven Maven是 Apache 下的一个纯 Java 开发的开源项目&#x…

鼎捷副总裁谢丽霞:从四大趋势来看,数智时代企业如何加速研发创新

目录 导读 01 研发创新 势不可挡 ① 从逆向设计走向正向设计 ② 从专业协助走向全面协同 ③ 从单点场景走向业务闭环 ④ 从知识管理走向知识工程 02 鼎捷雅典娜 数智驱动企业新未来 03 鼎捷PLM 赋能企业研发创新 导读 研发&#xff0c;企业长青的必备源动能。如何在…

游戏录屏怎么录?学会这几招,轻松搞定!

电子游戏已成为人们日常生活中重要的娱乐方式之一&#xff0c;许多玩家希望在游戏的过程中录制一些精彩的瞬间&#xff0c;或与他人分享自己的游戏体验&#xff0c;因此游戏录屏成为了一种普遍的需求。可是游戏录屏怎么录呢&#xff1f;在本文中&#xff0c;我们将为大家介绍两…

OpenGL笔记:纹理的初次使用

说明 纹理的代码写完后&#xff0c;一直出不来结果&#xff0c;原因是没有设置GL_TEXTURE_MIN_FILTER&#xff0c; 它的默认值为GL_NEAREST_MIPMAP_LINEAR&#xff0c; 因为这里我还没用到Mipmap&#xff0c;所以使用这个默认值&#xff0c;结果是错误的&#xff0c;关于mipma…

Paragon NTFS16Mac读写外置移动硬盘专业工具

Paragon NTFS for Mac16是一款非常不错的Mac读写工具&#xff0c;解决了大部分Mac电脑用户无法读取移动硬盘的困扰&#xff0c;Paragon NTFS for 16版一直是Mac OS平台上最受欢迎的NTFS硬盘格式读取工具&#xff0c;有了NTFS for Mac &#xff0c;安装了双系统的Mac用户可以在O…

从Android面试题目溯源-1、创建线程有那几种方式

概念 程序执行流的最小单位&#xff0c;处理器调度调度和分派的基本单位。 如何理解这个概念 如下图&#xff0c;可以简单类比吉他&#xff0c;六根弦代表六个线程&#xff0c;每个线程独立且单独运行&#xff0c;且持有上一个音的状态&#xff0c;每根手指可类比为一个CPU的…

C#开发的OpenRA游戏之属性SelectionDecorations(12)

C#开发的OpenRA游戏之属性SelectionDecorations(12) 前面分析了显示选择框的指示器类SelectionBoxAnnotationRenderable,它的作用就是画一个四个角的方角。 这个类是在属性SelectionDecorations里调用的,如下: protected override IEnumerable<IRenderable> Rende…

企业如何选择安全又快速的大文件传输平台

在现代信息化社会&#xff0c;数据已经成为各个行业的重要资源&#xff0c;而数据的传输和交换则是数据价值的体现。在很多场合&#xff0c;企业需要传输或接收大文件&#xff0c;例如设计图纸、视频素材、软件开发包、数据库备份等。这些文件的大小通常在几百兆字节到几十个字…

交流负载的原理与应用

交流负载是指能够消耗交流电能的设备或系统&#xff0c;在电力系统中&#xff0c;交流负载是不可或缺的一部分&#xff0c;它们将电能转化为其他形式的能量&#xff0c;以满足人们生产和生活的需求。交流负载的原理与应用涉及到许多方面&#xff0c;包括电气工程、电子技术、自…

数据库系统概述之国产数据库

当今世界&#xff0c;数据已成为重要的生产要素&#xff0c;数据库管理系统更是广泛应用于信息化行业各领域&#xff0c;国内数据库产业能否健康可持续的发展&#xff0c;在很大程度上影响着国民经济发展和网络空间安全。 当前&#xff0c;国产数据库行业竞争非常激烈&#xf…

Docker 安装kafka 并创建topic 进行消息通信

Apache Kafka是一个分布式流处理平台&#xff0c;用于构建高性能、可扩展的实时数据流应用程序。本文将介绍如何使用Docker容器化技术来安装和配置Apache Kafka。 一、使用镜像安装 1、kafka安装必须先安装Zookpper 2、下载镜像 docker pull wurstmeister/kafka 3、查看下载…

万户协同办公平台ezoffice SendFileCheckTemplateEdit.jsp接口存在SQL注入漏洞 附POC

@[toc] 万户协同办公平台ezoffice SendFileCheckTemplateEdit.jsp接口存在SQL注入漏洞 附POC 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文…

Leetcode—1670.设计前中后队列【中等】

2023每日刷题&#xff08;四十三&#xff09; Leetcode—1670.设计前中后队列 实现代码 erase(iterator position)在删除vector中的元素后&#xff0c;会将该元素的后面所有元素都往前挪一位。因此&#xff0c;原先的迭代器指向的元素就不是原来那个了&#xff0c;而是它的后…

Phpstudy v8.0/8.1添加 php-7.4.9

1、官网下载最新的php版本 打开Windows版的官网下载&#xff0c;地址&#xff1a;PHP For Windows: Binaries and sources Releases 页面上有不同的PHP版本&#xff0c;这里我们下载的是64位nts版的PHP7.4.9&#xff0c;php-7.4.9-nts-Win32-vc15-x64.zip。 2、解压下载的文…

推荐一款好用的BMP转PNG工具BMP2PNG

推荐一款好用的BMP转PNG工具BMP2PNG 自己写的一个BMP转PNG工具BMP2PNG 写这个工具是因为要使用传奇的部分素材在COCOS2DX使用&#xff0c; 但是COCOS2DX不支持BMP 如果直接将BMP转换到PNG的话&#xff0c;网上找到的工具都不支持透明色转换。难道要用PS一个一个抠图吗&#xf…

网络聊天室项目

服务器端 #include <myhd.h>//传输结构体 struct cli {char type; // L/C/Qchar name[20];char text[128]; }; int main(int argc, const char *argv[]) {if(argc!3){printf("请输入ip地址和端口号\n");return -1;}//1、创建用于通信的套接字文件描述符in…

Kubernetes Dashboard 涉及的一些常规技巧

Kubernetes Dashboard 提供了一个GUI形式的K8S集群管理工具&#xff0c;通过它我们能很容易的观察到集群资源消耗情况、服务器运行状态以及针对Pod的相关观察与操作&#xff1b; Dashboard 的相关配置 Dashboard 提供了通过配置启动命令行参数来控制其相关行为的能力&#xf…