import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Rect;
import android.hardware.Camera;
import android.os.AsyncTask;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import com.example.toso.utils.L;
import java.io.IOException;
import java.util.List;
public class CameraSurfaceView extends SurfaceView implements SurfaceHolder.Callback, Camera.PreviewCallback {
private final static String TAG = "SurfaceView";
private SurfaceHolder surfaceHolder;
private int mCameraIndex = 0;
private Camera mCamera;
private int mRotatePre = 0;
private int mRotatePic = 0;
private int mWidth = 0;
private int mHeight = 0;
private Context context;
private onPreviewChangedListener mOnPreviewChangedListener = null;
public static final int DEFAULT_CAMERA_IMAGE_WIDTH = 320;
public static final int DEFAULT_CAMERA_IMAGE_HEIGHT = 240;
public static final int DEFAULT_CAMERA_IMAGE_ROTATE = 90;
public static final int DEFAULT_CAMERA_PRE_ROTATE = 270;
private NV21ToBitmap nv21ToBitmap;
public CameraSurfaceView(Context context, AttributeSet attrs) {
super(context, attrs);
}
// /**
// * 打开 cameraId = 1 的摄像头
// * 预览画面默认是横屏的,需要旋转90度
// */
// public void openCamera() {
//
// openCamera(1, DEFAULT_CAMERA_PRE_ROTATE,
// DEFAULT_CAMERA_IMAGE_ROTATE, DEFAULT_CAMERA_IMAGE_WIDTH, DEFAULT_CAMERA_IMAGE_HEIGHT);
//
// }
/**
* 打开摄像头
*
* @param cameraId 摄像头序号
* @param rotatePre 预览画面旋转角度
* @param rotatePic 获取到的图片旋转角度
* @param cameraImageWidth 图像preview宽度
* @param cameraImageHeight 图像preview高度
*/
public void openCamera(Context context, int cameraId, int rotatePre, int rotatePic, int cameraImageWidth, int cameraImageHeight) {
this.context = context;
Log.d(TAG, "开始 打开摄像头--------");
int mNumberOfCameras = Camera.getNumberOfCameras();
Log.d(TAG, " mNumberOfCameras: " + mNumberOfCameras);
if (mNumberOfCameras > cameraId) {
initCameraView(cameraId, rotatePre, rotatePic, cameraImageWidth, cameraImageHeight);
}
}
/**
* 打印支持的previewSizes
*
* @param params
*/
public void printSupportPreviewSize(Camera.Parameters params) {
List<Camera.Size> previewSizes = params.getSupportedPreviewSizes();
for (int i = 0; i < previewSizes.size(); i++) {
Camera.Size size = previewSizes.get(i);
Log.i("bhyf", "----- previewSizes:width = " + size.width + " height = " + size.height);
}
}
/**
* 打印支持的pictureSizes
*
* @param params
*/
public void printSupportPictureSize(Camera.Parameters params) {
List<Camera.Size> pictureSizes = params.getSupportedPictureSizes();
for (int i = 0; i < pictureSizes.size(); i++) {
Camera.Size size = pictureSizes.get(i);
Log.i("bhyf", " ======= pictureSizes:width = " + size.width + " height = " + size.height);
}
}
/**
* @param cameraIndex 摄像头序号
* @param rotatePre 预览画面旋转角度
* @param rotatePic 获取到的图片旋转角度
* @param width 图像preview宽度
* @param height 图像preview高度
*/
private void initCameraView(int cameraIndex, int rotatePre, int rotatePic, int width, int height) {
surfaceHolder = this.getHolder();
surfaceHolder.addCallback(this);
mCameraIndex = cameraIndex;
mRotatePre = rotatePre;
mRotatePic = rotatePic;
mWidth = width;
mHeight = height;
nv21ToBitmap = new NV21ToBitmap(context);
Log.d(TAG, " initCameraView()");
}
private boolean isGetImage = true; //true: 获取图片 false:不获取图片
public void setGetImage(boolean getImage) {
isGetImage = getImage;
}
/**
* 初始化SurfaceView时调用一次,另外更改surface或者onpause->onresume时调用
*/
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
Log.d(TAG, "CameraView surfaceChanged()");
if (mCamera != null) {
Camera.Parameters parameters = mCamera.getParameters();
// 选择合适的图片尺寸,必须是手机支持的尺寸
printSupportPreviewSize(parameters);
printSupportPictureSize(parameters);
/*
List<Camera.Size> sizeList = parameters.getSupportedPictureSizes();
// 如果sizeList只有一个我们也没有必要做什么了,因为就他一个别无选择
if (sizeList.size() > 1) {
int w = 0;
int h = 0;
for (int j = 0; j < sizeList.size(); j++) {
Camera.Size size = sizeList.get(j);
w = size.width;
h = size.height;
Log.i(TAG,"w:" + w + " h:" + h);
}
}
*/
//设置照片的大小
Log.d(TAG, "setPictureSize mWidth:" + mWidth + " mHeight:" + mHeight);
parameters.setPreviewSize(mWidth, mHeight);
parameters.setPictureSize(mWidth, mHeight);
// List<int[]> range=parameters.getSupportedPreviewFpsRange();
// L.i( "Fps range:"+range.size());
// for(int j=0;j < range.size() ; j++){
// int[] r=range.get(j);
// for (int i = 0; i < r.length; i++) {
// L.i( TAG+r[i]);
// }
// }
// parameters.setPreviewFrameRate(15);
parameters.setPreviewFpsRange(20 * 1000, 30 * 1000);
try {
mCamera.setParameters(parameters);
} catch (RuntimeException ex) {
ex.printStackTrace();
}
try {
mCamera.setPreviewDisplay(holder);
mCamera.setPreviewCallback(this);
} catch (IOException e) {
e.printStackTrace();
}
//调用相机预览功能
mCamera.startPreview();
Log.d(TAG, "mCamera.startPreview() 调用相机预览功能");
}
}
@Override
public void surfaceCreated(SurfaceHolder holder) {
Log.d(TAG, "CameraView surfaceCreated()");
if (null == mCamera) {
//Camera.open()方法说明:2.3以后支持多摄像头,所以开启前可以通过getNumberOfCameras先获取摄像头数目,
// 再通过 getCameraInfo得到需要开启的摄像头id,然后传入Open函数开启摄像头,
// 假如摄像头开启成功则返回一个Camera对象
try {
mCamera = Camera.open(mCameraIndex);
//预览画面默认是横屏的,需要旋转90度
mCamera.setDisplayOrientation(mRotatePre);
} catch (Exception e) {
}
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
Log.d(TAG, "CameraView surfaceDestroyed()");
isRunning = false;
if (null != mCamera) {
try {
mCamera.setPreviewDisplay(null);
mCamera.setPreviewCallback(null);
} catch (IOException e) {
e.printStackTrace();
}
//停止预览
mCamera.stopPreview();
//释放相机资源
mCamera.release();
mCamera = null;
}
}
int preCount = 0;
long preTime = 0;
boolean preFirst = true;
@Override
public void onPreviewFrame(final byte[] data, final Camera camera) {
boolean isPreview = true;
if (preFirst) {
preTime = System.currentTimeMillis();
preFirst = false;
}
long t = System.currentTimeMillis();
if (preCount != 0)
Log.d(TAG, "数据入堆 preCount: " + preCount + " ; all time = " + (t - preTime) + " ; 平均 : " + ((t - preTime) / preCount));
++preCount;
onPreviewChanged(data, isPreview);
}
public void setOnPreviewChangedListener(onPreviewChangedListener mPreviewChangedListener) {
this.mOnPreviewChangedListener = mPreviewChangedListener;
}
public interface onPreviewChangedListener {
void onPreviewChanged(Bitmap bitmap, long preTime);
void onOpenBack(boolean isPreview);
}
private static boolean isDisplay = false;
public void cameraResume() {
// TODO Auto-generated method stub
isDisplay = true;
if (faceDetectTask != null) {
faceDetectTask.setStop(false);
}
}
public void cameraPause() {
// TODO Auto-generated method stub
isDisplay = false;
if (faceDetectTask != null) {
faceDetectTask.setStop(true);
}
}
public void cameraDestroy() {
// TODO Auto-generated method stub
if (faceDetectTask != null) {
faceDetectTask.setStop(true);
faceDetectTask.cancel(true);
faceDetectTask = null;
}
}
public void onPreviewChanged(byte[] data, boolean isPreview) {
if (mOnPreviewChangedListener != null) {
mOnPreviewChangedListener.onOpenBack(isPreview);
}
if (isDisplay && isPreview && !isRunning) {
Log.i(TAG, "====onPreviewChanged() isDisplay:" + isDisplay);
Log.i(TAG, "====onPreviewChanged() isPreview:" + isPreview);
Log.i(TAG, "====onPreviewChanged() isRunning:" + isRunning);
startRecognizeUser(data);
} else {
if (faceDetectTask != null)
faceDetectTask.setData(data,++pre_data_version);
}
}
private boolean isRunning = false;
private FaceDetectTask faceDetectTask;
private int pre_data_version = 0;
public void startRecognizeUser(byte[] data) {
Log.d(TAG, "startRecognizeUser isRunning: " + isRunning);
if (!isRunning) {
isRunning = true;
Log.d(TAG, "startRecognizeUser isRunning: " + isRunning);
if (faceDetectTask != null) {
faceDetectTask.setStop(true);
faceDetectTask = null;
}
faceDetectTask = new FaceDetectTask();
faceDetectTask.setStop(false);
faceDetectTask.setData(data,++pre_data_version);
faceDetectTask.execute();
}
}
/**
* 定义一个类,让其继承AsyncTask这个类
*/
class FaceDetectTask extends AsyncTask<Void, Rect, Void> {
private boolean isStop = false;
private byte[] data;
private int data_version = 0;
private int history_data_version = 0;
public void setStop(boolean isStop) {
this.isStop = isStop;
}
public void setData(byte[] data,int data_version) {
Log.d(TAG, "FaceDetectTask setData data : " + data+" ; data_version: "+data_version);
this.data = data;
this.data_version = data_version;
}
@Override
protected Void doInBackground(Void... voids) {
Log.d(TAG, "doInBackground isStop : " + isStop);
Log.d(TAG, "doInBackground isRunning : " + isRunning);
while (!isStop && isRunning) {
// 用于判断是不是同一个data数据,
// 因为doInBackground里面处理data的速度比onPreviewFrame获取的data的速度更快,
// 就可能会导致doInBackground中对同一个data进行多次处理
if (data != null && history_data_version != data_version) {
history_data_version = data_version;
Log.d(TAG, "doInBackground 开始 获取图片 ");
long timeData2 = System.currentTimeMillis();
if (countData != 0)
L.i("图片获取间隔1 = " + (timeData2 - timeData1)+ " ; 平均 : " + ((timeData2 - preTime) / countData)
+ " ; timeData2: " + timeData2 + " ; timeData1 : " + timeData1
+ " ; countData: " + countData + " ; all time = " + (timeData2 - preTime) );
++countData;
timeData1 = System.currentTimeMillis();
long t1 = System.currentTimeMillis();
Bitmap bitmapCamera = nv21ToBitmap.nv21ToBgrBitmap(data, mWidth, mHeight);
long t3 = System.currentTimeMillis();
Log.i(TAG, "dealData 获取到的图片 转换过程时间2 总时间 --> " + (t3 - t1));
if (bitmapCamera != null) {
isGetImage = true;
Log.i(TAG, "doInBackground 完成图片获取 isGetImage : " + isGetImage);
// // TODO 获取到图片
// Message message = Message.obtain();
// message.what = 12341;
// message.obj = bitmapCamera;
// handler.sendMessage(message);
if (mOnPreviewChangedListener != null) {
mOnPreviewChangedListener.onPreviewChanged(bitmapCamera, preTime);
}
}
}
}
return null;
}
}
long timeData1 = 0;
int countData = 0;
Handler handler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 12341) {
Bitmap bitmap = (Bitmap) msg.obj;
if (mOnPreviewChangedListener != null) {
mOnPreviewChangedListener.onPreviewChanged(bitmap, preTime);
}
}
}
};
public class CameraActivity extends Activity {
private CameraSurfaceView surfaceView_word;
private Bitmap bgrBitmap;
// private HandlerThread mHandlerThread;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_ocr_test3);
surfaceView_word = (CameraSurfaceView) findViewById(R.id.surfaceView_word);
surfaceView_word.setOnPreviewChangedListener(wordCameraListener);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.doc_iamge);
bgrBitmap = BitmapUtil.imgToBgrBitmap(this, bitmap);
L.i(" bgrBitmap : "+bgrBitmap);
if (bgrBitmap != null) {
L.i("w = "+bgrBitmap.getWidth() +" ; h : "+bgrBitmap.getHeight());
}
openWordCamera();
}
/**
* 打开文档拍照摄像头
*/
private void openWordCamera() {
L.i("开始 打开文档拍照摄像头--------");
surfaceView_word.openCamera(this, 0, 90, 0, 3840, 2880);
}
/**
* 文档拍照图片返回
*/
CameraSurfaceView.onPreviewChangedListener wordCameraListener = new CameraSurfaceView.onPreviewChangedListener() {
@Override
public void onPreviewChanged(final Bitmap bitmap, final long time) {
L.i("CameraSurfaceViewWord onPreviewChanged bitmap : " + bitmap + " ; time: " + time);
preTime = time;
setBitmap(bitmap);
doPreviewBitmap();
}
@Override
public void onOpenBack(boolean isPreview) {
}
};
int count = 0;
long preTime = 0;
private Thread mThread = null;
private boolean isStop = false;
private boolean isDestroy = false;
private Bitmap bitmap;
public void setStop(boolean isStop) {
this.isStop = isStop;
}
public void setDestroy(boolean destroy) {
isDestroy = destroy;
}
public void setBitmap(Bitmap bitmap) {
this.bitmap = bitmap;
L.i("CameraSurfaceViewWord setBitmap bitmap = " + bitmap);
}
private Bitmap historyBitmap = null;
private void doPreviewBitmap() {
if (mThread == null) {
mThread = new Thread(new Runnable() {
@Override
public void run() {
while (!isDestroy) {
if (!isStop && bitmap != null) {
// 用于判断是不是同一个bitmap数据,
// 因为showImageDealAfter里面处理bitmap的速度比onPreviewFrame获取的bitmap的速度更快,
// 就可能会导致showImageDealAfter中对同一个bitmap进行多次处理
if (historyBitmap != bitmap) {
showImageDealAfter(bitmap);
historyBitmap = bitmap;
}
}
}
}
});
mThread.start();
}
}
private void showImageDealAfter(Bitmap bitmap) {
long t1 = System.currentTimeMillis();
//TODO 对图片进行处理
int result = DealImage.detectDoc(bitmap);
long t2 = System.currentTimeMillis();
long detectDocTime = t2 - t1;
long allTime = (System.currentTimeMillis() - preTime);
++count;
if (count != 0)
L.i(" result : " + result + " ; detectDocTime : " + detectDocTime + " ; count: " + count + " ; allTime = " + allTime + " ; 平均 : " + (allTime / count) + " bitmap w : " + bitmap.getWidth() + " ; h : " + bitmap.getHeight() + " ; bitmap : " + bitmap);
}
public void back(View view) {
finish();
}
@Override
protected void onResume() {
// TODO Auto-generated method stub
super.onResume();
if (surfaceView_word != null)
surfaceView_word.cameraResume();
setStop(false);
}
@Override
protected void onPause() {
// TODO Auto-generated method stub
super.onPause();
if (surfaceView_word != null)
surfaceView_word.cameraPause();
setStop(true);
}
@Override
protected void onDestroy() {
setDestroy(true);
setStop(true);
if (surfaceView_word != null)
surfaceView_word.cameraDestroy();
// 步骤5:结束线程,即停止线程的消息循环
// mHandlerThread.quit();
super.onDestroy();
}
}
import android.content.Context;
import android.graphics.Bitmap;
import android.renderscript.Allocation;
import android.renderscript.Element;
import android.renderscript.RenderScript;
import android.renderscript.ScriptIntrinsicYuvToRGB;
import android.renderscript.Type;
public class NV21ToBitmap {
private RenderScript rs;
private ScriptIntrinsicYuvToRGB yuvToRgbIntrinsic;
private Type.Builder yuvType, rgbaType;
private Allocation in, out;
public NV21ToBitmap(Context context) {
rs = RenderScript.create(context);
yuvToRgbIntrinsic = ScriptIntrinsicYuvToRGB.create(rs, Element.U8_4(rs));
}
public Bitmap nv21ToBgrBitmap(byte[] nv21, int width, int height){
if (yuvType == null){
yuvType = new Type.Builder(rs, Element.U8(rs)).setX(nv21.length);
in = Allocation.createTyped(rs, yuvType.create(), Allocation.USAGE_SCRIPT);
rgbaType = new Type.Builder(rs, Element.RGBA_8888(rs)).setX(width).setY(height);
out = Allocation.createTyped(rs, rgbaType.create(), Allocation.USAGE_SCRIPT);
}
in.copyFrom(nv21);
yuvToRgbIntrinsic.setInput(in);
yuvToRgbIntrinsic.forEach(out);
Bitmap bmpout = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
out.copyTo(bmpout);
return bmpout;
}
}