|
|
|
|
package com.yeyupiaoling.teststadiometry;
|
|
|
|
|
|
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
|
import androidx.appcompat.app.AppCompatActivity;
|
|
|
|
|
|
|
|
|
|
import android.Manifest;
|
|
|
|
|
import android.annotation.SuppressLint;
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.pm.PackageManager;
|
|
|
|
|
import android.graphics.Bitmap;
|
|
|
|
|
import android.graphics.ImageFormat;
|
|
|
|
|
import android.graphics.Matrix;
|
|
|
|
|
import android.graphics.SurfaceTexture;
|
|
|
|
|
import android.hardware.camera2.CameraAccessException;
|
|
|
|
|
import android.hardware.camera2.CameraCaptureSession;
|
|
|
|
|
import android.hardware.camera2.CameraCharacteristics;
|
|
|
|
|
import android.hardware.camera2.CameraDevice;
|
|
|
|
|
import android.hardware.camera2.CameraManager;
|
|
|
|
|
import android.hardware.camera2.CaptureFailure;
|
|
|
|
|
import android.hardware.camera2.CaptureRequest;
|
|
|
|
|
import android.hardware.camera2.CaptureResult;
|
|
|
|
|
import android.hardware.camera2.params.StreamConfigurationMap;
|
|
|
|
|
import android.media.ImageReader;
|
|
|
|
|
import android.os.Build;
|
|
|
|
|
import android.os.Bundle;
|
|
|
|
|
import android.os.Handler;
|
|
|
|
|
import android.os.HandlerThread;
|
|
|
|
|
import android.util.Log;
|
|
|
|
|
import android.util.Size;
|
|
|
|
|
import android.view.Surface;
|
|
|
|
|
import android.view.TextureView;
|
|
|
|
|
import android.view.View;
|
|
|
|
|
import android.widget.Button;
|
|
|
|
|
import android.widget.ImageView;
|
|
|
|
|
import android.widget.LinearLayout;
|
|
|
|
|
import android.widget.TextView;
|
|
|
|
|
|
|
|
|
|
import org.opencv.android.OpenCVLoader;
|
|
|
|
|
|
|
|
|
|
import java.util.Arrays;
|
|
|
|
|
import java.util.List;
|
|
|
|
|
|
|
|
|
|
public class CameraActivity extends AppCompatActivity {
|
|
|
|
|
private static final String TAG = CameraActivity.class.getSimpleName();
|
|
|
|
|
private CameraCaptureSession mCaptureSession;
|
|
|
|
|
private CameraDevice mCameraDevice;
|
|
|
|
|
|
|
|
|
|
private HandlerThread mCaptureThread;
|
|
|
|
|
private Handler mCaptureHandler;
|
|
|
|
|
|
|
|
|
|
private ImageReader mImageReader;
|
|
|
|
|
private boolean isFont = false;
|
|
|
|
|
private Size mPreviewSize;
|
|
|
|
|
private boolean mCapturing;
|
|
|
|
|
|
|
|
|
|
private AutoFitTextureView mTextureView;
|
|
|
|
|
private ImageView imageViewLeft;
|
|
|
|
|
private ImageView imageViewRight;
|
|
|
|
|
private ImageView imageViewResult;
|
|
|
|
|
private int sensorOrientation = 0;
|
|
|
|
|
private View bgView;
|
|
|
|
|
private LinearLayout ll;
|
|
|
|
|
private TextView textView;
|
|
|
|
|
private StereoBMUtil stereoBMUtil;
|
|
|
|
|
private Bitmap leftBitmap;
|
|
|
|
|
private Bitmap rightBitmap;
|
|
|
|
|
|
|
|
|
|
@SuppressLint("ClickableViewAccessibility")
|
|
|
|
|
@Override
|
|
|
|
|
protected void onCreate(Bundle savedInstanceState) {
|
|
|
|
|
super.onCreate(savedInstanceState);
|
|
|
|
|
setContentView(R.layout.activity_camera);
|
|
|
|
|
|
|
|
|
|
// 权限申请
|
|
|
|
|
if (!hasPermission()) {
|
|
|
|
|
requestPermission();
|
|
|
|
|
}
|
|
|
|
|
//初始化
|
|
|
|
|
if (OpenCVLoader.initDebug()) {
|
|
|
|
|
Log.d(TAG, "OpenCVLoader初始化成功");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stereoBMUtil = new StereoBMUtil();
|
|
|
|
|
mTextureView = findViewById(R.id.texture_view);
|
|
|
|
|
imageViewLeft = findViewById(R.id.imageViewLeft);
|
|
|
|
|
imageViewRight = findViewById(R.id.imageViewRight);
|
|
|
|
|
imageViewResult = findViewById(R.id.imageViewResult);
|
|
|
|
|
bgView = findViewById(R.id.bg_view);
|
|
|
|
|
ll = findViewById(R.id.show_ll);
|
|
|
|
|
textView = findViewById(R.id.result_tv);
|
|
|
|
|
|
|
|
|
|
Button button2 = findViewById(R.id.button2);
|
|
|
|
|
Button button3 = findViewById(R.id.button3);
|
|
|
|
|
Button button4 = findViewById(R.id.button4);
|
|
|
|
|
|
|
|
|
|
// 拍照获取左右摄像头的图像
|
|
|
|
|
button2.setOnClickListener(v -> {
|
|
|
|
|
bgView.setVisibility(View.VISIBLE);
|
|
|
|
|
ll.setVisibility(View.VISIBLE);
|
|
|
|
|
Bitmap imgBitmap = mTextureView.getBitmap();
|
|
|
|
|
Bitmap b = Utils.rotateBitmap(imgBitmap, 360 - sensorOrientation);
|
|
|
|
|
List<Bitmap> bitmapList = Utils.bisectionBitmap(b);
|
|
|
|
|
// 左右目摄像头的图像
|
|
|
|
|
leftBitmap = bitmapList.get(0);
|
|
|
|
|
rightBitmap = bitmapList.get(1);
|
|
|
|
|
imageViewLeft.setImageBitmap(leftBitmap);
|
|
|
|
|
imageViewRight.setImageBitmap(rightBitmap);
|
|
|
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 显示相机预览
|
|
|
|
|
button3.setOnClickListener(v -> {
|
|
|
|
|
bgView.setVisibility(View.GONE);
|
|
|
|
|
ll.setVisibility(View.GONE);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 执行StereoBM算法
|
|
|
|
|
button4.setOnClickListener(v -> {
|
|
|
|
|
Bitmap result = stereoBMUtil.compute(leftBitmap, rightBitmap);
|
|
|
|
|
imageViewResult.setImageBitmap(result);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// 点击计算后的图片,获取三维坐标数据
|
|
|
|
|
imageViewResult.setOnTouchListener((v, event) -> {
|
|
|
|
|
// 获取触摸点的坐标 x, y
|
|
|
|
|
float x = event.getX();
|
|
|
|
|
float y = event.getY();
|
|
|
|
|
float[] dst = new float[2];
|
|
|
|
|
Matrix imageMatrix = imageViewResult.getImageMatrix();
|
|
|
|
|
Matrix inverseMatrix = new Matrix();
|
|
|
|
|
imageMatrix.invert(inverseMatrix);
|
|
|
|
|
inverseMatrix.mapPoints(dst, new float[]{x, y});
|
|
|
|
|
int dstX = (int) dst[0];
|
|
|
|
|
int dstY = (int) dst[1];
|
|
|
|
|
// 获取该点的三维坐标
|
|
|
|
|
double[] c = stereoBMUtil.getCoordinate(dstX, dstY);
|
|
|
|
|
String s = String.format("点(%d, %d) 三维坐标:[%.2f, %.2f, %.2f]", dstX, dstY, c[0], c[1], c[2]);
|
|
|
|
|
Log.d(TAG, s);
|
|
|
|
|
textView.setText(s);
|
|
|
|
|
return true;
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 初始化以下变量和状态
|
|
|
|
|
private void initStatus() {
|
|
|
|
|
// 启动线程
|
|
|
|
|
startCaptureThread();
|
|
|
|
|
|
|
|
|
|
// 判断SurfaceTexture是否可用,可用就直接启动捕获图片
|
|
|
|
|
if (mTextureView.isAvailable()) {
|
|
|
|
|
startCapture();
|
|
|
|
|
} else {
|
|
|
|
|
mTextureView.setSurfaceTextureListener(new TextureView.SurfaceTextureListener() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) {
|
|
|
|
|
startCapture();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onSurfaceTextureUpdated(SurfaceTexture surface) {
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 启动捕获图片
|
|
|
|
|
private void startCapture() {
|
|
|
|
|
// 判断是否正处于捕获图片的状态
|
|
|
|
|
if (mCapturing) return;
|
|
|
|
|
mCapturing = true;
|
|
|
|
|
|
|
|
|
|
final CameraManager manager = (CameraManager) getSystemService(Context.CAMERA_SERVICE);
|
|
|
|
|
|
|
|
|
|
String cameraIdAvailable = null;
|
|
|
|
|
try {
|
|
|
|
|
assert manager != null;
|
|
|
|
|
for (final String cameraId : manager.getCameraIdList()) {
|
|
|
|
|
final CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
|
|
|
|
|
|
|
|
|
|
final Integer facing = characteristics.get(CameraCharacteristics.LENS_FACING);
|
|
|
|
|
// 设置相机前摄像头或者后摄像头
|
|
|
|
|
if (isFont) {
|
|
|
|
|
if (facing != null && facing == CameraCharacteristics.LENS_FACING_FRONT) {
|
|
|
|
|
cameraIdAvailable = cameraId;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
if (facing != null && facing == CameraCharacteristics.LENS_FACING_BACK) {
|
|
|
|
|
cameraIdAvailable = cameraId;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} catch (CameraAccessException e) {
|
|
|
|
|
Log.e(TAG, "启动图片捕获异常 ", e);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
assert cameraIdAvailable != null;
|
|
|
|
|
final CameraCharacteristics characteristics =
|
|
|
|
|
manager.getCameraCharacteristics(cameraIdAvailable);
|
|
|
|
|
|
|
|
|
|
final StreamConfigurationMap map =
|
|
|
|
|
characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP);
|
|
|
|
|
try {
|
|
|
|
|
sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
|
|
|
|
|
Log.i(TAG, "orientation: " + sensorOrientation);
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
assert map != null;
|
|
|
|
|
mPreviewSize = Utils.chooseOptimalSize(map.getOutputSizes(SurfaceTexture.class),
|
|
|
|
|
mTextureView.getWidth(),
|
|
|
|
|
mTextureView.getHeight());
|
|
|
|
|
Log.d("mPreviewSize", String.valueOf(mPreviewSize));
|
|
|
|
|
mTextureView.setAspectRatio(mPreviewSize.getHeight(), mPreviewSize.getWidth());
|
|
|
|
|
|
|
|
|
|
manager.openCamera(cameraIdAvailable, new CameraDevice.StateCallback() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onOpened(@NonNull CameraDevice camera) {
|
|
|
|
|
mCameraDevice = camera;
|
|
|
|
|
createCaptureSession();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onDisconnected(@NonNull CameraDevice camera) {
|
|
|
|
|
camera.close();
|
|
|
|
|
mCameraDevice = null;
|
|
|
|
|
mCapturing = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onError(@NonNull CameraDevice camera, final int error) {
|
|
|
|
|
Log.e(TAG, "打开相机错误 = " + error);
|
|
|
|
|
camera.close();
|
|
|
|
|
mCameraDevice = null;
|
|
|
|
|
mCapturing = false;
|
|
|
|
|
}
|
|
|
|
|
}, mCaptureHandler);
|
|
|
|
|
} catch (CameraAccessException | SecurityException e) {
|
|
|
|
|
mCapturing = false;
|
|
|
|
|
Log.e(TAG, "启动图片捕获异常 ", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建捕获图片session
|
|
|
|
|
private void createCaptureSession() {
|
|
|
|
|
try {
|
|
|
|
|
final SurfaceTexture texture = mTextureView.getSurfaceTexture();
|
|
|
|
|
texture.setDefaultBufferSize(mPreviewSize.getWidth(), mPreviewSize.getHeight());
|
|
|
|
|
|
|
|
|
|
final Surface surface = new Surface(texture);
|
|
|
|
|
final CaptureRequest.Builder captureRequestBuilder = mCameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW);
|
|
|
|
|
captureRequestBuilder.addTarget(surface);
|
|
|
|
|
|
|
|
|
|
mImageReader = ImageReader.newInstance(
|
|
|
|
|
mPreviewSize.getWidth(), mPreviewSize.getHeight(), ImageFormat.JPEG, 10);
|
|
|
|
|
|
|
|
|
|
mCameraDevice.createCaptureSession(
|
|
|
|
|
Arrays.asList(surface, mImageReader.getSurface()),
|
|
|
|
|
new CameraCaptureSession.StateCallback() {
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onConfigured(@NonNull CameraCaptureSession cameraCaptureSession) {
|
|
|
|
|
if (null == mCameraDevice) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
mCaptureSession = cameraCaptureSession;
|
|
|
|
|
try {
|
|
|
|
|
captureRequestBuilder.set(
|
|
|
|
|
CaptureRequest.CONTROL_AF_MODE,
|
|
|
|
|
CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_PICTURE);
|
|
|
|
|
captureRequestBuilder.set(
|
|
|
|
|
CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON_AUTO_FLASH);
|
|
|
|
|
|
|
|
|
|
CaptureRequest previewRequest = captureRequestBuilder.build();
|
|
|
|
|
mCaptureSession.setRepeatingRequest(
|
|
|
|
|
previewRequest, new CameraCaptureSession.CaptureCallback() {
|
|
|
|
|
@Override
|
|
|
|
|
public void onCaptureProgressed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureResult partialResult) {
|
|
|
|
|
super.onCaptureProgressed(session, request, partialResult);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onCaptureFailed(@NonNull CameraCaptureSession session, @NonNull CaptureRequest request, @NonNull CaptureFailure failure) {
|
|
|
|
|
super.onCaptureFailed(session, request, failure);
|
|
|
|
|
Log.d(TAG, "onCaptureFailed = " + failure.getReason());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onCaptureSequenceCompleted(@NonNull CameraCaptureSession session, int sequenceId, long frameNumber) {
|
|
|
|
|
super.onCaptureSequenceCompleted(session, sequenceId, frameNumber);
|
|
|
|
|
Log.d(TAG, "onCaptureSequenceCompleted");
|
|
|
|
|
}
|
|
|
|
|
}, mCaptureHandler);
|
|
|
|
|
} catch (final CameraAccessException e) {
|
|
|
|
|
Log.e(TAG, "onConfigured exception ", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onConfigureFailed(@NonNull final CameraCaptureSession cameraCaptureSession) {
|
|
|
|
|
Log.e(TAG, "onConfigureFailed ");
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
null);
|
|
|
|
|
} catch (final CameraAccessException e) {
|
|
|
|
|
Log.e(TAG, "创建捕获图片session异常 ", e);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 关闭相机
|
|
|
|
|
private void closeCamera() {
|
|
|
|
|
if (mCaptureSession != null) {
|
|
|
|
|
mCaptureSession.close();
|
|
|
|
|
mCaptureSession = null;
|
|
|
|
|
}
|
|
|
|
|
if (mCameraDevice != null) {
|
|
|
|
|
mCameraDevice.close();
|
|
|
|
|
mCameraDevice = null;
|
|
|
|
|
}
|
|
|
|
|
if (mImageReader != null) {
|
|
|
|
|
mImageReader.close();
|
|
|
|
|
mImageReader = null;
|
|
|
|
|
}
|
|
|
|
|
mCapturing = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 关闭捕获图片线程
|
|
|
|
|
private void stopCaptureThread() {
|
|
|
|
|
try {
|
|
|
|
|
if (mCaptureThread != null) {
|
|
|
|
|
mCaptureThread.quitSafely();
|
|
|
|
|
mCaptureThread.join();
|
|
|
|
|
}
|
|
|
|
|
mCaptureThread = null;
|
|
|
|
|
mCaptureHandler = null;
|
|
|
|
|
} catch (final Exception e) {
|
|
|
|
|
e.printStackTrace();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void onPause() {
|
|
|
|
|
// 关闭相机
|
|
|
|
|
closeCamera();
|
|
|
|
|
stopCaptureThread();
|
|
|
|
|
super.onPause();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void onStop() {
|
|
|
|
|
// 关闭相机
|
|
|
|
|
closeCamera();
|
|
|
|
|
stopCaptureThread();
|
|
|
|
|
super.onStop();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 启动捕获图片线程
|
|
|
|
|
private void startCaptureThread() {
|
|
|
|
|
mCaptureThread = new HandlerThread("capture");
|
|
|
|
|
mCaptureThread.start();
|
|
|
|
|
mCaptureHandler = new Handler(mCaptureThread.getLooper());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
protected void onResume() {
|
|
|
|
|
initStatus();
|
|
|
|
|
super.onResume();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// check had permission
|
|
|
|
|
private boolean hasPermission() {
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
|
|
|
return checkSelfPermission(Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED;
|
|
|
|
|
} else {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// request permission
|
|
|
|
|
private void requestPermission() {
|
|
|
|
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
|
|
|
|
requestPermissions(new String[]{Manifest.permission.CAMERA}, 1);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|