1 package com.introlab.rtabmap;
3 import java.nio.ByteBuffer;
4 import java.nio.FloatBuffer;
5 import java.util.ArrayList;
6 import java.util.Arrays;
7 import java.util.EnumSet;
9 import java.util.concurrent.atomic.AtomicBoolean;
11 import com.google.ar.core.Anchor;
12 import com.google.ar.core.Camera;
13 import com.google.ar.core.CameraConfig;
14 import com.google.ar.core.CameraConfigFilter;
15 import com.google.ar.core.CameraIntrinsics;
16 import com.google.ar.core.Config;
17 import com.google.ar.core.Coordinates2d;
18 import com.google.ar.core.Frame;
19 import com.google.ar.core.PointCloud;
20 import com.google.ar.core.Pose;
21 import com.google.ar.core.Session;
22 import com.google.ar.core.SharedCamera;
23 import com.google.ar.core.TrackingState;
24 import com.google.ar.core.exceptions.CameraNotAvailableException;
25 import com.google.ar.core.exceptions.NotYetAvailableException;
26 import com.google.ar.core.exceptions.UnavailableException;
28 import android.content.Context;
29 import android.graphics.ImageFormat;
30 import android.hardware.camera2.CameraAccessException;
31 import android.hardware.camera2.CameraCaptureSession;
32 import android.hardware.camera2.CameraCharacteristics;
33 import android.hardware.camera2.CameraDevice;
34 import android.hardware.camera2.CameraManager;
35 import android.hardware.camera2.CameraMetadata;
36 import android.hardware.camera2.CaptureFailure;
37 import android.hardware.camera2.CaptureRequest;
38 import android.hardware.camera2.TotalCaptureResult;
39 import android.media.Image;
40 import android.opengl.GLES20;
41 import android.opengl.GLSurfaceView;
42 import android.os.Handler;
43 import android.os.HandlerThread;
44 import android.support.annotation.NonNull;
45 import android.util.Log;
46 import android.view.Surface;
47 import android.widget.Toast;
55 -1.0f, -1.0f, +1.0f, -1.0f, -1.0f, +1.0f, +1.0f, +1.0f,
103 private AtomicBoolean
mReady =
new AtomicBoolean(
false);
115 ByteBuffer mPreviousDepth =
null;
116 double mPreviousDepthStamp = 0.0;
117 ByteBuffer mPreviousDepth2 =
null;
118 double mPreviousDepthStamp2 = 0.0;
129 new CameraDevice.StateCallback() {
131 public void onOpened(@NonNull CameraDevice
cameraDevice) {
138 public void onClosed(@NonNull CameraDevice
cameraDevice) {
144 public void onDisconnected(@NonNull CameraDevice
cameraDevice) {
145 Log.w(
TAG,
"Camera device ID " +
cameraDevice.getId() +
" disconnected.");
159 CameraCaptureSession.StateCallback cameraCaptureCallback =
160 new CameraCaptureSession.StateCallback() {
165 public void onConfigured(@NonNull CameraCaptureSession session) {
166 Log.d(
TAG,
"Camera capture session configured.");
172 public void onSurfacePrepared(
173 @NonNull CameraCaptureSession session, @NonNull Surface surface) {
174 Log.d(
TAG,
"Camera capture surface prepared.");
178 public void onReady(@NonNull CameraCaptureSession session) {
179 Log.d(
TAG,
"Camera capture session ready.");
183 public void onActive(@NonNull CameraCaptureSession session) {
184 Log.d(
TAG,
"Camera capture session active.");
189 public void onClosed(@NonNull CameraCaptureSession session) {
190 Log.d(
TAG,
"Camera capture session closed.");
194 public void onConfigureFailed(@NonNull CameraCaptureSession session) {
195 Log.e(
TAG,
"Failed to configure camera capture session.");
201 new CameraCaptureSession.CaptureCallback() {
204 public void onCaptureCompleted(
205 @NonNull CameraCaptureSession session,
206 @NonNull CaptureRequest request,
207 @NonNull TotalCaptureResult
result) {
212 public void onCaptureBufferLost(
213 @NonNull CameraCaptureSession session,
214 @NonNull CaptureRequest request,
217 Log.e(
TAG,
"onCaptureBufferLost: " + frameNumber);
221 public void onCaptureFailed(
222 @NonNull CameraCaptureSession session,
223 @NonNull CaptureRequest request,
224 @NonNull CaptureFailure failure) {
225 Log.e(
TAG,
"onCaptureFailed: " + failure.getFrameNumber() +
" " + failure.getReason());
229 public void onCaptureSequenceAborted(
230 @NonNull CameraCaptureSession session,
int sequenceId) {
231 Log.e(
TAG,
"onCaptureSequenceAborted: " + sequenceId +
" " + session);
243 Log.i(
TAG,
"Resume ARCore.");
248 }
catch (CameraNotAvailableException
e) {
249 Log.e(
TAG,
"Failed to resume ARCore session",
e);
262 }
catch (CameraAccessException
e) {
263 Log.e(
TAG,
"Failed to set repeating request",
e);
269 Log.e(
TAG,
"createCameraPreviewSession: " +
"starting camera preview session.");
278 List<Surface> surfaceList =
sharedCamera.getArCoreSurfaces();
279 Log.e(
TAG,
" createCameraPreviewSession: " +
"surfaceList: sharedCamera.getArCoreSurfaces(): " + surfaceList.size());
290 for (Surface surface : surfaceList) {
301 }
catch (CameraAccessException
e) {
302 Log.e(
TAG,
"CameraAccessException",
e);
322 }
catch (InterruptedException
e) {
323 Log.e(
TAG,
"Interrupted while trying to join background handler thread",
e);
336 private static boolean contains(
int[] modes,
int mode) {
340 for (
int i : modes) {
357 int[] textures =
new int[1];
358 GLES20.glGenTextures(1, textures, 0);
362 Log.v(
TAG,
"Perform various checks, then open camera device and create CPU image reader.");
372 }
catch (UnavailableException
e) {
373 Log.e(
TAG,
"Failed to create ARCore session that supports camera sharing",
e);
379 CameraConfigFilter cameraConfigFilter =
new CameraConfigFilter(
sharedSession);
380 CameraConfig[] cameraConfigs =
sharedSession.getSupportedCameraConfigs(cameraConfigFilter).toArray(
new CameraConfig[0]);
381 Log.i(
TAG,
"Size of supported CameraConfigs list is " + cameraConfigs.length);
384 int highestResolutionIndex=-1;
385 int highestResolution = 0;
386 for(
int i=0;
i<cameraConfigs.length; ++
i)
388 Log.i(
TAG,
"Camera ID: " + cameraConfigs[
i].getCameraId());
389 Log.i(
TAG,
"Resolution: " + cameraConfigs[
i].getImageSize().getWidth() +
"x" + cameraConfigs[
i].getImageSize().getHeight());
390 if(highestResolution == 0 || highestResolution < cameraConfigs[
i].getImageSize().getWidth())
392 highestResolutionIndex =
i;
393 highestResolution = cameraConfigs[
i].getImageSize().getWidth();
396 if(highestResolutionIndex>=0)
405 config.setFocusMode(Config.FocusMode.FIXED);
406 config.setUpdateMode(Config.UpdateMode.BLOCKING);
407 config.setPlaneFindingMode(Config.PlaneFindingMode.DISABLED);
408 config.setLightEstimationMode(Config.LightEstimationMode.DISABLED);
409 config.setCloudAnchorMode(Config.CloudAnchorMode.DISABLED);
431 CameraCharacteristics characteristics =
cameraManager.getCameraCharacteristics(tmpCameraId);
433 Log.i(
TAG,
"Camera " + tmpCameraId +
" extrinsics:");
435 float[]
translation = characteristics.get(CameraCharacteristics.LENS_POSE_TRANSLATION);
440 float[]
rotation = characteristics.get(CameraCharacteristics.LENS_POSE_ROTATION);
443 Log.i(
TAG, String.format(
"Rotation (qx,qy,qz,qw): %f,%f,%f,%f",
rotation[0],
rotation[1],
rotation[2],
rotation[3]));
449 Log.i(
TAG,
"Set rgb extrinsics!");
452 if (!
contains(characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES), CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT) ||
453 characteristics.get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_FRONT) {
456 Log.i(
TAG,
"Camera " + tmpCameraId +
" has depth output available");
462 Log.i(
TAG,
"Set depth extrinsics!");
464 depthIntrinsics = characteristics.get(CameraCharacteristics.LENS_INTRINSIC_CALIBRATION);
465 Log.i(
TAG, String.format(
"Intrinsics (fx,fy,cx,cy,s): %f,%f,%f,%f,%f",
472 }
catch (CameraAccessException
e) {
489 if (resolutions !=
null) {
490 float[] newDepthIntrinsics =
null;
491 int largestWidth = 0;
492 for( String temp : resolutions) {
493 Log.i(
TAG,
"DEPTH16 resolution: " + temp);
494 depthWidth = Integer.parseInt(temp.split(
"x")[0]);
495 depthHeight = Integer.parseInt(temp.split(
"x")[1]);
500 if(largestWidth == 0 &&
depthWidth>largestWidth)
509 newDepthIntrinsics[0] *=
scale;
510 newDepthIntrinsics[1] *=
scale;
511 newDepthIntrinsics[2] *=
scale;
512 newDepthIntrinsics[3] *=
scale;
522 if (resolutions.size()>0) {
524 if(newDepthIntrinsics!=
null) {
556 }
catch (CameraAccessException
e) {
557 Log.e(
TAG,
"Failed to open camera",
e);
559 }
catch (IllegalArgumentException
e) {
560 Log.e(
TAG,
"Failed to open camera",
e);
562 }
catch (SecurityException
e) {
563 Log.e(
TAG,
"Failed to open camera",
e);
571 final float m00 =
R[0];
572 final float m10 =
R[1];
573 final float m20 =
R[2];
574 final float m01 =
R[4];
575 final float m11 =
R[5];
576 final float m21 =
R[6];
577 final float m02 =
R[8];
578 final float m12 =
R[9];
579 final float m22 =
R[10];
581 float tr = m00 + m11 + m22;
584 float S = (
float) Math.sqrt(tr + 1.0) * 2;
586 q[1] = (m21 - m12) /
S;
587 q[2] = (m02 - m20) /
S;
588 q[3] = (m10 - m01) /
S;
589 }
else if ((m00 > m11) & (m00 > m22)) {
590 float S = (
float) Math.sqrt(1.0 + m00 - m11 - m22) * 2;
592 q[0] = (m21 - m12) /
S;
594 q[2] = (m01 + m10) /
S;
595 q[3] = (m02 + m20) /
S;
596 }
else if (m11 > m22) {
597 float S = (
float) Math.sqrt(1.0 + m11 - m00 - m22) * 2;
599 q[0] = (m02 - m20) /
S;
600 q[1] = (m01 + m10) /
S;
602 q[3] = (m12 + m21) /
S;
604 float S = (
float) Math.sqrt(1.0 + m22 - m00 - m11) * 2;
606 q[0] = (m10 - m01) /
S;
607 q[1] = (m02 + m20) /
S;
608 q[2] = (m12 + m21) /
S;
617 Log.w(
TAG,
"close()");
652 public void updateGL() throws CameraNotAvailableException {
665 }
catch (Exception
e) {
672 camera = frame.getCamera();
675 Log.e(
TAG, String.format(
"frame.getCamera() null!"));
680 Log.e(
TAG, String.format(
"camera is null!"));
683 boolean lost =
false;
684 if (
camera.getTrackingState() != TrackingState.TRACKING) {
685 final String trackingState =
camera.getTrackingState().toString();
686 Log.e(
TAG, String.format(
"Tracking lost! state=%s", trackingState));
693 String
msg =
"Tracking lost! If you are mapping, you will need to relocalize before continuing.";
694 if(
mToast.getView() ==
null || !
mToast.getView().isShown())
697 msg, Toast.LENGTH_LONG).show();
708 if (frame.getTimestamp() != 0) {
710 double stamp = (double)frame.getTimestamp()/10e8;
711 CameraIntrinsics intrinsics =
camera.getImageIntrinsics();
713 Image image = frame.acquireCameraImage();
715 PointCloud cloud = frame.acquirePointCloud();
716 FloatBuffer points = cloud.getPoints();
718 if (image.getFormat() != ImageFormat.YUV_420_888) {
719 throw new IllegalArgumentException(
720 "Expected image in YUV_420_888 format, got format " + image.getFormat());
725 for(
int i =0;
i<image.getPlanes().
length;++
i)
727 Log.d(
TAG, String.format(
"Plane[%d] pixel stride = %d, row stride = %d",
i, image.getPlanes()[
i].getPixelStride(), image.getPlanes()[
i].getRowStride()));
731 float[] fl = intrinsics.getFocalLength();
732 float[] pp = intrinsics.getPrincipalPoint();
735 ByteBuffer
y = image.getPlanes()[0].getBuffer().asReadOnlyBuffer();
736 ByteBuffer u = image.getPlanes()[1].getBuffer().asReadOnlyBuffer();
737 ByteBuffer
v = image.getPlanes()[2].getBuffer().asReadOnlyBuffer();
740 image.getWidth(), image.getHeight(),
y.limit(), image.getFormat(), stamp));
742 float[] texCoord =
new float[8];
743 frame.transformCoordinates2d(
744 Coordinates2d.OPENGL_NORMALIZED_DEVICE_COORDINATES,
746 Coordinates2d.IMAGE_NORMALIZED,
749 float[]
p =
new float[16];
750 camera.getProjectionMatrix(
p, 0, 0.1
f, 100.0
f);
752 float[] viewMatrix =
new float[16];
753 camera.getDisplayOrientedPose().inverse().toMatrix(viewMatrix, 0);
754 float[]
quat =
new float[4];
767 if(mPreviousDepth ==
null)
769 mPreviousDepth = depth;
770 mPreviousDepthStamp = depthStamp;
772 if(mPreviousDepth2 ==
null)
774 mPreviousDepth2 = depth;
775 mPreviousDepthStamp2 = depthStamp;
783 lost?0:pose.tx(), lost?0:pose.ty(), lost?0:pose.tz(), lost?0:pose.qx(), lost?0:pose.qy(), lost?0:pose.qz(), lost?0:pose.qw(),
784 fl[0], fl[1], pp[0], pp[1],
789 depthStamp<=stamp?depthStamp:mPreviousDepthStamp<=stamp?mPreviousDepthStamp:mPreviousDepthStamp2,
790 y, u,
v,
y.limit(), image.getWidth(), image.getHeight(), image.getFormat(),
791 depthStamp<=stamp?depth:mPreviousDepthStamp<=stamp?mPreviousDepth:mPreviousDepth2,
792 depthStamp<=stamp?depth.limit():mPreviousDepthStamp<=stamp?mPreviousDepth.limit():mPreviousDepth2.limit(),
794 points, points.limit()/4,
795 viewMatrix[12], viewMatrix[13], viewMatrix[14],
quat[1],
quat[2],
quat[3],
quat[0],
796 p[0],
p[5],
p[8],
p[9],
p[10],
p[11],
p[14],
797 texCoord[0],texCoord[1],texCoord[2],texCoord[3],texCoord[4],texCoord[5],texCoord[6],texCoord[7]);
800 if(depthStamp != mPreviousDepthStamp)
802 mPreviousDepthStamp2 = mPreviousDepthStamp;
803 mPreviousDepth2 = mPreviousDepth;
804 mPreviousDepthStamp = depthStamp;
805 mPreviousDepth = depth;
812 lost?0:pose.tx(), lost?0:pose.ty(), lost?0:pose.tz(), lost?0:pose.qx(), lost?0:pose.qy(), lost?0:pose.qz(), lost?0:pose.qw(),
813 fl[0], fl[1], pp[0], pp[1],
816 y, u,
v,
y.limit(), image.getWidth(), image.getHeight(), image.getFormat(),
817 points, points.limit()/4,
818 viewMatrix[12], viewMatrix[13], viewMatrix[14],
quat[1],
quat[2],
quat[3],
quat[0],
819 p[0],
p[5],
p[8],
p[9],
p[10],
p[11],
p[14],
820 texCoord[0],texCoord[1],texCoord[2],texCoord[3],texCoord[4],texCoord[5],texCoord[6],texCoord[7]);
827 }
catch (NotYetAvailableException
e) {
839 Log.v(
TAG,
"getResolutions: cameraId:" +
cameraId +
" imageFormat: " + imageFormat);
841 ArrayList<String> output =
new ArrayList<String>();
843 CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
844 CameraCharacteristics characteristics = manager.getCameraCharacteristics(
cameraId);
846 for (android.util.Size
s : characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(imageFormat)) {
847 output.add(
s.getWidth() +
"x" +
s.getHeight());
849 }
catch (Exception
e) {