现在做图像分类、分割、目标侦测等项目,大家可能首先想到的都是CNN。深度学习虽然看起来很高大上,既是项目的卖点,又容易实现,真心是最耗的选择。然而,CNN需要一定量的标注数据,而对于一些特定领域,拿标注数据本身就很难。没有标注数据,CNN、RNN就是废铁一堆。
最近就在一堆没有标注信息的特定领域图像中倒腾,倒腾了一段时间后,最大的感触就是,像笨妞这样的AI最底层技工,用深度学习实际上就像一般人用windows,傻瓜式的应用,虚的很,那些底层的图像处理技术才是真正的硬功夫。
瞎倒腾了大半个月,对于图像处理做个初认识总结吧。
之前也有浅浅的用深度学习做图像分割,基本上的流程是:筛选数据集-->图像预处理-->切分训练集和测试集-->训练-->预测。
像keras这样的框架已经自带了图像处理的接口,主要做图像的几何变换,以及颜色归一化等,只需要选择合适的参数即可。即便是自己做图像预处理,调用python-opencv、skimage这些库,也很easy。
然而,如果没有标注数据,要做分割,就得自己抽特征,而抽特征就是一个复杂而琐碎的工程,基本上纯图像处理啊。
首先,笨妞用到的图像处理的工具主要有python-opencv、skimage、scipy.ndimage,还有一些没怎么用的pillow、专门读tif格式的libtiff等(图像新手,只知道这么多)。
笨妞用的这3个库中,python-opencv是老牌图像处理工具opencv的python接口,大部分C有的接口,python都有,而且参数设置,使用方式基本保持和C一致。个人感觉opencv提供的接口功能更细更全,并且接口可配置参数更丰富、返回值也更全面。但是,各功能块系统性不强,初学者上手比较麻烦。我基本上都是对着别人翻译的《OpenCV-Python-Toturial-中文版》来用的。但是这本书介绍的接口和参数并不全,使用起来局限性很大。
skimage和scipy.ndimage,他们的集成度高很多,各模块划分很清晰,新手使用起来更方便,对着官网直接选接口就可以,一个api就是一个比较大的功能。但是,说实话,灵活性很差。
对着skimage的功能划分,可以管窥图像处理的几大重要模块。
1. 读、写、保存,展示,这些是最基本的功能,没啥可说的。
2. 色彩空间变化:基本上读入图像之后接下来就会做这一步(如果需要的话),转gray、hsv、cielab的可能会多一些。因为很多计算都必须单个通道做,而RGB颜色通道特征不够明显,所以,通常转为灰度、亮度之类的。这块在opencv中统一用cvtColor接口,通过参数控制转换的空间;而skimage则直接由color功能块下的不同的接口对不同的转换空间。
3. 滤波:滤波必不可少,去噪、锐化什么的。各种滤波器尝试。滤波器典型的高斯滤波、均值、中值,基本上都是模糊;而双边、非局部均值滤波等号称是保留边缘的模糊。在opencv中,这些算作blur一类,在skimage中都包含在filters中。
4. 提取边缘: 典型的提取边缘canny算子,而个人觉得拉普拉斯算子、sobel算子、高斯梯度等计算出来的图像梯度也可以当作是一种边缘。在opencv中sobel、laplacian算子各有接口,由参数控制方向,而skimage的滤波、边缘、梯度、阈值分割全部被放在filters模块中。不同方向的梯度用不同的接口。
5. 阈值分割:阈值分割完全以灰度总图像分割,这个在背景单一且和前景有较明显差异时,用来做粗分割还是很好的。在opencv中threshold、adaptiveThreshold两个接口包揽了阈值分割的天下,实际上前者更实用,分割方式由参数决定,我用过的主要是手动设定阈值、otsu自动计算阈值、triangle算法,另外通过参数控制白色和黑色区域的选择。skimage中,有很多种阈值分割接口。
6. 图像轮廓:这各功能块还是opencv更好用,findContours和drawContours几乎可以画出你想要的全部特征,轮廓可以树结构存储,也可以列表存储,可以任意选择轮廓。同时,可以计算轮廓的各种性质。只是有一点,输入最好是二值图,也就是你得自己把图像根据轮廓需求处理成二值图,才可以获得轮廓。比如,通过一个阈值分割,然后以阈值分割输出的二值图画轮廓。当然,也可以通过其他分割方式,将前景背景用不同灰度表示,然后找轮廓。 在skimage中,findContours被放到了measure模块中,一些轮廓的性质计算也在里面。同时,在segmentation模块中也有find_boundaries和make_boundaries,只是find_boundaries返回的是同尺寸的矩阵。make_boundaries基本上用在图像分割后画分割边缘。
7. 形态学:腐蚀、膨胀、开运算、闭运算、黑帽、礼帽等。opencv提供的比较明显的接口就这些;skimage提供了很多接口,包括以上算法的灰度返回、二值返回;还有ball、diamond、rectangle等,都是处理邻域的,好多还没来得及用。值得注意的是,在opencv中轮廓的凸包在skimage是放到morphology中的。
8. 画图形: 这个用得比较少,个人目前只用实心的图像来掩盖图像中不需要的部分。能画的有圆形、椭圆形、矩形等。在opencv中circle、ellipse、rectangle、polylines等接口,在skimage中有draw模块中。
9. 图像的特征:HOG、Haar_like、LBP、灰度共生矩阵、hessian矩阵等。在opencv和skimage都有很好的支持,只是,目前使用的还比较少。后续可能会更多接触这块。这些都算是人工设计特征,以前人脸识别什么的会用到,但在深度学习大行其道的当下,可能会越来越被弱化吧。
10. 图像分割:这块在opencv中现成的接口只看到了分水岭,其他的可能都需要自己组织;而skimage中典型的超像素slic、多种snake、CV等都有现成接口。
11.另外还有图像转换、目标检测,目前的项目运用中暂时没有用到。
图像处理真的很博大精深,比起拿着图像喂到网络里面难很多。本来是不打算涉足这个领域的,无奈,进来了,就得往下走。毕竟CNN不是什么时候都奏效的。