python实现图片的抖音效果

前两篇文章 Affinity Photo绘制抖音音符Sketch练习稿之绘制抖音音符 研究了如何用设计软件绘制抖音音符,本篇文章将说一下如何使用python将普通图片处理成抖音效果,甚至制作gif动图。

基本原理

Sketch练习稿之绘制抖音音符 中讲述了抖音效果的原理,领域内可能有人称这种效果为红蓝溢出效果。按照前面文章中的描述,这里以一张图片为例简单再讲一下原理。

一张正常的位图,一般 jpg 图片颜色方案为 RGB,而 png图片除了 RGB色彩通道还有 A通道控制透明,不过色彩配置还是一致的,以手上的图片 glasses.jpg 为例。

去掉 GB 两通道的图片如下:

去掉 R 通道的图片如下:

如果之间将两张图以相加的方式进行混合,就会得到原图,即第一张正常的图片。如果去掉 R 通道的图片在去掉 GB 通道的图片上方,并且向上和向左错开10px,就会得到抖音效果的图片:

实现图片抖音效果

使用python3为图片添加抖音效果

库安装

需要用到两个库,一个是 pillow 用来读写图片数据,另一个是 numpy 用来处理图片数据转换成的的矩阵数据,使用 pip3 安装即可:

pip3 install pillow
pip3 install numpy

安装完成后,执行 pip3 list 会列出安装的包,检查是否完成安装。

库的操作

pillow

本文主要用到库中的 Image 模块。

from PIL import Image

使用 Image 模块的 open 方法可以打开图片得到图片原生数据,类型为 PIL.JpegImagePlugin.JpegImageFile

image_data = Image.open('picname.jpg')

上述对象有两个常用的方法:

  • show() : 显示图片,比如image_data.show()
  • save(path): 按照指定路径保存图片,比如image_data.save(path)

numpy

这里主要使用numpy 库的矩阵操作,可以很方便的对矩阵进行切片操作,与 matlab 中的操作极其类似,首先导入库:

import numpy as np

np.array() 方法可以将上面 PIL.JpegImagePlugin.JpegImageFile 对象转换为原始矩阵数据,生成的矩阵为三维矩阵,前两维度为高宽像素点坐标,第三维度为 RGB 三通道,需要注意的是转换得到的矩阵数据类型为 numpy.uint8

img_array = np.array(image_data)

上面的操作可以逆向进行,也就是将 img_array 转换为 PIL.JpegImagePlugin.JpegImageFile 对象,需要依赖于 Image 的另一个方法 fromarray(array)

image = Image.fromarray(img_array)

可以很方便地使用切片操作处理图片矩阵数据中三个通道的数据,比如将 R 通道的数据设置为0:

img_array[:, :, 0] = 0

另外还需要用到矩阵复制的方法 numpy.copy(array),会得到 array 的复制对象:

img_other = np.copy(img_array)

具体实现

  • 导入两个库
    import numpy as np
    from PIL import Image
    
  • 打开指定图片,这里以 glasses.jpg 为例,转换得到图片矩阵数据:
    img_data = Image.open('glasses.jpg')
    img_array = np.array(img_data)
    
  • 复制得到两个新的矩阵:
    img_r = np.copy(img_array)
    img_bg = np.copy(img_array)
    
  • 这里需要注意的是,为了保证得到数据保存后的图片还是原图片的尺寸,这里只对有错位相加部分的像素点进行去通道操作,这里计划将 img_gb 向上向左错位10px,那么只需处理 img_gb 宽和高纬度上第 11px 到最后的像素点的 R 通道数据为0,同时 img_r 宽和高纬度上从第0到倒数第11个像素点的 GB 通道数据为0:
    # 去GB两通道数据
    img_r[:-10, :-10, 1:3] = 0
    # 去除R通道数据
    img_gb[10:, 10:, 0] = 0
    
  • 将两个矩阵数据错位相加保存到 img_array 中,即 img_r[:-10,:-10,:] 数据与 img_gb[10:, 10:, :]数据相加,赋值给 img_array[:-10, :10, :]
    img_array[:-10, :-10, :] = img_r[:-10, :-10, :] + img_gb[10:, 10:, :]
    
  • 从矩阵数据创建 PIL.JpegImagePlugin.JpegImageFile 对象,并保存和显示图片:
    image = Image.fromarray(img_array)
    image.save('glasses_douyin.jpg')
    image.show()
    

