实现《你的名字》同款滤镜,python+opencv

好久没有上,最近上来一看发现这篇文章阅读量远超了其他的文章,还有评论提到说在讲技术的时候卖萌不好。哈哈,当时写的时候完全没想过会有人搜到看,只是为自己的作品留个念想,所以文风比较散漫随意。于是这次来小修了一遍,谢谢阅读~



前很长一段时间,时光相册火了一个应用《你的名字》同款滤镜,一时间这种鲜艳靓丽的卡通天空滤镜刷遍了QQ空间朋友圈。

时光相册的效果是这样的。

实现《你的名字》同款滤镜,python+opencv_第1张图片
左:原图,右:滤镜图

他们在新闻采访中说自己和prisma一样用到了深度学习的技术,不过是用在了天空区域提取上。

我初步理解下就是:

1. 使用深度学习提取了天空区域

2. 蒙版替换了预设的卡通天空图片

3. 辅以传统美图滤镜方法美化效果。

天空区域真的需要用深度学习来提取吗?在知乎上逛了,下果然有人和我有相似的疑问。

我觉得深度学习真的很难把控,这是自己做着玩的小东西,所以我就用opencv实现了一个极简版=v=


首先确定编码流程:

1). 实现天空提取检测模块

2). 实现无缝融合模块

3). 实现日系色调滤镜

4). 整合测试及联调



PART1. 天空区域提取

尝试了三种方法,两种是来自论文的,一种是随便写写的,从最终的平均质量来看,还是拍脑袋决定的简单方法A的平均质量更高。

方法A. 阈值分割,蓝色消除

核心思想是将蓝色作为天空进行消除。利用HSV颜色模型做色调分离,首先将原图转换到HSV空间,并进行蓝色部分的选择,然后做个阈值分割,从而使得蓝色可以被分割走。只要我们选取到了合适的H值,那么就可以把蓝色去掉。

下表是颜色对应的HSV的值:

实现《你的名字》同款滤镜,python+opencv_第2张图片

这种方案在天空较均匀,蓝色较明显时表现较好

我的效果(目前用的opencv里的copyto接口,傻乎乎的粘贴了卡通天空图去检测到的区域)所以边界还比较僵硬。

实现《你的名字》同款滤镜,python+opencv_第3张图片

我的天空区域提取代码:首先是cvtColor,给原图从BGR转HSV去,然后把hsv的三个通道split一下

用Inrange分出我们需要的蓝色阈值区域。中值滤波一下消除杂点,让Mask看起来比较完整。跟着一个开操作,再滤波一下。其实这些都是我随便定的,目的就是让提取出的黑白Mask更完整一点,别尽是小杂点,我们只需要保证大致的准确就行。把检测区域存在mask里,做成一个黑白图片。(用来提取天空region的mask),下面是这段文字的顺序代码描述。

实现《你的名字》同款滤镜,python+opencv_第4张图片

B.《sky region detection in a single image for autonomous ground robot navigation》

和其他的方法不同,这个算法可以同时用于灰度图和彩色图。做法是:1、获取图像的梯度信息;2、根据能量函数优化计算【梯度域的最优分割阈值】,估计初始天空区域;3、最后一步后处理是为了细化前期天空区域的检测,比如途中没有天空区域出现,或天空对象伸出地面时。、

这个我实现了,测试时很容易检测出奇奇怪怪的东西。可能是我写的不对,如果最终要求是70%图能看,那么还是A方法好一些。

C.《一种基于灰度阈值的天地背景轮廓线提取方法》

针对天地背景轮廓线具有波动起伏、边缘模糊及轮廓边缘灰度值变化缓慢的特点,采用灰度阈值方法,实现了多种天地背景边缘轮廓提取

天地背景图像通常包括天空区域和地表区域,常见的有天空海面、天空平原、天空山地、天空沙漠等景物图像。在摄录远距离天地背景图像时,背景图像除了噪声增大外,还会因大气湍流等因素影响而产生抖动或起伏,这种现象在背景边缘轮廓附近尤为明显。其结果造成图像轮廓边缘模糊、波动起伏,图像边缘区域灰度值变化呈现连续缓慢变化状态,导致建立在微分理论基础上的传统经典图像边缘检测算法对天地背景图像的边缘轮廓提取失效。

实现《你的名字》同款滤镜,python+opencv_第5张图片

同上,可能是我写的不对,如果最终要求是70%图能看,那么还是草率决定的A方法好一些。


无缝融合

在展示方法A效果的时候,我用copyto函数进行的融合,那融合效果十分僵硬,边缘一看就是抠图贴上去的,这种看起来就很没品并外行的效果,咱们是必须拒绝的。

那么怎么做融合才能无缝?这里我了解的方法中和时光相册效果最像的是一个叫【泊松融合】的方法。seamlessClone这个泊松函数在Opencv2里没有,所以我重新去下opencv3。下来opencv3后,发现报错提示我Numpy跟不上版本,本来装的是Numpy1.9,说要升级到10以上。然后跑去sourceforge里补了一个numpy 1.10.2。当环境配好之后,seamlessClone就自己通了。详细代码是这样的:

