Android 自定义相机

检测Android设备是否支持照相机

    /**
     * 检测设备是否支持相机
     *
     * @param context
     * @return
     */
    private boolean checkCameraHardware(Context context) {
        if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA)) {
            return true;
        }
        return false;
    }

定制拍照程序的步骤:

1、打开相机:Camera.open();
2、创建SurfaceView对象;
3、添加回调监听器(SurfaceHolder.Callback);
4、预览(mCamera.startPreview);
5、拍照(mCamera.takePicture);

网上资料:

网上写的挺详细的具体自定义操作请查阅以下资料:

Android 自定义Camera相机
https://blog.csdn.net/qq_38001118/article/details/81871564

Android: Camera相机开发详解(上) —— 知识储备
https://www.jianshu.com/p/f8d0d1467584
Android: Camera相机开发详解(中) ——实现预览、拍照、保存照片等功能
https://www.jianshu.com/p/e20a2ad6ad9a
Android: Camera相机开发详解(下) —— 实现人脸检测功能
https://www.jianshu.com/p/3bb301c302e8
Android:Camera2开发详解(上):实现预览、拍照、保存照片等功能
https://www.jianshu.com/p/0ea5e201260f

项目中遇到的问题:

魔镜项目中人脸识别需要一个宽高为630x780px的框而相机中给的预览和图片尺寸没有给定与项目接近的值

07-19 17:29:58.280 24520-24520/com.hzy.exampledemo D/mPreviewSizes-0: width:1280--height:720
07-19 17:29:58.280 24520-24520/com.hzy.exampledemo D/mPreviewSizes-1: width:1920--height:1080
07-19 17:29:58.280 24520-24520/com.hzy.exampledemo D/mPreviewSizes-2: width:208--height:144
07-19 17:29:58.280 24520-24520/com.hzy.exampledemo D/mPreviewSizes-3: width:176--height:144
07-19 17:29:58.280 24520-24520/com.hzy.exampledemo D/mPreviewSizes-4: width:352--height:288
07-19 17:29:58.280 24520-24520/com.hzy.exampledemo D/mPreviewSizes-5: width:320--height:240
07-19 17:29:58.280 24520-24520/com.hzy.exampledemo D/mPreviewSizes-6: width:480--height:320
07-19 17:29:58.280 24520-24520/com.hzy.exampledemo D/mPreviewSizes-7: width:640--height:480
07-19 17:29:58.280 24520-24520/com.hzy.exampledemo D/mPreviewSizes-8: width:800--height:480
07-19 17:29:58.280 24520-24520/com.hzy.exampledemo D/mPreviewSizes-9: width:960--height:544
07-19 17:29:58.280 24520-24520/com.hzy.exampledemo D/mPreviewSizes-10: width:960--height:720
07-19 17:29:58.280 24520-24520/com.hzy.exampledemo D/mPreviewSizes-11: width:720--height:720

07-19 17:36:17.400 24520-24520/com.hzy.exampledemo D/mPictureSizes-0: width:320--height:240
07-19 17:36:17.400 24520-24520/com.hzy.exampledemo D/mPictureSizes-1: width:640--height:480
07-19 17:36:17.400 24520-24520/com.hzy.exampledemo D/mPictureSizes-2: width:1280--height:720
07-19 17:36:17.400 24520-24520/com.hzy.exampledemo D/mPictureSizes-3: width:1920--height:1080
07-19 17:36:17.400 24520-24520/com.hzy.exampledemo D/mPictureSizes-4: width:2432--height:2432
07-19 17:36:17.400 24520-24520/com.hzy.exampledemo D/mPictureSizes-5: width:3264--height:2448
07-19 17:36:17.400 24520-24520/com.hzy.exampledemo D/mPictureSizes-6: width:4160--height:2336
07-19 17:36:17.400 24520-24520/com.hzy.exampledemo D/mPictureSizes-7: width:5152--height:2896
07-19 17:36:17.400 24520-24520/com.hzy.exampledemo D/mPictureSizes-8: width:5152--height:3888

解决思路:

1、我们设置图片尺寸和预览尺寸为1920x1080px;
2、在布局中添加一个同样大小位置的蒙层,其中中间通过计算留出630x780px;
3、对拍照的图片通过位置计算进行截取;

1、我们设置图片尺寸和预览尺寸为1920x1080px;
        parameters.setPreviewSize(1920, 1080);
        parameters.setPictureSize(1920, 1080);