最终得到图片如下:

20180704153070669239617.jpg

创建gif动图

上面我们实现了普通图片添加抖音效果,那么想不想看一下错位不同大小的抖音效果的变化呢?可以创建不同错位下的静态抖音效果图,然后用静态图创建gif动图,废话不多说,行动!

库安装

这里创建gif动图,使用到 imageio 库,同样可以使用 pip3 安装:

pip3 install imageio

使用 imageio 模块的 mimsave() 方法生成 gif 动图,比较简单,利用方法封装得到 create_gif 函数:

def create_gif(image_list, gif_name):
    '''创建gif图片
    :param image_list: 图片名称列表
    :type image_list: list
    :param gif_name: gif图片路径
    :type gif_name: unicode字符串
    '''
    print(f'\nCreating 「{gif_name}」from {image_list} ...')
    frames = []
    for image_name in image_list:
        frames.append(imageio.imread(image_name))
    imageio.mimsave(gif_name, frames, 'GIF', duration = 0.05)
    print(f'Saved {gif_name}!')

封装抖音效果添加函数

为了更方便得到不同错位尺寸下的静态抖音效果图,这里封装上面的实现,得到以下函数接口:

def convert_douyin_image(pic_path, offset=10):
    '''为普通图片添加红蓝溢出位移效果,抖音app效果
    :param pic_path: 图片路径
    :type pic_path: unicode字符串
    :param offset: 红蓝位移大小,单位像素,默认值是10
    :return r_pic_path: 返回转换图片的路径
    :rtype: unicode字符串
    '''
    if os.path.exists(pic_path):
        pic_name, extension = os.path.splitext(pic_path)
        pic_path_new = pic_name + '_' + str(offset) + extension
        img_data = Image.open(pic_path)
        img_array = np.array(img_data)
        if offset > 0:
            img_r = np.copy(img_array)
            img_gb = np.copy(img_array)
            img_r[:-offset, :-offset, 1:3] = 0
            img_gb[offset:, offset:, 0] = 0
            img_array[:-offset, :-offset, :] = img_r[:-offset, :-offset, :] + img_gb[offset:, offset:, :]
        image = Image.fromarray(img_array)
        image.save(pic_path_new)
        print(f'Saved {pic_path_new}!')
        return pic_path_new

接口中,对 offset 为 0 时做了处理,直接保存原图,最终函数返回保存的图片路径,方便生成图片路径列表用于生成gif。

整体实现

导入必要库:

import os
import imageio
import numpy as np
from PIL import Image

这里定义一个图片路径,方便指定待处理图片:

PIC_PATH = 'glasses.jpg'

最后,先得到错位[0, 2, 4, 6, 8, 10]px 的静态抖音效果图和图片路径列表,为了是动图连贯,处理列表中元素按照错位尺寸为 [0, 2, 4, 6, 8, 10, 8, 6, 4, 2, 0]px,然后根据 PIC_PATH 得到 gif图片保存路径,调用 create_gif 函数生成gif:

if __name__ == '__main__':
    pic_list = []
    for i in range(0, 11, 2):
        pic_path = convert_douyin_image(PIC_PATH, i)
        if pic_path:
            pic_list.append(pic_path)
    temp_l = list.copy(pic_list)
    temp_l.reverse()
    pic_list = pic_list + temp_l[1:]
    p_name, p_ext = os.path.splitext(PIC_PATH)
    gif_name = PIC_PATH.replace(p_ext, '.gif')
    create_gif(pic_list, gif_name)

最终得到的gif图片效果如下:

20180704153070846317421.gif

完整源码参考:

https://github.com/smslit/tools-with-script/blob/master/douyin/douyin.py

参考


python

1964 字

2018-07-04 21:01 +0800