Android DIY抠图——想怎么抠就怎么抠

本文介绍了在Android中实现抠图功能的详细步骤,包括获取本地图片、全屏预览、手势层与图片层分离、监听手指轨迹生成Path、绘制轨迹和去除超出图片的闭合区域。通过插值算法使轨迹平滑,确保用户能精确抠取所需图像。最后展示了预览和抠图效果。
摘要由CSDN通过智能技术生成

下面我分享Android的一个抠图技巧,这篇文章只适合有Android基础和向量基础的小伙伴,如果朋友们刚学Android不久,建议先去了解Android自定义View、Touch机制、Canvas/Path/Paint、向量等相关知识。
先来看看效果图:这张是原图
这里写图片描述

抠出脸部图片,下面是结果:
这里写图片描述

下面我给小伙伴们讲述具体流程。

1,获取本地相册,很简单,直接代码,不解释

public void scanAlbum(Context context, AlbumScanListener listener){
        try {
            if(listener == null){
                return;
            }
            List<LDAPhoto> photos = new ArrayList<>();
            String[] projection = {MediaStore.Images.ImageColumns.DATA};
            Cursor cursor = context.getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, projection, null, null,null);
            while(cursor.moveToNext()) {
                LDAPhoto photo = new LDAPhoto();
                String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA));
                File file = new File(path);
                if(FileUtil.isFileExisted(path)) {
                    photo.setPath(path);
                    photo.setCreateTime(file.lastModified());
                    photos.add(photo);
                }
            }
            listener.onCompleted(photos);
        }catch (Exception e){
            listener.onScannerFailed();
        }
    }

2,全屏预览图片,手势层与图片层分离
整个view分图片层、带透明度的手势层(Mask),mask层覆盖图片层,手势相关逻辑都在mask层展开
这里写图片描述

简而言之,就是预览图片,上面铺一层蒙层,然后在蒙层里进行相关的抠图操作,预览的时候建议不是直接加载原图,而是根据屏幕宽高对图片进行自适应缩放,比如原图可能10000x10000,而屏幕只有100x100,那直接加载原图直接oom了,可以参考我的另一篇博客,如何巧妙的读取本地图片——bitmap的常用小技巧

3手势层监听手指轨迹,生成对应闭合区域(Path)
核心思想:定义mCanvas,操作bitmap,通过onDraw,中回调的canvas绘制到屏幕。

(1)初始化画笔:
mMaskPaint是蒙层画笔,mPathPaint是手指轨迹画笔,mCirclePaint是圆滑起点和终点的画笔(手指轨迹可能不是闭合,此时应该对两端点进行圆滑处理,mPath即用户手指轨迹)
令注:mStartX,mStartY是图片的左上角坐标,mBmWidth,mBmHeight是图片宽高

 private void initPaint() {
        mMaskPaint = new Paint();//mask画笔
        mMaskPaint.setAntiAlias(true);
        mMaskPaint.setStyle(Paint.Style.FILL);
        mMaskPaint.setStrokeCap(Paint.Cap.ROUND);
        mMaskPaint.setStrokeJoin(Paint.Join.ROUND);
        mMaskPaint.setColor(Color.parseColor("#d9000000"));

        mPathPaint = new Paint();//path画笔
        mPathPaint.setAlpha(0);
        mPathPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        mPathPaint.setPathEffect(new CornerPathEffect(mPathWidth / 2));
        mPathPaint.setAntiAlias(true);
        mPathPaint.setDither(true);
        mPathPaint.setStyle(Paint.Style.STROKE);
        mPathPaint.setStrokeJoin(Paint.Join.ROUND);
        mPathPaint.setStrokeWidth(mPathWidth);

        mCirclePaint = new Paint();//圆滑两端的圆形画笔
        mCirclePaint.setAlpha(0);
        mCirclePaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
        mCirclePaint.setPathEffect(new CornerPathEffect(mPathWidth / 2));
        mCirclePaint.setAntiAlias(true);
        mCirclePaint.setDither(true);
        mCirclePaint.setStyle(Paint.Style.FILL);

        mPath = new Path();//轨迹
        mPathRect = new RectF();//轨迹所在的矩形区域
    }

(2)初始化onDraw,第一次调用onDraw操作

         if(mBitmap == null){
            mBitma
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值