Fork me on GitHub
代码改变世界

iOS客户端图片智能裁剪

2018-12-12 15:08 KenshinCui 阅读(...) 评论(...) 编辑 收藏

SmartCrop_Logo

概述

所谓智能裁剪其实就是按照指定尺寸裁剪或显示出包含图片核心特征的区域,目前很多智能裁剪都是在服务器端做的,在客户端需要访问时直接裁剪放到Redis或者提前裁剪好以备访问。但是找了一圈直接在iOS客户端进行裁剪的库还不多,或者使用成本比较高,不能即拿即用。但是有时候客户端可能并非直接从服务器端获取数据而是读取相册数据,不可能先把图片存放到服务器端裁剪然后再拿来用,考虑到这种场景也不再少数,因此就有必要思考一套客户端智能裁剪的方案。

免费好用的智能裁剪库

最近两天整理了之前开发一个软件过程中自己开发的一个客户端智能裁剪库供有需要的同学使用,当然后面有时间的话会整理开源。说是库本质就是一套算法而已,但是在编写这套算法期间也参考评估过很多已有或者想要使用而没有使用的解决方案。

首先说一下目前在网上比较容易找到的一些库存在的问题:

  • 没有iOS对应的版本,集成起来极其复杂,之前为了用一个不错的库甚至在iOS调用Python库
  • 速度慢,生成一张智能裁剪后的图片需要1s左右,不再可容忍范围之内
  • 人像识别不准确,图片中占比较小的人脸识别不出来,甚至有可能出现误识别(这个其实比识别不出来问题还大)
  • 基于专利收费算法实现(例如使用SRUF),不仅开发者使用起来要引用大量的库而且有收费风险
  • 集成比较麻烦,使用起来光配置环境就要摆弄半天,还不一定能成功

当然,事实上在探索过程中也走了不少的弯路,遇到的问题要比上面多得多,包括有些算法只能裁剪横图,对于宽高比较小的竖图支持很差,又或者引入大量的库造成app本身大小直线上升等等。。。因此这也就是为什么自己要开发一个新的库SmartCrop.framework而不是基于现有库来做的原因。

那么SmartCrop.framework智能裁剪库又有什么特点呢:

  • 跨平台,当然既然作为一个iOS开发者一定要包含iOS版本(尽管此文中只提供了iOS版本,不过其实这个库本身基于c++实现,天然具有跨平台特性,后续有时间也会整理其他平台的版本)
  • 速度快,几乎可以做到实时裁剪😆(当然这个比较理想,不过测试中本文提供的库对于裁剪1000px以上的大图iPhone X上已经可以做到0.1s以下,后续会持续优化)
  • 精准的人脸识别,基于神经网络进行识别,让人像识别更加精准迅速(尽管需要一个训练好的模型,不过模型本身并不大)
  • 免费、好用,没有专利之争、集成迅速,按照步骤一分钟之内完成

当然,SmartCrop.framework也并非完美,这个库本身基于OpenCV的c++算法实现,综合了很多算法实现了特征点检测,这也就是说App需要集成opencv2.framework。另外算法本身还有优化空间,特别是特征点检测中对于色差分辨不是特变明显的图片裁剪精准度会有下降,后面也会进一步优化,不过对比了几个线上已有的库来说精准度应该要比这些库提高不少,毕竟再好的智能裁剪也是基于某些特征,和人为的意识还有不少差别。

和其他库的对比

这里选取了之前使用过的一个Python库作为对比,在iOS中运行10张1000px左右的图片裁剪需要15s左右,这也是之前app中使用的实际结果。当然这其中有间接调用Python的成本,以至于后来直接测试了它的Android版本,大概耗时10s。下面是10张图的裁剪结果对比,为了方便看出裁剪效果使用了横图裁剪成竖图的对比,而图片选择部分尽量包括了人像和非人像图片,视频中每组图有三张,分别是原图、第三方库裁剪后的效果、SmartCrop.framework裁剪后的效果:

compareVideo

当然从视频不难看出,SmartCrop.framework人像裁剪相当精准,第1、3、4中的人脸第三方库没有识别出来,在非人脸识别的图片中第6张树的裁剪不理想。当然SmartCrop.framework也不是百分百完美,最后一张猫的图片裁剪效果不如第三方库,因为除了猫之外将右侧的树识别成了关键特征位置。当然也会发现第2张图片中两个库都识别出了多个人脸,也都在有限的宽度内裁剪除了两个人,但是位置不同,这个和裁剪策略和特征分析算法有关。

简单的使用方法

引入SmartCrop.framework只需要从这里下载SmartCropDemo,找到其中的SmartCrop.framework直接将此库拖拽到自己的项目中,在Xcode的Embedded Binaries中添加SmartCrop.framework即可(或者Build Phase的Copy File中添加SmartCrop.framework),然后在Linked Frameworks and Libraries中添加libc++.tbd,最后将opencv2.framework拖拽到项目中即可(注意由于github文件大小限制,这个库没有直接在code中提供,可以到这里直接下载解压使用)。

SmartCrop.framework在开发的过程中尽量的简化,通篇只有一个类SmartCropper,此类也只有两个方法并且以ObjC静态方法出现:

+(UIImage *)cropImage:(UIImage *)image size:(CGSize)size;
+(CGRect)cropRectWithImage:(UIImage *)image size:(CGSize)size;

而通常情况下直接调用最上面的一个方法即可满足裁剪需求,那么为什么还要提供第二个API呢?原因是有些情况下并不想裁剪图片而只想找到图片的核心区域,SmartCrop.framework也已经做好了。

当然Swift中使用也仅仅需要一个bridge header而已,然后调用SmartCropper.cropImage(image, size:size)即完成了所有裁剪操作。

SmartCrop裁剪效果:

原图

1sr

SmartCrop裁剪后

1dst

原图

2sr

SmartCrop裁剪后

2dst

原图

3sr

SmartCrop裁剪后

3dst

性能究竟怎么样

Demo界面:

DemoUI

为了验证性能做了一个上面提到的demo,在主界面选择Photo Library可以实时预览相册中的图片智能裁剪后的效果,按住主界面可以对比原图;点击Browser是对于前面提到的10张测试图的实时预览,可以从下面的展示效果看到几乎是实时生成的,没有太多卡顿,上面说的1000px以上的图片,低于0.1s可以完成裁剪应该不会太夸张,当然实际使用中不会每张图都实时显示实时生成,可以提前存储,加上预加载可以做到0卡顿效果。

运行效果如下:

demoVideo

还要说一下,SmartCrop.framework本身基于OpenCV 3.4.4进行开发,理论上可以向下兼容几个版本,但是太旧的api可能无法使用,为了获得更稳定的效果建议直接使用3.4.4版本。另外文中所有演示图片来源于互联网,仅作为演示学习之用,如存在版权问题请联系本人(kenshincui@hotmail.com),即刻下线。