Android使用Camera截取身份证号

主要是利用Camera的拍照,画了几个框,然后Bitmap的裁剪。自动对焦成功5次之后自动拍照,其中处理照片放在了UI线程, 大家做的时候可以放到后端处理更好。

大家可以看看官方文档tranning和api guide里面关于Camera这块的文章,还有apiDemos里面的CameraPreview.java。看完基本上就能做一个独立的摄像头app了。

package com.example.myapp;
/*
* Copyright (C) 2007 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.hardware.Camera;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.*;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import java.io.IOException;
import java.util.List;


// ----------------------------------------------------------------------

public class CameraPreview extends Activity implements Camera.PictureCallback {
private Preview mPreview;
Camera mCamera;
int numberOfCameras;
int cameraCurrentlyLocked;

// The first rear facing camera
int defaultCameraId;

private Handler handler;

private FrameLayout previewView;
private ImageView resultImageView;

public int previewWidth;
public int previewHeight;
public int cameraWidth;
public int cameraHeight;

public int autoFocusSuccessTimes;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

// Hide the window title.
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
setContentView(R.layout.main);
handler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
prepareCameraLayout();
}
};

previewView = (FrameLayout) findViewById(R.id.preview);
resultImageView = (ImageView) findViewById(R.id.result);
// Create a RelativeLayout container that will hold a SurfaceView,
// and set it as the content of our activity.
mPreview = new Preview(this);
mPreview.handler = this.handler;
previewView.addView(mPreview);
previewView.addView(new CardHintView(this));

// Find the total number of cameras available
numberOfCameras = Camera.getNumberOfCameras();

// Find the ID of the default camera
Camera.CameraInfo cameraInfo = new Camera.CameraInfo();
for (int i = 0; i < numberOfCameras; i++) {
Camera.getCameraInfo(i, cameraInfo);
if (cameraInfo.facing == Camera.CameraInfo.CAMERA_FACING_BACK) {
defaultCameraId = i;
}
}
handler.postDelayed(new Runnable() {
@Override
public void run() {
mCamera.autoFocus(autoFocusCallback);
}
}, 1000);// 每10毫秒连续聚焦
}


/**
* 聚焦事件内部类
*/
Camera.AutoFocusCallback autoFocusCallback = new Camera.AutoFocusCallback() {

@Override
public void onAutoFocus(boolean success, Camera camera) {//这里是连续聚焦算法

Log.i("Camera", "success:" + success);
if (success) {
autoFocusSuccessTimes++;
} else {
autoFocusSuccessTimes = 0;
}
if (autoFocusSuccessTimes > 4) {
Log.i("Camera", "auto focus 5 time");
autoFocusSuccessTimes = 0;
camera.takePicture(null, null, CameraPreview.this);
} else {
handler.postDelayed(new Runnable() {
@Override
public void run() {
mCamera.autoFocus(autoFocusCallback);
}
}, 10);// 每10毫秒连续聚焦
}
}
};

@Override
protected void onResume() {
super.onResume();

// Open the default i.e. the first rear facing camera.
mCamera = Camera.open();
cameraCurrentlyLocked = defaultCameraId;
mPreview.setCamera(mCamera);
}

@Override
protected void onPause() {
super.onPause();

// Because the Camera object is a shared resource, it's very
// important to release it when the activity is paused.
if (mCamera != null) {
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
}
}

public void prepareCameraLayout() {
RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) previewView.getLayoutParams();
layoutParams.width = cameraWidth;
layoutParams.height = cameraHeight;
previewView.setLayoutParams(layoutParams);
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {

// Inflate our menu which can gather user input for switching camera
MenuInflater inflater = getMenuInflater();
inflater.inflate(R.menu.camera_menu, menu);
return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle item selection
switch (item.getItemId()) {
case R.id.switch_cam:
// check for availability of multiple cameras
if (numberOfCameras == 1) {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Device has only one camera!")
.setNeutralButton("Close", null);
AlertDialog alert = builder.create();
alert.show();
return true;
}

// OK, we have multiple cameras.
// Release this camera -> cameraCurrentlyLocked
if (mCamera != null) {
mCamera.stopPreview();
mPreview.setCamera(null);
mCamera.release();
mCamera = null;
}

// Acquire the next camera and request Preview to reconfigure
// parameters.
mCamera = Camera
.open((cameraCurrentlyLocked + 1) % numberOfCameras);
cameraCurrentlyLocked = (cameraCurrentlyLocked + 1)
% numberOfCameras;
mPreview.switchCamera(mCamera);

// Start the preview
mCamera.startPreview();
return true;
default:
return super.onOptionsItemSelected(item);
}
}

@Override
public void onPictureTaken(byte[] data, Camera camera) {
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
int width = bitmap.getWidth();
int height = bitmap.getHeight();
int cardWidth = width * 8 / 10;
int cardHeight = (int) (cardWidth / 1.58f);
// canvas.drawRect((width - cardWidth) / 2 + cardWidth*4/13f, (height - cardHeight) / 2 + cardHeight * 10f/ 13 , (width - cardWidth) / 2 + cardWidth*12/13f, (height - cardHeight) / 2 + cardHeight*12/13 , paint);
// Bitmap noBitmap = bitmap.createBitmap(bitmap, (float)50 + cardWidth * 4f/13, (height - cardHeight) / 2f + cardHeight * 10f / 13, cardWidth * 8f / 13, cardHeight * 2f / 13);
Bitmap noBitmap = bitmap.createBitmap(bitmap, (int) ((width - cardWidth) / 2 + cardWidth * 4f / 13), (int) ((height - cardHeight) / 2f + cardHeight * 10f / 13), (int) (cardWidth * 8f / 13), (int) (cardHeight * 2f / 13));
resultImageView.setVisibility(View.VISIBLE);
previewView.setVisibility(View.GONE);
resultImageView.setImageBitmap(noBitmap);
}

@Override
public void onBackPressed() {

if (previewView.getVisibility() == View.GONE && resultImageView.getVisibility() == View.VISIBLE) {
previewView.setVisibility(View.VISIBLE);
resultImageView.setVisibility(View.GONE);
//restart camera
// OK, we have multiple cameras.
// Release this camera -> cameraCurrentlyLocked
if (mCamera != null) {
mCamera.startPreview();
handler.postDelayed(new Runnable() {
@Override
public void run() {
mCamera.autoFocus(autoFocusCallback);
}
}, 1000);// 每10毫秒连续聚焦
}
} else {
super.onBackPressed();
}
}
}

// ----------------------------------------------------------------------

/**
* A simple wrapper around a Camera and a SurfaceView that renders a centered preview of the Camera
* to the surface. We need to center the SurfaceView because not all devices have cameras that
* support preview sizes at the same aspect ratio as the device's display.
*/
class Preview extends ViewGroup implements SurfaceHolder.Callback {
private final String TAG = "Preview";

SurfaceView mSurfaceView;
SurfaceHolder mHolder;
Camera.Size mPreviewSize;
List<Camera.Size> mSupportedPreviewSizes;
Camera mCamera;
private CameraPreview activity;

public Handler handler;

Preview(Context context) {
super(context);
activity = (CameraPreview) context;
mSurfaceView = new SurfaceView(context);
addView(mSurfaceView);

// Install a SurfaceHolder.Callback so we get notified when the
// underlying surface is created and destroyed.
mHolder = mSurfaceView.getHolder();
mHolder.addCallback(this);
mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);
}

public void setCamera(Camera camera) {
mCamera = camera;
if (mCamera != null) {
mSupportedPreviewSizes = mCamera.getParameters().getSupportedPreviewSizes();
requestLayout();
}
}

public void switchCamera(Camera camera) {
setCamera(camera);
try {
camera.setPreviewDisplay(mHolder);
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
Camera.Parameters parameters = camera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();

camera.setParameters(parameters);
}

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// We purposely disregard child measurements because act as a
// wrapper to a SurfaceView that centers the camera preview instead
// of stretching it.
final int width = resolveSize(getSuggestedMinimumWidth(), widthMeasureSpec);
final int height = resolveSize(getSuggestedMinimumHeight(), heightMeasureSpec);
setMeasuredDimension(width, height);
Log.v(TAG, "preview width:" + width + ", height:" + height);
activity.previewWidth = width;
activity.previewHeight = height;

if (mSupportedPreviewSizes != null) {
mPreviewSize = getOptimalPreviewSize(mSupportedPreviewSizes, width, height);
}
Log.v(TAG, "camera width:" + mPreviewSize.width + ", height:" + mPreviewSize.height);
activity.cameraWidth = mPreviewSize.width;
activity.cameraHeight = mPreviewSize.height;
handler.sendEmptyMessageDelayed(0, 1000);
// activity.prepareCameraLayout();
}

@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (changed && getChildCount() > 0) {
final View child = getChildAt(0);

final int width = r - l;
final int height = b - t;

int previewWidth = width;
int previewHeight = height;
if (mPreviewSize != null) {
previewWidth = mPreviewSize.width;
previewHeight = mPreviewSize.height;
}

// Center the child SurfaceView within the parent.
if (width * previewHeight > height * previewWidth) {
final int scaledChildWidth = previewWidth * height / previewHeight;
child.layout((width - scaledChildWidth) / 2, 0,
(width + scaledChildWidth) / 2, height);
} else {
final int scaledChildHeight = previewHeight * width / previewWidth;
child.layout(0, (height - scaledChildHeight) / 2,
width, (height + scaledChildHeight) / 2);
}
}
}

public void surfaceCreated(SurfaceHolder holder) {
// The Surface has been created, acquire the camera and tell it where
// to draw.
try {
if (mCamera != null) {
mCamera.setPreviewDisplay(holder);
}
} catch (IOException exception) {
Log.e(TAG, "IOException caused by setPreviewDisplay()", exception);
}
}

public void surfaceDestroyed(SurfaceHolder holder) {
// Surface will be destroyed when we return, so stop the preview.
if (mCamera != null) {
mCamera.stopPreview();
}
}


private Camera.Size getOptimalPreviewSize(List<Camera.Size> sizes, int w, int h) {
final double ASPECT_TOLERANCE = 0.1;
double targetRatio = (double) w / h;
if (sizes == null) {
return null;
}

Camera.Size optimalSize = null;
double minDiff = Double.MAX_VALUE;

int targetHeight = h;

// Try to find an size match aspect ratio and size
for (Camera.Size size : sizes) {
double ratio = (double) size.width / size.height;
if (Math.abs(ratio - targetRatio) > ASPECT_TOLERANCE) {
continue;
}
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}

// Cannot find the one match the aspect ratio, ignore the requirement
if (optimalSize == null) {
minDiff = Double.MAX_VALUE;
for (Camera.Size size : sizes) {
if (Math.abs(size.height - targetHeight) < minDiff) {
optimalSize = size;
minDiff = Math.abs(size.height - targetHeight);
}
}
}
return optimalSize;
}

public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
// Now that the size is known, set up the camera parameters and begin
// the preview.
Camera.Parameters parameters = mCamera.getParameters();
parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);
parameters.setPictureSize(mPreviewSize.width, mPreviewSize.height);
requestLayout();

mCamera.setParameters(parameters);
mCamera.startPreview();
}

}

class CardHintView extends View {

private Paint paint = new Paint();

public CardHintView(Context context) {
super(context);

}

public CardHintView(Context context, AttributeSet attrs) {
super(context, attrs);

}

public CardHintView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);

}

