Android 交互式抠图总结

概述

    图片编辑中常需要用到抠图功能,将图片想要的部分扣出来再合成到别的图中。本片文章主要介绍一种通过手指选取抠图前景进行抠图的方案,主要利用OpenCV 的grabCut分割算法进行抠图。

抠图原理:

1.bitmap转mat。

2.采集mask,用户选择抠图区域时,记录point 加入list中。

3.Imgproc.grabCut 传入mask进行抠图,得到抠出部分并做边缘处理。

4.mat转bitmap,得到最终抠出的bitmap。

流程:

        按比例放缩图片--> 采集mask --> grabCut --> 边缘处理 -->  得到抠出的图片grabcutBitmap --> grabcutBitmap转化为纯色colorBitimap -->colorBitimap放缩到原始大小,用于显示最终扣出的图片区域。(原图按比例放缩到目标尺寸,因为opencv 图片越大抠图时间越长,需要适当缩小图片,最终抠图耗时600毫秒左右)

1.选择一张图片

2.选取需要抠出的部分,这里我想抠这只狗子,只需要手指涂抹这只狗子,如图,只需要选中大致区域就可以,需要注意的是,这只狗通体白色,如果只选中白色区域,最后抠出来的图,就会缺少眼睛和鼻子部分,所以需要把眼睛和鼻子的部分也选中。我们需要记录手指滑动经过过位置的point,放入一个list。


3.抠图

3.1 Bitmap 转Mat

Mat imgPR =new Mat();

Utils.bitmapToMat(mScaleBitmap, imgPR);

3.2 收集mask,手指移动是,将point 传给firstMask

Mat firstMask =new Mat();

Size size =new Size(mScaleBitmap.getWidth(), mScaleBitmap.getHeight());

firstMask.create(size, CvType.CV_8UC1);

firstMask.setTo(new Scalar(GC_PR_BGD));//扣前景

for (int j =0; j < points.size(); j++) {

final Point point = points.get(j);

Imgproc.circle(firstMask, mPoint, radiusCircle, new Scalar(GC_FGD)); (mPoint就是触摸的点)}

3.4执行grabCut 方法

grabCut(Mat img, Mat mask, Rect rect, Mat bgdModel, Mat fgdModel, int iterCount, int mode)

img:输入图像,输入图像越小识别越快

mask: 选取的前景mask

rect: 包含前景的矩形

bgModel,fgModel : 前景、背景

iterCount: 迭代次数 次数越多识别越精确,但耗时更长

3.5 最终识别的区域,如下图,最终识别的区域就是这些,还是比较准确的。


3.6 算法原理

在图片中定义(一个或者多个)包含物体的矩形。

矩形外的区域被自动认为是背景。

对于用户定义的矩形区域,可用背景中的数据来区分它里面的前景和背景区域。

用高斯混合模型(GMM)来对背景和前景建模,并将未定义的像素标记为可能的前景或者背景。

图像中的每一个像素都被看做通过虚拟边与周围像素相连接,而每条边都有一个属于前景或者背景的概率,这是基于它与周边像素颜色上的相似性。

每一个像素(即算法中的节点)会与一个前景或背景节点连接。

在节点完成连接后(可能与背景或前景连接),若节点之间的边属于不同终端(即一个节点属于前景,另一个节点属于背景),则会切断他们之间的边,这就能将图像各部分分割出来

ps:当前景与背景像素颜色接近时,识别不精准,选取mask时 尽量包含前景矩形区域内所有颜色。

你可能感兴趣的:(Android 交互式抠图总结)