Added depth/rgb registration option

This commit is contained in:
matlabbe
2021-06-10 11:07:25 -04:00
parent d7b5fa5d17
commit ba38d9f321
13 changed files with 842 additions and 140 deletions

View File

@@ -56,13 +56,13 @@ CameraMobile::CameraMobile(bool smoothing) :
Camera(10), Camera(10),
deviceTColorCamera_(Transform::getIdentity()), deviceTColorCamera_(Transform::getIdentity()),
spinOncePreviousStamp_(0.0), spinOncePreviousStamp_(0.0),
textureId_(9999),
uvs_initialized_(false),
previousStamp_(0.0), previousStamp_(0.0),
stampEpochOffset_(0.0), stampEpochOffset_(0.0),
smoothing_(smoothing), smoothing_(smoothing),
colorCameraToDisplayRotation_(ROTATION_0), colorCameraToDisplayRotation_(ROTATION_0),
originUpdate_(false), originUpdate_(false)
textureId_(9999),
uvs_initialized_(false)
{ {
glGenTextures(1, &textureId_); glGenTextures(1, &textureId_);
} }
@@ -156,7 +156,7 @@ void CameraMobile::setData(const SensorData & data, const Transform & pose, cons
LOGD("CameraMobile::setData textureId_=%d", (int)textureId_); LOGD("CameraMobile::setData textureId_=%d", (int)textureId_);
if(textureId_ != 0) if(textureId_ != 0 && texCoord != 0)
{ {
cv::Mat rgbImage; cv::Mat rgbImage;
cv::cvtColor(data.imageRaw(), rgbImage, CV_BGR2RGBA); cv::cvtColor(data.imageRaw(), rgbImage, CV_BGR2RGBA);

View File

@@ -916,6 +916,7 @@ void RTABMapApp::stopCamera()
camera_->close(); camera_->close();
delete camera_; delete camera_;
camera_ = 0; camera_ = 0;
poseBuffer_.clear();
} }
} }
{ {
@@ -1243,7 +1244,7 @@ int RTABMapApp::Render()
if(main_scene_.background_renderer_ == 0) if(main_scene_.background_renderer_ == 0)
{ {
main_scene_.background_renderer_ = new BackgroundRenderer(); main_scene_.background_renderer_ = new BackgroundRenderer();
main_scene_.background_renderer_->InitializeGlContent(((rtabmap::CameraARCore*)camera_)->getTextureId()); main_scene_.background_renderer_->InitializeGlContent(((rtabmap::CameraARCore*)camera_)->getTextureId(), true);
} }
if(((rtabmap::CameraARCore*)camera_)->uvsInitialized()) if(((rtabmap::CameraARCore*)camera_)->uvsInitialized())
{ {
@@ -1277,7 +1278,7 @@ int RTABMapApp::Render()
if(main_scene_.background_renderer_ == 0) if(main_scene_.background_renderer_ == 0)
{ {
main_scene_.background_renderer_ = new BackgroundRenderer(); main_scene_.background_renderer_ = new BackgroundRenderer();
main_scene_.background_renderer_->InitializeGlContent(((rtabmap::CameraMobile*)camera_)->getTextureId()); main_scene_.background_renderer_->InitializeGlContent(((rtabmap::CameraMobile*)camera_)->getTextureId(), false);
} }
if(((rtabmap::CameraMobile*)camera_)->uvsInitialized()) if(((rtabmap::CameraMobile*)camera_)->uvsInitialized())
{ {
@@ -3657,7 +3658,7 @@ int RTABMapApp::postProcessing(int approach)
} }
void RTABMapApp::postCameraPoseEvent( void RTABMapApp::postCameraPoseEvent(
float x, float y, float z, float qx, float qy, float qz, float qw) float x, float y, float z, float qx, float qy, float qz, float qw, double stamp)
{ {
boost::mutex::scoped_lock lock(cameraMutex_); boost::mutex::scoped_lock lock(cameraMutex_);
if(cameraDriver_ == 3 && camera_) if(cameraDriver_ == 3 && camera_)
@@ -3665,18 +3666,28 @@ void RTABMapApp::postCameraPoseEvent(
rtabmap::Transform pose(x,y,z,qx,qy,qz,qw); rtabmap::Transform pose(x,y,z,qx,qy,qz,qw);
pose = rtabmap::rtabmap_world_T_opengl_world * pose * rtabmap::opengl_world_T_rtabmap_world; pose = rtabmap::rtabmap_world_T_opengl_world * pose * rtabmap::opengl_world_T_rtabmap_world;
camera_->poseReceived(pose); camera_->poseReceived(pose);
poseBuffer_.insert(std::make_pair(stamp, pose));
if(poseBuffer_.size() > 1000)
{
poseBuffer_.erase(poseBuffer_.begin());
}
} }
} }
void RTABMapApp::postOdometryEvent( void RTABMapApp::postOdometryEvent(
float x, float y, float z, float qx, float qy, float qz, float qw, rtabmap::Transform pose,
float fx, float fy, float cx, float cy, float rgb_fx, float rgb_fy, float rgb_cx, float rgb_cy,
float depth_fx, float depth_fy, float depth_cx, float depth_cy,
const rtabmap::Transform & rgbFrame,
const rtabmap::Transform & depthFrame,
double stamp, double stamp,
double depthStamp,
const void * yPlane, const void * uPlane, const void * vPlane, int yPlaneLen, int rgbWidth, int rgbHeight, int rgbFormat, const void * yPlane, const void * uPlane, const void * vPlane, int yPlaneLen, int rgbWidth, int rgbHeight, int rgbFormat,
const void * depth, int depthLen, int depthWidth, int depthHeight, int depthFormat, const void * depth, int depthLen, int depthWidth, int depthHeight, int depthFormat,
const void * conf, int confLen, int confWidth, int confHeight, int confFormat, const void * conf, int confLen, int confWidth, int confHeight, int confFormat,
const float * points, int pointsLen, int pointsChannels, const float * points, int pointsLen, int pointsChannels,
float vx, float vy, float vz, float vqx, float vqy, float vqz, float vqw, const rtabmap::Transform & viewMatrix,
float p00, float p11, float p02, float p12, float p22, float p32, float p23, float p00, float p11, float p02, float p12, float p22, float p32, float p23,
float t0, float t1, float t2, float t3, float t4, float t5, float t6, float t7) float t0, float t1, float t2, float t3, float t4, float t5, float t6, float t7)
{ {
@@ -3684,7 +3695,7 @@ void RTABMapApp::postOdometryEvent(
boost::mutex::scoped_lock lock(cameraMutex_); boost::mutex::scoped_lock lock(cameraMutex_);
if(cameraDriver_ == 3 && camera_) if(cameraDriver_ == 3 && camera_)
{ {
if(fx > 0.0f && fy > 0.0f && cx > 0.0f && cy > 0.0f && stamp > 0.0f && yPlane && vPlane && yPlaneLen == rgbWidth*rgbHeight) if(rgb_fx > 0.0f && rgb_fy > 0.0f && rgb_cx > 0.0f && rgb_cy > 0.0f && stamp > 0.0f && yPlane && vPlane && yPlaneLen == rgbWidth*rgbHeight)
{ {
#ifndef DISABLE_LOG #ifndef DISABLE_LOG
//LOGD("rgb format = %d depth format =%d ", rgbFormat, depthFormat); //LOGD("rgb format = %d depth format =%d ", rgbFormat, depthFormat);
@@ -3770,10 +3781,87 @@ void RTABMapApp::postOdometryEvent(
if(!outputRGB.empty()) if(!outputRGB.empty())
{ {
rtabmap::CameraModel model = rtabmap::CameraModel(fx, fy, cx, cy, camera_->getDeviceTColorCamera(), 0, cv::Size(rgbWidth, rgbHeight));
rtabmap::Transform pose(x,y,z,qx,qy,qz,qw);
pose = rtabmap::rtabmap_world_T_opengl_world * pose * rtabmap::opengl_world_T_rtabmap_world; pose = rtabmap::rtabmap_world_T_opengl_world * pose * rtabmap::opengl_world_T_rtabmap_world;
// Registration depth to rgb
if(!outputDepth.empty() && !depthFrame.isNull() && depth_fx!=0 && (rgbFrame != depthFrame || depthStamp!=stamp))
{
UTimer time;
rtabmap::Transform motion = rtabmap::Transform::getIdentity();
if(depthStamp != stamp && !poseBuffer_.empty())
{
// Interpolate pose
if(!poseBuffer_.empty())
{
if(poseBuffer_.rbegin()->first < depthStamp)
{
UWARN("Could not find poses to interpolate at time %f (last is %f)...", depthStamp, poseBuffer_.rbegin()->first);
}
else
{
std::map<double, rtabmap::Transform >::const_iterator iterB = poseBuffer_.lower_bound(depthStamp);
std::map<double, rtabmap::Transform >::const_iterator iterA = iterB;
rtabmap::Transform poseDepth;
if(iterA != poseBuffer_.begin())
{
iterA = --iterA;
}
if(iterB == poseBuffer_.end())
{
iterB = --iterB;
}
if(iterA == iterB && depthStamp == iterA->first)
{
poseDepth = iterA->second;
}
else if(depthStamp >= iterA->first && depthStamp <= iterB->first)
{
poseDepth = iterA->second.interpolate((depthStamp-iterA->first) / (iterB->first-iterA->first), iterB->second);
}
else if(depthStamp < iterA->first)
{
UERROR("Could not find poses to interpolate at image time %f (earliest is %f). Are sensors synchronized?", depthStamp, iterA->first);
}
else
{
UERROR("Could not find poses to interpolate at image time %f (between %f and %f), Are sensors synchronized?", depthStamp, iterA->first, iterB->first);
}
if(!poseDepth.isNull())
{
#ifndef DISABLE_LOG
UDEBUG("poseRGB =%s (stamp=%f)", pose.prettyPrint().c_str(), depthStamp);
UDEBUG("poseDepth=%s (stamp=%f)", poseDepth.prettyPrint().c_str(), depthStamp);
#endif
motion = pose.inverse()*poseDepth;
// transform in camera frame
#ifndef DISABLE_LOG
UDEBUG("motion=%s", motion.prettyPrint().c_str());
#endif
motion = rtabmap::CameraModel::opticalRotation().inverse() * motion * rtabmap::CameraModel::opticalRotation();
#ifndef DISABLE_LOG
UDEBUG("motion=%s", motion.prettyPrint().c_str());
#endif
}
}
}
}
rtabmap::Transform rgbToDepth = motion*rgbFrame.inverse()*depthFrame;
float scale = (float)outputDepth.cols/(float)outputRGB.cols;
cv::Mat colorK = (cv::Mat_<double>(3,3) <<
rgb_fx*scale, 0, rgb_cx*scale,
0, rgb_fy*scale, rgb_cy*scale,
0, 0, 1);
cv::Mat depthK = (cv::Mat_<double>(3,3) <<
depth_fx, 0, depth_cx,
0, depth_fy, depth_cy,
0, 0, 1);
outputDepth = rtabmap::util2d::registerDepth(outputDepth, depthK, outputDepth.size(), colorK, rgbToDepth);
#ifndef DISABLE_LOG
UDEBUG("Depth registration time: %fs", time.elapsed());
#endif
}
rtabmap::CameraModel model = rtabmap::CameraModel(rgb_fx, rgb_fy, rgb_cx, rgb_cy, camera_->getDeviceTColorCamera(), 0, cv::Size(rgbWidth, rgbHeight));
#ifndef DISABLE_LOG #ifndef DISABLE_LOG
//LOGI("pointCloudData size=%d", pointsLen); //LOGI("pointCloudData size=%d", pointsLen);
#endif #endif
@@ -3818,7 +3906,7 @@ void RTABMapApp::postOdometryEvent(
projectionMatrix[2][2] = p22; projectionMatrix[2][2] = p22;
projectionMatrix[2][3] = p32; projectionMatrix[2][3] = p32;
projectionMatrix[3][2] = p23; projectionMatrix[3][2] = p23;
glm::mat4 viewMatrix = rtabmap::glmFromTransform(rtabmap::Transform(vx, vy, vz, vqx, vqy, vqz, vqw)); glm::mat4 viewMatrixMat = rtabmap::glmFromTransform(viewMatrix);
float texCoords[8]; float texCoords[8];
texCoords[0] = t0; texCoords[0] = t0;
texCoords[1] = t1; texCoords[1] = t1;
@@ -3828,7 +3916,7 @@ void RTABMapApp::postOdometryEvent(
texCoords[5] = t5; texCoords[5] = t5;
texCoords[6] = t6; texCoords[6] = t6;
texCoords[7] = t7; texCoords[7] = t7;
camera_->setData(data, pose, viewMatrix, projectionMatrix, texCoords); camera_->setData(data, pose, viewMatrixMat, projectionMatrix, main_scene_.GetCameraType() == tango_gl::GestureCamera::kFirstPerson?texCoords:0);
camera_->spinOnce(); camera_->spinOnce();
} }
} }
@@ -3836,7 +3924,7 @@ void RTABMapApp::postOdometryEvent(
else else
{ {
UERROR("Missing image information! fx=%f fy=%f cx=%f cy=%f stamp=%f yPlane=%d vPlane=%d yPlaneLen=%d rgbWidth=%d rgbHeight=%d", UERROR("Missing image information! fx=%f fy=%f cx=%f cy=%f stamp=%f yPlane=%d vPlane=%d yPlaneLen=%d rgbWidth=%d rgbHeight=%d",
fx, fy, cx, cy, stamp, yPlane?1:0, vPlane?1:0, yPlaneLen, rgbWidth, rgbHeight); rgb_fx, rgb_fy, rgb_cx, rgb_cy, stamp, yPlane?1:0, vPlane?1:0, yPlaneLen, rgbWidth, rgbHeight);
} }
} }
#else #else

View File

@@ -176,17 +176,21 @@ class RTABMapApp : public UEventsHandler {
int postProcessing(int approach); int postProcessing(int approach);
void postCameraPoseEvent( void postCameraPoseEvent(
float x, float y, float z, float qx, float qy, float qz, float qw); float x, float y, float z, float qx, float qy, float qz, float qw, double stamp);
void postOdometryEvent( void postOdometryEvent(
float x, float y, float z, float qx, float qy, float qz, float qw, rtabmap::Transform pose,
float fx, float fy, float cx, float cy, float rgb_fx, float rgb_fy, float rgb_cx, float rgb_cy,
double stamp, float depth_fx, float depth_fy, float depth_cx, float depth_cy,
const rtabmap::Transform & rgbFrame,
const rtabmap::Transform & depthFrame,
double stamp,
double depthStamp,
const void * yPlane, const void * uPlane, const void * vPlane, int yPlaneLen, int rgbWidth, int rgbHeight, int rgbFormat, const void * yPlane, const void * uPlane, const void * vPlane, int yPlaneLen, int rgbWidth, int rgbHeight, int rgbFormat,
const void * depth, int depthLen, int depthWidth, int depthHeight, int depthFormat, const void * depth, int depthLen, int depthWidth, int depthHeight, int depthFormat,
const void * conf, int confLen, int confWidth, int confHeight, int confFormat, const void * conf, int confLen, int confWidth, int confHeight, int confFormat,
const float * points, int pointsLen, int pointsChannels, const float * points, int pointsLen, int pointsChannels,
float vx, float vy, float vz, float vqx, float vqy, float vqz, float vqw, //view matrix const rtabmap::Transform & viewMatrix, //view matrix
float p00, float p11, float p02, float p12, float p22, float p32, float p23, // projection matrix float p00, float p11, float p02, float p12, float p22, float p32, float p23, // projection matrix
float t0, float t1, float t2, float t3, float t4, float t5, float t6, float t7); // tex coord float t0, float t1, float t2, float t3, float t4, float t5, float t6, float t7); // tex coord
@@ -265,6 +269,7 @@ class RTABMapApp : public UEventsHandler {
std::list<rtabmap::RtabmapEvent*> rtabmapEvents_; std::list<rtabmap::RtabmapEvent*> rtabmapEvents_;
std::list<rtabmap::OdometryEvent> odomEvents_; std::list<rtabmap::OdometryEvent> odomEvents_;
std::list<rtabmap::Transform> poseEvents_; std::list<rtabmap::Transform> poseEvents_;
std::map<double, rtabmap::Transform> poseBuffer_;
rtabmap::Transform mapToOdom_; rtabmap::Transform mapToOdom_;

View File

@@ -34,17 +34,21 @@ const std::string kVertexShader =
" v_TexCoord = a_TexCoord;\n" " v_TexCoord = a_TexCoord;\n"
"}\n"; "}\n";
const std::string kFragmentShader = const std::string kFragmentShaderOES =
#ifdef __ANDROID__
"#extension GL_OES_EGL_image_external : require\n" "#extension GL_OES_EGL_image_external : require\n"
#endif
"precision mediump float;\n" "precision mediump float;\n"
"varying vec2 v_TexCoord;\n" "varying vec2 v_TexCoord;\n"
#ifdef __ANDROID__
"uniform samplerExternalOES sTexture;\n" "uniform samplerExternalOES sTexture;\n"
#else "void main() {\n"
" vec4 sample = texture2D(sTexture, v_TexCoord);\n"
" float grey = 0.21 * sample.r + 0.71 * sample.g + 0.07 * sample.b;\n"
" gl_FragColor = vec4(grey, grey, grey, 0.5);\n"
"}\n";
const std::string kFragmentShader =
"precision mediump float;\n"
"varying vec2 v_TexCoord;\n"
"uniform sampler2D sTexture;\n" "uniform sampler2D sTexture;\n"
#endif
"void main() {\n" "void main() {\n"
" vec4 sample = texture2D(sTexture, v_TexCoord);\n" " vec4 sample = texture2D(sTexture, v_TexCoord);\n"
" float grey = 0.21 * sample.r + 0.71 * sample.g + 0.07 * sample.b;\n" " float grey = 0.21 * sample.r + 0.71 * sample.g + 0.07 * sample.b;\n"
@@ -73,11 +77,14 @@ const std::string kFragmentShader =
} // namespace } // namespace
void BackgroundRenderer::InitializeGlContent(GLuint textureId) void BackgroundRenderer::InitializeGlContent(GLuint textureId, bool oes)
{ {
texture_id_ = textureId; texture_id_ = textureId;
oes_ = oes;
shader_program_ = tango_gl::util::CreateProgram(kVertexShader.c_str(), kFragmentShader.c_str()); shader_program_ = tango_gl::util::CreateProgram(
kVertexShader.c_str(),
oes_?kFragmentShaderOES.c_str():kFragmentShader.c_str());
if (!shader_program_) { if (!shader_program_) {
LOGE("Could not create program."); LOGE("Could not create program.");
} }
@@ -95,11 +102,10 @@ void BackgroundRenderer::Draw(const float * transformed_uvs) {
glEnable (GL_BLEND); glEnable (GL_BLEND);
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
#ifdef __ANDROID__ if(oes_)
glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_); glBindTexture(GL_TEXTURE_EXTERNAL_OES, texture_id_);
#else else
glBindTexture(GL_TEXTURE_2D, texture_id_); glBindTexture(GL_TEXTURE_2D, texture_id_);
#endif
glVertexAttribPointer(attribute_vertices_, 2, GL_FLOAT, GL_FALSE, 0, BackgroundRenderer_kVertices); glVertexAttribPointer(attribute_vertices_, 2, GL_FLOAT, GL_FALSE, 0, BackgroundRenderer_kVertices);
glVertexAttribPointer(attribute_uvs_, 2, GL_FLOAT, GL_FALSE, 0, transformed_uvs?transformed_uvs:BackgroundRenderer_kTexCoord); glVertexAttribPointer(attribute_uvs_, 2, GL_FLOAT, GL_FALSE, 0, transformed_uvs?transformed_uvs:BackgroundRenderer_kTexCoord);

View File

@@ -55,7 +55,7 @@ public:
// Sets up OpenGL state. Must be called on the OpenGL thread and before any // Sets up OpenGL state. Must be called on the OpenGL thread and before any
// other methods below. // other methods below.
void InitializeGlContent(GLuint textureId); void InitializeGlContent(GLuint textureId, bool oes);
// Draws the background image. This methods must be called for every ArFrame // Draws the background image. This methods must be called for every ArFrame
// returned by ArSession_update() to catch display geometry change events. // returned by ArSession_update() to catch display geometry change events.
@@ -65,6 +65,7 @@ public:
GLuint shader_program_; GLuint shader_program_;
GLuint texture_id_; GLuint texture_id_;
bool oes_ = false;
GLuint attribute_vertices_; GLuint attribute_vertices_;
GLuint attribute_uvs_; GLuint attribute_uvs_;

View File

@@ -869,11 +869,11 @@ Java_com_introlab_rtabmap_RTABMapLib_postProcessing(
JNIEXPORT void JNICALL JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_postCameraPoseEvent( Java_com_introlab_rtabmap_RTABMapLib_postCameraPoseEvent(
JNIEnv* env, jclass, jlong native_application, JNIEnv* env, jclass, jlong native_application,
float x, float y, float z, float qx, float qy, float qz, float qw) float x, float y, float z, float qx, float qy, float qz, float qw, double stamp)
{ {
if(native_application) if(native_application)
{ {
native(native_application)->postCameraPoseEvent(x,y,z,qx,qy,qz,qw); native(native_application)->postCameraPoseEvent(x,y,z,qx,qy,qz,qw, stamp);
} }
else else
{ {
@@ -886,30 +886,36 @@ JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_postOdometryEvent( Java_com_introlab_rtabmap_RTABMapLib_postOdometryEvent(
JNIEnv* env, jclass, jlong native_application, JNIEnv* env, jclass, jlong native_application,
float x, float y, float z, float qx, float qy, float qz, float qw, float x, float y, float z, float qx, float qy, float qz, float qw,
float fx, float fy, float cx, float cy, float rgb_fx, float rgb_fy, float rgb_cx, float rgb_cy,
float rgbFrameX, float rgbFrameY, float rgbFrameZ, float rgbFrameQX, float rgbFrameQY, float rgbFrameQZ, float rgbFrameQW,
double stamp, double stamp,
jobject yPlane, jobject uPlane, jobject vPlane, int yPlaneLen, int rgbWidth, int rgbHeight, int rgbFormat, jobject yPlane, jobject uPlane, jobject vPlane, int yPlaneLen, int rgbWidth, int rgbHeight, int rgbFormat,
jobject depth, int depthLen, int depthWidth, int depthHeight, int depthFormat, jobject points, int pointsLen,
jobject points, int pointsLen) float vx, float vy, float vz, float vqx, float vqy, float vqz, float vqw, //view matrix
float p00, float p11, float p02, float p12, float p22, float p32, float p23, // projection matrix
float t0, float t1, float t2, float t3, float t4, float t5, float t6, float t7) // tex coord
{ {
if(native_application) if(native_application)
{ {
void *yPtr = env->GetDirectBufferAddress(yPlane); void *yPtr = env->GetDirectBufferAddress(yPlane);
void *uPtr = env->GetDirectBufferAddress(uPlane); void *uPtr = env->GetDirectBufferAddress(uPlane);
void *vPtr = env->GetDirectBufferAddress(vPlane); void *vPtr = env->GetDirectBufferAddress(vPlane);
void *depthPtr = env->GetDirectBufferAddress(depth);
float *pointsPtr = (float *)env->GetDirectBufferAddress(points); float *pointsPtr = (float *)env->GetDirectBufferAddress(points);
native(native_application)->postOdometryEvent( native(native_application)->postOdometryEvent(
x,y,z,qx,qy,qz,qw, rtabmap::Transform(x,y,z,qx,qy,qz,qw),
fx,fy,cx,cy, rgb_fx,rgb_fy,rgb_cx,rgb_cy,
0,0,0,0,
rtabmap::Transform(rgbFrameX, rgbFrameY, rgbFrameZ, rgbFrameQX, rgbFrameQY, rgbFrameQZ, rgbFrameQW),
rtabmap::Transform(),
stamp, stamp,
0,
yPtr, uPtr, vPtr, yPlaneLen, rgbWidth, rgbHeight, rgbFormat, yPtr, uPtr, vPtr, yPlaneLen, rgbWidth, rgbHeight, rgbFormat,
depthPtr, depthLen, depthWidth, depthHeight, depthFormat, 0,0,0,0,0, //depth
0,0,0,0,0, 0,0,0,0,0, //conf
pointsPtr, pointsLen, 4, pointsPtr, pointsLen, 4,
0,0,0,0,0,0,0, rtabmap::Transform(vx, vy, vz, vqx, vqy, vqz, vqw),
0,0,0,0,0,0,0, p00, p11, p02, p12, p22, p32, p23,
0,0,0,0,0,0,0,0); t0, t1, t2, t3, t4, t5, t6, t7);
} }
else else
{ {
@@ -918,6 +924,44 @@ Java_com_introlab_rtabmap_RTABMapLib_postOdometryEvent(
} }
} }
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_postOdometryEventDepth(
JNIEnv* env, jclass, jlong native_application,
float x, float y, float z, float qx, float qy, float qz, float qw,
float rgb_fx, float rgb_fy, float rgb_cx, float rgb_cy,
float depth_fx, float depth_fy, float depth_cx, float depth_cy,
float rgbFrameX, float rgbFrameY, float rgbFrameZ, float rgbFrameQX, float rgbFrameQY, float rgbFrameQZ, float rgbFrameQW,
float depthFrameX, float depthFrameY, float depthFrameZ, float depthFrameQX, float depthFrameQY, float depthFrameQZ, float depthFrameQW,
double rgbStamp,
double depthStamp,
jobject yPlane, jobject uPlane, jobject vPlane, int yPlaneLen, int rgbWidth, int rgbHeight, int rgbFormat,
jobject depth, int depthLen, int depthWidth, int depthHeight, int depthFormat,
jobject points, int pointsLen,
float vx, float vy, float vz, float vqx, float vqy, float vqz, float vqw, //view matrix
float p00, float p11, float p02, float p12, float p22, float p32, float p23, // projection matrix
float t0, float t1, float t2, float t3, float t4, float t5, float t6, float t7) // tex coord)
{
void *yPtr = env->GetDirectBufferAddress(yPlane);
void *uPtr = env->GetDirectBufferAddress(uPlane);
void *vPtr = env->GetDirectBufferAddress(vPlane);
void *depthPtr = env->GetDirectBufferAddress(depth);
float *pointsPtr = (float *)env->GetDirectBufferAddress(points);
native(native_application)->postOdometryEvent(
rtabmap::Transform(x,y,z,qx,qy,qz,qw),
rgb_fx,rgb_fy,rgb_cx,rgb_cy,
depth_fx,depth_fy,depth_cx,depth_cy,
rtabmap::Transform(rgbFrameX, rgbFrameY, rgbFrameZ, rgbFrameQX, rgbFrameQY, rgbFrameQZ, rgbFrameQW),
rtabmap::Transform(depthFrameX, depthFrameY, depthFrameZ, depthFrameQX, depthFrameQY, depthFrameQZ, depthFrameQW),
rgbStamp,
depthStamp,
yPtr, uPtr, vPtr, yPlaneLen, rgbWidth, rgbHeight, rgbFormat,
depthPtr, depthLen, depthWidth, depthHeight, depthFormat,
0,0,0,0,0, // conf
pointsPtr, pointsLen, 4,
rtabmap::Transform(vx, vy, vz, vqx, vqy, vqz, vqw),
p00, p11, p02, p12, p22, p32, p23,
t0, t1, t2, t3, t4, t5, t6, t7);
}
#ifdef __cplusplus #ifdef __cplusplus

View File

@@ -51,7 +51,7 @@
<string name="pref_key_remove_button">pref_key_remove_button</string> <string name="pref_key_remove_button">pref_key_remove_button</string>
<string name="pref_key_reset_button">pref_key_reset_button</string> <string name="pref_key_reset_button">pref_key_reset_button</string>
<string name="pref_key_density">pref_key_density</string> <string name="pref_key_density">pref_key_density</string>
<string name="pref_default_density">1</string> <string name="pref_default_density">2</string>
<string name="pref_key_min_depth">pref_key_min_depth</string> <string name="pref_key_min_depth">pref_key_min_depth</string>
<string name="pref_default_min_depth">0</string> <string name="pref_default_min_depth">0</string>
<string name="pref_key_depth">pref_key_depth</string> <string name="pref_key_depth">pref_key_depth</string>

View File

@@ -11,8 +11,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
import com.google.ar.core.Camera; import com.google.ar.core.Camera;
import com.google.ar.core.CameraIntrinsics; import com.google.ar.core.CameraIntrinsics;
import com.google.ar.core.Config; import com.google.ar.core.Config;
import com.google.ar.core.Coordinates2d;
import com.google.ar.core.Frame; import com.google.ar.core.Frame;
import com.google.ar.core.ImageMetadata;
import com.google.ar.core.PointCloud; import com.google.ar.core.PointCloud;
import com.google.ar.core.Pose; import com.google.ar.core.Pose;
import com.google.ar.core.Session; import com.google.ar.core.Session;
@@ -29,6 +29,7 @@ import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraDevice; import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager; import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CameraMetadata;
import android.hardware.camera2.CaptureFailure; import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest; import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult; import android.hardware.camera2.TotalCaptureResult;
@@ -45,7 +46,11 @@ public class ARCoreSharedCamera {
public static final String TAG = ARCoreSharedCamera.class.getSimpleName(); public static final String TAG = ARCoreSharedCamera.class.getSimpleName();
private static final float[] QUAD_COORDS =
new float[] {
-1.0f, -1.0f, +1.0f, -1.0f, -1.0f, +1.0f, +1.0f, +1.0f,
};
private static RTABMapActivity mActivity; private static RTABMapActivity mActivity;
public ARCoreSharedCamera(RTABMapActivity c) { public ARCoreSharedCamera(RTABMapActivity c) {
mActivity = c; mActivity = c;
@@ -53,8 +58,8 @@ public class ARCoreSharedCamera {
// Depth TOF Image. // Depth TOF Image.
// Use 240 * 180 for now, hardcoded for Huawei P30 Pro // Use 240 * 180 for now, hardcoded for Huawei P30 Pro
private static final int DEPTH_WIDTH = 240; private int depthWidth = 640;
private static final int DEPTH_HEIGHT = 180; private int depthHeight = 480;
// GL Surface used to draw camera preview image. // GL Surface used to draw camera preview image.
public GLSurfaceView surfaceView; public GLSurfaceView surfaceView;
@@ -81,6 +86,11 @@ public class ARCoreSharedCamera {
// Camera ID for the camera used by ARCore. // Camera ID for the camera used by ARCore.
private String cameraId; private String cameraId;
private String depthCameraId;
private Pose rgbExtrinsics;
private Pose depthExtrinsics;
private float[] depthIntrinsics = null;
private AtomicBoolean mReady = new AtomicBoolean(false); private AtomicBoolean mReady = new AtomicBoolean(false);
@@ -95,6 +105,7 @@ public class ARCoreSharedCamera {
public boolean isDepthSupported() {return mTOFAvailable;} public boolean isDepthSupported() {return mTOFAvailable;}
// Camera device state callback. // Camera device state callback.
private final CameraDevice.StateCallback cameraDeviceCallback = private final CameraDevice.StateCallback cameraDeviceCallback =
new CameraDevice.StateCallback() { new CameraDevice.StateCallback() {
@@ -176,7 +187,7 @@ public class ARCoreSharedCamera {
@NonNull CameraCaptureSession session, @NonNull CameraCaptureSession session,
@NonNull CaptureRequest request, @NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) { @NonNull TotalCaptureResult result) {
Log.i(TAG, "onCaptureCompleted"); //Log.i(TAG, "onCaptureCompleted");
} }
//@Override // android 23 //@Override // android 23
@@ -251,7 +262,7 @@ public class ARCoreSharedCamera {
// Add a CPU image reader surface. On devices that don't support CPU image access, the image // Add a CPU image reader surface. On devices that don't support CPU image access, the image
// may arrive significantly later, or not arrive at all. // may arrive significantly later, or not arrive at all.
if (mTOFAvailable) surfaceList.add(mTOFImageReader.imageReader.getSurface()); if (mTOFAvailable && cameraId.compareTo(depthCameraId) == 0) surfaceList.add(mTOFImageReader.imageReader.getSurface());
// Surface list should now contain three surfacemReadymReadys: // Surface list should now contain three surfacemReadymReadys:
// 0. sharedCamera.getSurfaceTexture() // 0. sharedCamera.getSurfaceTexture()
// 1. … // 1. …
@@ -272,8 +283,6 @@ public class ARCoreSharedCamera {
} catch (CameraAccessException e) { } catch (CameraAccessException e) {
Log.e(TAG, "CameraAccessException", e); Log.e(TAG, "CameraAccessException", e);
} }
} }
// Start background handler thread, used to run callbacks without blocking UI thread. // Start background handler thread, used to run callbacks without blocking UI thread.
@@ -301,6 +310,25 @@ public class ARCoreSharedCamera {
private long mPreviousTime = 0; private long mPreviousTime = 0;
/**
* Return true if the given array contains the given integer.
*
* @param modes array to check.
* @param mode integer to get for.
* @return true if the array contains the given integer, otherwise false.
*/
private static boolean contains(int[] modes, int mode) {
if (modes == null) {
return false;
}
for (int i : modes) {
if (i == mode) {
return true;
}
}
return false;
}
// Perform various checks, then open camera device and create CPU image reader. // Perform various checks, then open camera device and create CPU image reader.
public boolean openCamera() { public boolean openCamera() {
@@ -317,7 +345,7 @@ public class ARCoreSharedCamera {
cameraTextureId = textures[0]; cameraTextureId = textures[0];
} }
Log.v(TAG + " opencamera: ", "Perform various checks, then open camera device and create CPU image reader."); Log.v(TAG, "Perform various checks, then open camera device and create CPU image reader.");
// Don't open camera if already opened. // Don't open camera if already opened.
if (cameraDevice != null) { if (cameraDevice != null) {
return false; return false;
@@ -335,10 +363,10 @@ public class ARCoreSharedCamera {
// Enable auto focus mode while ARCore is running. // Enable auto focus mode while ARCore is running.
Config config = sharedSession.getConfig(); Config config = sharedSession.getConfig();
config.setFocusMode(Config.FocusMode.FIXED); config.setFocusMode(Config.FocusMode.FIXED);
config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE); config.setUpdateMode(Config.UpdateMode.BLOCKING);
config.setPlaneFindingMode(Config.PlaneFindingMode.DISABLED); config.setPlaneFindingMode(Config.PlaneFindingMode.DISABLED);
config.setLightEstimationMode(Config.LightEstimationMode.DISABLED); config.setLightEstimationMode(Config.LightEstimationMode.DISABLED);
//config.setCloudAnchorMode(Config.CloudAnchorMode.ENABLED); config.setCloudAnchorMode(Config.CloudAnchorMode.DISABLED);
sharedSession.configure(config); sharedSession.configure(config);
} }
@@ -347,27 +375,128 @@ public class ARCoreSharedCamera {
sharedCamera = sharedSession.getSharedCamera(); sharedCamera = sharedSession.getSharedCamera();
// Store the ID of the camera used by ARCore. // Store the ID of the camera used by ARCore.
cameraId = sharedSession.getCameraConfig().getCameraId(); cameraId = sharedSession.getCameraConfig().getCameraId();
initCamera(mActivity, cameraId, 1);
ArrayList<String> resolutions; Log.d(TAG, "Shared camera ID: " + cameraId);
mTOFAvailable = false; mTOFAvailable = false;
// Store a reference to the camera system service.
cameraManager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
depthCameraId = null;
// show all cameras
try {
// Find a CameraDevice that supports DEPTH16 captures, and configure state.
for (String tmpCameraId : cameraManager.getCameraIdList()) {
CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(tmpCameraId);
resolutions = getResolutions(mActivity, cameraId, ImageFormat.DEPTH16); Log.i(TAG, "Camera " + tmpCameraId + " extrinsics:");
if (resolutions != null) {
for( String temp : resolutions) { float[] translation = characteristics.get(CameraCharacteristics.LENS_POSE_TRANSLATION);
Log.e(TAG + "DEPTH16 resolution: ", temp); if(translation != null)
}; {
if (resolutions.size()>0) mTOFAvailable = true; Log.i(TAG, String.format("Translation (x,y,z): %f,%f,%f", translation[0], translation[1], translation[2]));
}
float[] rotation = characteristics.get(CameraCharacteristics.LENS_POSE_ROTATION);
if(rotation != null)
{
Log.i(TAG, String.format("Rotation (qx,qy,qz,qw): %f,%f,%f,%f", rotation[0], rotation[1], rotation[2], rotation[3]));
}
if(tmpCameraId.compareTo(cameraId)==0 && translation!=null && rotation!=null)
{
rgbExtrinsics = new Pose(translation, rotation);
Log.i(TAG,"Set rgb extrinsics!");
}
if (!contains(characteristics.get(CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES), CameraCharacteristics.REQUEST_AVAILABLE_CAPABILITIES_DEPTH_OUTPUT) ||
characteristics.get(CameraCharacteristics.LENS_FACING) == CameraMetadata.LENS_FACING_FRONT) {
continue;
}
Log.i(TAG, "Camera " + tmpCameraId + " has depth output available");
depthCameraId = tmpCameraId;
if(translation!=null && rotation != null)
{
depthExtrinsics = new Pose(translation, rotation);
Log.i(TAG,"Set depth extrinsics!");
}
depthIntrinsics = characteristics.get(CameraCharacteristics.LENS_INTRINSIC_CALIBRATION);
Log.i(TAG, String.format("Intrinsics (fx,fy,cx,cy,s): %f,%f,%f,%f,%f",
depthIntrinsics[0],
depthIntrinsics[1],
depthIntrinsics[2],
depthIntrinsics[3],
depthIntrinsics[4]));
}
} catch (CameraAccessException e) {
e.printStackTrace();
}
if(rgbExtrinsics == null)
{
float[] translation = {0,0,0};
float[] rotation = {0,0,0,1};
rgbExtrinsics = new Pose(translation, rotation);
} }
if(depthExtrinsics == null)
{
depthExtrinsics = rgbExtrinsics;
}
if(depthCameraId != null)
{
ArrayList<String> resolutions = getResolutions(mActivity, depthCameraId, ImageFormat.DEPTH16);
if (resolutions != null) {
float[] newDepthIntrinsics = null;
int largestWidth = 0;
for( String temp : resolutions) {
Log.i(TAG, "DEPTH16 resolution: " + temp);
depthWidth = Integer.parseInt(temp.split("x")[0]);
depthHeight = Integer.parseInt(temp.split("x")[1]);
if(depthIntrinsics != null)
{
if(depthIntrinsics[0] != 0)
{
if(largestWidth == 0 && depthWidth>largestWidth)
{
largestWidth = depthWidth; // intrinsics should match this resolution
}
// Samsung Galaxy Note10+: take smallest resolution and match the intrinsics
if(depthWidth < largestWidth)
{
float scale = (float)depthWidth/(float)largestWidth;
newDepthIntrinsics = depthIntrinsics.clone();
newDepthIntrinsics[0] *= scale;
newDepthIntrinsics[1] *= scale;
newDepthIntrinsics[2] *= scale;
newDepthIntrinsics[3] *= scale;
}
}
else if(depthWidth ==240 && depthHeight==180)
{
// Huawei P30 Pro: only 240x180 is working
break;
}
}
}
if (resolutions.size()>0) {
mTOFAvailable = true;
if(newDepthIntrinsics!=null) {
depthIntrinsics = newDepthIntrinsics;
}
}
}
}
Log.i(TAG, "TOF_available: " + mTOFAvailable);
// Color CPU Image. // Color CPU Image.
// Use the currently configured CPU image size. // Use the currently configured CPU image size.
//Size desiredCPUImageSize = sharedSession.getCameraConfig().getImageSize(); //Size desiredCPUImageSize = sharedSession.getCameraConfig().getImageSize();
if (mTOFAvailable) mTOFImageReader.createImageReader(DEPTH_WIDTH, DEPTH_HEIGHT); if (mTOFAvailable) mTOFImageReader.createImageReader(depthWidth, depthHeight);
// When ARCore is running, make sure it also updates our CPU image surface. // When ARCore is running, make sure it also updates our CPU image surface.
if (mTOFAvailable) { if (mTOFAvailable && cameraId.compareTo(depthCameraId) == 0) {
sharedCamera.setAppSurfaces(this.cameraId, Arrays.asList(mTOFImageReader.imageReader.getSurface())); sharedCamera.setAppSurfaces(this.cameraId, Arrays.asList(mTOFImageReader.imageReader.getSurface()));
} }
@@ -376,15 +505,14 @@ public class ARCoreSharedCamera {
// Wrap our callback in a shared camera callback. // Wrap our callback in a shared camera callback.
CameraDevice.StateCallback wrappedCallback = sharedCamera.createARDeviceStateCallback(cameraDeviceCallback, backgroundHandler); CameraDevice.StateCallback wrappedCallback = sharedCamera.createARDeviceStateCallback(cameraDeviceCallback, backgroundHandler);
// Store a reference to the camera system service.
cameraManager = (CameraManager) mActivity.getSystemService(Context.CAMERA_SERVICE);
// Get the characteristics for the ARCore camera.
//CameraCharacteristics characteristics = cameraManager.getCameraCharacteristics(this.cameraId);
// Open the camera device using the ARCore wrapped callback. // Open the camera device using the ARCore wrapped callback.
cameraManager.openCamera(cameraId, wrappedCallback, backgroundHandler); cameraManager.openCamera(cameraId, wrappedCallback, backgroundHandler);
if(mTOFAvailable && cameraId.compareTo(depthCameraId) != 0)
{
cameraManager.openCamera(depthCameraId, mTOFImageReader.cameraDeviceCallback, mTOFImageReader.backgroundHandler);
}
} catch (CameraAccessException e) { } catch (CameraAccessException e) {
Log.e(TAG, "Failed to open camera", e); Log.e(TAG, "Failed to open camera", e);
return false; return false;
@@ -395,14 +523,58 @@ public class ARCoreSharedCamera {
Log.e(TAG, "Failed to open camera", e); Log.e(TAG, "Failed to open camera", e);
return false; return false;
} }
Log.i(TAG, " opencamera: TOF_available: " + mTOFAvailable);
return true; return true;
} }
public static void rotationMatrixToQuaternion(float[] R, float[] q) {
final float m00 = R[0];
final float m10 = R[1];
final float m20 = R[2];
final float m01 = R[4];
final float m11 = R[5];
final float m21 = R[6];
final float m02 = R[8];
final float m12 = R[9];
final float m22 = R[10];
float tr = m00 + m11 + m22;
if (tr > 0) {
float S = (float) Math.sqrt(tr + 1.0) * 2; // S=4*qw
q[0] = 0.25f * S;/* w w w.j ava 2s.co m*/
q[1] = (m21 - m12) / S;
q[2] = (m02 - m20) / S;
q[3] = (m10 - m01) / S;
} else if ((m00 > m11) & (m00 > m22)) {
float S = (float) Math.sqrt(1.0 + m00 - m11 - m22) * 2; //
// S=4*q[1]
q[0] = (m21 - m12) / S;
q[1] = 0.25f * S;
q[2] = (m01 + m10) / S;
q[3] = (m02 + m20) / S;
} else if (m11 > m22) {
float S = (float) Math.sqrt(1.0 + m11 - m00 - m22) * 2; //
// S=4*q[2]
q[0] = (m02 - m20) / S;
q[1] = (m01 + m10) / S;
q[2] = 0.25f * S;
q[3] = (m12 + m21) / S;
} else {
float S = (float) Math.sqrt(1.0 + m22 - m00 - m11) * 2; //
// S=4*q[3]
q[0] = (m10 - m01) / S;
q[1] = (m02 + m20) / S;
q[2] = (m12 + m21) / S;
q[3] = 0.25f * S;
}
}
// Close the camera device. // Close the camera device.
public void close() { public void close() {
Log.w(TAG, "close()");
if (sharedSession != null) { if (sharedSession != null) {
sharedSession.pause(); sharedSession.pause();
@@ -415,11 +587,8 @@ public class ARCoreSharedCamera {
if (cameraDevice != null) { if (cameraDevice != null) {
cameraDevice.close(); cameraDevice.close();
} }
if (mTOFImageReader.imageReader != null) { mTOFImageReader.close();
mTOFImageReader.imageReader.close();
mTOFImageReader.imageReader = null;
}
if(cameraTextureId>=0) if(cameraTextureId>=0)
{ {
@@ -429,8 +598,12 @@ public class ARCoreSharedCamera {
stopBackgroundThread(); stopBackgroundThread();
} }
/*************************************************** ONDRAWFRAME ARCORE ************************************************************* */ public void setDisplayGeometry(int rotation, int width, int height)
{
sharedSession.setDisplayGeometry(rotation, width, height);
}
/*************************************************** ONDRAWFRAME ARCORE ************************************************************* */
// Draw frame when in AR mode. Called on the GL thread. // Draw frame when in AR mode. Called on the GL thread.
public void updateGL() throws CameraNotAvailableException { public void updateGL() throws CameraNotAvailableException {
@@ -463,12 +636,12 @@ public class ARCoreSharedCamera {
if (camera.getTrackingState() == TrackingState.PAUSED) return; if (camera.getTrackingState() == TrackingState.PAUSED) return;
if (frame.getTimestamp() != 0) { if (frame.getTimestamp() != 0) {
Pose pose = camera.getPose(); Pose pose = camera.getPose();
if(!RTABMapActivity.DISABLE_LOG) Log.d(TAG, String.format("pose=%f %f %f q=%f %f %f %f", pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw())); double stamp = (double)frame.getTimestamp()/10e8;
RTABMapLib.postCameraPoseEvent(RTABMapActivity.nativeApplication, pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw()); if(!RTABMapActivity.DISABLE_LOG) Log.d(TAG, String.format("pose=%f %f %f q=%f %f %f %f stamp=%f", pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw(), stamp));
RTABMapLib.postCameraPoseEvent(RTABMapActivity.nativeApplication, pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw(), stamp);
int rateMs = 100; // send images at most 10 Hz int rateMs = 100; // send images at most 10 Hz (to save battery)
if(System. currentTimeMillis() - mPreviousTime < rateMs) if(System. currentTimeMillis() - mPreviousTime < rateMs)
{ {
return; return;
@@ -478,6 +651,7 @@ public class ARCoreSharedCamera {
CameraIntrinsics intrinsics = camera.getImageIntrinsics(); CameraIntrinsics intrinsics = camera.getImageIntrinsics();
try{ try{
Image image = frame.acquireCameraImage(); Image image = frame.acquireCameraImage();
if(!RTABMapActivity.DISABLE_LOG) Log.d(TAG, String.format("frame=%d vs image=%d", frame.getTimestamp(), image.getTimestamp()));
PointCloud cloud = frame.acquirePointCloud(); PointCloud cloud = frame.acquirePointCloud();
FloatBuffer points = cloud.getPoints(); FloatBuffer points = cloud.getPoints();
@@ -502,33 +676,66 @@ public class ARCoreSharedCamera {
ByteBuffer u = image.getPlanes()[1].getBuffer().asReadOnlyBuffer(); ByteBuffer u = image.getPlanes()[1].getBuffer().asReadOnlyBuffer();
ByteBuffer v = image.getPlanes()[2].getBuffer().asReadOnlyBuffer(); ByteBuffer v = image.getPlanes()[2].getBuffer().asReadOnlyBuffer();
double stamp = (double)image.getTimestamp()/10e8; if(!RTABMapActivity.DISABLE_LOG) Log.d(TAG, String.format("RGB %dx%d len=%dbytes format=%d stamp=%f",
if(!RTABMapActivity.DISABLE_LOG) Log.d(TAG, String.format("RGB %dx%d len=%dbytes format=%d =%f",
image.getWidth(), image.getHeight(), y.limit(), image.getFormat(), stamp)); image.getWidth(), image.getHeight(), y.limit(), image.getFormat(), stamp));
float[] texCoord = new float[8];
frame.transformCoordinates2d(
Coordinates2d.OPENGL_NORMALIZED_DEVICE_COORDINATES,
QUAD_COORDS,
Coordinates2d.TEXTURE_NORMALIZED,
texCoord);
float[] p = new float[16];
camera.getProjectionMatrix(p, 0, 0.1f, 100.0f);
float[] viewMatrix = new float[16];
camera.getViewMatrix(viewMatrix, 0);
float[] quat = new float[4];
rotationMatrixToQuaternion(viewMatrix, quat);
if(mTOFAvailable) if(mTOFAvailable)
{ {
if(!RTABMapActivity.DISABLE_LOG) Log.d(TAG, String.format("Depth %dx%d len=%dbytes format=%d stamp=%f", ByteBuffer depth;
mTOFImageReader.WIDTH, mTOFImageReader.HEIGHT, mTOFImageReader.depth16_raw.limit(), ImageFormat.DEPTH16, (double)mTOFImageReader.timestamp/10e9)); double depthStamp;
synchronized (mTOFImageReader) {
depth = mTOFImageReader.depth16_raw;
depthStamp = (double)mTOFImageReader.timestamp/10e8;
}
RTABMapLib.postOdometryEvent( if(!RTABMapActivity.DISABLE_LOG) Log.d(TAG, String.format("Depth %dx%d len=%dbytes format=%d stamp=%f",
mTOFImageReader.WIDTH, mTOFImageReader.HEIGHT, depth.limit(), ImageFormat.DEPTH16, depthStamp));
RTABMapLib.postOdometryEventDepth(
RTABMapActivity.nativeApplication, RTABMapActivity.nativeApplication,
pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw(), pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw(),
fl[0], fl[1], pp[0], pp[1], stamp, fl[0], fl[1], pp[0], pp[1],
depthIntrinsics[0], depthIntrinsics[1], depthIntrinsics[2], depthIntrinsics[3],
rgbExtrinsics.tx(), rgbExtrinsics.ty(), rgbExtrinsics.tz(), rgbExtrinsics.qx(), rgbExtrinsics.qy(), rgbExtrinsics.qz(), rgbExtrinsics.qw(),
depthExtrinsics.tx(), depthExtrinsics.ty(), depthExtrinsics.tz(), depthExtrinsics.qx(), depthExtrinsics.qy(), depthExtrinsics.qz(), depthExtrinsics.qw(),
stamp,
depthStamp,
y, u, v, y.limit(), image.getWidth(), image.getHeight(), image.getFormat(), y, u, v, y.limit(), image.getWidth(), image.getHeight(), image.getFormat(),
mTOFImageReader.depth16_raw, mTOFImageReader.depth16_raw.limit(), mTOFImageReader.WIDTH, mTOFImageReader.HEIGHT, ImageFormat.DEPTH16, depth, depth.limit(), mTOFImageReader.WIDTH, mTOFImageReader.HEIGHT, ImageFormat.DEPTH16,
points, points.limit()/4); points, points.limit()/4,
viewMatrix[12], viewMatrix[13], viewMatrix[14], quat[1], quat[2], quat[3], quat[0],
p[0], p[5], p[8], p[9], p[10], p[11], p[14],
texCoord[0],texCoord[1],texCoord[2],texCoord[3],texCoord[4],texCoord[5],texCoord[6],texCoord[7]);
} }
else else
{ {
ByteBuffer bb = ByteBuffer.allocate(0);
RTABMapLib.postOdometryEvent( RTABMapLib.postOdometryEvent(
RTABMapActivity.nativeApplication, RTABMapActivity.nativeApplication,
pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw(), pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw(),
fl[0], fl[1], pp[0], pp[1], stamp, fl[0], fl[1], pp[0], pp[1],
rgbExtrinsics.tx(), rgbExtrinsics.ty(), rgbExtrinsics.tz(), rgbExtrinsics.qx(), rgbExtrinsics.qy(), rgbExtrinsics.qz(), rgbExtrinsics.qw(),
stamp,
y, u, v, y.limit(), image.getWidth(), image.getHeight(), image.getFormat(), y, u, v, y.limit(), image.getWidth(), image.getHeight(), image.getFormat(),
bb, 0, 0, 0, ImageFormat.DEPTH16, points, points.limit()/4,
points, points.limit()/4); viewMatrix[12], viewMatrix[13], viewMatrix[14], quat[1], quat[2], quat[3], quat[0],
p[0], p[5], p[8], p[9], p[10], p[11], p[14],
texCoord[0],texCoord[1],texCoord[2],texCoord[3],texCoord[4],texCoord[5],texCoord[6],texCoord[7]);
} }
image.close(); image.close();
@@ -545,8 +752,8 @@ public class ARCoreSharedCamera {
/********************************************************************************************************************* */ /********************************************************************************************************************* */
public ArrayList<String> getResolutions (Context context, String cameraId,int imageFormat){ public ArrayList<String> getResolutions (Context context, String cameraId, int imageFormat){
Log.v(TAG + "getResolutions:", " cameraId:" + cameraId + " imageFormat: " + imageFormat); Log.v(TAG, "getResolutions: cameraId:" + cameraId + " imageFormat: " + imageFormat);
ArrayList<String> output = new ArrayList<String>(); ArrayList<String> output = new ArrayList<String>();
try { try {
@@ -562,27 +769,4 @@ public class ARCoreSharedCamera {
return output; return output;
} }
public void initCamera (Context context, String cameraId,int index){
boolean ok = false;
try {
int current = 0;
CameraManager manager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
CameraCharacteristics characteristics = manager.getCameraCharacteristics(cameraId);
for (android.util.Size s : characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP).getOutputSizes(ImageFormat.DEPTH16)) {
ok = true;
if (current == index)
break;
else ;
current++;
}
} catch (Exception e) {
e.printStackTrace();
}
if (!ok) {
Log.e(TAG + " initCamera", "Depth sensor not found!");
}
}
} }

View File

@@ -0,0 +1,166 @@
package com.introlab.rtabmap;
/*
* Copyright 2017 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import android.app.Activity;
import android.content.Context;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCharacteristics;
import android.hardware.camera2.CameraManager;
import android.hardware.display.DisplayManager;
import android.hardware.display.DisplayManager.DisplayListener;
import android.view.Display;
import android.view.Surface;
import android.view.WindowManager;
import com.google.ar.core.Session;
/**
* Helper to track the display rotations. In particular, the 180 degree rotations are not notified
* by the onSurfaceChanged() callback, and thus they require listening to the android display
* events.
*/
public final class DisplayRotationHelper implements DisplayListener {
private boolean viewportChanged;
private int viewportWidth;
private int viewportHeight;
private final Display display;
private final DisplayManager displayManager;
private final CameraManager cameraManager;
/**
* Constructs the DisplayRotationHelper but does not register the listener yet.
*
* @param context the Android {@link Context}.
*/
public DisplayRotationHelper(Context context) {
displayManager = (DisplayManager) context.getSystemService(Context.DISPLAY_SERVICE);
cameraManager = (CameraManager) context.getSystemService(Context.CAMERA_SERVICE);
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
display = windowManager.getDefaultDisplay();
}
/** Registers the display listener. Should be called from {@link Activity#onResume()}. */
public void onResume() {
displayManager.registerDisplayListener(this, null);
}
/** Unregisters the display listener. Should be called from {@link Activity#onPause()}. */
public void onPause() {
displayManager.unregisterDisplayListener(this);
}
/**
* Records a change in surface dimensions. This will be later used by {@link
* #updateSessionIfNeeded(Session)}. Should be called from {@link
* android.opengl.GLSurfaceView.Renderer
* #onSurfaceChanged(javax.microedition.khronos.opengles.GL10, int, int)}.
*
* @param width the updated width of the surface.
* @param height the updated height of the surface.
*/
public void onSurfaceChanged(int width, int height) {
viewportWidth = width;
viewportHeight = height;
viewportChanged = true;
}
/**
* Updates the session display geometry if a change was posted either by {@link
* #onSurfaceChanged(int, int)} call or by {@link #onDisplayChanged(int)} system callback. This
* function should be called explicitly before each call to {@link Session#update()}. This
* function will also clear the 'pending update' (viewportChanged) flag.
*
* @param session the {@link Session} object to update if display geometry changed.
*/
public void updateSessionIfNeeded(ARCoreSharedCamera session) {
if (viewportChanged) {
int displayRotation = display.getRotation();
session.setDisplayGeometry(displayRotation, viewportWidth, viewportHeight);
viewportChanged = false;
}
}
/**
* Returns the aspect ratio of the GL surface viewport while accounting for the display rotation
* relative to the device camera sensor orientation.
*/
public float getCameraSensorRelativeViewportAspectRatio(String cameraId) {
float aspectRatio;
int cameraSensorToDisplayRotation = getCameraSensorToDisplayRotation(cameraId);
switch (cameraSensorToDisplayRotation) {
case 90:
case 270:
aspectRatio = (float) viewportHeight / (float) viewportWidth;
break;
case 0:
case 180:
aspectRatio = (float) viewportWidth / (float) viewportHeight;
break;
default:
throw new RuntimeException("Unhandled rotation: " + cameraSensorToDisplayRotation);
}
return aspectRatio;
}
/**
* Returns the rotation of the back-facing camera with respect to the display. The value is one of
* 0, 90, 180, 270.
*/
public int getCameraSensorToDisplayRotation(String cameraId) {
CameraCharacteristics characteristics;
try {
characteristics = cameraManager.getCameraCharacteristics(cameraId);
} catch (CameraAccessException e) {
throw new RuntimeException("Unable to determine display orientation", e);
}
// Camera sensor orientation.
int sensorOrientation = characteristics.get(CameraCharacteristics.SENSOR_ORIENTATION);
// Current display orientation.
int displayOrientation = toDegrees(display.getRotation());
// Make sure we return 0, 90, 180, or 270 degrees.
return (sensorOrientation - displayOrientation + 360) % 360;
}
private int toDegrees(int rotation) {
switch (rotation) {
case Surface.ROTATION_0:
return 0;
case Surface.ROTATION_90:
return 90;
case Surface.ROTATION_180:
return 180;
case Surface.ROTATION_270:
return 270;
default:
throw new RuntimeException("Unknown rotation " + rotation);
}
}
@Override
public void onDisplayAdded(int displayId) {}
@Override
public void onDisplayRemoved(int displayId) {}
@Override
public void onDisplayChanged(int displayId) {
viewportChanged = true;
}
}

View File

@@ -104,7 +104,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
// Tag for debug logging. // Tag for debug logging.
public static final String TAG = RTABMapActivity.class.getSimpleName(); public static final String TAG = RTABMapActivity.class.getSimpleName();
public static boolean DISABLE_LOG = true; public static boolean DISABLE_LOG = false;
// The minimum Tango Core version required from this application. // The minimum Tango Core version required from this application.
private static final int MIN_TANGO_CORE_VERSION = 9377; private static final int MIN_TANGO_CORE_VERSION = 9377;

View File

@@ -134,13 +134,30 @@ public class RTABMapLib
public static native float getUpdateTime(long nativeApplication); public static native float getUpdateTime(long nativeApplication);
public static native int getLoopClosureId(long nativeApplication); public static native int getLoopClosureId(long nativeApplication);
public static native void postCameraPoseEvent(long nativeApplication, float x, float y, float z, float qx, float qy, float qz, float qw); public static native void postCameraPoseEvent(long nativeApplication, float x, float y, float z, float qx, float qy, float qz, float qw, double stamp);
public static native void postOdometryEvent(long nativeApplication, public static native void postOdometryEvent(long nativeApplication,
float x, float y, float z, float qx, float qy, float qz, float qw, float x, float y, float z, float qx, float qy, float qz, float qw,
float fx, float fy, float cx, float cy, float rgb_fx, float rgb_fy, float rgb_cx, float rgb_cy,
float rgbFrameX, float rgbFrameY, float rgbFrameZ, float rgbFrameQX, float rgbFrameQY, float rgbFrameQZ, float rgbFrameQW,
double stamp, double stamp,
ByteBuffer yPlane, ByteBuffer uPlane, ByteBuffer vPlane, int yPlaneLen, int rgbWidth, int rgbHeight, int rgbFormat, ByteBuffer yPlane, ByteBuffer uPlane, ByteBuffer vPlane, int yPlaneLen, int rgbWidth, int rgbHeight, int rgbFormat,
FloatBuffer points, int pointsLen,
float vx, float vy, float vz, float vqx, float vqy, float vqz, float vqw, //view matrix
float p00, float p11, float p02, float p12, float p22, float p32, float p23, // projection matrix
float t0, float t1, float t2, float t3, float t4, float t5, float t6, float t7); // tex coord
public static native void postOdometryEventDepth(long nativeApplication,
float x, float y, float z, float qx, float qy, float qz, float qw,
float rgb_fx, float rgb_fy, float rgb_cx, float rgb_cy,
float depth_fx, float depth_fy, float depth_cx, float depth_cy,
float rgbFrameX, float rgbFrameY, float rgbFrameZ, float rgbFrameQX, float rgbFrameQY, float rgbFrameQZ, float rgbFrameQW,
float depthFrameX, float depthFrameY, float depthFrameZ, float depthFrameQX, float depthFrameQY, float depthFrameQZ, float depthFrameQW,
double rgbStamp,
double depthStamp,
ByteBuffer yPlane, ByteBuffer uPlane, ByteBuffer vPlane, int yPlaneLen, int rgbWidth, int rgbHeight, int rgbFormat,
ByteBuffer depth, int depthLen, int depthWidth, int depthHeight, int depthFormat, ByteBuffer depth, int depthLen, int depthWidth, int depthHeight, int depthFormat,
FloatBuffer points, int pointsLen); FloatBuffer points, int pointsLen,
float vx, float vy, float vz, float vqx, float vqy, float vqz, float vqw, //view matrix
float p00, float p11, float p02, float p12, float p22, float p32, float p23, // projection matrix
float t0, float t1, float t2, float t3, float t4, float t5, float t6, float t7); // tex coord
} }

View File

@@ -44,12 +44,14 @@ public class Renderer implements GLSurfaceView.Renderer {
private float mTextColor = 1.0f; private float mTextColor = 1.0f;
private int mOffset = 0; private int mOffset = 0;
private ARCoreSharedCamera mCamera = null; private ARCoreSharedCamera mCamera = null;
private DisplayRotationHelper mDisplayRotationHelper = null;
private Vector<TextObject> mTexts; private Vector<TextObject> mTexts;
private static RTABMapActivity mActivity; private static RTABMapActivity mActivity;
public Renderer(RTABMapActivity c) { public Renderer(RTABMapActivity c) {
mActivity = c; mActivity = c;
mDisplayRotationHelper = new DisplayRotationHelper(/*context=*/ c);
} }
private ProgressDialog mProgressDialog = null; private ProgressDialog mProgressDialog = null;
@@ -76,6 +78,11 @@ public class Renderer implements GLSurfaceView.Renderer {
public void setCamera(ARCoreSharedCamera camera) public void setCamera(ARCoreSharedCamera camera)
{ {
mCamera = camera; mCamera = camera;
if(mCamera!=null)
{
mDisplayRotationHelper.onDisplayChanged(0);
mDisplayRotationHelper.updateSessionIfNeeded(mCamera);
}
} }
// Render loop of the Gl context. // Render loop of the Gl context.
@@ -176,6 +183,12 @@ public class Renderer implements GLSurfaceView.Renderer {
RTABMapLib.setupGraphic(mActivity.nativeApplication, width, height); RTABMapLib.setupGraphic(mActivity.nativeApplication, width, height);
} }
mDisplayRotationHelper.onSurfaceChanged(width, height);
if(mCamera!=null)
{
mDisplayRotationHelper.updateSessionIfNeeded(mCamera);
}
mSurfaceHeight = (float)height; mSurfaceHeight = (float)height;
// Clear our matrices // Clear our matrices

View File

@@ -2,18 +2,33 @@ package com.introlab.rtabmap;
import android.graphics.ImageFormat; import android.graphics.ImageFormat;
import android.hardware.camera2.CameraAccessException;
import android.hardware.camera2.CameraCaptureSession;
import android.hardware.camera2.CameraDevice;
import android.hardware.camera2.CameraManager;
import android.hardware.camera2.CaptureFailure;
import android.hardware.camera2.CaptureRequest;
import android.hardware.camera2.TotalCaptureResult;
import android.media.Image; import android.media.Image;
import android.media.ImageReader; import android.media.ImageReader;
import android.os.Handler; import android.os.Handler;
import android.os.HandlerThread; import android.os.HandlerThread;
import android.support.annotation.NonNull;
import android.util.Log; import android.util.Log;
import android.view.Surface;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class TOF_ImageReader implements ImageReader.OnImageAvailableListener { public class TOF_ImageReader implements ImageReader.OnImageAvailableListener {
public int WIDTH; public static final String TAG = TOF_ImageReader.class.getSimpleName();
public int HEIGHT;
public int WIDTH;
public int HEIGHT;
public ImageReader imageReader; public ImageReader imageReader;
public int frameCount = 0; public int frameCount = 0;
public long timestamp; public long timestamp;
@@ -21,16 +36,177 @@ public class TOF_ImageReader implements ImageReader.OnImageAvailableListener {
// Looper handler thread. // Looper handler thread.
private HandlerThread backgroundThread; private HandlerThread backgroundThread;
// Looper handler. // Looper handler.
private Handler backgroundHandler; public Handler backgroundHandler;
public ByteBuffer depth16_raw; public ByteBuffer depth16_raw;
// Camera capture session.
private CameraCaptureSession captureSession = null;
// Camera device.
private CameraDevice cameraDevice = null;
// Camera preview capture request builder
private CaptureRequest.Builder previewCaptureRequestBuilder;
TOF_ImageReader(){ TOF_ImageReader(){
} }
public void close()
{
Log.i(TAG, "close()");
if (captureSession != null) {
captureSession.close();
captureSession = null;
}
if (cameraDevice != null) {
cameraDevice.close();
cameraDevice = null;
}
if (imageReader != null) {
imageReader.close();
imageReader = null;
}
}
// Camera device state callback.
public final CameraDevice.StateCallback cameraDeviceCallback =
new CameraDevice.StateCallback() {
@Override
public void onOpened(@NonNull CameraDevice cameraDevice) {
Log.d(TAG, "Camera depth ID " + cameraDevice.getId() + " opened.");
TOF_ImageReader.this.cameraDevice = cameraDevice;
createCameraPreviewSession();
}
@Override
public void onClosed(@NonNull CameraDevice cameraDevice) {
Log.d(TAG, "Camera device ID " + cameraDevice.getId() + " closed.");
TOF_ImageReader.this.cameraDevice = null;
}
@Override
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
Log.w(TAG, "Camera depth ID " + cameraDevice.getId() + " disconnected.");
cameraDevice.close();
TOF_ImageReader.this.cameraDevice = null;
}
@Override
public void onError(@NonNull CameraDevice cameraDevice, int error) {
Log.e(TAG, "Camera depth ID " + cameraDevice.getId() + " error " + error);
cameraDevice.close();
TOF_ImageReader.this.cameraDevice = null;
}
};
private CameraCaptureSession.StateCallback captureStateCallback = new CameraCaptureSession.StateCallback() {
// Called when the camera capture session is first configured after the app
// is initialized, and again each time the activity is resumed.
@Override
public void onConfigured(@NonNull CameraCaptureSession session) {
Log.d(TAG, "Camera capture session configured.");
captureSession = session;
setRepeatingCaptureRequest();
}
@Override
public void onSurfacePrepared(
@NonNull CameraCaptureSession session, @NonNull Surface surface) {
Log.d(TAG, "Camera capture surface prepared.");
}
@Override
public void onReady(@NonNull CameraCaptureSession session) {
Log.d(TAG, "Camera capture session ready.");
}
@Override
public void onActive(@NonNull CameraCaptureSession session) {
Log.d(TAG, "Camera capture session active.");
}
@Override
public void onClosed(@NonNull CameraCaptureSession session) {
Log.d(TAG, "Camera capture session closed.");
}
@Override
public void onConfigureFailed(@NonNull CameraCaptureSession session) {
Log.e(TAG, "Failed to configure camera capture session.");
}
};
// Repeating camera capture session capture callback.
private final CameraCaptureSession.CaptureCallback captureSessionCallback =
new CameraCaptureSession.CaptureCallback() {
@Override
public void onCaptureCompleted(
@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull TotalCaptureResult result) {
//Log.i(TAG, "onCaptureCompleted");
}
//@Override // android 23
public void onCaptureBufferLost(
@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull Surface target,
long frameNumber) {
Log.e(TAG, "onCaptureBufferLost: " + frameNumber);
}
@Override
public void onCaptureFailed(
@NonNull CameraCaptureSession session,
@NonNull CaptureRequest request,
@NonNull CaptureFailure failure) {
Log.e(TAG, "onCaptureFailed: " + failure.getFrameNumber() + " " + failure.getReason());
}
@Override
public void onCaptureSequenceAborted(
@NonNull CameraCaptureSession session, int sequenceId) {
Log.e(TAG, "onCaptureSequenceAborted: " + sequenceId + " " + session);
}
};
// Called when starting non-AR mode or switching to non-AR mode.
// Also called when app starts in AR mode, or resumes in AR mode.
private void setRepeatingCaptureRequest() {
try {
captureSession.setRepeatingRequest(
previewCaptureRequestBuilder.build(), captureSessionCallback, backgroundHandler);
} catch (CameraAccessException e) {
Log.e(TAG, "Failed to set repeating request", e);
}
}
private void createCameraPreviewSession() {
Log.e(TAG, "createCameraPreviewSession: " + "starting camera preview session.");
frameCount = 0;
try {
// Create an ARCore compatible capture request using `TEMPLATE_RECORD`.
previewCaptureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
previewCaptureRequestBuilder.addTarget(imageReader.getSurface());
// Create camera capture session for camera preview using callback.
cameraDevice.createCaptureSession(Arrays.asList(imageReader.getSurface()), captureStateCallback, backgroundHandler);
} catch (CameraAccessException e) {
Log.e(TAG, "CameraAccessException", e);
}
}
public void createImageReader(int width, int height){ public void createImageReader(int width, int height){
this.WIDTH = width; Log.w(TAG, String.valueOf(width) + "x" + String.valueOf(height));
this.HEIGHT = height; WIDTH = width;
HEIGHT = height;
this.imageReader = this.imageReader =
ImageReader.newInstance( ImageReader.newInstance(
width, width,
@@ -45,18 +221,20 @@ public class TOF_ImageReader implements ImageReader.OnImageAvailableListener {
public void onImageAvailable(ImageReader imageReader) { public void onImageAvailable(ImageReader imageReader) {
Image image = imageReader.acquireLatestImage(); Image image = imageReader.acquireLatestImage();
if (image == null) { if (image == null) {
Log.w("RTABMapActivity", "onImageAvailable: Skipping null image."); Log.w(TAG, "onImageAvailable: Skipping null image.");
return; return;
} }
else{ else{
if(image.getFormat() == ImageFormat.DEPTH16){ if(image.getFormat() == ImageFormat.DEPTH16){
this.timestamp = image.getTimestamp(); synchronized (this) {
depth16_raw = image.getPlanes()[0].getBuffer().asReadOnlyBuffer(); depth16_raw = image.getPlanes()[0].getBuffer().asReadOnlyBuffer();
timestamp = image.getTimestamp();
}
// copy raw undecoded DEPTH16 format depth data to NativeBuffer // copy raw undecoded DEPTH16 format depth data to NativeBuffer
frameCount++; frameCount++;
} }
else{ else{
Log.w("RTABMapActivity", "onImageAvailable: depth image not in DEPTH16 format, skipping image"); Log.w(TAG, "onImageAvailable: depth image not in DEPTH16 format, skipping image");
} }
} }
image.close(); image.close();
@@ -78,7 +256,7 @@ public class TOF_ImageReader implements ImageReader.OnImageAvailableListener {
this.backgroundThread = null; this.backgroundThread = null;
this.backgroundHandler = null; this.backgroundHandler = null;
} catch (InterruptedException e) { } catch (InterruptedException e) {
Log.e("RTABMapActivity", "Interrupted while trying to join depth background handler thread", e); Log.e(TAG, "Interrupted while trying to join depth background handler thread", e);
} }
} }
} }