2、在布局中添加一个同样大小位置的蒙层,其中中间通过计算留出630x780px;
        

        
package com.yx.mirror.third.camera.view;

import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;

import androidx.annotation.Nullable;

import com.yx.mirror.R;

/**
 * Description 遮挡的View
 *
 * @author hzy
 * Create on 2019/7/23 10:13
 */
public class OcclusionView extends View {

    private Paint mPaint;
    private int mMaskColor; // 取景框外的背景颜色
    private int mCameraWidth;
    private int mCameraHeight;
    private int mPicWidth;
    private int mPicHeight;
    /**
     * 中点距离和marginTop的差值,由于横向是居中,所以不用计算
     */
    private int marginDifference;
    private OcclusionView mOcclusionView;

    public OcclusionView(Context context) {
        super(context);
        initView();
    }

    public OcclusionView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        initView();
    }

    private void initView() {
        Resources resources = getResources();
        mMaskColor = resources.getColor(R.color.black_back);
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        // 绘制取景框外的暗灰色的表面,分四个矩形绘制
        mPaint.setColor(mMaskColor);
    }

    public void setOcclusionView(OcclusionView mOcclusionView, int mCameraWidth, int mCameraHeight, int mPicWidth, int mPicHeight, int marginDifference) {
        this.mOcclusionView = mOcclusionView;
        this.mCameraWidth = mCameraWidth;
        this.mCameraHeight = mCameraHeight;
        this.mPicWidth = mPicWidth;
        this.mPicHeight = mPicHeight;
        this.marginDifference = marginDifference;
    }

    @Override
    public void onDraw(Canvas canvas) {
        if (mOcclusionView == null) {
            return; // not ready yet, early draw before done configuring
        }

        // 黑色区域
        Path path1 = new Path();
        path1.addRect(new RectF(0, 0, mCameraWidth, mCameraHeight), Path.Direction.CW);

        //透明区域
        Path path2 = new Path();
        path2.addRect(new RectF((mCameraWidth - mPicWidth) / 2, (mCameraHeight - mPicHeight) / 2 + marginDifference, (mCameraWidth + mPicWidth) / 2, (mCameraHeight + mPicHeight) / 2 + marginDifference), Path.Direction.CW);

        //DIFFERENCE,path1减去path1和path2相交部分
        path1.op(path2, Path.Op.DIFFERENCE);
        canvas.drawPath(path1, mPaint);
    }
}

3、对拍照的图片通过位置计算进行截取;
    /**
     * 人脸照片处理
     *
     * @param bmp
     */
    private void showFragment(Bitmap bmp) {
        translateAnimation.cancel();//动画取消
        mImvLine.setVisibility(View.GONE);
        Matrix matrix = new Matrix();
        //镜子效果
        matrix.setScale(-1, 1);
        matrix.postTranslate(bmp.getWidth(), 0);
        //旋转图片
        Bitmap rotateBitmap = Bitmap.createBitmap(bmp, 0, 0, bmp.getWidth(), bmp.getHeight(), matrix, true);
        //截图至当前图片的大小
        Bitmap bitmap = cropBitmap(rotateBitmap, 630, 780);
        photoPath = "/qimg/report/" + DateUtil.getDateYmd() + "/" + System.currentTimeMillis() + ".png";
        writeBitmapToFile(bitmap, photoPath);
        mCameraContainer.setVisibility(View.GONE);
        mPhotoIv.setImageBitmap(bitmap);
        mPhotoIv.setVisibility(View.VISIBLE);
        postImg(bitmap);
    }

    /**
     * 裁剪
     * https://blog.csdn.net/qunqunstyle99/article/details/87869018
     *
     * @param bitmap 原图
     * @return 裁剪后的图像
     */
    private Bitmap cropBitmap(Bitmap bitmap, int picWidth, int picHeight) {
        int w = bitmap.getWidth();
        int h = bitmap.getHeight();
        int x = 0;
        int y = 0;
        if (bitmap.getWidth() < picWidth) {
            Toast.makeText(this, "x + width must be <= bitmap.width()", Toast.LENGTH_SHORT).show();
            return bitmap;
        }
        if (bitmap.getHeight() < picHeight) {
            Toast.makeText(this, "y + height must be <= bitmap.height()", Toast.LENGTH_SHORT).show();
            return bitmap;
        }
        x = (w - picWidth) / 2;
        y = (h - picHeight) / 2;
        return Bitmap.createBitmap(bitmap, x, y, picWidth, picHeight, null, false);
    }

你可能感兴趣的:(Android 自定义相机)