其实完全就是调用用seamlessClone这个函数么,前期需要做一些准备工作。找出边缘,给出定位(确定要把卡通图贴在什么位置、按什么比例缩放后再贴)

然后调用seamlessClone,按api上要求的给他传他要的那些参数就Ok了。这里选的融合方式是normal_clone,不清楚原因,只是把选项都试了试这个效果最好。

实现《你的名字》同款滤镜,python+opencv_第6张图片

这个变化真真是超明显的。下面放对比图,左边是没有seamlessclone的,右边是seamlessClone的。可以看左边的树的间隙(好明显的异样感),右边是用seamlessclone之后,瞬间就无痕了。

实现《你的名字》同款滤镜,python+opencv_第7张图片

这样看起来右边就已经挺自然的了。不过还缺了点“动漫感”,为什么呢,因为没有调色。


调色滤镜

其实这玩意卡了我很久,因为压根没在网上看到“教教我怎么做滤镜”这样的教程。一搜一大把都是用着那些很基本的函数弄来弄去,都是些很丑很土气的滤镜效果

那么多美图应用都提供了什么“和风滤镜”,“小清新滤镜”,“午后阳光滤镜”,Blabla…………

有木有人可以告诉我他们都是咋做的?

我唯一的参考资料就是只需 4 步,手把手教你如何实现滤镜功能

谢谢大神,虽然完全没有感受到手把手的教(擦泪),但是连猜带蒙的我还是给整出来了。

就让我来手把手的教大家一下(擦泪)。

首先,有一张(被公认很标准的)色卡图,当原始颜色映射表,左图是原始颜色表,右图是对应着某个色彩滤镜“比如和风”的滤镜色卡表。

实现《你的名字》同款滤镜,python+opencv_第8张图片

这两个色卡表说是表,其实就是图片,就是一堆有RGB通道的像素点集。

我说下滤镜的思想:

        要给一张图片刷滤镜,遍历它的每个像素点,比如坐标(0,0)的像素点,它的颜色是(123,132,231)先在表1查颜色(123,132,231)对应的色卡表位置(坐标),再去表二查出对位坐标的新的颜色值(RGB)替换掉当前像素点的颜色(RGB)。基本都是自行脑补出来的思路,原始色卡说白了就是一堆数值,一堆有规律的数值。

我们需要跟着输入图的各个像素点上的RGB值,找到它位于原始色卡的坐标。那么就是要找到原始色卡每个点的RGB值和它的坐标的对应关系。这个原石色卡表当然是有规律的,它每个坐标上的RGB数值都是和坐标挂钩的,是有规则的。

经过一段时间的归纳总结我推出来了映射公式:(AB二维是坐标,xyz是三个颜色通道)

A = y/4 + (x/32)*64

B = z/4 + ((x%32)/4)*64

这个公式我验证了完全正确,用网上给出的一个示例色卡,能刷出滤镜色如下。

是不是看起来挺高级?有点美图秀秀的feel了吧!

实现《你的名字》同款滤镜,python+opencv_第9张图片

可能有人想问??右边那个对应新滤镜的色卡是怎么来的?

答:我在网上下载的。(好吧,专业的滤镜制作公司应该会需要艺术家?设计师来做那张色卡)这是艺术范畴了我等程序猿只要知道怎么怎么进行映射,怎么写代码转换风格就可以了。不过,毕竟是冲着实现你的名字同款滤镜的目标做的。那你的名字同款色调也是必须的。

那么我来介绍一下我制作右侧色卡的方法把。。

……

感觉说出来会很丢人。

……

但不失为一个好办法。

【把左侧的原始色卡存到手机里,放到任意一个美图应用里 “刷一下” ,刷哪个滤镜,就出哪个滤镜的色卡。等于是复刻色卡】

如果是盈利性质的这样做肯定是不行的,应该让设计师设计,咱们宅着自己练技术玩,这方法还不错。

实现《你的名字》同款滤镜,python+opencv_第10张图片

下面是我对色卡操作的代码:

实现《你的名字》同款滤镜,python+opencv_第11张图片

整合前三块

最后就是简单的加法,把前三块串起来就Ok了

可以大概看看最终效果,我觉得还挺梦幻的,不过因为天空提取的算法太简单,所以有些图片的天空的表现很辣鸡就是了。。Just for fun!

实现《你的名字》同款滤镜,python+opencv_第12张图片
实现《你的名字》同款滤镜,python+opencv_第13张图片
实现《你的名字》同款滤镜,python+opencv_第14张图片
实现《你的名字》同款滤镜,python+opencv_第15张图片

嘿嘿嘿我要写当然是放好看的效果了。至于不好看的,就不展示了

批量测试的结果(100张图):

好看的结果普遍在50%左右,能看(不保证好看)的结果在80%以上。不能看的在15%左右。不能看图就是固定的几张,都是因为天空区域提取出错了(多选/少选)。如果想做成专业应用,在天空区域提取这步肯定不能像我写的方法A这么随意。

以上。

谢谢阅读~

你可能感兴趣的:(实现《你的名字》同款滤镜,python+opencv)