Python 3 实现简单滤镜

Python 3 实现简单滤镜
一、课程介绍
在这个人人自拍的年代,每个人的智能手机中至少都装了一款美颜相机或者美图软件,而这些软件实现美图功能又主要是靠滤镜来实现的。而这门课程将带领大家使用 Python 编写一个简单的滤镜程序。
备注:本次课程项目来源于 https://github.com/pfdevilliers/python-image-filters ,该项目基于 MIT 许可证。 在该项目的基础上我做了以下优化:
• 使用 docopt 构建命令行解析器
• 添加函数 get_name ,避免在同时对多个文件进行处理的时候因为输出文件名相同而导致的文件覆盖问题
1.1 课程知识点
通过本次课程的学习我们接触到以下知识点:
• 使用 docopt 构建命令行解析器
• 使用 struct 模块解析 ACV 格式文件
• Pillow 图像操作
1.2 主要流程
本次实验的流程为:
• 依赖模块安装
• 编写程序
1.3 环境配置信息
Python:3.5.2
Numy:1.11.2
Scipy:0.18.1
Pillow:3.4.2
1.4 效果截图
先来展示一下滤镜的效果。
这是原图。

使用 nashville 滤镜之后。

使用 country 滤镜之后。

二、依赖模块安装
这一章节我们将介绍一些基础知识。
2.1 numpy 安装
NumPy是Python语言的一个扩充程序库。支持高级大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。NumPy的前身Numeric最早是由Jim Hugunin与其它协作者共同开发,2005年,Travis Oliphant在Numeric中结合了另一个同性质的程序库Numarray的特色,并加入了其它扩展而开发了NumPy。
NumPy参考CPython(一个使用字节码的解释器),而在这个Python实现解释器上所写的数学算法代码通常远比编译过的相同代码要来得慢。为了解决这个难题,NumPy引入了多维数组以及可以直接有效率地操作多维数组的函数与运算符。因此在NumPy上只要能被表示为针对数组或矩阵运算的算法,其运行效率几乎都可以与编译过的等效C语言代码一样快。
参考:维基百科--Numpy
安装步骤如下:
$ sudo python3 -m pip install --upgrade pip
$ sudo pip3 install numpy
2.2 Scipy 安装
SciPy是一个开源的Python算法库和数学工具包。SciPy包含的模块有最优化、线性代数、积分、插值、特殊函数、快速傅里叶变换、信号处理和图像处理、常微分方程求解和其他科学与工程中常用的计算。
参考:维基百科--Scipy
Scipy 的安装方法如下:
$ sudo pip3 install scipy
2.3 Pillow 安装
Pillow 是 Python 的图像处理库。
参考:Pillow 官方文档
安装方法依然方便快捷。
$ sudo pip3 install pillow
2.4 docopt 安装
docopt 能自动地根据帮助文档构建出命令行解析器,然后从 Shell 操作命令中解析出参数字段。
参考:docopt 官方文档
使用 pip3 进行安装。
$ sudo pip3 install docopt
三、编程实现
在开始讲解代码前,我们首先来考虑一下程序的功能需求。
1. 需要构建命令行解析器从命令中解析出文件路径参数
2. 加载图像与滤镜文件
3. 处理图像
4. 保存处理后的图像
需求很简单,构建命令行可以使用 docopt 模块来实现,图像处理的思路在之后会介绍,现在开始实现代码。
进入 Code 目录,创建文件夹 course688 作为项目目录,之后本课程所有的文件都位于该目录之下。
3.1 构建命令行解析器
创建 filter.py 文件,可以使用 gedit 或 vim 进行编辑编写文档,或者使用 web IDE 。
在下方的代码中,在程序段首我们编写了一段程序帮助文档,该文档默认由 __doc__ 变量引用,通过将该变量作为参数传递给 docopt 方法可以快速构建起命令行解析器。然后我们还导入了所有需要用到的模块。
"""
filter can add filter to the photo.

Usage: filter [options]

Options:
-h --help show the help message
-v --version show the version information
"""

from struct import unpack
from scipy import interpolate

from PIL import Image
import numpy as np
import scipy

from docopt import docopt

__version__ = '1.0'

... ...

def main():
# 构建语法解析器
args = docopt(__doc__, version=__version__)

if __name__ == '__main__':
main()
3.1.1 docopt 使用介绍
这里为了方便大家理解 docopt 的使用,我们先偏离一下主题单独讲解 docopt 模块。首先为了获得最直观的感受,我们不妨在以上代码中添加一句 print(args) 来打印解析器参数解析结果。

测试结果如上图,我们发现 docopt 库返回了一个字典,字典中的键由我们给出的 Usage 与 Options 中的选项构成。
所以 docopt(__doc__, version=__version__) 函数能自动根据三个双引号中的文档内容(存储于 __doc__ 中)生成命令行解析器,并将解析结果以字典对象返回。因此使用 docopt 进行命令行解析,我们唯一需要做好的事情就是编写好帮助文档,然后其它一切解析的问题都可以甩手给 docopt 自动解决。
补充:关于帮助文档的编写格式以及关于 docopt 的更多信息请自行参考:
• docopt 官网查阅文档
3.2 main 函数完善
main 函数是整个程序的主体,在这里我们除了实现命令行解析,还加载了图像,给图像添加滤镜并保存处理之后的图像。
`python ... def main():
# 构建语法解析器
args = docopt(__doc__, version=__version__)

# 创建一个滤镜类 Filter 的实例
img_filter = Filter(args[''], 'crgb')

# 程序读取指定图片
im = Image.open(args[''])

# 转换数据类型,便于后续处理
image_array = np.array(im)