最近帮同学实现了一个简单的图像识别程序,顺便复习了一下 python 的知识。

问题背景大致如下,需要从图片中按照指定尺寸识别并裁剪出包含目标对象的矩形区域。

准备工作

在 python 中也有依赖包管理工具,类似 Node.js 中的 npm,这就是 pip:

sudo easy_install pip

既然涉及到图像识别,使用 OpenCV 无疑是最佳选择,而且针对不同语言都有官方或者非官方的实现版本。 我这里使用了一个非官方的库 opencv-python

pip install opencv-python

另外,由于涉及到科学计算,numpy 也是需要安装的:

python -m pip install --user numpy scipy matplotlib ipython jupyter pandas sympy nose

到这里准备工作就算完成了,可以仔细思考下这个问题的解决思路。

大致思路

首先从原始输入图片中不难看出,其中包含了很多噪音,去除他们会给后续处理带来便利。 其次,我们需要将灰度图转换成黑白双色图,便于后续的轮廓识别。 然后,通过轮廓识别找出矩形边框,根据需要的裁剪尺寸作出调整。 最后,根据调整后的区域在原图中进行裁剪。

下面让我们依次根据这个思路实现。

具体实现

先学习一波 python 的语法知识。

python 语法

类似 ES6 中的模块语法,通过 import 我们可以引入指定模块或者其中的方法:

import cv2
from math import floor
from os import makedirs,listdir

另外,由于使用了中文注释,需要在源码顶部第一行声明编码类型:

#coding:utf-8

作为一个 python 初学者,看到很多 python 代码中包含下面一段类似程序入口的判断。原来一个 python 文件既可以独立运行,也可以被其他文件引用,通过 __name__ 能判断运行环境:

if __name__ == "__main__":
    main()

读取图片

OpenCV 提供了图片的读写方法,比如 imread() 将图片读入数组中:

original_img = cv2.imread(join(input_dir,src_img))

去噪

OpenCV 提供了去噪方法,这里我们使用针对灰度图的:

denoised_img = cv2.fastNlMeansDenoising(original_img,None,10,7,21)

轮廓检测

把 8 位的灰度图转换成黑白图,设置阈值 127。另外这里出现了 python 中方法多个返回值,不需要的可以命名为 _,比如这里第一个返回值是原始数组,我们并不需要:

_, binary_img = cv2.threshold(gray_img,127,255,cv2.THRESH_BINARY)

关于轮廓检测 OpenCV 有专门的章节介绍。值得注意的是,由于对象内部也会存在“黑点”,构成很小的区域,我们需要通过计算轮廓面积,筛选掉这些小小的区域:

_, contours, hierarchy = cv2.findContours(binary_img,cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
    if cv2.contourArea(cnt)>1000:
        # 后续处理轮廓

现在我们得到了轮廓区域的包围矩形,需要根据裁剪矩形做出调整。 首先我们对齐两个矩形的中心,然后检测是否触碰到了整个图片的边缘:

# 轮廓区域
x,y,w,h = cv2.boundingRect(cnt)
# 对齐中心
crop_y = y+floor((h-crop_h)/2)
crop_x = x+floor((w-crop_w)/2)
# 边缘检测
crop_x = min(max(0, crop_x),original_img_w-crop_w)
crop_y = min(max(0, crop_y),original_img_h-crop_h)

最后在原图中裁剪,python 操作矩阵数组真是方便:

crop_img = original_img[crop_y:crop_y+crop_h,crop_x:crop_x+crop_w]
output_path = '...'
cv2.imwrite(output_path, crop_img)

总结

经常看到使用 python 编写机器学习,网络爬虫的文章。个人感觉语法类似 Ruby 和 JS 的混合体,非常值得学习。 尤其是这次结合 OpenCV 的尝试,让我觉得可以用他们继续实现更加有趣的功能,例如 OCR 和人脸识别等等,即使完全不了解其中的算法细节。

参考资料