本篇博客其实跟OpenCV也没什么多大关系,因为是同一个项目,博客就顺溜着写了。
在自研设备开发过程中,在项目研发过程中碰到了双目摄像头双开(一个普通摄像头,一个红外摄像头)并获取当前帧的这么一个需求,我觉得有必要总结一下:
这边的demo使用的是两个Camera,本来想用两个OpenCV里的JavaCameraView,但结果并不如人意,可能还需要在康康OpenCV的源码,最终我项目中使用了JavaCameraView+Camera,如果后面研究有成,再来更新本博客
首先硬件上是必须要支持多开的,这样的话一般的手机估计是不能用来测试了,如果不支持请联系摄像头厂商和主板厂商,以下文件是必须要修改的:
当然我厂商回复我的截图长这样:
接下来就简单放一个预览demo好了:
新建一个camerademo项目,并做一下动态权限获取,我这边用的permissionsdispatcher:
GitHub:https://github.com/permissions-dispatcher/PermissionsDispatcher
接下来就是愉快的贴代码环节:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.zhb.camerademo">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.CAMERA"/>
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-feature
android:name="android.hardware.camera"
android:required="false" />
<uses-feature
android:name="android.hardware.camera.autofocus"
android:required="false" />
<uses-feature
android:name="android.hardware.camera.front"
android:required="false" />
<uses-feature
android:name="android.hardware.camera.front.autofocus"
android:required="false" />
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
配置build.gradle
apply plugin: 'com.android.application'
android {
compileSdkVersion 30
buildToolsVersion "30.0.0"
defaultConfig {
applicationId "com.zhb.camerademo"
minSdkVersion 23
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(dir: "libs", include: ["*.jar"])
implementation 'androidx.appcompat:appcompat:1.1.0'
implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0'
// Permission
implementation 'com.github.hotchemi:permissionsdispatcher:3.2.0'
annotationProcessor 'com.github.hotchemi:permissionsdispatcher-processor:3.2.0'
}
MainActivity
本来想通过takePicture()方法拍照获取,结果发现在双目摄像头下,能拍摄普通摄像头的图片,但不能拍摄红外摄像头图片,调用takePicture后,红外摄像头被关闭了,我想这可能是主板系统的问题,不能速度解决的情况下,只能通过PreviewCallback预览回调获取下一帧图片
package com.zhb.camerademo;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.Manifest;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.hardware.Camera;
import android.os.Bundle;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.widget.ImageView;
import java.io.IOException;
import permissions.dispatcher.NeedsPermission;
import permissions.dispatcher.RuntimePermissions;
@RuntimePermissions
public class MainActivity extends AppCompatActivity {
SurfaceView surfaceview1;
SurfaceHolder holder1;
Camera mCamera1;
SurfaceView surfaceview2;
SurfaceHolder holder2;
Camera mCamera2;
ImageView imageView;
boolean showClick1 = false;
boolean showClick2 = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_main);
surfaceview1 = findViewById(R.id.surfaceView1);
holder1 = surfaceview1.getHolder();
holder1.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
try {
mCamera1.setPreviewDisplay(holder);
mCamera1.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
surfaceview2 = findViewById(R.id.surfaceView2);
holder2 = surfaceview2.getHolder();
holder2.addCallback(new SurfaceHolder.Callback() {
@Override
public void surfaceCreated(SurfaceHolder holder) {
}
@Override
public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
try {
mCamera2.setPreviewDisplay(holder);
mCamera2.startPreview();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void surfaceDestroyed(SurfaceHolder holder) {
}
});
imageView = findViewById(R.id.imageView);
surfaceview1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showClick1 = true;
}
});
surfaceview2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
showClick2 = true;
}
});
}
@Override
protected void onPause() {
super.onPause();
if(mCamera1 != null){
mCamera1.stopPreview();
mCamera1.release();
}
if(mCamera2 != null){
mCamera2.stopPreview();
mCamera2.release();
}
}
@Override
public void onResume() {
super.onResume();
MainActivityPermissionsDispatcher.CAMERAWithPermissionCheck(this);
}
@Override
public void onDestroy() {
super.onDestroy();
}
public Bitmap rawByteArray2RGBABitmap2(byte[] data, int width, int height) {
int frameSize = width * height;
int[] rgba = new int[frameSize];
for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++) {
int y = (0xff & ((int) data[i * width + j]));
int u = (0xff & ((int) data[frameSize + (i >> 1) * width + (j & ~1) + 0]));
int v = (0xff & ((int) data[frameSize + (i >> 1) * width + (j & ~1) + 1]));
y = y < 16 ? 16 : y;
int r = Math.round(1.164f * (y - 16) + 1.596f * (v - 128));
int g = Math.round(1.164f * (y - 16) - 0.813f * (v - 128) - 0.391f * (u - 128));
int b = Math.round(1.164f * (y - 16) + 2.018f * (u - 128));
r = r < 0 ? 0 : (r > 255 ? 255 : r);
g = g < 0 ? 0 : (g > 255 ? 255 : g);
b = b < 0 ? 0 : (b > 255 ? 255 : b);
rgba[i * width + j] = 0xff000000 + (b << 16) + (g << 8) + r;
}
Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
bmp.setPixels(rgba, 0 , width, 0, 0, width, height);
return bmp;
}
public static Bitmap Bytes2Bimap(byte[] b) {
if (b.length != 0) {
return BitmapFactory.decodeByteArray(b, 0, b.length);
} else {
Log.i("zzz ", "Byte = null");
return null;
}
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// NOTE: delegate the permission handling to generated method
MainActivityPermissionsDispatcher.onRequestPermissionsResult(this, requestCode, grantResults);
}
@NeedsPermission({
Manifest.permission.READ_EXTERNAL_STORAGE,
Manifest.permission.WRITE_EXTERNAL_STORAGE,
Manifest.permission.CAMERA
})
void CAMERA() {
mCamera1 = Camera.open(0);
mCamera1.setDisplayOrientation(90);
mCamera2 = Camera.open(1);
mCamera2.setDisplayOrientation(90);
mCamera1.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
if(showClick1){
showClick1 = false;
int w = camera.getParameters().getPreviewSize().width;
int h = camera.getParameters().getPreviewSize().height;
Bitmap bitmap = rawByteArray2RGBABitmap2(bytes, w, h);
imageView.setImageBitmap(bitmap);
}
}
});
mCamera2.setPreviewCallback(new Camera.PreviewCallback() {
@Override
public void onPreviewFrame(byte[] bytes, Camera camera) {
if(showClick2){
showClick2 = false;
int w = camera.getParameters().getPreviewSize().width;
int h = camera.getParameters().getPreviewSize().height;
Bitmap bitmap = rawByteArray2RGBABitmap2(bytes, w, h);
imageView.setImageBitmap(bitmap);
}
}
});
}
}
布局layout_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<SurfaceView
android:layout_weight="1"
android:id="@+id/surfaceView1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<SurfaceView
android:layout_weight="1"
android:id="@+id/surfaceView2"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
demo:https://download.csdn.net/download/u013370255/12694880