如果你受够了网上那些乱七八糟的代码,你可以了解下我这个,能同时打开多个摄像头,在界面上预览,并且可以取得摄像头数据,byte[] 转为 Bitmap,保存为 jpg图片。

最近我们的某个项目要加上Android人脸识别,虽然有别人写好的“考勤”、“门口闸机”这些,但不能直接用于我们的项目,我们有自己的业务需求。

我们机器有3个摄像头,在进行人脸识别的时候,3个摄像头都要处于工作状态;分别是:一个主摄像头本来就一直处于拍照检测中的,另外的双目摄像头,一个用于人脸检测,另一个是红外摄像头于用进行活体检测。

当我开始调整的时候,才发现原来用的“androidx.camera”并不能同时打开多个摄像头,然后我去了解 camera2,发现使用比较复杂,我的想法是,简单实用就好,并不要非常强大的各种功能,后来我再去了解"camera1",即 “android.hardware.Camera”,这个虽然现在被弃用了,但是还能用,而且我感觉这个比较好理解,基于它我实现了需求。

如果你想要快速获得摄像头数据(甚至不用在界面显示预览),像下面这样即可:

android.hardware.Camera mCamera;

android.graphics.SurfaceTexture mSurface;

/**

* 摄像头快速预览并取得数据

* 注意:mCamera和mSurface不要在本方法内定义

*/

private void startCamera() {

int cameraId = 0;

try {

// 打开相机

mCamera = Camera.open(cameraId);

// 设置图像尺寸

Camera.Parameters params = mCamera.getParameters();

params.setPreviewSize(640, 480);

mCamera.setParameters(params);

// 设置预览视图

mSurface = new SurfaceTexture(0);

mCamera.setPreviewTexture(mSurface);

// 设置图像数据回调

mCamera.setPreviewCallback(new Camera.PreviewCallback() {

@Override

public void onPreviewFrame(byte[] data, Camera camera) {

// 取得图像数据,每一帧图像都回调到这里,在这里做图像处理

// 该方法高频调用,用RXJava做流控,data转换为Bitmap或Mat等

}

});

// 开启预览

mCamera.startPreview();

} catch (Exception ignored) {

// 发生异常

}

}

下面是我摄像头的相关代码,有需求的朋友可参考:

package cn.example.test.facesdk.camera;

import android.graphics.SurfaceTexture;

import android.hardware.Camera;

import android.view.TextureView;

import java.io.IOException;

import java.util.List;

public class PreviewCamera {

private Camera mCamera;

private boolean mirror = false; // 镜像(左右翻转)

private int rotate = -1; // 旋转(相机传感器方向相对于设备自然方向的角度)

private int zoom = -1; // 焦距(有些摄像头可能不支持)

public void setMirror(boolean mirror) {

this.mirror = mirror;

}

public void setRotate(int rotate) {

this.rotate = rotate;

}

public void setZoom(int zoom) {

this.zoom = zoom;

}

public void startCamera(TextureView textureView, int cameraIndex, int width, int height, ICallback callback) {

stopCamera();

try {

mCamera = Camera.open(cameraIndex);

checkPreviewSize(width, height);

// 设置参数(尺寸、对焦、焦距、旋转)

Camera.Parameters params = mCamera.getParameters();

//List list = params.getSupportedPreviewFormats();

params.setPreviewSize(width, height);

List focusModes = params.getSupportedFocusModes();

if (focusModes.contains(Camera.Parameters.FOCUS_MODE_AUTO)) {

params.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);

}

if (this.zoom >= 0 && params.isZoomSupported() && this.zoom <= params.getMaxZoom()) {

params.setZoom(this.zoom);

mCamera.setParameters(params);

}

mCamera.setParameters(params);

if (this.rotate >= 0) {

mCamera.setDisplayOrientation(this.rotate);

}

// 预览初始化(左右翻转)

initPreview(textureView);

if (this.mirror) {

textureView.setRotationY(180);

}

// 回调

mCamera.setPreviewCallback(new Camera.PreviewCallback() {

@Override

public void onPreviewFrame(byte[] data, Camera camera) {

if (callback != null) {

callback.onData(data, camera);

}

}

});

if (callback != null) {

callback.onSucc(mCamera);

}

} catch (Exception e) {

e.printStackTrace();

if (callback != null) {

callback.onError(e);

}

}

}

public void stopCamera() {

try {

mCamera.setPreviewCallback(null);

mCamera.stopPreview();

mCamera.release();

mCamera = null;

} catch (Exception e) {

}

}

private void checkPreviewSize(int width, int height) throws Exception {

boolean sizeOk = false;

List sizeList = mCamera.getParameters().getSupportedPreviewSizes();

for (Camera.Size size : sizeList) {

if (size.width == width && size.height == height) {

sizeOk = true;

}

}

if (!sizeOk) {

throw new Exception(String.format("不支持该预览尺寸: [%d,%d]", width, height));

}

}

private TextureView initPreview(TextureView textureView) {

textureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {

@Override

public void onSurfaceTextureAvailable(SurfaceTexture surfaceTexture, int i, int i1) {

try {

if (mCamera != null) {

mCamera.setPreviewTexture(surfaceTexture);

mCamera.startPreview();

}

} catch (IOException e) {

e.printStackTrace();

}

}

@Override

public void onSurfaceTextureSizeChanged(SurfaceTexture surfaceTexture, int i, int i1) {

}

@Override

public boolean onSurfaceTextureDestroyed(SurfaceTexture surfaceTexture) {

stopCamera();

return false;

}

@Override

public void onSurfaceTextureUpdated(SurfaceTexture surfaceTexture) {

}

});

