android 拍照人像对正框

项目中要绘制一个人像对正框,第一个想到的就是先绘制背景,然后利用PorterDuffXfermode(PorterDuff.Mode.XOR)将人像抠掉,绘制人像框,然而,调了许久才发现当预览区域的背景是半透明的,PorterDuff.Mode.XOR不能将重叠区域抠掉,预览区域是不透明时就可以抠掉,具体原因可能是PorterDuff.Mode对透明度有一些要求吧。后来想到ucrop库在裁剪图片时的对正框和这里很类似,看了源码后,才知道还有这种操作,主要是clipPath方法的第二个参数,话不多说,看图上代码。
设计稿:
在这里插入图片描述
实现:
在这里插入图片描述

实现方式:上方是一个贝塞尔曲线,下方是大半个椭圆
在这里插入图片描述

public class FaceAlignView extends View {
    private Context mContext;
    private RectF mBgRect;
    private Path mClipPath;
    private Paint mClipPaint;
    private float mVerticalMargin;
    private float mHorizontalMargin;
    private PathMeasure mPathMeasure;

    public FaceAlignView(Context context) {
        this(context, null);
    }

    public FaceAlignView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FaceAlignView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mContext = context;
        initPaint();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mBgRect.left = 0;
        mBgRect.top = 0;
        mBgRect.right = w;
        mBgRect.bottom = h;
        mClipPath.reset();
        //画下方的椭圆
        mClipPath.addArc(mHorizontalMargin, mVerticalMargin / 3f, w - mHorizontalMargin, h - mVerticalMargin, -35, 250);
        //取出椭圆的右上角的起始坐标
        float[] pos = new float[2];
        float[] tan = new float[2];
        mPathMeasure.setPath(mClipPath, false);
        mPathMeasure.getPosTan(0, pos, tan);
        //画上方的二阶贝塞尔曲线
        mClipPath.moveTo(w - pos[0], pos[1]);
        mClipPath.cubicTo(w - pos[0] * 0.86f, pos[1] * 0.35f, pos[0] * 0.86f, pos[1] * 0.35f, pos[0], pos[1]);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.save();
        //截取人像透明区域 Region.Op.DIFFERENCE path外的区域才允许绘制
        canvas.clipPath(mClipPath, Region.Op.DIFFERENCE);
        canvas.drawColor(mContext.getResources().getColor(R.color.face_align_bg));
        canvas.restore();
        //绘制人像边缘
        canvas.drawPath(mClipPath, mClipPaint);
    }

    private void initPaint() {
        mBgRect = new RectF();
        mClipPath = new Path();
        mPathMeasure = new PathMeasure();
        mClipPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mClipPaint.setColor(mContext.getResources().getColor(R.color.face_align_clip_path));
        mClipPaint.setStrokeWidth(DisplayUtils.dpToPx(4));
        mClipPaint.setStyle(Paint.Style.STROKE);
        mClipPaint.setStrokeCap(Paint.Cap.ROUND);
        mVerticalMargin = dpToPx(50);
        mHorizontalMargin = dpToPx(40);
    }

    public static int dpToPx(int dp) {
        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, Resources.getSystem().getDisplayMetrics());
    }

}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
Android 相机预览界面中添加人像框,可以通过在 SurfaceView 或 TextureView 上叠加一个带有透明背景的 ImageView 来实现。以下是实现步骤: 1. 在布局文件中添加 SurfaceView 或 TextureView 和 ImageView。 ```xml <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent"> <!-- SurfaceView 或 TextureView --> <SurfaceView android:id="@+id/surface_view" android:layout_width="match_parent" android:layout_height="match_parent" /> <!-- 带有透明背景的 ImageView --> <ImageView android:id="@+id/face_frame" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@android:color/transparent" android:src="@drawable/face_frame" /> </RelativeLayout> ``` 其中,@drawable/face_frame 是一个带有人像框的图片资源。 2. 调整 ImageView 的位置和大小,使其与预览画面重合。 ```java SurfaceView surfaceView = findViewById(R.id.surface_view); ImageView faceFrame = findViewById(R.id.face_frame); surfaceView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { @Override public void onGlobalLayout() { // 获取 SurfaceView 的宽高 int width = surfaceView.getWidth(); int height = surfaceView.getHeight(); // 调整 ImageView 的位置和大小 RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) faceFrame.getLayoutParams(); layoutParams.width = width / 2; layoutParams.height = height / 2; layoutParams.leftMargin = width / 4; layoutParams.topMargin = height / 4; faceFrame.setLayoutParams(layoutParams); // 只需要调整一次,移除监听器 surfaceView.getViewTreeObserver().removeOnGlobalLayoutListener(this); } }); ``` 其中,调整 ImageView 的位置和大小需要在 SurfaceView 的尺寸确定后进行,因此需要在 onGlobalLayout 回调中进行。 3. 调用相机 API 开始预览。 ```java private Camera camera; private Camera.PreviewCallback previewCallback = new Camera.PreviewCallback() { @Override public void onPreviewFrame(byte[] data, Camera camera) { // 获取预览数据的 byte 数组 } }; private void startCameraPreview() { camera = Camera.open(); try { camera.setPreviewDisplay(surfaceView.getHolder()); camera.setPreviewCallback(previewCallback); camera.startPreview(); } catch (IOException e) { e.printStackTrace(); } } ``` 在预览回调中,可以获取预览数据的 byte 数组,用于后续的人脸检测等操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值