如果你受够了网上那些乱七八糟的代码,你可以了解下我这个,能同时打开多个摄像头,在界面上预览,并且可以取得摄像头数据,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<Integer> list = params.getSupportedPreviewFormats();
params.setPreviewSize(width, height);
List<String> 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<Camera.Size> 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();
}
}
另外,记得声明权限,示例:文章来源:https://www.toymoban.com/news/detail-717283.html
<uses-feature
android:name="android.hardware.camera.any"
android:required="true" />
<uses-permission android:name="android.permission.CAMERA" />
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 {
}
-------------------(完)-------------------文章来源地址https://www.toymoban.com/news/detail-717283.html
到了这里,关于全网最简单实用Android摄像头开发,同时预览多个摄像头,双目摄像头,同时打开手机前后摄像头(红外摄像头、人脸识别、活体检测、Android Camera、缩放、焦距、旋转、镜像、截图保存)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!