return textureView;

}

public interface ICallback {

void onSucc(Camera camera);

void onData(byte[] data, Camera camera);

void onError(Exception e);

}

}

上面代码直接放到你项目即可,使用也非常简单明了,如下:

package cn.example.test.Activity;

import android.graphics.Bitmap;

import android.hardware.Camera;

import android.os.Bundle;

import android.view.TextureView;

import cn.example.test.Activity.Base.BaseActivity;

import cn.example.test.R;

import cn.example.test.facesdk.camera.PreviewCamera;

import cn.example.test.facesdk.camera.PreviewCameraUtils;

public class MainActivity extends BaseActivity {

PreviewCamera previewCamera1 = new PreviewCamera();

@Override

protected void onCreate(Bundle savedInstanceState) {

super.onCreate(savedInstanceState);

setContentView(R.layout.activity_main);

}

@Override

protected void onResume() {

super.onResume();

start();

}

@Override

protected void onPause() {

super.onPause();

stop();

}

private void start() {

TextureView textureView1 = findViewById(R.id.camera_preview);

// 设置镜像(左右翻转)

previewCamera1.setMirror(false);

// 设置旋转角度

//previewCamera1.setRotate(90);

// 设置焦距

//previewCamera1.setZoom(50);

previewCamera1.startCamera(textureView1, 0, 640, 480, new PreviewCamera.ICallback() {

@Override

public void onData(byte[] data, Camera camera) {

dealData1(data, camera);

}

@Override

public void onSucc(Camera camera) {

}

@Override

public void onError(Exception e) {

}

});

}

private void stop() {

previewCamera1.stopCamera();

}

long lastTime1 = 0;

private void dealData1(byte[] data, Camera camera) {

// 控制下频率

long currTime = System.currentTimeMillis();

if (currTime - lastTime1 < 5000) {

return;

}

lastTime1 = currTime;

// 转换为Bitmpa

Bitmap bitmap = PreviewCameraUtils.cameraDataToBitmap(data, camera);

// 旋转&翻转

bitmap = PreviewCameraUtils.bitmapXform(bitmap, 270, false, true);

// 保存为jpg

String path = PreviewCameraUtils.getSDCardPath() + "/" + System.currentTimeMillis() + ".jpg";

PreviewCameraUtils.saveBitmapToFile(bitmap, path);

}

}

上面就是核心的代码,已经可以把摄像头使用起来了,下面放几个常用的帮助方法:

package cn.example.test.facesdk.camera;

import android.graphics.Bitmap;

import android.graphics.BitmapFactory;

import android.graphics.Matrix;

import android.graphics.Rect;

import android.graphics.YuvImage;

import android.hardware.Camera;

import android.os.Environment;

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.FileOutputStream;

import java.io.IOException;

public class PreviewCameraUtils {

public static Bitmap cameraDataToBitmap(byte[] data, Camera camera) {

Camera.Parameters parameters = camera.getParameters();

int width = parameters.getPreviewSize().width;

int height = parameters.getPreviewSize().height;

int format = parameters.getPreviewFormat();

Bitmap bitmap = yuvToBitmap(data, format, width, height);

return bitmap;

}

/**

* 摄像头数据转换为Bitmap

*

* @param data

* @param format

* @param width

* @param height

* @return

*/

public static Bitmap yuvToBitmap(byte[] data, int format, int width, int height) {

ByteArrayOutputStream out = new ByteArrayOutputStream();

YuvImage yuvImage = new YuvImage(data, format, width, height, null);

yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, out);

byte[] imageBytes = out.toByteArray();

return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);

}

/**

* Bitmap进行旋转和翻转

*

* @param bitmap

* @param rotate 旋转的角度

* @param leftRightTurn 是否左右翻转

* @param upDownTurn 是否上下翻转

* @return

*/

public static Bitmap bitmapXform(Bitmap bitmap, int rotate, boolean leftRightTurn, boolean upDownTurn) {

int width = bitmap.getWidth();

int height = bitmap.getHeight();

Matrix matrix = new Matrix();

if (leftRightTurn) {

matrix.preScale(-1f, 1f);

}

if (upDownTurn) {

matrix.preScale(1f, -1f);

}

if (rotate > 0) {

matrix.postRotate(rotate);

}

Bitmap rotatedBitmap = Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true);

return rotatedBitmap;

}

/**

* 把Bitmap保存为jpg文件

*

* @param bitmap

* @param filePath 绝对路径

*/

public static void saveBitmapToFile(Bitmap bitmap, String filePath) {

File file = new File(filePath);

try {

// 创建文件输出流

FileOutputStream outputStream = new FileOutputStream(file);

// 将bitmap写入输出流中

bitmap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);

// 刷新缓冲区

outputStream.flush();

// 关闭输出流

outputStream.close();

} catch (IOException e) {

e.printStackTrace();

}

}

/**

* 取得SDCard根路径

*

* @return

*/

public static String getSDCardPath() {

return "" + Environment.getExternalStorageDirectory();

}

}

另外,记得声明权限,示例:

android:name="android.hardware.camera.any"

android:required="true" />

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_DENIED) {

requestPermissions(new String[]{Manifest.permission.CAMERA}, CAMERA_PERMIS_CODE);

} else {

}

-------------------(完)-------------------

参考阅读

评论可见,请评论后查看内容,谢谢!!!
 您阅读本篇文章共花了: