基于Android 的易拍画软件设计与实现

2020-10-12 09:20胡奇超王赠凯易文亮卢奇
现代计算机 2020年24期
关键词:简笔画轮廓梯度

胡奇超,王赠凯,易文亮,卢奇

(嘉兴学院数理与信息工程学院,嘉兴 314001)

0 引言

调查研究发现,年龄在4-7 岁的儿童富于想象力和创造力,特别喜欢随时随地勾画周边的感兴趣物体。这个阶段的孩子大部分并不掌握基本的绘画技巧,实际表现就是在纸上或墙上随意涂画。而很多家长并不能在绘画方面给予孩子很好的指导,他们不擅长将身边看到的任何意思的物体通过寥寥几笔勾勒出来。虽然网络上有一些特定物体的简笔画图案供家长和孩子学习参考,但却无法满足家长和孩子在任意时间对任意场景中任意物体的简笔画图案的需求。作为计算机应用领域中的一个重要技术,图像处理技术能够对数字图像进行分析、处理和变换,从中抽取出用户感兴趣的东西。基于此,本文试图利用图像处理技术实现一个能够自动生成感兴趣物体简笔画图案的移动端软件,最大程度地满足家长和孩子对简笔画图案的需求。

所谓简笔画,就是用简单的线条来勾勒出物体的基本特征,简笔画绘制已成为非真实感绘制研究领域的一个重要组成部分[1]。目前最常见的生成简笔画的做法是将源图像转化成灰度图像,再对灰度图像进行平滑、锐化图像增强处理,然后在此基础上对增强后的图像进行边缘检测[2-5]、边缘细化、轮廓提取[6-8],对得到的轮廓图进行分层处理,最后利用LIC 算法模拟产生铅笔纹理,从而完成图像的简笔画风格[9]。传统的做法中,使用Canny 边缘检测[4]具有定位准、精度高的优点;使用图层的划分技术和LIC 算法,能够较为真实的达到简笔画绘制的效果。但也存在一定的缺点,例如传统的Canny 边缘检测算法忽略了图像的色彩信息、人为设定上下阈值等,这些缺陷导致检测结果中包含了假边缘或是丢失了某些真实边缘[10-11],以及LIC 算法需要对各个像素进行卷积,计算量相对较大,比较费时。

本文就如何利用计算机图像处理技术开发基于Android 的“易拍画”软件进行论述。“易拍画”软件通过对手机拍摄对照片或网上下载的图片,实现对彩色图像进行简笔画风格转换,得到只具有原图像轮廓的简笔画。这种简笔画正适合儿童模仿创造,解决了家长在对儿童进行绘画指导中可能会碰到的问题。

1 轮廓检测算法

图片简笔画方案的生成可以利用计算机图像处理中的轮廓检测技术进行自动检测,其步骤如图1 所示。

图1 轮廓检测步骤

首先获取源图像,对源图像进行灰度处理,对得到的灰度图像进行边缘检测,其中边缘检测步骤包括图像平滑处理、计算梯度值与方向、非极大值抑制、双阈值检测连接;最后是轮廓提取,得到轮廓输出图像。

1.1 灰度化处理

灰度化处理是将彩色数字图像转化为灰度图像的过程。彩色数字图像的每一个像素点都是由红、蓝、绿三个通道组成,分别对这三个通道每个分量分配不同的比重就可以产生世界上所有的颜色。在图像的RGB模型中,当R=G=B 时,表示为一种灰度颜色,其中R=G=B 的值叫做图像的灰度值,将图像进行灰度化处理本质上就是使彩色图像的R,G,B 分量值相等的过程。灰度化处理方法[12]有平均值法,最大值法和加权平均值法。本文使用基于OpenCV 的图像灰度化处理,其函数原型是 CV_EXPORTS_W void cvtColor(InputArray src, OutputArray dst, int code, int dstCn = 0),参数含义如表1 所示。

表1 cvtColor 函数参数说明

1.2 边缘检测

边缘检测是图像处理的重要操作,是对图像进行分割和对象特征提取的关键步骤。当一个像素点的四周像素灰度发生阶跃性变化时,则把这种像素点的集合叫做边缘。边缘检测的算法众多,而Canny 算子由于其在抑制噪声和检测边缘之间能够取得较好的平衡,因而被广泛应用。用Canny 算子得到边缘点的具体算法步骤如下所示:

(1)平滑处理

噪声对边缘检测的算法效果影响很大,需要使用滤波器对图像进行降噪处理。常用的滤波器有均值滤波器、中值滤波器和高斯滤波器。由于高斯滤波器对去除服从正态分布的噪声十分有效,对于去除高斯噪声也有很好的效果。本文采用高斯滤波器对图像进行平滑处理,具体使用OpenCV 的GaussianBlur 函数进行滤波,函数原型是void GaussianBlur(Mat src, Mat dst,Size ksize, double sigmaX, double sigmaY, int border-Type),参数说明如表 2。

表2 GaussianBlur 函数参数说明

(2)计算梯度幅值与方向

平滑后的图像使用3×3 的一阶有限差分进行图像的梯度幅值与方向计算。图像的边缘有不同方向的指向,Canny 算子用了四个梯度算子分别计算水平、垂直和对角线方向的梯度。要计算水平和垂直方向的差分Gx和Gy,可以使用边缘差分算子进行计算,计算梯度模和方向的公式如下,Gx,Gy分别代表x,y方向的梯度,θ代表梯度角度:

梯度角度θ的范围为-π到π,把它近似到四个方向,分别代表水平,垂直和两个对角线方向(0°,45°,90°,135°)。以 ±iπ/8(i=1,3,5,7)分割,给每个区域中下降的梯度角一个特定值,以表示四个方向之一。

(3)非极大值抑制

Canny 算子针对梯度幅值进行非极大值抑制。通过检测同一梯度方向上每个像素点的梯度幅值,判断其是否为局部最大值。如果该点的梯度幅值不是最大值,则对应的灰度值将被设置为0,如此大多数非边缘点就可以被移除。如果该点的梯度幅值是最大值,它将被保留为边缘点。

(4)滞后阈值处理

要确定图像的哪些边界才是真正的边界。如图2所示,需要设置两个阈值:minVal 和maxVal,当图像的灰度梯度高于maxVal 时被认为是真的边界,而低与minVal 的则被抛弃。如果介于两者之间的话,则判断这个点是否与某个被确定为真正边界的点相连,如果是就认为这个点是边界点,如果不是就抛弃。

图2 滞后阈值示意图

A 高于阈值maxVal 所以是真正的边界点,C 介于maxVal 与minVal 之间并与A 相连,所以也被认为是真正的边界点。而B 就会被抛弃,其低于maxVal 且不与真正的边界点相连。所以选择合适的maxVal 和min-Val 对于能否取得好的边缘十分重要。

1.3 轮廓提取

轮廓简单来说就是一系列边缘的集合,通过对一系列的边缘进行组合就可以得到一个完整的轮廓。用Canny 边缘检测算子对二值化后的图像进行处理后,得到只含边缘的二值图像。通过基于OpenCV 的find-Contours 函数对得到的只含边缘的二值化图像进行轮廓提取,再通过drawContours 函数就可将轮廓绘制出来得到了轮廓图。findContours 函数原型是void find-Contours(InputOutputArray image, OutputArrayOfArrays contours,OutputArray hierarchy, int mode,int method,Point offset=Point()),参数说明如表3。

drawContours 函数原型 void drawContours( Input-OutputArray image, InputArrayOfArrays contours, int contourIdx, const Scalar& color,int thickness = 1, int line-Type = LINE_8, InputArray hierarchy = noArray(),int maxLevel=INT_MAX,Point offset=Point())是,参数说明如表4。

表3 findContours 函数参数说明

表4 drawContours 函数参数说明

2 “易拍画”软件设计

本文在基于传统做法基础上做出了一定的改进。在传统的Canny 边缘检测算法的基础上,进行了对梯度幅值进行非极大值抑制;用双阈值算法检测和连接边缘等操作提升了效果。具体使用的图像处理操作基于 OpenCV 开源库[13-14]。

2.1 总体架构

本文实现一个基于Android 移动端的“易拍画”软件,主要功能为将彩色图像转简笔画风格图像[15-16]。将通过拍照或下载得到的源图像进行灰度化处理,将得到的灰度图像通过Canny 边缘检测算法对其进行模糊、去噪得到边缘图像,在得到的边缘图像的基础上提取其轮廓,然后对图像进行分层处理,提出了适用于图层的白噪声生成方法,最后采用快速积分卷积(FLIC)替代传统线积分卷积)LIC)进行模拟纹理[17],并将各层结果以及图像轮廓进行叠加生成简笔画[18-20]。软件的功能架构如图3 所示。

图3“易拍画“软件的功能架构

“易拍画”软件包括4 个主要功能。本地相册选图:用户通过选择本地相册的图片,裁剪后作为简笔画的原图像。拍照取图:用户启动手机的相机拍照,拍完照片后裁剪,作为简笔画的原图像。简笔画生成:基于OpenCV 开源库对用户选择的图像进行处理后得到简笔画。保存简笔画:将生成的铅笔画保存到系统目录下。

2.2 本地相册

功能描述:此功能按钮通过用户直接选择相册中的图片以便进行之后的裁剪并简笔画操作。

实现方法:checkReadPermission()是处理执行时的权限的逻辑的函数,判断是否被授权,授权时直接进行操作,未授权时根据请求结果进行处理。请求处理结果在onRequestPermissonsResult()函数中。这里,执行权限申请按组处理,即属于同一组的权限要求相同,如果用户授权一个权限,同一组的权限也同时授权。SD 卡的读写都属于STORAGE 组,所以在申请SD 卡的读写权限的时候申请读写权限或者写权限就可以了。之后调用choseHeadImageFromGallery()函数处理Intent 的 Activity,请求码是 CODE_GALLERY_REQUEST。

2.3 拍照选图

功能描述:此功能按钮通过用户拍照并显示图片以便进行之后的裁剪并简笔画操作。

实现方法:checkStoragePermission()函数同样用于处理运行时权限的逻辑,需要Manifest.permission.CAMERA,Manifest.permission.READ_EXTERNAL_STOR -AGE 这两个权限,判断是否被授权,授权时直接进行操作,未授权时根据请求结果进行处理。之后调用choseHeadImageFromCameraCapture()函数。addflags的作用是标记Intent,允许Intent 启动的Activity 使用FileProvider 封装的Uri。接着启动Activity,请求代码为CODE_CAMERA_REQUEST。由此,完成拍摄请求,转移到系统的拍摄接口,接着处理拍摄的照片。

从Android 7.0(SDK>=24)开始,直接使用本地真实的URI 被认为是不安全的,会抛出一个FileUriExposedException 异常,需要使用 FileProvider 上封装的URI。FileProvider 的使用:新建 provider_paths.xml,paths指定要使用的目录,external-path 为SD 卡根目录,接下来,在AndroidManifest.xml 中注册provider。grantU-riPermissions 设为true,以允许系统相机临时使用此provider。authorities 与此前使用FileProvider 时一样,exported 必须为false,否则将返回错误。

2.4 照片裁剪

功能描述:此功能用于将本地相册选的图片或拍照选的图片进行裁剪以达到用户所期望的图片。

实现方法:cropRawPhoto(Uri uri)函数参数为拍照或本地图片得到的图片的Uri,创建com.android.camera.action.CROP 的 Intent,通过 intent.putExtra 方法设置裁剪的大小比例,然后将裁剪好的图输出到所建文件中,图片裁剪完成后回调的是case CODE_RESULT_REQUEST 下 的 setImageToHeadView(Intent a,Bitmap b)方法提取保存裁剪之后的图片数据,并设置图像部分的View。

