|
@@ -0,0 +1,862 @@
|
|
|
+package com.oumasoft.facelibrary;
|
|
|
+
|
|
|
+import android.Manifest;
|
|
|
+import android.content.ContentValues;
|
|
|
+import android.content.Context;
|
|
|
+import android.content.Intent;
|
|
|
+import android.content.pm.PackageManager;
|
|
|
+import android.database.Cursor;
|
|
|
+import android.graphics.*;
|
|
|
+import android.hardware.camera2.*;
|
|
|
+import android.hardware.camera2.params.MeteringRectangle;
|
|
|
+import android.hardware.camera2.params.StreamConfigurationMap;
|
|
|
+import android.media.Image;
|
|
|
+import android.media.ImageReader;
|
|
|
+import android.net.Uri;
|
|
|
+import android.os.*;
|
|
|
+import android.provider.MediaStore;
|
|
|
+import android.text.TextUtils;
|
|
|
+import android.util.DisplayMetrics;
|
|
|
+import android.util.Log;
|
|
|
+import android.util.Size;
|
|
|
+import android.util.SparseIntArray;
|
|
|
+import android.view.Surface;
|
|
|
+import android.view.TextureView;
|
|
|
+import android.view.View;
|
|
|
+import android.view.WindowManager;
|
|
|
+import android.widget.ImageView;
|
|
|
+import android.widget.LinearLayout;
|
|
|
+import android.widget.TextView;
|
|
|
+import androidx.annotation.NonNull;
|
|
|
+import androidx.appcompat.app.AppCompatActivity;
|
|
|
+import androidx.core.app.ActivityCompat;
|
|
|
+import androidx.core.content.ContextCompat;
|
|
|
+import cn.gxeea.zk.R;
|
|
|
+import com.ouma.faceimagelib.FaceQCEngine;
|
|
|
+import com.ouma.faceimagelib.ReturnData;
|
|
|
+
|
|
|
+import java.io.*;
|
|
|
+import java.nio.ByteBuffer;
|
|
|
+import java.util.ArrayList;
|
|
|
+import java.util.Arrays;
|
|
|
+import java.util.List;
|
|
|
+import java.util.concurrent.ExecutorService;
|
|
|
+import java.util.concurrent.Executors;
|
|
|
+
|
|
|
+public class TakePhoto extends AppCompatActivity {
|
|
|
+
|
|
|
+ private static final int CAMERA_PERMISSION_REQUEST_CODE = 100;
|
|
|
+ private TextureView textureView;
|
|
|
+ private CameraDevice cameraDevice;
|
|
|
+ private CameraCaptureSession captureSession;
|
|
|
+ private Size previewSize;
|
|
|
+ private String cameraId;
|
|
|
+ private int currentCameraIndex = 1; // 0 for back camera, 1 for front camera
|
|
|
+ private CameraManager cameraManager;
|
|
|
+ private String[] cameraIdList;
|
|
|
+ private AutoFocusManager autoFocusManager;
|
|
|
+ private ImageView btn_changeFront;
|
|
|
+
|
|
|
+ private int mWidth=0,mHeight=0,screenWidth=0;
|
|
|
+ ImageView btnOK,btnClose,imgtest;
|
|
|
+ private ImageReader imageReader;
|
|
|
+// CameraCaptureSession.CaptureCallback previewCallback;//预览回调
|
|
|
+ boolean bPZClick=false;
|
|
|
+ FaceQCEngine face;//sdk对象
|
|
|
+ String showmsg="";
|
|
|
+ TextView tvFBL;
|
|
|
+ private final Size DESIRED_PREVIEW_SIZE = new Size(1920, 1080);
|
|
|
+
|
|
|
+
|
|
|
+ // 处理屏幕旋转角度
|
|
|
+ private static final SparseIntArray ORIENTATIONS = new SparseIntArray();
|
|
|
+ static {
|
|
|
+ ORIENTATIONS.append(Surface.ROTATION_0, 90);
|
|
|
+ ORIENTATIONS.append(Surface.ROTATION_90, 0);
|
|
|
+ ORIENTATIONS.append(Surface.ROTATION_180, 270);
|
|
|
+ ORIENTATIONS.append(Surface.ROTATION_270, 180);
|
|
|
+ }
|
|
|
+
|
|
|
+ private LinearLayout layoutButton;
|
|
|
+ private ImageView ivGreen;
|
|
|
+ private ImageView ivRed;
|
|
|
+ private TextView tvResult;
|
|
|
+
|
|
|
+ private String params = "";
|
|
|
+
|
|
|
+
|
|
|
+ //get pixels
|
|
|
+ private byte[] getPixelsRGBA(Bitmap image) {
|
|
|
+ // calculate how many bytes our image consists of
|
|
|
+ int bytes = image.getByteCount();
|
|
|
+ ByteBuffer buffer = ByteBuffer.allocate(bytes); // Create a new buffer
|
|
|
+ image.copyPixelsToBuffer(buffer); // Move the byte data to the buffer
|
|
|
+ byte[] temp = buffer.array(); // Get the underlying array containing the
|
|
|
+
|
|
|
+ return temp;
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
|
|
|
+ super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
|
|
+ if (requestCode == PERMISSION_REQUEST_CODE) {
|
|
|
+ boolean allGranted = true;
|
|
|
+
|
|
|
+ for (int result : grantResults) {
|
|
|
+ if (result != PackageManager.PERMISSION_GRANTED) {
|
|
|
+ allGranted = false;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (allGranted) {
|
|
|
+ // 所有权限已授予
|
|
|
+ ToastUtil.show("所有权限已授予");
|
|
|
+ } else {
|
|
|
+ // 权限被拒绝
|
|
|
+ ToastUtil.show("权限被拒绝,无法继续操作");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ private static final int PERMISSION_REQUEST_CODE = 1;
|
|
|
+
|
|
|
+ private void requestPermissions() {
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
|
+ List<String> permissions = new ArrayList<>();
|
|
|
+
|
|
|
+ // 检查是否缺少权限
|
|
|
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
|
|
+ permissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
|
|
|
+ }
|
|
|
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
|
|
+ permissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
|
|
|
+ }
|
|
|
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
|
|
+ permissions.add(Manifest.permission.CAMERA);
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ // 如果有权限未被授予,则申请权限
|
|
|
+ if (!permissions.isEmpty()) {
|
|
|
+ ActivityCompat.requestPermissions(this, permissions.toArray(new String[0]), PERMISSION_REQUEST_CODE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onCreate(Bundle savedInstanceState) {
|
|
|
+ super.onCreate(savedInstanceState);
|
|
|
+ setContentView(R.layout.takephoto);
|
|
|
+ requestPermissions();
|
|
|
+
|
|
|
+ String paramsLast = getIntent().getStringExtra("params");
|
|
|
+ if (!TextUtils.isEmpty(paramsLast)){
|
|
|
+ params = paramsLast;
|
|
|
+ }else {
|
|
|
+ ToastUtil.show("参数丢失,请重试");
|
|
|
+ finish();
|
|
|
+ }
|
|
|
+
|
|
|
+ tvFBL=findViewById(R.id.tvFBL);
|
|
|
+ //tvFBL.setVisibility(View.GONE);
|
|
|
+ imgtest=findViewById(R.id.imgtest);
|
|
|
+ imgtest.setVisibility(View.GONE);
|
|
|
+
|
|
|
+ ivGreen = findViewById(R.id.iv_green); //绿色脸部轮廓
|
|
|
+ ivRed = findViewById(R.id.iv_red); //红色轮廓
|
|
|
+ tvResult = findViewById(R.id.tv_result); //人脸合规识别结果
|
|
|
+
|
|
|
+ layoutButton = findViewById(R.id.layout_button);
|
|
|
+ btnOK=(ImageView)findViewById(R.id.btnOK); //拍摄按钮
|
|
|
+ btnClose=(ImageView)findViewById(R.id.btnClose);
|
|
|
+ textureView = findViewById(R.id.textureView);
|
|
|
+ textureView.setSurfaceTextureListener(textureListener);
|
|
|
+ DisplayMetrics displayMetrics = new DisplayMetrics();
|
|
|
+ WindowManager windowManager = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
|
|
|
+ windowManager.getDefaultDisplay().getMetrics(displayMetrics);
|
|
|
+ screenWidth = displayMetrics.widthPixels;
|
|
|
+
|
|
|
+ // 初始化 CameraManager
|
|
|
+ cameraManager = (CameraManager) getSystemService(CAMERA_SERVICE);
|
|
|
+ try {
|
|
|
+ cameraIdList = cameraManager.getCameraIdList();
|
|
|
+ } catch (CameraAccessException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+
|
|
|
+ //是否合规时自动拍照
|
|
|
+ boolean autoPhoto = SharedPreferencesUtils.getInstance().getValue("autoPhoto", false);
|
|
|
+ if (autoPhoto) {
|
|
|
+ btnOK.setVisibility(View.GONE);
|
|
|
+ }
|
|
|
+
|
|
|
+ btn_changeFront = findViewById(R.id.btn_changeFront);
|
|
|
+ btn_changeFront.setOnClickListener(new OnClickListener() {
|
|
|
+ @Override
|
|
|
+ public void onClick(View view) {
|
|
|
+ if (isDoubleClick())
|
|
|
+ return;
|
|
|
+ switchCamera();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ // 关闭
|
|
|
+ btnClose.setOnClickListener(new View.OnClickListener() {
|
|
|
+
|
|
|
+ @Override
|
|
|
+ public void onClick(View v) {
|
|
|
+
|
|
|
+ //if(mBitmap!=null)
|
|
|
+ //mBitmap.recycle();
|
|
|
+
|
|
|
+ //Intent it=new Intent();
|
|
|
+ //setResult(RESULT_OK,it);
|
|
|
+ finish();
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ // 拍摄按钮
|
|
|
+ btnOK.setOnClickListener(new View.OnClickListener() {
|
|
|
+ @Override
|
|
|
+ public void onClick(View v) {
|
|
|
+ takePhoto();
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private final TextureView.SurfaceTextureListener textureListener = new TextureView.SurfaceTextureListener() {
|
|
|
+ @Override
|
|
|
+ public void onSurfaceTextureAvailable(@NonNull SurfaceTexture surface, int width, int height) {
|
|
|
+ mWidth=width;
|
|
|
+ mHeight=height;
|
|
|
+ openCamera(width, height);
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public void onSurfaceTextureSizeChanged(@NonNull SurfaceTexture surface, int width, int height) {
|
|
|
+ configureTransform(width, height);
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public boolean onSurfaceTextureDestroyed(@NonNull SurfaceTexture surface) {
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public void onSurfaceTextureUpdated(@NonNull SurfaceTexture surface) {
|
|
|
+ }
|
|
|
+ };
|
|
|
+ CameraCharacteristics characteristics;
|
|
|
+ private boolean isCameraOpened = false;
|
|
|
+ private void openCamera(int width, int height) {
|
|
|
+ if (isCameraOpened) {
|
|
|
+ Log.d("CameraDebug", "Camera is already opened");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ //创建sdk对象并初始化
|
|
|
+ if(face==null) {
|
|
|
+ face=new FaceQCEngine();
|
|
|
+ face.ModelInit();
|
|
|
+ }
|
|
|
+ isCameraOpened = true;
|
|
|
+ CameraManager manager = (CameraManager) getSystemService(CAMERA_SERVICE);
|
|
|
+ try {
|
|
|
+ cameraId = manager.getCameraIdList()[currentCameraIndex];
|
|
|
+ characteristics = manager.getCameraCharacteristics(cameraId);
|
|
|
+ StreamConfigurationMap map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
|
|
+
|
|
|
+ if (map != null) {
|
|
|
+ // 获取合适的预览尺寸
|
|
|
+ previewSize = chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class), width, height);
|
|
|
+ previewSize = new Size(DESIRED_PREVIEW_SIZE.getWidth(), DESIRED_PREVIEW_SIZE.getHeight());
|
|
|
+// imageReader = ImageReader.newInstance(width, height,
|
|
|
+// ImageFormat.YUV_420_888, 2); // 设置最大图像缓冲区数量
|
|
|
+ imageReader = ImageReader.newInstance(previewSize.getWidth(), previewSize.getHeight(),
|
|
|
+ ImageFormat.YUV_420_888, 2); // 设置最大图像缓冲区数量
|
|
|
+ tvFBL.setText("预览分辨率:"+previewSize.getWidth()+"*"+previewSize.getHeight());
|
|
|
+ Log.e("test", "预览分辨率:"+previewSize.getWidth()+"*"+previewSize.getHeight());
|
|
|
+ imageReader.setOnImageAvailableListener(this::onImageAvailable, null);
|
|
|
+
|
|
|
+ configureTransform(width, height);
|
|
|
+ }
|
|
|
+
|
|
|
+ if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
|
|
|
+ ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.CAMERA}, CAMERA_PERMISSION_REQUEST_CODE);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ manager.openCamera(cameraId, stateCallback, null);
|
|
|
+
|
|
|
+ } catch (CameraAccessException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //旋转bitmap
|
|
|
+ private Bitmap rotateBitmap(Bitmap bitmap, int degrees) {
|
|
|
+ Matrix matrix = new Matrix();
|
|
|
+ matrix.postRotate(degrees);
|
|
|
+ return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
|
|
+ }
|
|
|
+
|
|
|
+ private final CameraDevice.StateCallback stateCallback = new CameraDevice.StateCallback() {
|
|
|
+ @Override
|
|
|
+ public void onOpened(@NonNull CameraDevice camera) {
|
|
|
+ cameraDevice = camera;
|
|
|
+ createCameraPreview();
|
|
|
+ configureTransform(textureView.getWidth(), textureView.getHeight());
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public void onDisconnected(@NonNull CameraDevice camera) {
|
|
|
+ cameraDevice.close();
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public void onError(@NonNull CameraDevice camera, int error) {
|
|
|
+ cameraDevice.close();
|
|
|
+ cameraDevice = null;
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 创建相机预览
|
|
|
+ */
|
|
|
+ private void createCameraPreview() {
|
|
|
+ try {
|
|
|
+ SurfaceTexture texture = textureView.getSurfaceTexture();
|
|
|
+ assert texture != null;
|
|
|
+
|
|
|
+ texture.setDefaultBufferSize(previewSize.getWidth(), previewSize.getHeight());
|
|
|
+ Surface surface = new Surface(texture);
|
|
|
+ Log.e("test", "surface 分辨率:"+previewSize.getWidth()+"*"+previewSize.getHeight());
|
|
|
+
|
|
|
+ CaptureRequest.Builder builder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
|
|
+ builder.addTarget(surface);
|
|
|
+ // 设置自动对焦
|
|
|
+ builder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_AUTO);
|
|
|
+ //CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE);
|
|
|
+ builder.addTarget(imageReader.getSurface());
|
|
|
+
|
|
|
+ // 设置对焦区域,自动对焦会在这个区域进行
|
|
|
+ Rect focusArea = new Rect(100, 100, 500, 500); // 可以修改这个区域大小
|
|
|
+ builder.set(CaptureRequest.CONTROL_AF_REGIONS, new MeteringRectangle[]{new MeteringRectangle(focusArea, MeteringRectangle.METERING_WEIGHT_MAX)});
|
|
|
+ builder.set(CaptureRequest.CONTROL_AE_REGIONS, new MeteringRectangle[]{new MeteringRectangle(focusArea, MeteringRectangle.METERING_WEIGHT_MAX)});
|
|
|
+ int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
|
|
|
+ // 获取设备的旋转角度
|
|
|
+ int rotation = getWindowManager().getDefaultDisplay().getRotation();
|
|
|
+ // 计算拍照的方向
|
|
|
+ int jpegOrientation = (270+sensorOrientation + ORIENTATIONS.get(rotation)) % 360;
|
|
|
+
|
|
|
+ // 设置 JPEG 的方向
|
|
|
+ builder.set(CaptureRequest.JPEG_ORIENTATION, jpegOrientation);
|
|
|
+ cameraDevice.createCaptureSession(Arrays.asList(surface, imageReader.getSurface()), new CameraCaptureSession.StateCallback() {
|
|
|
+ @Override
|
|
|
+ public void onConfigured(@NonNull CameraCaptureSession session) {
|
|
|
+ captureSession = session;
|
|
|
+ try {
|
|
|
+ captureSession.setRepeatingRequest(builder.build(), null, null);
|
|
|
+ } catch (CameraAccessException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ @Override
|
|
|
+ public void onConfigureFailed(@NonNull CameraCaptureSession session) {
|
|
|
+ ToastUtil.show("Camera configuration failed");
|
|
|
+ }
|
|
|
+ }, null);
|
|
|
+
|
|
|
+ } catch (CameraAccessException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ //获取预览画面大小
|
|
|
+ private Size chooseOptimalSize(Size[] choices, int width, int height) {
|
|
|
+ final double ASPECT_TOLERANCE = 0.1;
|
|
|
+ double targetRatio = (double) height / width;
|
|
|
+
|
|
|
+ if (choices == null) return null;
|
|
|
+
|
|
|
+ Size optimalSize = null;
|
|
|
+ double minDiff = Double.MAX_VALUE;
|
|
|
+
|
|
|
+ int targetHeight = height;
|
|
|
+
|
|
|
+ for (Size size : choices) {
|
|
|
+ double ratio = (double) size.getWidth() / size.getHeight();
|
|
|
+ if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) continue;
|
|
|
+ if (Math.abs(size.getHeight() - targetHeight) < minDiff) {
|
|
|
+ optimalSize = size;
|
|
|
+ minDiff = Math.abs(size.getHeight() - targetHeight);
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (optimalSize == null) {
|
|
|
+ minDiff = Double.MAX_VALUE;
|
|
|
+ for (Size size : choices) {
|
|
|
+ if (Math.abs(size.getHeight() - targetHeight) < minDiff) {
|
|
|
+ optimalSize = size;
|
|
|
+ minDiff = Math.abs(size.getHeight() - targetHeight);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return optimalSize;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 设置输出画面缩放适配
|
|
|
+ *
|
|
|
+ * @param viewWidth mTextureView 的宽度
|
|
|
+ * @param viewHeight mTextureView 的高度
|
|
|
+ */
|
|
|
+ private void configureTransform(int viewWidth, int viewHeight) {
|
|
|
+
|
|
|
+ //屏幕方向
|
|
|
+ //int rotation = windowManager.getDefaultDisplay().getRotation();
|
|
|
+ final Matrix matrix = new Matrix();
|
|
|
+ RectF viewRect = new RectF(0, 0, viewWidth, viewHeight);
|
|
|
+ RectF bufferRect = new RectF(0, 0, previewSize.getHeight(), previewSize.getWidth());
|
|
|
+ float centerX = viewRect.centerX();
|
|
|
+ float centerY = viewRect.centerY();
|
|
|
+ //相机宽度小于界面高度时,使用矩阵缩放适配
|
|
|
+ if (previewSize.getWidth() < viewHeight) {
|
|
|
+
|
|
|
+ bufferRect.offset(centerX - bufferRect.centerX(), centerY - bufferRect.centerY());
|
|
|
+ matrix.setRectToRect(viewRect, bufferRect, Matrix.ScaleToFit.FILL);
|
|
|
+ float scale = Math.max((float) viewHeight / previewSize.getWidth(), (float) viewWidth / previewSize.getHeight());
|
|
|
+ //设置缩放
|
|
|
+ matrix.postScale(scale, scale, centerX, centerY);
|
|
|
+ //设置旋转角度
|
|
|
+ //matrix.postRotate(90 * (rotation - 2), centerX, centerY);
|
|
|
+ } else {
|
|
|
+
|
|
|
+ }
|
|
|
+ textureView.post(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ textureView.setTransform(matrix);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ private void closeCamera() {
|
|
|
+ if (cameraDevice != null) {
|
|
|
+ cameraDevice.close();
|
|
|
+ cameraDevice = null;
|
|
|
+ }
|
|
|
+ isCameraOpened=false;
|
|
|
+ }
|
|
|
+ private void switchCamera() {
|
|
|
+ if(currentCameraIndex==0) {
|
|
|
+ currentCameraIndex = 1;
|
|
|
+ }else {
|
|
|
+ currentCameraIndex = 0;
|
|
|
+ }
|
|
|
+ //currentCameraIndex = (currentCameraIndex + 1) % cameraIdList.length;
|
|
|
+ closeCamera();
|
|
|
+
|
|
|
+ //openCamera(textureView.getWidth(), textureView.getHeight());
|
|
|
+ openCamera(DESIRED_PREVIEW_SIZE.getWidth(), DESIRED_PREVIEW_SIZE.getHeight());
|
|
|
+
|
|
|
+ }
|
|
|
+ // 拍照方法
|
|
|
+ private void takePhoto() {
|
|
|
+ if(showmsg.equals("请保持当前位置拍照") || showmsg.equals("请保持当前位置")) {
|
|
|
+ bPZClick = true; //可以进行拍照
|
|
|
+ }else {
|
|
|
+ runOnUiThread(() -> ToastUtil.show("请调整好位置再进行拍照"));
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 释放相机资源
|
|
|
+ */
|
|
|
+ private void releaseCameraResources() {
|
|
|
+ try {
|
|
|
+ if (captureSession != null) {
|
|
|
+ captureSession.stopRepeating();
|
|
|
+ captureSession.abortCaptures();
|
|
|
+ captureSession.close();
|
|
|
+ captureSession = null;
|
|
|
+ if (cameraDevice != null) {
|
|
|
+ cameraDevice.close();
|
|
|
+ cameraDevice = null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ int ncount=0;
|
|
|
+ Image image=null;
|
|
|
+ boolean bCanDetect=true; //是否可以进行照片处理
|
|
|
+ boolean bFinish =true; //true时代表可以处理照片,false时代表已经拍摄照片了,不用再处理了
|
|
|
+ private ExecutorService imageProcessingExecutor = Executors.newSingleThreadExecutor();
|
|
|
+ Bitmap rotatedBitmap=null;
|
|
|
+ long currentTime = 0, imgTime = 0;
|
|
|
+
|
|
|
+ // 预览回调, 可获取预览图像
|
|
|
+ private void onImageAvailable(ImageReader reader) {
|
|
|
+
|
|
|
+ //图像获取间隔200毫秒,防止太快 处理速度跟不上
|
|
|
+ if (System.currentTimeMillis() - currentTime < 200) {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ currentTime = System.currentTimeMillis();
|
|
|
+ Log.e("test","次数:"+ncount++);
|
|
|
+
|
|
|
+ try {
|
|
|
+ //已获取图像为空时,去获取最新的图像;不为空时,且2秒都没获取过新图像,就将其释放掉
|
|
|
+ if (image == null) {
|
|
|
+ imgTime = System.currentTimeMillis();
|
|
|
+ // 获取最新图像
|
|
|
+ image = reader.acquireLatestImage();
|
|
|
+ //使用线程池 处理图像
|
|
|
+ imageProcessingExecutor.submit(() -> processImage());
|
|
|
+ }else {
|
|
|
+ if (System.currentTimeMillis() - imgTime > 2000) {
|
|
|
+ if (image != null) {
|
|
|
+ image.close(); // 确保释放图像资源
|
|
|
+ image=null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ runOnUiThread(() -> ToastUtil.show("异常 " + e.getMessage()));
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+ String fileName="",filePathName="";
|
|
|
+ int rotateWidth, rotateHeight, screenW, screenH, faceBottom, faceWidth, faceHeight, faceX, faceY;
|
|
|
+ private void processImage() {
|
|
|
+ // 在后台线程处理图像
|
|
|
+ try {
|
|
|
+ if(bFinish)
|
|
|
+ if (image != null&& (bCanDetect||bPZClick)) {
|
|
|
+ // bCanDetect:控制每次只处理一个图像;或者点了拍照了,也继续进行处理
|
|
|
+ bCanDetect = false;
|
|
|
+ if (bPZClick) { //点了拍照以后,后续的都不再处理
|
|
|
+ bFinish = false;
|
|
|
+ }
|
|
|
+
|
|
|
+ int imageWidth = image.getWidth();
|
|
|
+ int imageHeight = image.getHeight();
|
|
|
+
|
|
|
+
|
|
|
+ byte[] data68 = ImageUtil.getBytesFromImageAsType(image, 2);
|
|
|
+ int rgb[] = ImageUtil.decodeYUV420SP(data68, imageWidth, imageHeight);
|
|
|
+ Bitmap bitmap = Bitmap.createBitmap(rgb, 0, imageWidth,
|
|
|
+ imageWidth, imageHeight,
|
|
|
+ Bitmap.Config.ARGB_8888);
|
|
|
+
|
|
|
+
|
|
|
+ if (image != null) {
|
|
|
+ image.close(); // 确保释放图像资源
|
|
|
+ image = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ // 旋转Bitmap,确保显示方向正确
|
|
|
+ int degrees = 0;
|
|
|
+ if (currentCameraIndex == 0) {//后置摄像头
|
|
|
+ degrees = CameraUtil.getBackCameraDirection(getApplicationContext());
|
|
|
+ }else { //前置
|
|
|
+ degrees = CameraUtil.getFrontCameraDirection(getApplicationContext());
|
|
|
+ }
|
|
|
+ rotatedBitmap = rotateBitmap(bitmap, degrees);
|
|
|
+ if (bitmap != null) {
|
|
|
+ bitmap.recycle();
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ byte[] imageData = getPixelsRGBA(rotatedBitmap);
|
|
|
+ //tvmsg.setText("正在检测...");
|
|
|
+ List<ReturnData> returndata=null;
|
|
|
+
|
|
|
+ if(face != null) {
|
|
|
+ if(!bPZClick) { //不是拍照,只对图片检测是否合规
|
|
|
+ returndata = face.FaceQCDetect(imageData, rotatedBitmap.getWidth(), rotatedBitmap.getHeight(), 4, params, 0);
|
|
|
+ }else { //点了拍照后,对图片进行合规处理
|
|
|
+ returndata = face.FaceQCDetect(imageData, rotatedBitmap.getWidth(), rotatedBitmap.getHeight(), 4, params, 1);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //合规结果
|
|
|
+ if(returndata!=null) {
|
|
|
+ //returndata.get(0).getInfo() 获取合规结果描述
|
|
|
+ // 合规时,FaceQCDetect传入0时,只检测是否合规,返回结果为"请保持当前位置拍照";
|
|
|
+ // 传入1时,进行合规处理,返回结果为"合规"
|
|
|
+ showmsg=returndata.get(0).getInfo();
|
|
|
+ // runOnUiThread(() -> Toast.makeText(this, "检测结果: "+showmsg, Toast.LENGTH_SHORT).show());
|
|
|
+ Log.e("camera",showmsg);
|
|
|
+
|
|
|
+ if(showmsg.startsWith("请保持当前位置") || showmsg.equals("合规")) {
|
|
|
+ updateSurface();
|
|
|
+ }else {
|
|
|
+ updateSurface();
|
|
|
+ bCanDetect=true; //不合规,设置为可继续进行处理
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Bitmap bitmapnew=returndata.get(0).getBitmap(); //合规处理后的照片
|
|
|
+ if(bPZClick&&bitmapnew!=null) { //点了拍照,并且有合规处理完成的照片,即已经拍完了
|
|
|
+ bPZClick=false;
|
|
|
+ releaseCameraResources(); //释放相机资源
|
|
|
+ if (imageReader != null) {
|
|
|
+ imageReader.close(); //释放图像捕捉类
|
|
|
+ imageReader = null;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ String name = String.valueOf(System.currentTimeMillis());
|
|
|
+ String tempfileName = name + ".jpg";
|
|
|
+ try{
|
|
|
+ fileName = tempfileName;
|
|
|
+ String filePath = Environment.getExternalStorageDirectory()+"/";
|
|
|
+ filePathName = getFilePathName(filePath, fileName);
|
|
|
+ byte[] imgData = getPixelsRGBA(bitmapnew);
|
|
|
+
|
|
|
+
|
|
|
+ //给合规图片加水印
|
|
|
+ byte[] bytes = face.EmbedSY(imgData, bitmapnew.getWidth(), bitmapnew.getHeight(), 4, params);
|
|
|
+
|
|
|
+ //将返回的字节数组数据 保存
|
|
|
+ if (bytes != null) {
|
|
|
+ SaveJpg(bytes,fileName,filePathName);
|
|
|
+ }else {
|
|
|
+ runOnUiThread(() -> ToastUtil.show("照片无法保存,请重试"));
|
|
|
+ }
|
|
|
+
|
|
|
+ //保存拍摄的原图
|
|
|
+ String name2 = String.valueOf(System.currentTimeMillis());
|
|
|
+ String fileName2 = name2 + ".jpg";
|
|
|
+ String filePathName2 = Environment.getExternalStorageDirectory()+"/"+fileName2;
|
|
|
+ SaveJpg(rotatedBitmap,fileName2,filePathName2); //拍照原图
|
|
|
+ //bitmap.recycle();
|
|
|
+
|
|
|
+ //将合规、加水印后的照片传回上一页面
|
|
|
+ Intent it=new Intent();
|
|
|
+ it.putExtra("resultName", fileName);
|
|
|
+ it.putExtra("resultPath", filePathName);
|
|
|
+ setResult(1001,it);
|
|
|
+ //关闭页面
|
|
|
+ handler.sendEmptyMessage(0);
|
|
|
+ //resultName=fileName;
|
|
|
+ //resultPath=filePathName;
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ runOnUiThread(() -> ToastUtil.show("异常: " + e.getMessage()));
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //bitmap.recycle();
|
|
|
+ bCanDetect=true; //一张图片的处理完,允许下一个照片进行处理
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ runOnUiThread(() -> ToastUtil.show("异常: " + e.getMessage()));
|
|
|
+ } finally {
|
|
|
+ if (image != null) {
|
|
|
+ image.close(); // 确保释放图像资源
|
|
|
+ image=null;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据文件夹路径、文件名称,返回文件保存路径(文件夹路径+名称)
|
|
|
+ * 当系统版本为Android Q及以上时,将获取系统保存路径并返回
|
|
|
+ */
|
|
|
+ public String getFilePathName(String filePath, String fileName) {
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
|
+ // 分区存储模式
|
|
|
+ ContentValues values = new ContentValues();
|
|
|
+ values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
|
|
|
+ values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
|
|
|
+ values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
|
|
|
+
|
|
|
+ Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
|
|
+ if (uri != null) {
|
|
|
+ return getRealPathFromURI(uri);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ File file = new File(filePath, fileName);
|
|
|
+ return file.getPath();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 将bitmap保存到指定路径下
|
|
|
+ * 若Android系统版本在Q及以上,会使用分区存储模式,获取相应的系统保存路径并返回
|
|
|
+ * @param bitmap bitmap对象
|
|
|
+ * @param fileName 文件名称
|
|
|
+ * @param filePathName 文件保存路径 (Android Q以下时使用)
|
|
|
+ * @return 文件保存路径(Android Q及以上时 会和传入的路径不一致)
|
|
|
+ */
|
|
|
+ public String SaveJpg(Bitmap bitmap ,String fileName,String filePathName) {
|
|
|
+ try {
|
|
|
+ File file = new File(filePathName);
|
|
|
+ OutputStream out = null;
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
|
+ // 分区存储模式
|
|
|
+ ContentValues values = new ContentValues();
|
|
|
+ values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
|
|
|
+ values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
|
|
|
+ values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
|
|
|
+
|
|
|
+ Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
|
|
+ if (uri != null) {
|
|
|
+ out = getContentResolver().openOutputStream(uri);
|
|
|
+ filePathName = getRealPathFromURI(uri);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ out = new FileOutputStream(file);
|
|
|
+ }
|
|
|
+ bitmap.compress(Bitmap.CompressFormat.JPEG, 80, out);
|
|
|
+ out.flush();
|
|
|
+ out.close();
|
|
|
+ return filePathName;
|
|
|
+ } catch (FileNotFoundException fileNotFoundException) {
|
|
|
+ fileNotFoundException.printStackTrace();
|
|
|
+ } catch (IOException ioException) {
|
|
|
+ ioException.printStackTrace();
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 将图片的字节数组数据保存到指定路径下
|
|
|
+ * 若Android系统版本在Q及以上,会使用分区存储模式,获取相应的系统保存路径并返回
|
|
|
+ * @param bytes 图片的字节数组数据
|
|
|
+ * @param fileName 文件名称
|
|
|
+ * @param filePathName 文件保存路径 (Android Q以下时使用)
|
|
|
+ * @return 文件保存路径(Android Q及以上时 会和传入的路径不一致)
|
|
|
+ */
|
|
|
+ public String SaveJpg(byte[] bytes,String fileName,String filePathName) {
|
|
|
+ try {
|
|
|
+ File file = new File(filePathName);
|
|
|
+ OutputStream out = null;
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
|
|
+ // 分区存储模式
|
|
|
+ ContentValues values = new ContentValues();
|
|
|
+ values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName);
|
|
|
+ values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpg");
|
|
|
+ values.put(MediaStore.Images.Media.RELATIVE_PATH, Environment.DIRECTORY_PICTURES);
|
|
|
+
|
|
|
+ Uri uri = getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
|
|
+ if (uri != null) {
|
|
|
+ out = getContentResolver().openOutputStream(uri);
|
|
|
+ filePathName = getRealPathFromURI(uri);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ out = new FileOutputStream(file);
|
|
|
+ }
|
|
|
+ out.write(bytes);
|
|
|
+ out.flush();
|
|
|
+ out.close();
|
|
|
+ return filePathName;
|
|
|
+ } catch (FileNotFoundException fileNotFoundException) {
|
|
|
+ fileNotFoundException.printStackTrace();
|
|
|
+ } catch (IOException ioException) {
|
|
|
+ ioException.printStackTrace();
|
|
|
+ }
|
|
|
+ return "";
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 从uri中,获取文件保存路径
|
|
|
+ */
|
|
|
+ private String getRealPathFromURI(Uri contentUri) {
|
|
|
+ String[] projection = {MediaStore.Images.Media.DATA};
|
|
|
+ Cursor cursor = getContentResolver().query(contentUri, projection, null, null, null);
|
|
|
+ if (cursor != null) {
|
|
|
+ int columnIndex = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
|
|
|
+ cursor.moveToFirst();
|
|
|
+ String path = cursor.getString(columnIndex);
|
|
|
+ cursor.close();
|
|
|
+ return path;
|
|
|
+ }
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 初始化并获取预览回调对象
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+// private CameraCaptureSession.CaptureCallback getPreviewCallback (){
|
|
|
+// if(previewCallback == null){
|
|
|
+// previewCallback = new CameraCaptureSession.CaptureCallback(){
|
|
|
+// public void onCaptureCompleted(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull TotalCaptureResult result) {
|
|
|
+// }
|
|
|
+// };
|
|
|
+// }
|
|
|
+// return previewCallback;
|
|
|
+// }
|
|
|
+
|
|
|
+ final Handler handler=new Handler() {
|
|
|
+ @Override
|
|
|
+ public void handleMessage(Message msg) {
|
|
|
+ if (msg.what == 0) {
|
|
|
+ Log.e("camera2","收到关闭消息");
|
|
|
+ btnClose.performClick();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+
|
|
|
+ public static int dp2px(Context context, float dipValue) {
|
|
|
+ final float scale = context.getResources().getDisplayMetrics().density;
|
|
|
+ return Math.round(dipValue * scale);
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 更新界面
|
|
|
+ */
|
|
|
+ private void updateSurface() {
|
|
|
+ runOnUiThread(new Runnable() {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ if (!TextUtils.isEmpty(showmsg)) {
|
|
|
+ if (showmsg.startsWith("请保持当前位置")|| showmsg.equals("合规")) {
|
|
|
+ //绿色脸部轮廓
|
|
|
+ ivGreen.setVisibility(View.VISIBLE);
|
|
|
+ ivRed.setVisibility(View.INVISIBLE);
|
|
|
+ } else {
|
|
|
+ //红色脸部轮廓
|
|
|
+ ivRed.setVisibility(View.VISIBLE);
|
|
|
+ ivGreen.setVisibility(View.INVISIBLE);
|
|
|
+ }
|
|
|
+ tvResult.setText(showmsg);
|
|
|
+ tvResult.setVisibility(View.VISIBLE);
|
|
|
+ }else {
|
|
|
+ tvResult.setVisibility(View.INVISIBLE);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ });
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onResume() {
|
|
|
+ super.onResume();
|
|
|
+ openCamera(DESIRED_PREVIEW_SIZE.getWidth(), DESIRED_PREVIEW_SIZE.getHeight());
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onStop() {
|
|
|
+ super.onStop();
|
|
|
+ closeCamera();
|
|
|
+ releaseCameraResources();
|
|
|
+ }
|
|
|
+
|
|
|
+ @Override
|
|
|
+ protected void onDestroy() {
|
|
|
+ super.onDestroy();
|
|
|
+ //face.ModelUnInit();
|
|
|
+ releaseCameraResources();
|
|
|
+ if(face!=null) {
|
|
|
+ face.ModelUnInit();
|
|
|
+ face=null;
|
|
|
+ }
|
|
|
+ if (cameraDevice != null) {
|
|
|
+ cameraDevice.close();
|
|
|
+ cameraDevice = null;
|
|
|
+ }
|
|
|
+ if (imageReader != null) {
|
|
|
+ imageReader.close();
|
|
|
+ imageReader = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ }
|
|
|
+}
|