@Override
protected void onDraw(Canvas canvas) {
int width = canvas.getWidth();
int height = canvas.getHeight();
// canvas.drawColor(0X60000000);
//
paint.setStyle(Paint.Style.STROKE);
int cardWidth = width * 8 / 10;
int cardHeight = (int) (cardWidth / 1.58f);
paint.setColor(0XFF00ccff);
paint.setStrokeWidth(4);
canvas.drawRect((width - cardWidth) / 2, (height - cardHeight) / 2, width - (width - cardWidth) / 2, height - (height - cardHeight) / 2, paint);

paint.setColor(0XFFFF0000);
canvas.drawRect((width - cardWidth) / 2 + cardWidth * 4 / 13f, (height - cardHeight) / 2 + cardHeight * 10f / 13, (width - cardWidth) / 2 + cardWidth * 12 / 13f, (height - cardHeight) / 2 + cardHeight * 12 / 13, paint);
invalidate();
}
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 使用 camera2 API 可以更加灵活、可定制和高效地完成 Android 相机应用开发,其相比 camera1 API 的性能有大幅提升。 在使用 camera2 API 完成预览和拍照前,需要进行以下几个步骤: 1. 获取 CameraManager 对象,查找可用的摄像头列表,并选择需要打开的摄像头。 2. 创建 CameraCaptureSession 对象,用于处理相机触发器的请求,并连接 CameraDevice 和 Surface。 3. 匹配预览和图片输出的 Surface,设置相应的尺寸和格式。 4. 创建 CaptureRequest 对象,设置相应的参数,如自动对焦模式、曝光模式等。 5. 使用 CameraCaptureSession 进行预览或拍照。 在预览时,可以使用 TextureView 或 SurfaceView 进行实时数据渲染,比如显示相机预览画面、拍照后处理和显示等,同时可以通过设置监听器动态获取相机输出的图像流数据。 在拍照时,需要创建 ImageReader 对象,设置输出数据的格式和尺寸,同时需要建立对应的 Surface,将其传入 CaptureRequest.Builder,设置请求类型并发起拍照请求。通过设置 ImageReader 的 OnImageAvailableListener 接口,即可接收到图片数据,并进行后续处理和保存。 以上是使用 camera2 API 完成预览和拍照的基本流程,实际开发中需要根据具体需求进行优化和调整。 ### 回答2: Android Camera2 API 是 Android 系统中相机功能的一种全新的 API,使用 Camera2 可以更灵活地操作相机设备并获得更高质量的照片。 使用 Camera2 实现预览非常简单,我们只需要实现一个 CameraDevice.StateCallback 接口实现类和一个 SurfaceView 主界面。在 StateCallback 的 onOpened 回调中获得 CameraDevice 的实例,然后通过 ImageReader 创建 SurfaceHolder,最后将 SurfaceHolder 通过 CameraDevice.createCaptureSession 接口跟 CameraDevice 进行绑定即可实现预览。 拍照的实现过程与预览类似,首先获得 CameraDevice 实例,然后创建一个 CaptureRequest.Builder 对象,将拍照设置参数通过 CaptureRequest.Builder.set 方法设置到 CaptureRequest.Builder 对象中,最后通过 CameraCaptureSession.capture 接口启动拍照操作即可。 当然,在使用 Camera2 API 进行操作相机时,还需要注意一些其他问题,比如不同的相机设备有不同的特性,需要针对不同的设备进行优化和适配,还需要保证应用的流畅性和稳定性,以达到更好的用户体验。 总之,使用 Camera2 API 实现预览和拍照是 Android 开发的一个重要技能,需要开发者深入了解该 API 的机制和使用方式,才能更好地实现优秀的相机应用。 ### 回答3: Android中的camera2是一种相机应用程序接口(API),旨在提高相机应用程序的功能和性能。相较于早期版本的camera API,camera2 API提供了更多的控制选项,允许开发者定制相机应用程序的功能,从而实现更好的用户体验。 使用camera2 API实现预览和拍照需要以下步骤: 1. 获取CameraManager对象。使用该对象可以获取系统中可用的相机列表,并在需要的时候打开指定相机。 2. 打开指定相机。调用CameraManager.openCamera()方法打开相机。 3. 创建CaptureSession。CaptureSession是与相机关联的一组输出Surface的集合。 4. 创建CaptureRequest。CaptureRequest是一个指定相机操作和设置的重要对象,可以通过它来设置各种模式、参数和目标Surface。 5. 创建Preview Request。处理预览界面。 6. 启动相机预览。启动前,可以使用CaptureRequest.Builder设置其他预览参数。 7. 拍照。当用户点击拍照按钮时,调用CaptureSession.capture()方法,即可拍照并接收回调。 8. 关闭相机。释放所有占用的资源,以便其他应用程序可以使用相机。 总之,在使用camera2 API实现预览和拍照时,需要使用许多类和方法。但只要开发者掌握了API中的基本概念和流程,就可以自由地使用该API,设计新型的相机应用程序,提供更好的功能和性能。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值