intent.putExtra("return-data", false)函数参数 return-data 应设置为false,如果设置为true,那么裁剪后的图像直接以Bitmap 形式缓存到内存中,但Bitmap 相当大,如果手机内存不足或分配给手机的内存不足,就会因OOM 问题而闪退。

2.5 简笔画保存

功能描述:此功能用于将生成的简笔画保存到手机本地相册。

实现方法:设置点击监听器setOnClickListener,用户点击后调用saveImage()方法,首先获取ImageView,开启 DrawingCache,通过 getDrawingCache 方法获取ImageView 的Bitmap 格式的图像并调用saveBitmap-File()方法保存获取的图像,关闭DrawingCache,显示Toast“已保存”。saveBitmapFile()方法中获取系统时间并赋给图像名ImgName,new File("/sdcard/1StickFigure/")创建文件夹,new File("/sdcard/1StickFigure/"+ImgName+".jpg")将要保存图片的路径和图片名称,new FileOutputStream(file)保存到系统本地相册。

3 效果与评价

3.1 软件的实现

“易拍画”软件的开发环境为Android Studio 3.5.2,开发语言是Java 语言,利用JDK1.8 和开源图像处理工具OpenCV 3.4.3。由于Android 6.0 引入了运行时权限,用户不必在安装时授予所有权限,可以在使用到相关功能时再授权。

图4 展示了“易拍画”软件界面,界面中间是用来显示图像的ImageView 控件,点击本地相册和拍照选图按钮,分别是拍照和相册选择图片功能,其中都实现了照片的自动裁剪。裁剪后的图片通过ImageView 控件显示。如图4 所示,可见在背景较为简单的情况下,彩色图像的轮廓能很好地绘制出来,生成的轮廓完整清晰,无假边缘,并且实际生成时间在1 秒之内,一定程度上满足了用户对简笔画效果和等待时间的需求。

图4 易拍画软件实现效果图

3.2 轮廓检测效果测试

我们分别用不同类型的图片对本文轮廓检测算法进行来测试,其中部分实验效果如图5 所示。可以看到不同场景下,轮廓效果都较为完整。但在背景较复杂、物体细节特征较多的情况下,轮廓的丢失以及细节处理方面都还需要进一步改进。

3.3 用户评价

依据软件的实际使用人群分别对四个年龄段的人群进行调研打分,每组15 人分别打分,从边缘检测效果图的边缘完整性、边缘准确性、实际观看效果三个方面对效果图进行了综合评价,表5 给出了评分依据。评分结果如表6 所示。

图5 轮廓检测示例

第一行是源图像,第二行是检测结果

表5 评分依据

另外,选取10 组亲子家庭实际使用“易拍画”软件,在他们使用了一段时间后,分别从软件的易用性、界面设计、性能上进行评判,评判结果如表7 所示。

表6 评分结果表

表7 评分结果表

4 结语

本文提出了利用图像处理技术进行简笔画图像生成的方法,并利用OpenCV 开源库实现了基于Android平台“易拍画”软件。经测试表明,所提出的方法可行,“易拍画”软件的实现效果能够满足用户的基本需求,但仍然存在进一步改进的空间。可以通过使用不同场景下多样的滤波来代替单一高斯滤波,来改进Canny算子的边缘检测效果;在轮廓提取上可以使用轮廓近似来使轮廓更加完整。由于Android 手机的限制,简笔画图像生成速度也需进一步改善;在具有复杂背景的输入图片情况下,简笔画效果图需要在轮廓精确性和简化轮廓层次两个方面进一步平衡和提升。

猜你喜欢
简笔画轮廓梯度
神形兼备的简笔画
跟踪导练(三)
一个具梯度项的p-Laplace 方程弱解的存在性
内容、形式与表达——有梯度的语言教学策略研究
航磁梯度数据实测与计算对比研究
组合常见模型梯度设置问题
简笔画白鹭
儿童筒笔画
创造早秋新轮廓