mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-11 14:00:20 +08:00
Compare commits
3
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4873e770a | ||
|
|
3148ae2d76 | ||
|
|
8819b42f24 |
+1
-15
@@ -35,7 +35,7 @@ install:
|
||||
# OpenCV
|
||||
#- ps: wget 'http://kent.dl.sourceforge.net/project/opencvlibrary/opencv-win/3.3.1/opencv-3.3.1-vc14.exe' -outfile opencv-3.3.1-vc14.exe
|
||||
#- cmd: opencv-3.3.1-vc14.exe -o"C:\Program Files" -y
|
||||
- ps: $url = "https://downloads.sourceforge.net/project/opencvlibrary/opencv-win/2.4.13/opencv-2.4.13.6-vc14.exe?r=&ts="+([int64](([datetime]::UtcNow)-(get-date "1/1/1970")).TotalSeconds) ; wget $url -outfile opencv-2.4.13.6-vc14.exe
|
||||
- ps: wget 'http://kent.dl.sourceforge.net/project/opencvlibrary/opencv-win/2.4.13/opencv-2.4.13.6-vc14.exe' -outfile opencv-2.4.13.6-vc14.exe
|
||||
- cmd: opencv-2.4.13.6-vc14.exe -o"C:\Program Files" -y
|
||||
- ECHO "Installed OpenCV:"
|
||||
- ps: "ls \"C:/Program Files/opencv/build\""
|
||||
@@ -115,20 +115,6 @@ install:
|
||||
- cmd: yaml-cpp.exe -o"C:\Program Files" -y
|
||||
- ECHO "Installed yaml-cpp:"
|
||||
- ps: "ls \"C:/Program Files/yaml-cpp\""
|
||||
# RealSense2
|
||||
- ps: wget 'https://github.com/IntelRealSense/librealsense/releases/download/v2.40.0/Intel.RealSense.SDK-WIN10-2.40.0.2482.exe' -outfile realsense2.exe
|
||||
- cmd: realsense2.exe /VERYSILENT
|
||||
- ECHO "Installed RealSense2:"
|
||||
- ps: "ls \"C:/Program Files (x86)/Intel RealSense SDK 2.0\""
|
||||
- set PATH=%PATH%;C:\Program Files (x86)\Intel RealSense SDK 2.0\bin\x64
|
||||
- set RealSense2_ROOT_DIR=C:\Program Files (x86)\Intel RealSense SDK 2.0
|
||||
# Kinect 4 Azure
|
||||
- ps: wget 'https://download.microsoft.com/download/3/d/6/3d6d9e99-a251-4cf3-8c6a-8e108e960b4b/Azure%20Kinect%20SDK%201.4.1.exe' -outfile azure.exe
|
||||
- cmd: azure.exe /quiet
|
||||
- ECHO "Installed Kinect For Azure:"
|
||||
- ps: "ls \"C:/Program Files/Azure Kinect SDK v1.4.1\""
|
||||
- set PATH=%PATH%;C:\Program Files\Azure Kinect SDK v1.4.1\tools
|
||||
- set K4A_ROOT_DIR=C:\Program Files\Azure Kinect SDK v1.4.1
|
||||
|
||||
before_build:
|
||||
- cd c:\projects\rtabmap\build
|
||||
|
||||
@@ -8,5 +8,3 @@ app/android/.classpath
|
||||
app/android/.project
|
||||
app/android/AndroidManifest.xml
|
||||
app/android/res/raw/
|
||||
compile_flags.txt
|
||||
tags
|
||||
|
||||
+7
-12
@@ -21,7 +21,7 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
|
||||
#######################
|
||||
SET(RTABMAP_MAJOR_VERSION 0)
|
||||
SET(RTABMAP_MINOR_VERSION 20)
|
||||
SET(RTABMAP_PATCH_VERSION 7)
|
||||
SET(RTABMAP_PATCH_VERSION 2)
|
||||
SET(RTABMAP_VERSION
|
||||
${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION})
|
||||
|
||||
@@ -61,7 +61,7 @@ ELSE ()
|
||||
ENDIF()
|
||||
|
||||
if(POLICY CMP0020)
|
||||
cmake_policy(SET CMP0020 NEW)
|
||||
cmake_policy(SET CMP0020 OLD)
|
||||
endif()
|
||||
if(POLICY CMP0043)
|
||||
cmake_policy(SET CMP0043 OLD)
|
||||
@@ -427,10 +427,6 @@ ENDIF(WITH_CVSBA)
|
||||
IF(WITH_POINTMATCHER)
|
||||
find_package(libpointmatcher QUIET)
|
||||
IF(libpointmatcher_FOUND)
|
||||
find_package(Boost COMPONENTS thread filesystem system program_options date_time REQUIRED)
|
||||
if (Boost_MINOR_VERSION GREATER 47)
|
||||
find_package(Boost COMPONENTS thread filesystem system program_options date_time chrono timer REQUIRED)
|
||||
endif (Boost_MINOR_VERSION GREATER 47)
|
||||
MESSAGE(STATUS "Found libpointmatcher: ${libpointmatcher_INCLUDE_DIRS}")
|
||||
ENDIF(libpointmatcher_FOUND)
|
||||
ENDIF(WITH_POINTMATCHER)
|
||||
@@ -519,9 +515,9 @@ IF(WITH_ALICE_VISION)
|
||||
IF(AliceVision_FOUND)
|
||||
SET(CMAKE_MODULE_PATH "${CMAKE_MODULE_PATH};/usr/local/lib/cmake/modules")
|
||||
find_package(Geogram REQUIRED QUIET)
|
||||
add_definitions("-DRTABMAP_ALICE_VISION_MAJOR=${AliceVision_VERSION_MAJOR}")
|
||||
add_definitions("-DRTABMAP_ALICE_VISION_MINOR=${AliceVision_VERSION_MINOR}")
|
||||
add_definitions("-DRTABMAP_ALICE_VISION_PATCH=${AliceVision_VERSION_PATCH}")
|
||||
# Make sure the two following lines are also commented in AliceVision to avoid Eigen memory alignment error
|
||||
#add_definitions("-DEIGEN_DONT_ALIGN_STATICALLY=1")
|
||||
#add_definitions("-DEIGEN_DONT_VECTORIZE=1")
|
||||
ENDIF(AliceVision_FOUND)
|
||||
ENDIF(WITH_ALICE_VISION)
|
||||
|
||||
@@ -626,8 +622,7 @@ ELSEIF(G2O_FOUND OR
|
||||
okvis_FOUND OR
|
||||
open_chisel_FOUND OR
|
||||
msckf_vio_FOUND OR
|
||||
vins_FOUND OR
|
||||
libpointmatcher_FOUND)
|
||||
vins_FOUND)
|
||||
#Newest versions require std11
|
||||
IF(NOT MSVC)
|
||||
include(CheckCXXCompilerFlag)
|
||||
@@ -1214,7 +1209,7 @@ MESSAGE(STATUS " With OpenChisel = NO (open_chisel not found)")
|
||||
ENDIF()
|
||||
|
||||
IF(AliceVision_FOUND)
|
||||
MESSAGE(STATUS " With AliceVision ${AliceVision_VERSION} = YES (License: MPLv2)")
|
||||
MESSAGE(STATUS " With AliceVision = YES (License: MPLv2)")
|
||||
ELSEIF(NOT WITH_ALICE_VISION)
|
||||
MESSAGE(STATUS " With AliceVision = NO (WITH_ALICE_VISION=OFF)")
|
||||
ELSE()
|
||||
|
||||
@@ -76,17 +76,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
@PYMATCHER@#define RTABMAP_PYMATCHER
|
||||
@MADGWICK@#define RTABMAP_MADGWICK
|
||||
|
||||
#include <pcl/pcl_config.h>
|
||||
|
||||
#if PCL_VERSION_COMPARE(>, 1, 11, 1)
|
||||
#include <pcl/types.h>
|
||||
#define RTABMAP_PCL_INDEX pcl::index_t
|
||||
#elif PCL_VERSION_COMPARE(>=, 1, 10, 0)
|
||||
#define RTABMAP_PCL_INDEX std::uint32_t
|
||||
#else
|
||||
#include <pcl/pcl_macros.h>
|
||||
#define RTABMAP_PCL_INDEX pcl::uint32_t
|
||||
#endif
|
||||
|
||||
#endif /* VERSION_H_ */
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
android:excludeFromRecents="true"
|
||||
android:exported="false"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@android:style/Theme.Material.Light.Dialog.Alert" />
|
||||
android:theme="@style/ThemeApp" />
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
|
||||
@@ -308,7 +308,7 @@ int RTABMapApp::openDatabase(const std::string & databasePath, bool databaseInMe
|
||||
optRefPose_ = 0;
|
||||
}
|
||||
cv::Mat cloudMat;
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
|
||||
std::vector<std::vector<std::vector<unsigned int> > > polygons;
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
|
||||
#else
|
||||
@@ -2902,7 +2902,7 @@ bool RTABMapApp::exportMesh(
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
|
||||
pcl::fromPCLPointCloud2(polygonMesh->cloud, *cloud);
|
||||
cv::Mat cloudMat = rtabmap::compressData2(rtabmap::util3d::laserScanFromPointCloud(*cloud, rtabmap::Transform(), false)); // for database
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons(1);
|
||||
std::vector<std::vector<std::vector<unsigned int> > > polygons(1);
|
||||
polygons[0].resize(polygonMesh->polygons.size());
|
||||
for(unsigned int p=0; p<polygonMesh->polygons.size(); ++p)
|
||||
{
|
||||
@@ -2921,7 +2921,7 @@ bool RTABMapApp::exportMesh(
|
||||
cv::Mat cloudMat = rtabmap::compressData2(rtabmap::util3d::laserScanFromPointCloud(*cloud, rtabmap::Transform(), false)); // for database
|
||||
|
||||
// save in database
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons(textureMesh->tex_polygons.size());
|
||||
std::vector<std::vector<std::vector<unsigned int> > > polygons(textureMesh->tex_polygons.size());
|
||||
for(unsigned int t=0; t<textureMesh->tex_polygons.size(); ++t)
|
||||
{
|
||||
polygons[t].resize(textureMesh->tex_polygons[t].size());
|
||||
@@ -3114,7 +3114,7 @@ bool RTABMapApp::postExportation(bool visualize)
|
||||
{
|
||||
visualizingMesh_ = false;
|
||||
cv::Mat cloudMat;
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
|
||||
std::vector<std::vector<std::vector<unsigned int> > > polygons;
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
|
||||
#else
|
||||
@@ -3171,7 +3171,7 @@ bool RTABMapApp::writeExportedMesh(const std::string & directory, const std::str
|
||||
pcl::PolygonMesh::Ptr polygonMesh(new pcl::PolygonMesh);
|
||||
pcl::TextureMesh::Ptr textureMesh(new pcl::TextureMesh);
|
||||
cv::Mat cloudMat;
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > polygons;
|
||||
std::vector<std::vector<std::vector<unsigned int> > > polygons;
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > texCoords;
|
||||
#else
|
||||
@@ -3186,7 +3186,7 @@ bool RTABMapApp::writeExportedMesh(const std::string & directory, const std::str
|
||||
LOGI("writeExportedMesh: Found optimized mesh!");
|
||||
if(textures.empty())
|
||||
{
|
||||
polygonMesh = rtabmap::util3d::assemblePolygonMesh(cloudMat, polygons.size() == 1?polygons[0]:std::vector<std::vector<RTABMAP_PCL_INDEX> >());
|
||||
polygonMesh = rtabmap::util3d::assemblePolygonMesh(cloudMat, polygons.size() == 1?polygons[0]:std::vector<std::vector<unsigned int> >());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -1,588 +0,0 @@
|
||||
package com.introlab.rtabmap;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
import com.google.ar.core.Camera;
|
||||
import com.google.ar.core.CameraIntrinsics;
|
||||
import com.google.ar.core.Config;
|
||||
import com.google.ar.core.Frame;
|
||||
import com.google.ar.core.ImageMetadata;
|
||||
import com.google.ar.core.PointCloud;
|
||||
import com.google.ar.core.Pose;
|
||||
import com.google.ar.core.Session;
|
||||
import com.google.ar.core.SharedCamera;
|
||||
import com.google.ar.core.TrackingState;
|
||||
import com.google.ar.core.exceptions.CameraNotAvailableException;
|
||||
import com.google.ar.core.exceptions.NotYetAvailableException;
|
||||
import com.google.ar.core.exceptions.UnavailableException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.ImageFormat;
|
||||
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.TotalCaptureResult;
|
||||
import android.media.Image;
|
||||
import android.opengl.GLES20;
|
||||
import android.opengl.GLSurfaceView;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
import android.view.Surface;
|
||||
|
||||
public class ARCoreSharedCamera {
|
||||
|
||||
public static final String TAG = ARCoreSharedCamera.class.getSimpleName();
|
||||
|
||||
|
||||
private static RTABMapActivity mActivity;
|
||||
public ARCoreSharedCamera(RTABMapActivity c) {
|
||||
mActivity = c;
|
||||
}
|
||||
|
||||
// Depth TOF Image.
|
||||
// Use 240 * 180 for now, hardcoded for Huawei P30 Pro
|
||||
private static final int DEPTH_WIDTH = 240;
|
||||
private static final int DEPTH_HEIGHT = 180;
|
||||
|
||||
// GL Surface used to draw camera preview image.
|
||||
public GLSurfaceView surfaceView;
|
||||
|
||||
// ARCore session that supports camera sharing.
|
||||
private Session sharedSession;
|
||||
|
||||
// Camera capture session. Used by both non-AR and AR modes.
|
||||
private CameraCaptureSession captureSession;
|
||||
|
||||
// Reference to the camera system service.
|
||||
private CameraManager cameraManager;
|
||||
|
||||
// Camera device. Used by both non-AR and AR modes.
|
||||
private CameraDevice cameraDevice;
|
||||
|
||||
// Looper handler thread.
|
||||
private HandlerThread backgroundThread;
|
||||
// Looper handler.
|
||||
private Handler backgroundHandler;
|
||||
|
||||
// ARCore shared camera instance, obtained from ARCore session that supports sharing.
|
||||
private SharedCamera sharedCamera;
|
||||
|
||||
// Camera ID for the camera used by ARCore.
|
||||
private String cameraId;
|
||||
|
||||
private AtomicBoolean mReady = new AtomicBoolean(false);
|
||||
|
||||
// Camera preview capture request builder
|
||||
private CaptureRequest.Builder previewCaptureRequestBuilder;
|
||||
|
||||
private int cameraTextureId = -1;
|
||||
|
||||
// Image reader that continuously processes CPU images.
|
||||
public TOF_ImageReader mTOFImageReader = new TOF_ImageReader();
|
||||
private boolean mTOFAvailable = false;
|
||||
|
||||
public boolean isDepthSupported() {return mTOFAvailable;}
|
||||
|
||||
// Camera device state callback.
|
||||
private final CameraDevice.StateCallback cameraDeviceCallback =
|
||||
new CameraDevice.StateCallback() {
|
||||
@Override
|
||||
public void onOpened(@NonNull CameraDevice cameraDevice) {
|
||||
Log.d(TAG, "Camera device ID " + cameraDevice.getId() + " opened.");
|
||||
ARCoreSharedCamera.this.cameraDevice = cameraDevice;
|
||||
createCameraPreviewSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onClosed(@NonNull CameraDevice cameraDevice) {
|
||||
Log.d(TAG, "Camera device ID " + cameraDevice.getId() + " closed.");
|
||||
ARCoreSharedCamera.this.cameraDevice = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisconnected(@NonNull CameraDevice cameraDevice) {
|
||||
Log.w(TAG, "Camera device ID " + cameraDevice.getId() + " disconnected.");
|
||||
cameraDevice.close();
|
||||
ARCoreSharedCamera.this.cameraDevice = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(@NonNull CameraDevice cameraDevice, int error) {
|
||||
Log.e(TAG, "Camera device ID " + cameraDevice.getId() + " error " + error);
|
||||
cameraDevice.close();
|
||||
ARCoreSharedCamera.this.cameraDevice = null;
|
||||
}
|
||||
};
|
||||
|
||||
// Repeating camera capture session state callback.
|
||||
CameraCaptureSession.StateCallback cameraCaptureCallback =
|
||||
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.");
|
||||
resumeARCore();
|
||||
}
|
||||
|
||||
@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);
|
||||
}
|
||||
};
|
||||
|
||||
private void resumeARCore() {
|
||||
// Ensure that session is valid before triggering ARCore resume. Handles the case where the user
|
||||
// manually uninstalls ARCore while the app is paused and then resumes.
|
||||
if (sharedSession == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
Log.i(TAG, "Resume ARCore.");
|
||||
// Resume ARCore.
|
||||
sharedSession.resume();
|
||||
// Set capture session callback while in AR mode.
|
||||
sharedCamera.setCaptureCallback(captureSessionCallback, backgroundHandler);
|
||||
} catch (CameraNotAvailableException e) {
|
||||
Log.e(TAG, "Failed to resume ARCore session", e);
|
||||
return;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 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.");
|
||||
try {
|
||||
// Note that isGlAttached will be set to true in AR mode in onDrawFrame().
|
||||
sharedSession.setCameraTextureName(cameraTextureId);
|
||||
|
||||
// Create an ARCore compatible capture request using `TEMPLATE_RECORD`.
|
||||
previewCaptureRequestBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_RECORD);
|
||||
|
||||
// Build surfaces list, starting with ARCore provided surfaces.
|
||||
List<Surface> surfaceList = sharedCamera.getArCoreSurfaces();
|
||||
Log.e(TAG, " createCameraPreviewSession: " + "surfaceList: sharedCamera.getArCoreSurfaces(): " + surfaceList.size());
|
||||
|
||||
// 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.
|
||||
if (mTOFAvailable) surfaceList.add(mTOFImageReader.imageReader.getSurface());
|
||||
// Surface list should now contain three surfacemReadymReadys:
|
||||
// 0. sharedCamera.getSurfaceTexture()
|
||||
// 1. …
|
||||
// 2. depthImageReader.getSurface()
|
||||
|
||||
// Add ARCore surfaces and CPU image surface targets.
|
||||
for (Surface surface : surfaceList) {
|
||||
previewCaptureRequestBuilder.addTarget(surface);
|
||||
}
|
||||
|
||||
// Wrap our callback in a shared camera callback.
|
||||
CameraCaptureSession.StateCallback wrappedCallback = sharedCamera.createARSessionStateCallback(cameraCaptureCallback, backgroundHandler);
|
||||
|
||||
// Create camera capture session for camera preview using ARCore wrapped callback.
|
||||
cameraDevice.createCaptureSession(surfaceList, wrappedCallback, backgroundHandler);
|
||||
|
||||
mReady.set(true);
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "CameraAccessException", e);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Start background handler thread, used to run callbacks without blocking UI thread.
|
||||
private void startBackgroundThread() {
|
||||
backgroundThread = new HandlerThread("sharedCameraBackground");
|
||||
backgroundThread.start();
|
||||
backgroundHandler = new Handler(backgroundThread.getLooper());
|
||||
mTOFImageReader.startBackgroundThread();
|
||||
}
|
||||
|
||||
// Stop background handler thread.
|
||||
private void stopBackgroundThread() {
|
||||
if (backgroundThread != null) {
|
||||
backgroundThread.quitSafely();
|
||||
try {
|
||||
backgroundThread.join();
|
||||
backgroundThread = null;
|
||||
backgroundHandler = null;
|
||||
} catch (InterruptedException e) {
|
||||
Log.e(TAG, "Interrupted while trying to join background handler thread", e);
|
||||
}
|
||||
}
|
||||
mTOFImageReader.stopBackgroundThread();
|
||||
}
|
||||
|
||||
private long mPreviousTime = 0;
|
||||
|
||||
// Perform various checks, then open camera device and create CPU image reader.
|
||||
public boolean openCamera() {
|
||||
|
||||
close();
|
||||
|
||||
startBackgroundThread();
|
||||
|
||||
mPreviousTime = System.currentTimeMillis();
|
||||
|
||||
if(cameraTextureId == -1)
|
||||
{
|
||||
int[] textures = new int[1];
|
||||
GLES20.glGenTextures(1, textures, 0);
|
||||
cameraTextureId = textures[0];
|
||||
}
|
||||
|
||||
Log.v(TAG + " opencamera: ", "Perform various checks, then open camera device and create CPU image reader.");
|
||||
// Don't open camera if already opened.
|
||||
if (cameraDevice != null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (sharedSession == null) {
|
||||
try {
|
||||
// Create ARCore session that supports camera sharing.
|
||||
sharedSession = new Session(mActivity, EnumSet.of(Session.Feature.SHARED_CAMERA));
|
||||
} catch (UnavailableException e) {
|
||||
Log.e(TAG, "Failed to create ARCore session that supports camera sharing", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Enable auto focus mode while ARCore is running.
|
||||
Config config = sharedSession.getConfig();
|
||||
config.setFocusMode(Config.FocusMode.FIXED);
|
||||
config.setUpdateMode(Config.UpdateMode.LATEST_CAMERA_IMAGE);
|
||||
config.setPlaneFindingMode(Config.PlaneFindingMode.DISABLED);
|
||||
config.setLightEstimationMode(Config.LightEstimationMode.DISABLED);
|
||||
//config.setCloudAnchorMode(Config.CloudAnchorMode.ENABLED);
|
||||
sharedSession.configure(config);
|
||||
|
||||
}
|
||||
|
||||
// Store the ARCore shared camera reference.
|
||||
sharedCamera = sharedSession.getSharedCamera();
|
||||
// Store the ID of the camera used by ARCore.
|
||||
cameraId = sharedSession.getCameraConfig().getCameraId();
|
||||
initCamera(mActivity, cameraId, 1);
|
||||
ArrayList<String> resolutions;
|
||||
|
||||
mTOFAvailable = false;
|
||||
|
||||
resolutions = getResolutions(mActivity, cameraId, ImageFormat.DEPTH16);
|
||||
if (resolutions != null) {
|
||||
for( String temp : resolutions) {
|
||||
Log.e(TAG + "DEPTH16 resolution: ", temp);
|
||||
};
|
||||
if (resolutions.size()>0) mTOFAvailable = true;
|
||||
}
|
||||
|
||||
// Color CPU Image.
|
||||
// Use the currently configured CPU image size.
|
||||
//Size desiredCPUImageSize = sharedSession.getCameraConfig().getImageSize();
|
||||
|
||||
if (mTOFAvailable) mTOFImageReader.createImageReader(DEPTH_WIDTH, DEPTH_HEIGHT);
|
||||
|
||||
// When ARCore is running, make sure it also updates our CPU image surface.
|
||||
if (mTOFAvailable) {
|
||||
sharedCamera.setAppSurfaces(this.cameraId, Arrays.asList(mTOFImageReader.imageReader.getSurface()));
|
||||
}
|
||||
|
||||
try {
|
||||
|
||||
// Wrap our callback in a shared camera callback.
|
||||
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.
|
||||
cameraManager.openCamera(cameraId, wrappedCallback, backgroundHandler);
|
||||
|
||||
} catch (CameraAccessException e) {
|
||||
Log.e(TAG, "Failed to open camera", e);
|
||||
return false;
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.e(TAG, "Failed to open camera", e);
|
||||
return false;
|
||||
} catch (SecurityException e) {
|
||||
Log.e(TAG, "Failed to open camera", e);
|
||||
return false;
|
||||
}
|
||||
|
||||
Log.i(TAG, " opencamera: TOF_available: " + mTOFAvailable);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Close the camera device.
|
||||
public void close() {
|
||||
|
||||
if (sharedSession != null) {
|
||||
sharedSession.pause();
|
||||
}
|
||||
|
||||
if (captureSession != null) {
|
||||
captureSession.close();
|
||||
captureSession = null;
|
||||
}
|
||||
if (cameraDevice != null) {
|
||||
cameraDevice.close();
|
||||
}
|
||||
|
||||
if (mTOFImageReader.imageReader != null) {
|
||||
mTOFImageReader.imageReader.close();
|
||||
mTOFImageReader.imageReader = null;
|
||||
}
|
||||
|
||||
if(cameraTextureId>=0)
|
||||
{
|
||||
GLES20.glDeleteTextures(1, new int[] {cameraTextureId}, 0);
|
||||
}
|
||||
|
||||
stopBackgroundThread();
|
||||
}
|
||||
|
||||
/*************************************************** ONDRAWFRAME ARCORE ************************************************************* */
|
||||
|
||||
// Draw frame when in AR mode. Called on the GL thread.
|
||||
public void updateGL() throws CameraNotAvailableException {
|
||||
|
||||
if(!mReady.get())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (mTOFAvailable && mTOFImageReader.frameCount == 0) return;
|
||||
|
||||
// Perform ARCore per-frame update.
|
||||
Frame frame = null;
|
||||
try {
|
||||
frame = sharedSession.update();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return;
|
||||
}
|
||||
|
||||
Camera camera = null;
|
||||
if (frame != null) {
|
||||
camera = frame.getCamera();
|
||||
}else
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (camera == null) return;
|
||||
// If not tracking, don't draw 3D objects.
|
||||
if (camera.getTrackingState() == TrackingState.PAUSED) return;
|
||||
|
||||
if (frame.getTimestamp() != 0) {
|
||||
|
||||
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()));
|
||||
RTABMapLib.postCameraPoseEvent(RTABMapActivity.nativeApplication, pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw());
|
||||
|
||||
int rateMs = 100; // send images at most 10 Hz
|
||||
if(System. currentTimeMillis() - mPreviousTime < rateMs)
|
||||
{
|
||||
return;
|
||||
}
|
||||
mPreviousTime = System. currentTimeMillis();
|
||||
|
||||
CameraIntrinsics intrinsics = camera.getImageIntrinsics();
|
||||
try{
|
||||
Image image = frame.acquireCameraImage();
|
||||
PointCloud cloud = frame.acquirePointCloud();
|
||||
FloatBuffer points = cloud.getPoints();
|
||||
|
||||
if (image.getFormat() != ImageFormat.YUV_420_888) {
|
||||
throw new IllegalArgumentException(
|
||||
"Expected image in YUV_420_888 format, got format " + image.getFormat());
|
||||
}
|
||||
|
||||
if(!RTABMapActivity.DISABLE_LOG)
|
||||
{
|
||||
for(int i =0;i<image.getPlanes().length;++i)
|
||||
{
|
||||
Log.d(TAG, String.format("Plane[%d] pixel stride = %d, row stride = %d", i, image.getPlanes()[i].getPixelStride(), image.getPlanes()[i].getRowStride()));
|
||||
}
|
||||
}
|
||||
|
||||
float[] fl = intrinsics.getFocalLength();
|
||||
float[] pp = intrinsics.getPrincipalPoint();
|
||||
if(!RTABMapActivity.DISABLE_LOG) Log.d(TAG, String.format("fx=%f fy=%f cx=%f cy=%f", fl[0], fl[1], pp[0], pp[1]));
|
||||
|
||||
ByteBuffer y = image.getPlanes()[0].getBuffer().asReadOnlyBuffer();
|
||||
ByteBuffer u = image.getPlanes()[1].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 =%f",
|
||||
image.getWidth(), image.getHeight(), y.limit(), image.getFormat(), stamp));
|
||||
|
||||
if(mTOFAvailable)
|
||||
{
|
||||
if(!RTABMapActivity.DISABLE_LOG) Log.d(TAG, String.format("Depth %dx%d len=%dbytes format=%d stamp=%f",
|
||||
mTOFImageReader.WIDTH, mTOFImageReader.HEIGHT, mTOFImageReader.depth16_raw.limit(), ImageFormat.DEPTH16, (double)mTOFImageReader.timestamp/10e9));
|
||||
|
||||
RTABMapLib.postOdometryEvent(
|
||||
RTABMapActivity.nativeApplication,
|
||||
pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw(),
|
||||
fl[0], fl[1], pp[0], pp[1], stamp,
|
||||
y, u, v, y.limit(), image.getWidth(), image.getHeight(), image.getFormat(),
|
||||
mTOFImageReader.depth16_raw, mTOFImageReader.depth16_raw.limit(), mTOFImageReader.WIDTH, mTOFImageReader.HEIGHT, ImageFormat.DEPTH16,
|
||||
points, points.limit()/4);
|
||||
}
|
||||
else
|
||||
{
|
||||
ByteBuffer bb = ByteBuffer.allocate(0);
|
||||
RTABMapLib.postOdometryEvent(
|
||||
RTABMapActivity.nativeApplication,
|
||||
pose.tx(), pose.ty(), pose.tz(), pose.qx(), pose.qy(), pose.qz(), pose.qw(),
|
||||
fl[0], fl[1], pp[0], pp[1], stamp,
|
||||
y, u, v, y.limit(), image.getWidth(), image.getHeight(), image.getFormat(),
|
||||
bb, 0, 0, 0, ImageFormat.DEPTH16,
|
||||
points, points.limit()/4);
|
||||
}
|
||||
|
||||
image.close();
|
||||
cloud.close();
|
||||
|
||||
} catch (NotYetAvailableException e) {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/********************************************************************************************************************* */
|
||||
/*************************************************** End ************************************************************* */
|
||||
/********************************************************************************************************************* */
|
||||
|
||||
|
||||
public ArrayList<String> getResolutions (Context context, String cameraId,int imageFormat){
|
||||
Log.v(TAG + "getResolutions:", " cameraId:" + cameraId + " imageFormat: " + imageFormat);
|
||||
|
||||
ArrayList<String> output = new ArrayList<String>();
|
||||
try {
|
||||
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)) {
|
||||
output.add(s.getWidth() + "x" + s.getHeight());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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!");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -90,9 +90,9 @@ import android.widget.SeekBar.OnSeekBarChangeListener;
|
||||
import android.widget.Toast;
|
||||
import android.widget.ToggleButton;
|
||||
|
||||
import com.google.ar.core.ArCoreApk;
|
||||
//import com.google.ar.core.ArCoreApk;
|
||||
import com.google.atap.tangoservice.Tango;
|
||||
import com.huawei.hiar.AREnginesApk;
|
||||
//import com.huawei.hiar.AREnginesApk;
|
||||
|
||||
|
||||
// The main activity of the application. This activity shows debug information
|
||||
@@ -254,7 +254,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
|
||||
|
||||
GestureDetector mGesDetect = null;
|
||||
|
||||
ARCoreSharedCamera mArCoreCamera = null;
|
||||
//ARCoreSharedCamera mArCoreCamera = null;
|
||||
int mCameraDriver = 0;
|
||||
|
||||
//Tango Service connection.
|
||||
@@ -586,8 +586,8 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
|
||||
String cameraDriverStr = sharedPref.getString(getString(R.string.pref_key_camera_driver), getString(R.string.pref_default_camera_driver));
|
||||
mCameraDriver = Integer.parseInt(cameraDriverStr);
|
||||
|
||||
isArCoreAvailable();
|
||||
isArEngineAvailable();
|
||||
//isArCoreAvailable();
|
||||
//isArEngineAvailable();
|
||||
}
|
||||
|
||||
// Should be called only if read/write permissions are granted!
|
||||
@@ -613,7 +613,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
|
||||
Log.i(TAG, String.format("updateCameraDriverSettings() mCameraDriver=%d RTABMapLib.isBuiltWith(%d)=%d", mCameraDriver, mCameraDriver, RTABMapLib.isBuiltWith(nativeApplication, mCameraDriver)?1:0));
|
||||
|
||||
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
|
||||
|
||||
/*
|
||||
if(mCameraDriver == 0 && (!CheckTangoCoreVersion(MIN_TANGO_CORE_VERSION) || !RTABMapLib.isBuiltWith(nativeApplication, 0)))
|
||||
{
|
||||
if(mIsAREngineAvailable && RTABMapLib.isBuiltWith(nativeApplication, 2))
|
||||
@@ -659,9 +659,9 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
|
||||
editor.putString(getString(R.string.pref_key_camera_driver), "3");
|
||||
editor.commit();
|
||||
}
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/*
|
||||
private void isArCoreAvailable() {
|
||||
ArCoreApk.Availability availability = ArCoreApk.getInstance().checkAvailability(this);
|
||||
if (availability.isTransient()) {
|
||||
@@ -713,7 +713,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
@@ -1199,7 +1199,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
|
||||
mToast.makeText(this, "Current camera driver selected is Tango, but Tango service binding failed. Abort scanning...", mToast.LENGTH_LONG).show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}/*
|
||||
else if(mCameraDriver == 1 || mCameraDriver == 2 || mCameraDriver == 3)
|
||||
{
|
||||
if((mCameraDriver == 1 || mCameraDriver == 3) && !mIsARCoreAvailable)
|
||||
@@ -1281,7 +1281,7 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
|
||||
}
|
||||
});
|
||||
bindThread.start();
|
||||
}
|
||||
}*/
|
||||
else
|
||||
{
|
||||
mToast.makeText(this, "Supported camera driver not found! Cannot start a new scan.", mToast.LENGTH_LONG).show();
|
||||
@@ -2274,14 +2274,14 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
|
||||
}
|
||||
}
|
||||
|
||||
if(mArCoreCamera != null)
|
||||
/* if(mArCoreCamera != null)
|
||||
{
|
||||
synchronized (this) {
|
||||
mRenderer.setCamera(null);
|
||||
mArCoreCamera.close();
|
||||
mArCoreCamera = null;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
Thread stopThread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
@@ -2314,14 +2314,14 @@ public class RTABMapActivity extends FragmentActivity implements OnClickListener
|
||||
|
||||
updateState(State.STATE_IDLE);
|
||||
|
||||
if(mArCoreCamera != null)
|
||||
/*if(mArCoreCamera != null)
|
||||
{
|
||||
synchronized (this) {
|
||||
mRenderer.setCamera(null);
|
||||
mArCoreCamera.close();
|
||||
mArCoreCamera = null;
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
Thread stopThread = new Thread(new Runnable() {
|
||||
public void run() {
|
||||
|
||||
@@ -43,7 +43,7 @@ public class Renderer implements GLSurfaceView.Renderer {
|
||||
private float mSurfaceHeight = 0.0f;
|
||||
private float mTextColor = 1.0f;
|
||||
private int mOffset = 0;
|
||||
private ARCoreSharedCamera mCamera = null;
|
||||
//private ARCoreSharedCamera mCamera = null;
|
||||
|
||||
private Vector<TextObject> mTexts;
|
||||
|
||||
@@ -73,10 +73,10 @@ public class Renderer implements GLSurfaceView.Renderer {
|
||||
mOffset = offset;
|
||||
}
|
||||
|
||||
public void setCamera(ARCoreSharedCamera camera)
|
||||
{
|
||||
mCamera = camera;
|
||||
}
|
||||
//public void setCamera(ARCoreSharedCamera camera)
|
||||
//{
|
||||
// mCamera = camera;
|
||||
//}
|
||||
|
||||
// Render loop of the Gl context.
|
||||
public void onDrawFrame(GL10 useGLES20instead) {
|
||||
@@ -86,10 +86,10 @@ public class Renderer implements GLSurfaceView.Renderer {
|
||||
{
|
||||
try
|
||||
{
|
||||
if(mCamera!=null)
|
||||
{
|
||||
mCamera.updateGL();
|
||||
}
|
||||
// if(mCamera!=null)
|
||||
// {
|
||||
// mCamera.updateGL();
|
||||
// }
|
||||
|
||||
final int value = RTABMapLib.render(mActivity.nativeApplication);
|
||||
|
||||
|
||||
@@ -361,7 +361,7 @@ public class SettingsActivity extends PreferenceActivity implements OnSharedPref
|
||||
ed.commit(); //save it.
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] results) {
|
||||
|
||||
switch (requestCode) {
|
||||
|
||||
@@ -1,87 +0,0 @@
|
||||
package com.introlab.rtabmap;
|
||||
|
||||
|
||||
import android.graphics.ImageFormat;
|
||||
import android.media.Image;
|
||||
import android.media.ImageReader;
|
||||
import android.os.Handler;
|
||||
import android.os.HandlerThread;
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
public class TOF_ImageReader implements ImageReader.OnImageAvailableListener {
|
||||
|
||||
public int WIDTH;
|
||||
public int HEIGHT;
|
||||
public ImageReader imageReader;
|
||||
public int frameCount = 0;
|
||||
public long timestamp;
|
||||
|
||||
// Looper handler thread.
|
||||
private HandlerThread backgroundThread;
|
||||
// Looper handler.
|
||||
private Handler backgroundHandler;
|
||||
|
||||
public ByteBuffer depth16_raw;
|
||||
|
||||
TOF_ImageReader(){
|
||||
}
|
||||
|
||||
public void createImageReader(int width, int height){
|
||||
this.WIDTH = width;
|
||||
this.HEIGHT = height;
|
||||
this.imageReader =
|
||||
ImageReader.newInstance(
|
||||
width,
|
||||
height,
|
||||
ImageFormat.DEPTH16,
|
||||
2);
|
||||
this.imageReader.setOnImageAvailableListener(this, this.backgroundHandler);
|
||||
}
|
||||
|
||||
// CPU image reader callback.
|
||||
@Override
|
||||
public void onImageAvailable(ImageReader imageReader) {
|
||||
Image image = imageReader.acquireLatestImage();
|
||||
if (image == null) {
|
||||
Log.w("RTABMapActivity", "onImageAvailable: Skipping null image.");
|
||||
return;
|
||||
}
|
||||
else{
|
||||
if(image.getFormat() == ImageFormat.DEPTH16){
|
||||
this.timestamp = image.getTimestamp();
|
||||
depth16_raw = image.getPlanes()[0].getBuffer().asReadOnlyBuffer();
|
||||
// copy raw undecoded DEPTH16 format depth data to NativeBuffer
|
||||
frameCount++;
|
||||
}
|
||||
else{
|
||||
Log.w("RTABMapActivity", "onImageAvailable: depth image not in DEPTH16 format, skipping image");
|
||||
}
|
||||
}
|
||||
image.close();
|
||||
}
|
||||
|
||||
// Start background handler thread, used to run callbacks without blocking UI thread.
|
||||
public void startBackgroundThread() {
|
||||
this.backgroundThread = new HandlerThread("DepthDecoderThread");
|
||||
this.backgroundThread.start();
|
||||
this.backgroundHandler = new Handler(backgroundThread.getLooper());
|
||||
}
|
||||
|
||||
// Stop background handler thread.
|
||||
public void stopBackgroundThread() {
|
||||
if (this.backgroundThread != null) {
|
||||
this.backgroundThread.quitSafely();
|
||||
try {
|
||||
this.backgroundThread.join();
|
||||
this.backgroundThread = null;
|
||||
this.backgroundHandler = null;
|
||||
} catch (InterruptedException e) {
|
||||
Log.e("RTABMapActivity", "Interrupted while trying to join depth background handler thread", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -61,8 +61,6 @@ public:
|
||||
|
||||
cv::Mat generatePrediction(const Memory * memory, const std::vector<int> & ids);
|
||||
|
||||
unsigned long getMemoryUsed() const;
|
||||
|
||||
private:
|
||||
cv::Mat updatePrediction(const cv::Mat & oldPrediction,
|
||||
const Memory * memory,
|
||||
|
||||
@@ -158,7 +158,5 @@ private:
|
||||
Transform localTransform_;
|
||||
};
|
||||
|
||||
RTABMAP_EXP std::ostream& operator<<(std::ostream& os, const CameraModel& model);
|
||||
|
||||
} /* namespace rtabmap */
|
||||
#endif /* CAMERAMODEL_H_ */
|
||||
|
||||
@@ -72,15 +72,6 @@ public:
|
||||
void enableIMUFiltering(int filteringStrategy=1, const ParametersMap & parameters = ParametersMap());
|
||||
void disableIMUFiltering();
|
||||
|
||||
RTABMAP_DEPRECATED(void setScanParameters(
|
||||
bool fromDepth,
|
||||
int downsampleStep, // decimation of the depth image in case the scan is from depth image
|
||||
float rangeMin,
|
||||
float rangeMax,
|
||||
float voxelSize,
|
||||
int normalsK,
|
||||
int normalsRadius,
|
||||
bool forceGroundNormalsUp) , "Use new version of this function with groundNormalsUp=0.8 for forceGroundNormalsUp=True and groundNormalsUp=0.0 for forceGroundNormalsUp=False.");
|
||||
void setScanParameters(
|
||||
bool fromDepth,
|
||||
int downsampleStep=1, // decimation of the depth image in case the scan is from depth image
|
||||
@@ -89,7 +80,17 @@ public:
|
||||
float voxelSize = 0.0f,
|
||||
int normalsK = 0,
|
||||
int normalsRadius = 0.0f,
|
||||
float groundNormalsUp = 0.0f);
|
||||
bool forceGroundNormalsUp = false)
|
||||
{
|
||||
_scanFromDepth = fromDepth;
|
||||
_scanDownsampleStep=downsampleStep;
|
||||
_scanRangeMin = rangeMin;
|
||||
_scanRangeMax = rangeMax;
|
||||
_scanVoxelSize = voxelSize;
|
||||
_scanNormalsK = normalsK;
|
||||
_scanNormalsRadius = normalsRadius;
|
||||
_scanForceGroundNormalsUp = forceGroundNormalsUp;
|
||||
}
|
||||
|
||||
void postUpdate(SensorData * data, CameraInfo * info = 0) const;
|
||||
|
||||
@@ -118,7 +119,7 @@ private:
|
||||
float _scanVoxelSize;
|
||||
int _scanNormalsK;
|
||||
float _scanNormalsRadius;
|
||||
float _scanForceGroundNormalsUp;
|
||||
bool _scanForceGroundNormalsUp;
|
||||
StereoDense * _stereoDense;
|
||||
clams::DiscreteDepthDistortionModel * _distortionModel;
|
||||
bool _bilateralFiltering;
|
||||
|
||||
@@ -70,7 +70,6 @@ public:
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual bool isInMemory() const {return _url.empty();}
|
||||
const std::string & getUrl() const {return _url;}
|
||||
const std::string & getTargetVersion() const {return _targetVersion;}
|
||||
|
||||
void beginTransaction() const;
|
||||
void commit() const;
|
||||
@@ -110,7 +109,7 @@ public:
|
||||
cv::Mat load2DMap(float & xMin, float & yMin, float & cellSize) const;
|
||||
void saveOptimizedMesh(
|
||||
const cv::Mat & cloud,
|
||||
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons = std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > >(), // Textures -> polygons -> vertices
|
||||
const std::vector<std::vector<std::vector<unsigned int> > > & polygons = std::vector<std::vector<std::vector<unsigned int> > >(), // Textures -> polygons -> vertices
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords = std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > >(), // Textures -> uv coords for each vertex of the polygons
|
||||
#else
|
||||
@@ -118,7 +117,7 @@ public:
|
||||
#endif
|
||||
const cv::Mat & textures = cv::Mat()) const; // concatenated textures (assuming square textures with all same size);
|
||||
cv::Mat loadOptimizedMesh(
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > * polygons = 0,
|
||||
std::vector<std::vector<std::vector<unsigned int> > > * polygons = 0,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords = 0,
|
||||
#else
|
||||
@@ -132,7 +131,7 @@ public:
|
||||
bool openConnection(const std::string & url, bool overwritten = false);
|
||||
void closeConnection(bool save = true, const std::string & outputUrl = "");
|
||||
bool isConnected() const;
|
||||
unsigned long getMemoryUsed() const; // In bytes
|
||||
long getMemoryUsed() const; // In bytes
|
||||
std::string getDatabaseVersion() const;
|
||||
long getNodesMemoryUsed() const;
|
||||
long getLinksMemoryUsed() const;
|
||||
@@ -189,7 +188,7 @@ protected:
|
||||
virtual bool connectDatabaseQuery(const std::string & url, bool overwritten = false) = 0;
|
||||
virtual void disconnectDatabaseQuery(bool save = true, const std::string & outputUrl = "") = 0;
|
||||
virtual bool isConnectedQuery() const = 0;
|
||||
virtual unsigned long getMemoryUsedQuery() const = 0; // In bytes
|
||||
virtual long getMemoryUsedQuery() const = 0; // In bytes
|
||||
virtual bool getDatabaseVersionQuery(std::string & version) const = 0;
|
||||
virtual long getNodesMemoryUsedQuery() const = 0;
|
||||
virtual long getLinksMemoryUsedQuery() const = 0;
|
||||
@@ -248,7 +247,7 @@ protected:
|
||||
virtual cv::Mat load2DMapQuery(float & xMin, float & yMin, float & cellSize) const = 0;
|
||||
virtual void saveOptimizedMeshQuery(
|
||||
const cv::Mat & cloud,
|
||||
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons,
|
||||
const std::vector<std::vector<std::vector<unsigned int> > > & polygons,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
|
||||
#else
|
||||
@@ -256,7 +255,7 @@ protected:
|
||||
#endif
|
||||
const cv::Mat & textures) const = 0;
|
||||
virtual cv::Mat loadOptimizedMeshQuery(
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > * polygons,
|
||||
std::vector<std::vector<std::vector<unsigned int> > > * polygons,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,
|
||||
#else
|
||||
@@ -301,7 +300,6 @@ private:
|
||||
USemaphore _addSem;
|
||||
double _emptyTrashesTime;
|
||||
std::string _url;
|
||||
std::string _targetVersion;
|
||||
bool _timestampUpdate;
|
||||
};
|
||||
|
||||
|
||||
@@ -54,7 +54,7 @@ protected:
|
||||
virtual bool connectDatabaseQuery(const std::string & url, bool overwritten = false);
|
||||
virtual void disconnectDatabaseQuery(bool save = true, const std::string & outputUrl = "");
|
||||
virtual bool isConnectedQuery() const;
|
||||
virtual unsigned long getMemoryUsedQuery() const; // In bytes
|
||||
virtual long getMemoryUsedQuery() const; // In bytes
|
||||
virtual bool getDatabaseVersionQuery(std::string & version) const;
|
||||
virtual long getNodesMemoryUsedQuery() const;
|
||||
virtual long getLinksMemoryUsedQuery() const;
|
||||
@@ -113,7 +113,7 @@ protected:
|
||||
virtual cv::Mat load2DMapQuery(float & xMin, float & yMin, float & cellSize) const;
|
||||
virtual void saveOptimizedMeshQuery(
|
||||
const cv::Mat & cloud,
|
||||
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons,
|
||||
const std::vector<std::vector<std::vector<unsigned int> > > & polygons,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
|
||||
#else
|
||||
@@ -121,7 +121,7 @@ protected:
|
||||
#endif
|
||||
const cv::Mat & textures) const;
|
||||
virtual cv::Mat loadOptimizedMeshQuery(
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > * polygons,
|
||||
std::vector<std::vector<std::vector<unsigned int> > > * polygons,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,
|
||||
#else
|
||||
@@ -189,7 +189,7 @@ protected:
|
||||
std::string _version;
|
||||
|
||||
private:
|
||||
unsigned long _memoryUsedEstimate;
|
||||
long _memoryUsedEstimate;
|
||||
bool _dbInMemory;
|
||||
unsigned int _cacheSize;
|
||||
int _journalMode;
|
||||
|
||||
@@ -29,7 +29,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "rtabmap/utilite/UStl.h"
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/features2d/features2d.hpp>
|
||||
#include <pcl/point_cloud.h>
|
||||
@@ -92,133 +91,41 @@ public:
|
||||
* if a=[1 2 3 4 6], b=[1 2 4 5 6], results= [(1,1) (2,2) (4,4) (6,6)]
|
||||
* realPairsCount = 4
|
||||
*/
|
||||
template<typename T>
|
||||
static int findPairs(
|
||||
const std::map<int, T> & wordsA,
|
||||
const std::map<int, T> & wordsB,
|
||||
std::list<std::pair<int, std::pair<T, T> > > & pairs,
|
||||
bool ignoreNegativeIds = true)
|
||||
{
|
||||
int realPairsCount = 0;
|
||||
pairs.clear();
|
||||
for(typename std::map<int, T>::const_iterator i=wordsA.begin(); i!=wordsA.end(); ++i)
|
||||
{
|
||||
if(!ignoreNegativeIds || (ignoreNegativeIds && i->first>=0))
|
||||
{
|
||||
std::map<int, cv::KeyPoint>::const_iterator ptB = wordsB.find(i->first);
|
||||
if(ptB != wordsB.end())
|
||||
{
|
||||
pairs.push_back(std::pair<int, std::pair<T, T> >(i->first, std::make_pair(i->second, ptB->second)));
|
||||
++realPairsCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
return realPairsCount;
|
||||
}
|
||||
const std::map<int, cv::KeyPoint> & wordsA,
|
||||
const std::map<int, cv::KeyPoint> & wordsB,
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs,
|
||||
bool ignoreNegativeIds = true);
|
||||
|
||||
/**
|
||||
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(1,1a) (2,2) (4,4) (6a,6a) (6b,6b)]
|
||||
* realPairsCount = 5
|
||||
*/
|
||||
template<typename T>
|
||||
static int findPairs(
|
||||
const std::multimap<int, T> & wordsA,
|
||||
const std::multimap<int, T> & wordsB,
|
||||
std::list<std::pair<int, std::pair<T, T> > > & pairs,
|
||||
bool ignoreNegativeIds = true)
|
||||
{
|
||||
const std::list<int> & ids = uUniqueKeys(wordsA);
|
||||
typename std::multimap<int, T>::const_iterator iterA;
|
||||
typename std::multimap<int, T>::const_iterator iterB;
|
||||
pairs.clear();
|
||||
int realPairsCount = 0;
|
||||
for(std::list<int>::const_iterator i=ids.begin(); i!=ids.end(); ++i)
|
||||
{
|
||||
if(!ignoreNegativeIds || (ignoreNegativeIds && *i >= 0))
|
||||
{
|
||||
iterA = wordsA.find(*i);
|
||||
iterB = wordsB.find(*i);
|
||||
while(iterA != wordsA.end() && iterB != wordsB.end() && (*iterA).first == (*iterB).first && (*iterA).first == *i)
|
||||
{
|
||||
pairs.push_back(std::pair<int, std::pair<T, T> >(*i, std::make_pair((*iterA).second, (*iterB).second)));
|
||||
++iterA;
|
||||
++iterB;
|
||||
++realPairsCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
return realPairsCount;
|
||||
}
|
||||
const std::multimap<int, cv::KeyPoint> & wordsA,
|
||||
const std::multimap<int, cv::KeyPoint> & wordsB,
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs,
|
||||
bool ignoreNegativeIds = true);
|
||||
|
||||
/**
|
||||
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(2,2) (4,4)]
|
||||
* realPairsCount = 5
|
||||
*/
|
||||
template<typename T>
|
||||
static int findPairsUnique(
|
||||
const std::multimap<int, T> & wordsA,
|
||||
const std::multimap<int, T> & wordsB,
|
||||
std::list<std::pair<int, std::pair<T, T> > > & pairs,
|
||||
bool ignoreNegativeIds = true)
|
||||
{
|
||||
const std::list<int> & ids = uUniqueKeys(wordsA);
|
||||
int realPairsCount = 0;
|
||||
pairs.clear();
|
||||
for(std::list<int>::const_iterator i=ids.begin(); i!=ids.end(); ++i)
|
||||
{
|
||||
if(!ignoreNegativeIds || (ignoreNegativeIds && *i>=0))
|
||||
{
|
||||
std::list<T> ptsA = uValues(wordsA, *i);
|
||||
std::list<T> ptsB = uValues(wordsB, *i);
|
||||
if(ptsA.size() == 1 && ptsB.size() == 1)
|
||||
{
|
||||
pairs.push_back(std::pair<int, std::pair<T, T> >(*i, std::pair<T, T>(ptsA.front(), ptsB.front())));
|
||||
++realPairsCount;
|
||||
}
|
||||
else if(ptsA.size()>1 && ptsB.size()>1)
|
||||
{
|
||||
// just update the count
|
||||
realPairsCount += ptsA.size() > ptsB.size() ? ptsB.size() : ptsA.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
return realPairsCount;
|
||||
}
|
||||
const std::multimap<int, cv::KeyPoint> & wordsA,
|
||||
const std::multimap<int, cv::KeyPoint> & wordsB,
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs,
|
||||
bool ignoreNegativeIds = true);
|
||||
|
||||
/**
|
||||
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(1,1a) (1,1b) (2,2) (4,4) (6a,6a) (6a,6b) (6b,6a) (6b,6b)]
|
||||
* realPairsCount = 5
|
||||
*/
|
||||
template<typename T>
|
||||
static int findPairsAll(
|
||||
const std::multimap<int, T> & wordsA,
|
||||
const std::multimap<int, T> & wordsB,
|
||||
std::list<std::pair<int, std::pair<T, T> > > & pairs,
|
||||
bool ignoreNegativeIds = true)
|
||||
{
|
||||
const std::list<int> & ids = uUniqueKeys(wordsA);
|
||||
pairs.clear();
|
||||
int realPairsCount = 0;;
|
||||
for(std::list<int>::const_iterator iter=ids.begin(); iter!=ids.end(); ++iter)
|
||||
{
|
||||
if(!ignoreNegativeIds || (ignoreNegativeIds && *iter>=0))
|
||||
{
|
||||
std::list<T> ptsA = uValues(wordsA, *iter);
|
||||
std::list<T> ptsB = uValues(wordsB, *iter);
|
||||
|
||||
realPairsCount += ptsA.size() > ptsB.size() ? ptsB.size() : ptsA.size();
|
||||
|
||||
for(typename std::list<T>::iterator jter=ptsA.begin(); jter!=ptsA.end(); ++jter)
|
||||
{
|
||||
for(typename std::list<T>::iterator kter=ptsB.begin(); kter!=ptsB.end(); ++kter)
|
||||
{
|
||||
pairs.push_back(std::pair<int, std::pair<T, T> >(*iter, std::pair<T, T>(*jter, *kter)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return realPairsCount;
|
||||
}
|
||||
const std::multimap<int, cv::KeyPoint> & wordsA,
|
||||
const std::multimap<int, cv::KeyPoint> & wordsB,
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs,
|
||||
bool ignoreNegativeIds = true);
|
||||
|
||||
static cv::Mat linearLSTriangulation(
|
||||
cv::Point3d u, //homogenous image point (u,v,1)
|
||||
|
||||
@@ -61,7 +61,6 @@ typedef cv::gpu::FAST_GPU CV_FAST_GPU;
|
||||
namespace cv{
|
||||
namespace xfeatures2d {
|
||||
class FREAK;
|
||||
class DAISY;
|
||||
class BriefDescriptorExtractor;
|
||||
#if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION <= 3) || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION < 4 || (CV_MINOR_VERSION==4 && CV_SUBMINOR_VERSION<11)))
|
||||
class SIFT;
|
||||
@@ -82,7 +81,6 @@ typedef cv::SIFT CV_SIFT; // SIFT is back in features2d since 4.4.0 / 3.4.11
|
||||
typedef cv::xfeatures2d::SURF CV_SURF;
|
||||
typedef cv::FastFeatureDetector CV_FAST;
|
||||
typedef cv::xfeatures2d::FREAK CV_FREAK;
|
||||
typedef cv::xfeatures2d::DAISY CV_DAISY;
|
||||
typedef cv::GFTTDetector CV_GFTT;
|
||||
typedef cv::xfeatures2d::BriefDescriptorExtractor CV_BRIEF;
|
||||
typedef cv::BRISK CV_BRISK;
|
||||
@@ -117,11 +115,7 @@ public:
|
||||
kFeatureGfttOrb=8, //new 0.10.11
|
||||
kFeatureKaze=9, //new 0.13.2
|
||||
kFeatureOrbOctree=10, //new 0.19.2
|
||||
kFeatureSuperPointTorch=11, //new 0.19.7
|
||||
kFeatureSurfFreak=12, //new 0.20.4
|
||||
kFeatureGfttDaisy=13, //new 0.20.6
|
||||
kFeatureSurfDaisy=14}; //new 0.20.6
|
||||
|
||||
kFeatureSuperPointTorch=11}; //new 0.19.7
|
||||
static std::string typeName(Type type)
|
||||
{
|
||||
switch(type){
|
||||
@@ -149,12 +143,6 @@ public:
|
||||
return "ORB-OCTREE";
|
||||
case kFeatureSuperPointTorch:
|
||||
return "SUPERPOINT";
|
||||
case kFeatureSurfFreak:
|
||||
return "SURF+Freak";
|
||||
case kFeatureGfttDaisy:
|
||||
return "GFTT+Daisy";
|
||||
case kFeatureSurfDaisy:
|
||||
return "SURF+Daisy";
|
||||
default:
|
||||
return "Unknown";
|
||||
}
|
||||
@@ -467,28 +455,6 @@ private:
|
||||
cv::Ptr<CV_FREAK> _freak;
|
||||
};
|
||||
|
||||
//SURF_FREAK
|
||||
class RTABMAP_EXP SURF_FREAK : public SURF
|
||||
{
|
||||
public:
|
||||
SURF_FREAK(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~SURF_FREAK();
|
||||
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual Feature2D::Type getType() const {return kFeatureSurfFreak;}
|
||||
|
||||
private:
|
||||
virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
|
||||
private:
|
||||
bool orientationNormalized_;
|
||||
bool scaleNormalized_;
|
||||
float patternScale_;
|
||||
int nOctaves_;
|
||||
|
||||
cv::Ptr<CV_FREAK> _freak;
|
||||
};
|
||||
|
||||
//GFTT_ORB
|
||||
class RTABMAP_EXP GFTT_ORB : public GFTT
|
||||
{
|
||||
@@ -572,8 +538,6 @@ private:
|
||||
private:
|
||||
float scaleFactor_;
|
||||
int nLevels_;
|
||||
int patchSize_;
|
||||
int edgeThreshold_;
|
||||
int fastThreshold_;
|
||||
int fastMinThreshold_;
|
||||
|
||||
@@ -604,54 +568,6 @@ private:
|
||||
bool cuda_;
|
||||
};
|
||||
|
||||
//GFTT_DAISY
|
||||
class RTABMAP_EXP GFTT_DAISY : public GFTT
|
||||
{
|
||||
public:
|
||||
GFTT_DAISY(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~GFTT_DAISY();
|
||||
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual Feature2D::Type getType() const {return kFeatureGfttDaisy;}
|
||||
|
||||
private:
|
||||
virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
|
||||
private:
|
||||
bool orientationNormalized_;
|
||||
bool scaleNormalized_;
|
||||
float patternScale_;
|
||||
int nOctaves_;
|
||||
|
||||
#if CV_MAJOR_VERSION > 2
|
||||
cv::Ptr<CV_DAISY> _daisy;
|
||||
#endif
|
||||
};
|
||||
|
||||
//SURF_DAISY
|
||||
class RTABMAP_EXP SURF_DAISY : public SURF
|
||||
{
|
||||
public:
|
||||
SURF_DAISY(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~SURF_DAISY();
|
||||
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual Feature2D::Type getType() const {return kFeatureSurfDaisy;}
|
||||
|
||||
private:
|
||||
virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
|
||||
private:
|
||||
bool orientationNormalized_;
|
||||
bool scaleNormalized_;
|
||||
float patternScale_;
|
||||
int nOctaves_;
|
||||
|
||||
#if CV_MAJOR_VERSION > 2
|
||||
cv::Ptr<CV_DAISY> _daisy;
|
||||
#endif
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* FEATURES2D_H_ */
|
||||
|
||||
@@ -43,8 +43,8 @@ public:
|
||||
void release();
|
||||
unsigned int indexedFeatures() const;
|
||||
|
||||
// return Bytes
|
||||
unsigned long memoryUsed() const;
|
||||
// return KB
|
||||
unsigned int memoryUsed() const;
|
||||
|
||||
// Note that useDistanceL1 doesn't have any effect if LSH is used
|
||||
void buildLinearIndex(
|
||||
@@ -74,7 +74,7 @@ public:
|
||||
int featuresType() const {return featuresType_;}
|
||||
int featuresDim() const {return featuresDim_;}
|
||||
|
||||
std::vector<unsigned int> addPoints(const cv::Mat & features);
|
||||
unsigned int addPoints(const cv::Mat & features);
|
||||
|
||||
void removePoint(unsigned int index);
|
||||
|
||||
|
||||
@@ -35,7 +35,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <rtabmap/core/Parameters.h>
|
||||
#include <rtabmap/core/Link.h>
|
||||
#include <rtabmap/core/GPS.h>
|
||||
#include <rtabmap/core/CameraModel.h>
|
||||
|
||||
namespace rtabmap {
|
||||
class Memory;
|
||||
@@ -56,10 +55,10 @@ namespace graph {
|
||||
|
||||
bool RTABMAP_EXP importPoses(
|
||||
const std::string & filePath,
|
||||
int format, // 0=Raw, 1=RGBD-SLAM motion capture (10=without change of coordinate frame), 2=KITTI, 3=TORO, 4=g2o, 5=NewCollege(t,x,y), 6=Malaga Urban GPS, 7=St Lucia INS, 8=Karlsruhe, 9=EuRoC MAV
|
||||
int format, // 0=Raw, 1=RGBD-SLAM motion capture (10=without change of coordinate frame), 2=KITTI, 3=TORO, 4=g2o, 5=NewCollege(t,x,y), 6=Malaga Urban GPS, 7=St Lucia INS, 8=Karlsruhe
|
||||
std::map<int, Transform> & poses,
|
||||
std::multimap<int, Link> * constraints = 0, // optional for formats 3 and 4
|
||||
std::map<int, double> * stamps = 0); // optional for format 1 and 9
|
||||
std::map<int, double> * stamps = 0); // optional for format 1
|
||||
|
||||
bool RTABMAP_EXP exportGPS(
|
||||
const std::string & filePath,
|
||||
@@ -156,20 +155,12 @@ std::list<Link> RTABMAP_EXP findLinks(
|
||||
|
||||
std::multimap<int, Link> RTABMAP_EXP filterDuplicateLinks(
|
||||
const std::multimap<int, Link> & links);
|
||||
/**
|
||||
* Return links not of type "filteredType". If inverted=true, return links of of type "filteredType".
|
||||
*/
|
||||
std::multimap<int, Link> RTABMAP_EXP filterLinks(
|
||||
const std::multimap<int, Link> & links,
|
||||
Link::Type filteredType,
|
||||
bool inverted = false);
|
||||
/**
|
||||
* Return links not of type "filteredType". If inverted=true, return links of of type "filteredType".
|
||||
*/
|
||||
Link::Type filteredType);
|
||||
std::map<int, Link> RTABMAP_EXP filterLinks(
|
||||
const std::map<int, Link> & links,
|
||||
Link::Type filteredType,
|
||||
bool inverted = false);
|
||||
Link::Type filteredType);
|
||||
|
||||
//Note: This assumes a coordinate system where X is forward, * Y is up, and Z is right.
|
||||
std::map<int, Transform> RTABMAP_EXP frustumPosesFiltering(
|
||||
@@ -264,26 +255,11 @@ std::list<std::pair<int, Transform> > RTABMAP_EXP computePath(
|
||||
float linearVelocity = 0.0f, // m/sec
|
||||
float angularVelocity = 0.0f); // rad/sec
|
||||
|
||||
/**
|
||||
* Get the nearest node of the target pose
|
||||
* @param nodes the nodes to search for
|
||||
* @param targetPose the target pose to search around
|
||||
* @param distance squared distance of the nearest node found (optional)
|
||||
* @return the node id.
|
||||
*/
|
||||
int RTABMAP_EXP findNearestNode(
|
||||
const std::map<int, rtabmap::Transform> & nodes,
|
||||
const rtabmap::Transform & targetPose,
|
||||
float * distance = 0);
|
||||
const rtabmap::Transform & targetPose);
|
||||
|
||||
/**
|
||||
* Get K nearest nodes of the target pose
|
||||
* @param nodes the nodes to search for
|
||||
* @param targetPose the target pose to search around
|
||||
* @param k number of nearest neighbors to search for
|
||||
* @return the node ids with squared distance to target pose.
|
||||
*/
|
||||
std::map<int, float> RTABMAP_EXP findNearestNodes(
|
||||
std::vector<int> RTABMAP_EXP findNearestNodes(
|
||||
const std::map<int, rtabmap::Transform> & nodes,
|
||||
const rtabmap::Transform & targetPose,
|
||||
int k);
|
||||
@@ -299,20 +275,11 @@ std::map<int, float> RTABMAP_EXP getNodesInRadius(
|
||||
int nodeId,
|
||||
const std::map<int, Transform> & nodes,
|
||||
float radius);
|
||||
std::map<int, float> RTABMAP_EXP getNodesInRadius(
|
||||
const Transform & targetPose,
|
||||
const std::map<int, Transform> & nodes,
|
||||
float radius);
|
||||
std::map<int, Transform> RTABMAP_EXP getPosesInRadius(
|
||||
int nodeId,
|
||||
const std::map<int, Transform> & nodes,
|
||||
float radius,
|
||||
float angle = 0.0f);
|
||||
std::map<int, Transform> RTABMAP_EXP getPosesInRadius(
|
||||
const Transform & targetPose,
|
||||
const std::map<int, Transform> & nodes,
|
||||
float radius,
|
||||
float angle = 0.0f);
|
||||
|
||||
float RTABMAP_EXP computePathLength(
|
||||
const std::vector<std::pair<int, Transform> > & path,
|
||||
|
||||
@@ -97,7 +97,6 @@ public:
|
||||
float angleIncrement() const {return angleIncrement_;}
|
||||
Transform localTransform() const {return localTransform_;}
|
||||
|
||||
bool empty() const {return data_.empty();}
|
||||
bool isEmpty() const {return data_.empty();}
|
||||
int size() const {return data_.cols;}
|
||||
int dataType() const {return data_.type();}
|
||||
|
||||
@@ -50,8 +50,6 @@ private:
|
||||
cv::Ptr<cv::aruco::DetectorParameters> detectorParams_;
|
||||
float markerLength_;
|
||||
float maxDepthError_;
|
||||
float maxRange_;
|
||||
float minRange_;
|
||||
int dictionaryId_;
|
||||
cv::Ptr<cv::aruco::Dictionary> dictionary_;
|
||||
#endif
|
||||
|
||||
@@ -102,7 +102,7 @@ public:
|
||||
cv::Mat load2DMap(float & xMin, float & yMin, float & cellSize) const;
|
||||
void saveOptimizedMesh(
|
||||
const cv::Mat & cloud,
|
||||
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons = std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > >(), // Textures -> polygons -> vertices
|
||||
const std::vector<std::vector<std::vector<unsigned int> > > & polygons = std::vector<std::vector<std::vector<unsigned int> > >(), // Textures -> polygons -> vertices
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords = std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > >(), // Textures -> uv coords for each vertex of the polygons
|
||||
#else
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
#endif
|
||||
const cv::Mat & textures = cv::Mat()) const; // concatenated textures (assuming square textures with all same size)
|
||||
cv::Mat loadOptimizedMesh(
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > * polygons = 0,
|
||||
std::vector<std::vector<std::vector<unsigned int> > > * polygons = 0,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords = 0,
|
||||
#else
|
||||
@@ -199,10 +199,9 @@ public:
|
||||
cv::Mat getImageCompressed(int signatureId) const;
|
||||
SensorData getNodeData(int locationId, bool images, bool scan, bool userData, bool occupancyGrid) const;
|
||||
void getNodeWordsAndGlobalDescriptors(int nodeId,
|
||||
std::multimap<int, int> & words,
|
||||
std::vector<cv::KeyPoint> & wordsKpts,
|
||||
std::vector<cv::Point3f> & words3,
|
||||
cv::Mat & wordsDescriptors,
|
||||
std::multimap<int, cv::KeyPoint> & words,
|
||||
std::multimap<int, cv::Point3f> & words3,
|
||||
std::multimap<int, cv::Mat> & wordsDescriptors,
|
||||
std::vector<GlobalDescriptor> & globalDescriptors) const;
|
||||
void getNodeCalibration(int nodeId,
|
||||
std::vector<CameraModel> & models,
|
||||
@@ -226,7 +225,6 @@ public:
|
||||
virtual void dumpMemory(std::string directory) const;
|
||||
virtual void dumpSignatures(const char * fileNameSign, bool words3D) const;
|
||||
void dumpDictionary(const char * fileNameRef, const char * fileNameDesc) const;
|
||||
unsigned long getMemoryUsed() const; //Bytes
|
||||
|
||||
void generateGraph(const std::string & fileName, const std::set<int> & ids = std::set<int>());
|
||||
|
||||
|
||||
@@ -104,8 +104,6 @@ public:
|
||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & getMapObstacles() const {return assembledObstacles_;}
|
||||
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & getMapEmptyCells() const {return assembledEmptyCells_;}
|
||||
|
||||
unsigned long getMemoryUsed() const;
|
||||
|
||||
private:
|
||||
ParametersMap parameters_;
|
||||
int cloudDecimation_;
|
||||
|
||||
@@ -168,6 +168,9 @@ class RtabmapColorOcTree : public octomap::OccupancyOcTreeBase <RtabmapColorOcTr
|
||||
};
|
||||
|
||||
class RTABMAP_EXP OctoMap {
|
||||
public:
|
||||
static void HSVtoRGB(float *r, float *g, float *b, float h, float s, float v);
|
||||
|
||||
public:
|
||||
OctoMap(const ParametersMap & parameters);
|
||||
OctoMap(float cellSize = 0.1f, float occupancyThr = 0.5f, bool fullUpdate = false, float updateError=0.01f);
|
||||
|
||||
@@ -236,7 +236,6 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(Kp, IncrementalDictionary, bool, true, "");
|
||||
RTABMAP_PARAM(Kp, IncrementalFlann, bool, true, uFormat("When using FLANN based strategy, add/remove points to its index without always rebuilding the index (the index is built only when the dictionary increases of the factor \"%s\" in size).", kKpFlannRebalancingFactor().c_str()));
|
||||
RTABMAP_PARAM(Kp, FlannRebalancingFactor, float, 2.0, uFormat("Factor used when rebuilding the incremental FLANN index (see \"%s\"). Set <=1 to disable.", kKpIncrementalFlann().c_str()));
|
||||
RTABMAP_PARAM(Kp, ByteToFloat, bool, false, uFormat("For %s=1, binary descriptors are converted to float by converting each byte to float instead of converting each bit to float. When converting bytes instead of bits, less memory is used and search is faster at the cost of slightly less accurate matching.", kKpNNStrategy().c_str()));
|
||||
RTABMAP_PARAM(Kp, MaxDepth, float, 0, "Filter extracted keypoints by depth (0=inf).");
|
||||
RTABMAP_PARAM(Kp, MinDepth, float, 0, "Filter extracted keypoints by depth.");
|
||||
RTABMAP_PARAM(Kp, MaxFeatures, int, 500, "Maximum features extracted from the images (0 means not bounded, <0 means no extraction).");
|
||||
@@ -244,9 +243,9 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(Kp, NndrRatio, float, 0.8, "NNDR ratio (A matching pair is detected, if its distance is closer than X times the distance of the second nearest neighbor.)");
|
||||
#if CV_MAJOR_VERSION > 2 && !defined(HAVE_OPENCV_XFEATURES2D)
|
||||
// OpenCV>2 without xFeatures2D module doesn't have BRIEF
|
||||
RTABMAP_PARAM(Kp, DetectorStrategy, int, 8, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint 12=SURF/FREAK 13=GFTT/DAISY 14=SURF/DAISY");
|
||||
RTABMAP_PARAM(Kp, DetectorStrategy, int, 8, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint Torch.");
|
||||
#else
|
||||
RTABMAP_PARAM(Kp, DetectorStrategy, int, 6, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint 12=SURF/FREAK 13=GFTT/DAISY 14=SURF/DAISY");
|
||||
RTABMAP_PARAM(Kp, DetectorStrategy, int, 6, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint Torch.");
|
||||
#endif
|
||||
RTABMAP_PARAM(Kp, TfIdfLikelihoodUsed, bool, true, "Use of the td-idf strategy to compute the likelihood.");
|
||||
RTABMAP_PARAM(Kp, Parallelized, bool, true, "If the dictionary update and signature creation were parallelized.");
|
||||
@@ -265,7 +264,6 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(DbSqlite3, JournalMode, int, 3, "0=DELETE, 1=TRUNCATE, 2=PERSIST, 3=MEMORY, 4=OFF (see sqlite3 doc : \"PRAGMA journal_mode\")");
|
||||
RTABMAP_PARAM(DbSqlite3, Synchronous, int, 0, "0=OFF, 1=NORMAL, 2=FULL (see sqlite3 doc : \"PRAGMA synchronous\")");
|
||||
RTABMAP_PARAM(DbSqlite3, TempStore, int, 2, "0=DEFAULT, 1=FILE, 2=MEMORY (see sqlite3 doc : \"PRAGMA temp_store\")");
|
||||
RTABMAP_PARAM_STR(Db, TargetVersion, "", "Target database version for backward compatibility purpose. Only Major and minor versions are used and should be set (e.g., 0.19 vs 0.20 or 1.0 vs 2.0). Patch version is ignored (e.g., 0.20.1 and 0.20.3 will generate a 0.20 database).");
|
||||
|
||||
// Keypoints descriptors/detectors
|
||||
RTABMAP_PARAM(SURF, Extended, bool, false, "Extended descriptor flag (true - use extended 128-element descriptors; false - use 64-element descriptors).");
|
||||
@@ -301,9 +299,9 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(GFTT, UseHarrisDetector, bool, false, "");
|
||||
RTABMAP_PARAM(GFTT, K, double, 0.04, "");
|
||||
|
||||
RTABMAP_PARAM(ORB, ScaleFactor, float, 2, "Pyramid decimation ratio, greater than 1. scaleFactor==2 means the classical pyramid, where each next level has 4x less pixels than the previous, but such a big scale factor will degrade feature matching scores dramatically. On the other hand, too close to 1 scale factor will mean that to cover certain scale range you will need more pyramid levels and so the speed will suffer.");
|
||||
RTABMAP_PARAM(ORB, NLevels, int, 3, "The number of pyramid levels. The smallest level will have linear size equal to input_image_linear_size/pow(scaleFactor, nlevels).");
|
||||
RTABMAP_PARAM(ORB, EdgeThreshold, int, 19, "This is size of the border where the features are not detected. It should roughly match the patchSize parameter.");
|
||||
RTABMAP_PARAM(ORB, ScaleFactor, float, 1.2, "Pyramid decimation ratio, greater than 1. scaleFactor==2 means the classical pyramid, where each next level has 4x less pixels than the previous, but such a big scale factor will degrade feature matching scores dramatically. On the other hand, too close to 1 scale factor will mean that to cover certain scale range you will need more pyramid levels and so the speed will suffer.");
|
||||
RTABMAP_PARAM(ORB, NLevels, int, 8, "The number of pyramid levels. The smallest level will have linear size equal to input_image_linear_size/pow(scaleFactor, nlevels).");
|
||||
RTABMAP_PARAM(ORB, EdgeThreshold, int, 31, "This is size of the border where the features are not detected. It should roughly match the patchSize parameter.");
|
||||
RTABMAP_PARAM(ORB, FirstLevel, int, 0, "It should be 0 in the current implementation.");
|
||||
RTABMAP_PARAM(ORB, WTA_K, int, 2, "The number of points that produce each element of the oriented BRIEF descriptor. The default value 2 means the BRIEF where we take a random point pair and compare their brightnesses, so we get 0/1 response. Other possible values are 3 and 4. For example, 3 means that we take 3 random points (of course, those point coordinates are random, but they are generated from the pre-defined seed, so each element of BRIEF descriptor is computed deterministically from the pixel rectangle), find point of maximum brightness and output index of the winner (0, 1 or 2). Such output will occupy 2 bits, and therefore it will need a special variant of Hamming distance, denoted as NORM_HAMMING2 (2 bits per bin). When WTA_K=4, we take 4 random points to compute each bin (that will also occupy 2 bits with possible values 0, 1, 2 or 3).");
|
||||
RTABMAP_PARAM(ORB, ScoreType, int, 0, "The default HARRIS_SCORE=0 means that Harris algorithm is used to rank features (the score is written to KeyPoint::score and is used to retain best nfeatures features); FAST_SCORE=1 is alternative value of the parameter that produces slightly less stable keypoints, but it is a little faster to compute.");
|
||||
@@ -588,9 +586,9 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(Vis, Iterations, int, 300, "Maximum iterations to compute the transform.");
|
||||
#if CV_MAJOR_VERSION > 2 && !defined(HAVE_OPENCV_XFEATURES2D)
|
||||
// OpenCV>2 without xFeatures2D module doesn't have BRIEF
|
||||
RTABMAP_PARAM(Vis, FeatureType, int, 8, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint 12=SURF/FREAK 13=GFTT/DAISY 14=SURF/DAISY");
|
||||
RTABMAP_PARAM(Vis, FeatureType, int, 8, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint Torch.");
|
||||
#else
|
||||
RTABMAP_PARAM(Vis, FeatureType, int, 6, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint 12=SURF/FREAK 13=GFTT/DAISY 14=SURF/DAISY");
|
||||
RTABMAP_PARAM(Vis, FeatureType, int, 6, "0=SURF 1=SIFT 2=ORB 3=FAST/FREAK 4=FAST/BRIEF 5=GFTT/FREAK 6=GFTT/BRIEF 7=BRISK 8=GFTT/ORB 9=KAZE 10=ORB-OCTREE 11=SuperPoint Torch.");
|
||||
#endif
|
||||
RTABMAP_PARAM(Vis, MaxFeatures, int, 1000, "0 no limits.");
|
||||
RTABMAP_PARAM(Vis, MaxDepth, float, 0, "Max depth of the features (0 means no limit).");
|
||||
@@ -604,7 +602,7 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(Vis, GridCols, int, 1, uFormat("Number of columns of the grid used to extract uniformly \"%s / grid cells\" features from each cell.", kVisMaxFeatures().c_str()));
|
||||
RTABMAP_PARAM(Vis, CorType, int, 0, "Correspondences computation approach: 0=Features Matching, 1=Optical Flow");
|
||||
RTABMAP_PARAM(Vis, CorNNType, int, 1, uFormat("[%s=0] kNNFlannNaive=0, kNNFlannKdTree=1, kNNFlannLSH=2, kNNBruteForce=3, kNNBruteForceGPU=4, BruteForceCrossCheck=5, SuperGlue=6, GMS=7. Used for features matching approach.", kVisCorType().c_str()));
|
||||
RTABMAP_PARAM(Vis, CorNNDR, float, 0.8, uFormat("[%s=0] NNDR: nearest neighbor distance ratio. Used for knn features matching approach.", kVisCorType().c_str()));
|
||||
RTABMAP_PARAM(Vis, CorNNDR, float, 0.6, uFormat("[%s=0] NNDR: nearest neighbor distance ratio. Used for knn features matching approach.", kVisCorType().c_str()));
|
||||
RTABMAP_PARAM(Vis, CorGuessWinSize, int, 20, uFormat("[%s=0] Matching window size (pixels) around projected points when a guess transform is provided to find correspondences. 0 means disabled.", kVisCorType().c_str()));
|
||||
RTABMAP_PARAM(Vis, CorGuessMatchToProjection, bool, false, uFormat("[%s=0] Match frame's corners to source's projected points (when guess transform is provided) instead of projected points to frame's corners.", kVisCorType().c_str()));
|
||||
RTABMAP_PARAM(Vis, CorFlowWinSize, int, 16, uFormat("[%s=1] See cv::calcOpticalFlowPyrLK(). Used for optical flow approach.", kVisCorType().c_str()));
|
||||
@@ -644,15 +642,13 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(Icp, Epsilon, float, 0, "Set the transformation epsilon (maximum allowable difference between two consecutive transformations) in order for an optimization to be considered as having converged to the final solution.");
|
||||
RTABMAP_PARAM(Icp, CorrespondenceRatio, float, 0.1, "Ratio of matching correspondences to accept the transform.");
|
||||
#ifdef RTABMAP_POINTMATCHER
|
||||
RTABMAP_PARAM(Icp, PointToPlane, bool, true, "Use point to plane ICP.");
|
||||
RTABMAP_PARAM(Icp, PointToPlane, bool, true, "Use point to plane ICP.");
|
||||
#else
|
||||
RTABMAP_PARAM(Icp, PointToPlane, bool, false, "Use point to plane ICP.");
|
||||
RTABMAP_PARAM(Icp, PointToPlane, bool, false, "Use point to plane ICP.");
|
||||
#endif
|
||||
RTABMAP_PARAM(Icp, PointToPlaneK, int, 5, "Number of neighbors to compute normals for point to plane if the cloud doesn't have already normals.");
|
||||
RTABMAP_PARAM(Icp, PointToPlaneRadius, float, 1.0, "Search radius to compute normals for point to plane if the cloud doesn't have already normals.");
|
||||
RTABMAP_PARAM(Icp, PointToPlaneGroundNormalsUp, float, 0.0, "Invert normals on ground if they are pointing down (useful for ring-like 3D LiDARs). 0 means disabled, 1 means only normals perfectly aligned with -z axis. This is only done with 3D scans.");
|
||||
RTABMAP_PARAM(Icp, PointToPlaneMinComplexity, float, 0.02, uFormat("Minimum structural complexity (0.0=low, 1.0=high) of the scan to do PointToPlane registration, otherwise PointToPoint registration is done instead and strategy from %s is used. This check is done only when %s=true.", kIcpPointToPlaneLowComplexityStrategy().c_str(), kIcpPointToPlane().c_str()));
|
||||
RTABMAP_PARAM(Icp, PointToPlaneLowComplexityStrategy, int, 1, uFormat("If structural complexity is below %s: set to 0 to so that the transform is automatically rejected, set to 1 to limit ICP correction in axes with most constraints (e.g., for a corridor-like environment, the resulting transform will be limited in y and yaw, x will taken from the guess), set to 2 to accept \"as is\" the transform computed by PointToPoint.", kIcpPointToPlaneMinComplexity().c_str()));
|
||||
RTABMAP_PARAM(Icp, PointToPlaneK, int, 5, "Number of neighbors to compute normals for point to plane if the cloud doesn't have already normals.");
|
||||
RTABMAP_PARAM(Icp, PointToPlaneRadius, float, 1.0, "Search radius to compute normals for point to plane if the cloud doesn't have already normals.");
|
||||
RTABMAP_PARAM(Icp, PointToPlaneMinComplexity, float, 0.02, "Minimum structural complexity (0.0=low, 1.0=high) of the scan to do point to plane registration, otherwise point to point registration is done instead.");
|
||||
|
||||
// libpointmatcher
|
||||
#ifdef RTABMAP_POINTMATCHER
|
||||
@@ -663,7 +659,6 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM_STR(Icp, PMConfig, "", uFormat("Configuration file (*.yaml) used by libpointmatcher. Note that data filters set for libpointmatcher are done after filtering done by rtabmap (i.e., %s, %s), so make sure to disable those in rtabmap if you want to use only those from libpointmatcher. Parameters %s, %s and %s are also ignored if configuration file is set.", kIcpVoxelSize().c_str(), kIcpDownsamplingStep().c_str(), kIcpIterations().c_str(), kIcpEpsilon().c_str(), kIcpMaxCorrespondenceDistance().c_str()).c_str());
|
||||
RTABMAP_PARAM(Icp, PMMatcherKnn, int, 1, "KDTreeMatcher/knn: number of nearest neighbors to consider it the reference. For convenience when configuration file is not set.");
|
||||
RTABMAP_PARAM(Icp, PMMatcherEpsilon, float, 0.0, "KDTreeMatcher/epsilon: approximation to use for the nearest-neighbor search. For convenience when configuration file is not set.");
|
||||
RTABMAP_PARAM(Icp, PMMatcherIntensity, bool, false, uFormat("KDTreeMatcher: among nearest neighbors, keep only the one with the most similar intensity. This only work with %s>1.", kIcpPMMatcherKnn().c_str()));
|
||||
RTABMAP_PARAM(Icp, PMOutlierRatio, float, 0.95, "TrimmedDistOutlierFilter/ratio: For convenience when configuration file is not set. For kinect-like point cloud, use 0.65.");
|
||||
|
||||
// Stereo disparity
|
||||
@@ -757,8 +752,6 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(Marker, VarianceLinear, float, 0.001, "Linear variance to set on marker detections.");
|
||||
RTABMAP_PARAM(Marker, VarianceAngular, float, 0.01, "Angular variance to set on marker detections. Set to >=9999 to use only position (xyz) constraint in graph optimization.");
|
||||
RTABMAP_PARAM(Marker, CornerRefinementMethod, int, 0, "Corner refinement method (0: None, 1: Subpixel, 2:contour, 3: AprilTag2). For OpenCV <3.3.0, this is \"doCornerRefinement\" parameter: set 0 for false and 1 for true.");
|
||||
RTABMAP_PARAM(Marker, MaxRange, float, 0.0, "Maximum range in which markers will be detected. <=0 for unlimited range.");
|
||||
RTABMAP_PARAM(Marker, MinRange, float, 0.0, "Miniminum range in which markers will be detected. <=0 for unlimited range.");
|
||||
|
||||
RTABMAP_PARAM(ImuFilter, MadgwickGain, double, 0.1, "Gain of the filter. Higher values lead to faster convergence but more noise. Lower values lead to slower convergence but smoother signal, belongs in [0, 1].");
|
||||
RTABMAP_PARAM(ImuFilter, MadgwickZeta, double, 0.0, "Gyro drift gain (approx. rad/s), belongs in [-1, 1].");
|
||||
@@ -846,3 +839,4 @@ private:
|
||||
}
|
||||
|
||||
#endif /* PARAMETERS_H_ */
|
||||
|
||||
|
||||
@@ -69,14 +69,11 @@ private:
|
||||
bool _pointToPlane;
|
||||
int _pointToPlaneK;
|
||||
float _pointToPlaneRadius;
|
||||
float _pointToPlaneGroundNormalsUp;
|
||||
float _pointToPlaneMinComplexity;
|
||||
int _pointToPlaneLowComplexityStrategy;
|
||||
bool _libpointmatcher;
|
||||
std::string _libpointmatcherConfig;
|
||||
int _libpointmatcherKnn;
|
||||
float _libpointmatcherEpsilon;
|
||||
bool _libpointmatcherIntensity;
|
||||
float _libpointmatcherOutlierRatio;
|
||||
void * _libpointmatcherICP;
|
||||
};
|
||||
|
||||
@@ -75,7 +75,6 @@ public:
|
||||
|
||||
// RegistrationVis
|
||||
int inliers;
|
||||
float inliersRatio;
|
||||
float inliersMeanDistance;
|
||||
float inliersDistribution;
|
||||
std::vector<int> inliersIDs;
|
||||
|
||||
@@ -136,9 +136,11 @@ public:
|
||||
std::map<int, int> getWeights() const;
|
||||
int getTotalMemSize() const;
|
||||
double getLastProcessTime() const {return _lastProcessTime;};
|
||||
std::multimap<int, cv::KeyPoint> getWords(int locationId) const;
|
||||
bool isInSTM(int locationId) const;
|
||||
bool isIDsGenerated() const;
|
||||
const Statistics & getStatistics() const;
|
||||
//bool getMetricData(int locationId, cv::Mat & rgb, cv::Mat & depth, float & depthConstant, Transform & pose, Transform & localTransform) const;
|
||||
const std::map<int, Transform> & getLocalOptimizedPoses() const {return _optimizedPoses;}
|
||||
const std::multimap<int, Link> & getLocalConstraints() const {return _constraints;}
|
||||
Transform getPose(int locationId) const;
|
||||
@@ -196,8 +198,6 @@ public:
|
||||
bool withGrid = false,
|
||||
bool withWords = true,
|
||||
bool withGlobalDescriptors = true) const;
|
||||
std::map<int, Transform> getNodesInRadius(const Transform & pose, float radius); // If radius=0, RGBD/LocalRadius is used. Can return landmarks.
|
||||
std::map<int, Transform> getNodesInRadius(int nodeId, float radius); // If nodeId==0, return poses around latest node. If radius=0, RGBD/LocalRadius is used. Can return landmarks and use landmark id (negative) as request.
|
||||
int detectMoreLoopClosures(
|
||||
float clusterRadius = 0.5f,
|
||||
float clusterAngle = M_PI/6.0f,
|
||||
@@ -310,7 +310,6 @@ private:
|
||||
double _lastProcessTime;
|
||||
bool _someNodesHaveBeenTransferred;
|
||||
float _distanceTravelled;
|
||||
float _distanceTravelledSinceLastLocalization;
|
||||
bool _optimizeFromGraphEndChanged;
|
||||
|
||||
// Abstract classes containing all loop closure
|
||||
|
||||
@@ -275,7 +275,7 @@ public:
|
||||
void setLandmarks(const Landmarks & landmarks) {_landmarks = landmarks;}
|
||||
const Landmarks & landmarks() const {return _landmarks;}
|
||||
|
||||
unsigned long getMemoryUsed() const; // Return memory usage in Bytes
|
||||
long getMemoryUsed() const; // Return memory usage in Bytes
|
||||
/**
|
||||
* Clear compressed rgb/depth (left/right) images, compressed laser scan and compressed user data.
|
||||
* Raw data are kept is set.
|
||||
|
||||
@@ -104,18 +104,19 @@ public:
|
||||
|
||||
//visual words stuff
|
||||
void removeAllWords();
|
||||
void removeWord(int wordId);
|
||||
void changeWordsRef(int oldWordId, int activeWordId);
|
||||
void setWords(const std::multimap<int, int> & words, const std::vector<cv::KeyPoint> & keypoints, const std::vector<cv::Point3f> & words3, const cv::Mat & descriptors);
|
||||
void setWords(const std::multimap<int, cv::KeyPoint> & words);
|
||||
bool isEnabled() const {return _enabled;}
|
||||
void setEnabled(bool enabled) {_enabled = enabled;}
|
||||
const std::multimap<int, int> & getWords() const {return _words;}
|
||||
const std::vector<cv::KeyPoint> & getWordsKpts() const {return _wordsKpts;}
|
||||
const std::multimap<int, cv::KeyPoint> & getWords() const {return _words;}
|
||||
int getInvalidWordsCount() const {return _invalidWordsCount;}
|
||||
const std::map<int, int> & getWordsChanged() const {return _wordsChanged;}
|
||||
const cv::Mat & getWordsDescriptors() const {return _wordsDescriptors;}
|
||||
void setWordsDescriptors(const cv::Mat & descriptors);
|
||||
const std::multimap<int, cv::Mat> & getWordsDescriptors() const {return _wordsDescriptors;}
|
||||
void setWordsDescriptors(const std::multimap<int, cv::Mat> & descriptors) {_wordsDescriptors = descriptors;}
|
||||
|
||||
//metric stuff
|
||||
void setWords3(const std::multimap<int, cv::Point3f> & words3) {_words3 = words3;}
|
||||
void setPose(const Transform & pose) {_pose = pose;}
|
||||
void setGroundTruthPose(const Transform & pose) {_groundTruthPose = pose;}
|
||||
void setVelocity(float vx, float vy, float vz, float vroll, float vpitch, float vyaw) {
|
||||
@@ -128,7 +129,7 @@ public:
|
||||
_velocity[5]=vyaw;
|
||||
}
|
||||
|
||||
const std::vector<cv::Point3f> & getWords3() const {return _words3;}
|
||||
const std::multimap<int, cv::Point3f> & getWords3() const {return _words3;}
|
||||
const Transform & getPose() const {return _pose;}
|
||||
cv::Mat getPoseCovariance() const;
|
||||
const Transform & getGroundTruthPose() const {return _groundTruthPose;}
|
||||
@@ -137,7 +138,7 @@ public:
|
||||
SensorData & sensorData() {return _sensorData;}
|
||||
const SensorData & sensorData() const {return _sensorData;}
|
||||
|
||||
unsigned long getMemoryUsed(bool withSensorData=true) const; // Return memory usage in Bytes
|
||||
long getMemoryUsed(bool withSensorData=true) const; // Return memory usage in Bytes
|
||||
|
||||
private:
|
||||
int _id;
|
||||
@@ -154,10 +155,9 @@ private:
|
||||
// Contains all words (Some can be duplicates -> if a word appears 2
|
||||
// times in the signature, it will be 2 times in this list)
|
||||
// Words match with the CvSeq keypoints and descriptors
|
||||
std::multimap<int, int> _words; // word <id, keypoint index>
|
||||
std::vector<cv::KeyPoint> _wordsKpts;
|
||||
std::vector<cv::Point3f> _words3; // in base_link frame (localTransform applied))
|
||||
cv::Mat _wordsDescriptors;
|
||||
std::multimap<int, cv::KeyPoint> _words; // word <id, keypoint>
|
||||
std::multimap<int, cv::Point3f> _words3; // word <id, point> // in base_link frame (localTransform applied))
|
||||
std::multimap<int, cv::Mat> _wordsDescriptors;
|
||||
std::map<int, int> _wordsChanged; // <oldId, newId>
|
||||
bool _enabled;
|
||||
int _invalidWordsCount;
|
||||
|
||||
@@ -65,9 +65,7 @@ class RTABMAP_EXP Statistics
|
||||
RTABMAP_STATS(Loop, Map_id,);
|
||||
RTABMAP_STATS(Loop, Visual_words,);
|
||||
RTABMAP_STATS(Loop, Visual_inliers,);
|
||||
RTABMAP_STATS(Loop, Visual_inliers_ratio,);
|
||||
RTABMAP_STATS(Loop, Visual_matches,);
|
||||
RTABMAP_STATS(Loop, Distance_since_last_loc,);
|
||||
RTABMAP_STATS(Loop, Last_id,);
|
||||
RTABMAP_STATS(Loop, Optimization_max_error, m);
|
||||
RTABMAP_STATS(Loop, Optimization_max_error_ratio, );
|
||||
@@ -150,7 +148,6 @@ class RTABMAP_EXP Statistics
|
||||
RTABMAP_STATS(Memory, Odometry_variance_lin,);
|
||||
RTABMAP_STATS(Memory, Distance_travelled, m);
|
||||
RTABMAP_STATS(Memory, RAM_usage, MB);
|
||||
RTABMAP_STATS(Memory, RAM_estimated, MB);
|
||||
RTABMAP_STATS(Memory, Triangulated_points, );
|
||||
|
||||
RTABMAP_STATS(Timing, Memory_update, ms);
|
||||
@@ -173,7 +170,6 @@ class RTABMAP_EXP Statistics
|
||||
RTABMAP_STATS(Timing, Joining_trash, ms);
|
||||
RTABMAP_STATS(Timing, Emptying_trash, ms);
|
||||
RTABMAP_STATS(Timing, Finalizing_statistics, ms);
|
||||
RTABMAP_STATS(Timing, RAM_estimation, ms);
|
||||
|
||||
RTABMAP_STATS(TimingMem, Pre_update, ms);
|
||||
RTABMAP_STATS(TimingMem, Signature_creation, ms);
|
||||
|
||||
@@ -98,7 +98,6 @@ public:
|
||||
|
||||
float theta() const;
|
||||
|
||||
bool isInvertible() const;
|
||||
Transform inverse() const;
|
||||
Transform rotation() const;
|
||||
Transform translation() const;
|
||||
|
||||
@@ -100,9 +100,8 @@ public:
|
||||
int getLastIndexedWordId() const;
|
||||
int getTotalActiveReferences() const {return _totalActiveReferences;}
|
||||
unsigned int getIndexedWordsCount() const;
|
||||
unsigned int getIndexMemoryUsed() const; // KB
|
||||
unsigned long getMemoryUsed() const; //Bytes
|
||||
bool setNNStrategy(NNStrategy strategy); // Return true if the search tree has been re-initialized
|
||||
unsigned int getIndexMemoryUsed() const;
|
||||
void setNNStrategy(NNStrategy strategy);
|
||||
bool isIncremental() const {return _incrementalDictionary;}
|
||||
bool isIncrementalFlann() const {return _incrementalFlann;}
|
||||
void setIncrementalDictionary();
|
||||
@@ -118,8 +117,8 @@ public:
|
||||
void deleteUnusedWords();
|
||||
|
||||
public:
|
||||
static cv::Mat convertBinTo32F(const cv::Mat & descriptorsIn, bool byteToFloat = true);
|
||||
static cv::Mat convert32FToBin(const cv::Mat & descriptorsIn, bool byteToFloat = true);
|
||||
static cv::Mat convertBinTo32F(const cv::Mat & descriptorsIn);
|
||||
static cv::Mat convert32FToBin(const cv::Mat & descriptorsIn);
|
||||
|
||||
protected:
|
||||
int getNextId();
|
||||
@@ -132,7 +131,6 @@ private:
|
||||
bool _incrementalDictionary;
|
||||
bool _incrementalFlann;
|
||||
float _rebalancingFactor;
|
||||
bool _byteToFloat;
|
||||
float _nndrRatio;
|
||||
std::string _dictionaryPath; // a pre-computed dictionary (.txt or .db)
|
||||
std::string _newDictionaryPath; // a pre-computed dictionary (.txt or .db)
|
||||
|
||||
@@ -43,7 +43,6 @@ public:
|
||||
|
||||
void addRef(int signatureId);
|
||||
int removeAllRef(int signatureId);
|
||||
unsigned long getMemoryUsed() const;
|
||||
|
||||
int getTotalReferences() const {return _totalReferences;}
|
||||
int id() const {return _id;}
|
||||
|
||||
@@ -74,11 +74,6 @@ public:
|
||||
_syncImageRateWithStamps = syncImageRateWithStamps;
|
||||
}
|
||||
|
||||
void setConfigForEachFrame(bool value)
|
||||
{
|
||||
_hasConfigForEachFrame = value;
|
||||
}
|
||||
|
||||
void setScanPath(
|
||||
const std::string & dir,
|
||||
int maxScanPts = 0,
|
||||
@@ -121,14 +116,12 @@ public:
|
||||
|
||||
protected:
|
||||
virtual SensorData captureImage(CameraInfo * info = 0);
|
||||
|
||||
private:
|
||||
bool readPoses(
|
||||
std::list<Transform> & outputPoses,
|
||||
std::list<double> & stamps,
|
||||
const std::string & filePath,
|
||||
int format,
|
||||
double maxTimeDiff) const;
|
||||
std::list<Transform> & outputPoses,
|
||||
std::list<double> & stamps,
|
||||
const std::string & filePath,
|
||||
int format,
|
||||
double maxTimeDiff) const;
|
||||
|
||||
private:
|
||||
std::string _path;
|
||||
@@ -158,7 +151,6 @@ private:
|
||||
bool _depthFromScanFillHolesFromBorder;
|
||||
|
||||
bool _filenamesAreTimestamps;
|
||||
bool _hasConfigForEachFrame;
|
||||
std::string _timestampsPath;
|
||||
bool _syncImageRateWithStamps;
|
||||
|
||||
@@ -170,10 +162,8 @@ private:
|
||||
|
||||
std::list<double> _stamps;
|
||||
std::list<Transform> odometry_;
|
||||
std::list<cv::Mat> covariances_;
|
||||
std::list<Transform> groundTruth_;
|
||||
CameraModel _model;
|
||||
std::list<CameraModel> _models;
|
||||
|
||||
UTimer _captureTimer;
|
||||
double _captureDelay;
|
||||
|
||||
@@ -35,8 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "rtabmap/utilite/UTimer.h"
|
||||
|
||||
#ifdef RTABMAP_K4A
|
||||
#include <k4a/k4atypes.h>
|
||||
#include <k4arecord/playback.h>
|
||||
#include <k4a/k4atypes.h>
|
||||
#endif
|
||||
|
||||
namespace rtabmap
|
||||
@@ -73,14 +72,15 @@ private:
|
||||
private:
|
||||
|
||||
#ifdef RTABMAP_K4A
|
||||
k4a_device_t deviceHandle_;
|
||||
k4a_device_t device_;
|
||||
k4a_device_configuration_t config_;
|
||||
k4a_calibration_t calibration_;
|
||||
k4a_transformation_t transformationHandle_;
|
||||
k4a_capture_t captureHandle_;
|
||||
k4a_playback_t playbackHandle_;
|
||||
k4a_transformation_t transformation_;
|
||||
k4a_capture_t capture_;
|
||||
std::string serial_number_;
|
||||
|
||||
void* playbackHandle_;
|
||||
void* transformationHandle_;
|
||||
CameraModel model_;
|
||||
int deviceId_;
|
||||
std::string fileName_;
|
||||
|
||||
@@ -48,6 +48,8 @@ public:
|
||||
virtual ~CameraRGBDImages();
|
||||
|
||||
virtual bool init(const std::string & calibrationFolder = ".", const std::string & cameraName = "");
|
||||
virtual bool isCalibrated() const;
|
||||
virtual std::string getSerial() const;
|
||||
|
||||
virtual void setStartIndex(int index) {CameraImages::setStartIndex(index);cameraDepth_.setStartIndex(index);} // negative means last
|
||||
virtual void setMaxFrames(int value) {CameraImages::setMaxFrames(value);cameraDepth_.setMaxFrames(value);}
|
||||
|
||||
@@ -75,7 +75,6 @@ public:
|
||||
void setEmitterEnabled(bool enabled);
|
||||
void setIRFormat(bool enabled, bool useDepthInsteadOfRightImage);
|
||||
void setResolution(int width, int height, int fps = 30);
|
||||
void setGlobalTimeSync(bool enabled);
|
||||
void publishInterIMU(bool enabled);
|
||||
void setDualMode(bool enabled, const Transform & extrinsics);
|
||||
void setJsonConfig(const std::string & json);
|
||||
@@ -94,7 +93,7 @@ private:
|
||||
Transform & pose,
|
||||
unsigned int & poseConfidence,
|
||||
IMU & imu,
|
||||
int maxWaitTimeMs = 35);
|
||||
int maxWaitTimeMs = 35) const;
|
||||
#endif
|
||||
|
||||
protected:
|
||||
@@ -122,7 +121,6 @@ private:
|
||||
UMutex imuMutex_;
|
||||
double lastImuStamp_;
|
||||
bool clockSyncWarningShown_;
|
||||
bool imuGlobalSyncWarningShown_;
|
||||
|
||||
bool emitterEnabled_;
|
||||
bool ir_;
|
||||
@@ -132,13 +130,11 @@ private:
|
||||
int cameraWidth_;
|
||||
int cameraHeight_;
|
||||
int cameraFps_;
|
||||
bool globalTimeSync_;
|
||||
bool publishInterIMU_;
|
||||
bool dualMode_;
|
||||
Transform dualExtrinsics_;
|
||||
std::string jsonConfig_;
|
||||
bool closing_;
|
||||
bool isL500_;
|
||||
|
||||
static Transform realsense2PoseRotation_;
|
||||
static Transform realsense2PoseRotationInv_;
|
||||
|
||||
@@ -97,35 +97,28 @@ void segmentObstaclesFromGround(
|
||||
// cluster all surfaces for which the centroid is in the Z-range of the bigger surface
|
||||
if(clusteredFlatSurfaces.size())
|
||||
{
|
||||
Eigen::Vector4f biggestSurfaceMin,biggestSurfaceMax;
|
||||
Eigen::Vector4f min,max;
|
||||
if(maxGroundHeight != 0.0f)
|
||||
{
|
||||
// Search for biggest surface under max ground height
|
||||
size_t points = 0;
|
||||
biggestFlatSurfaceIndex = -1;
|
||||
for(size_t i=0;i<clusteredFlatSurfaces.size();++i)
|
||||
{
|
||||
Eigen::Vector4f min,max;
|
||||
pcl::getMinMax3D(*cloud, *clusteredFlatSurfaces.at(i), min, max);
|
||||
if(min[2]<maxGroundHeight && clusteredFlatSurfaces.size() > points)
|
||||
{
|
||||
points = clusteredFlatSurfaces.at(i)->size();
|
||||
biggestFlatSurfaceIndex = i;
|
||||
biggestSurfaceMin = min;
|
||||
biggestSurfaceMax = max;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pcl::getMinMax3D(*cloud, *clusteredFlatSurfaces.at(biggestFlatSurfaceIndex), biggestSurfaceMin, biggestSurfaceMax);
|
||||
}
|
||||
if(biggestFlatSurfaceIndex>=0)
|
||||
{
|
||||
ground = clusteredFlatSurfaces.at(biggestFlatSurfaceIndex);
|
||||
pcl::getMinMax3D(*cloud, *clusteredFlatSurfaces.at(biggestFlatSurfaceIndex), min, max);
|
||||
}
|
||||
ground = clusteredFlatSurfaces.at(biggestFlatSurfaceIndex);
|
||||
|
||||
if(!ground->empty() && (maxGroundHeight == 0.0f || biggestSurfaceMin[2] < maxGroundHeight))
|
||||
if(!ground->empty() && (maxGroundHeight == 0.0f || min[2] < maxGroundHeight))
|
||||
{
|
||||
for(unsigned int i=0; i<clusteredFlatSurfaces.size(); ++i)
|
||||
{
|
||||
@@ -133,7 +126,7 @@ void segmentObstaclesFromGround(
|
||||
{
|
||||
Eigen::Vector4f centroid(0,0,0,1);
|
||||
pcl::compute3DCentroid(*cloud, *clusteredFlatSurfaces.at(i), centroid);
|
||||
if(maxGroundHeight==0.0f || centroid[2] <= maxGroundHeight || centroid[2] <= biggestSurfaceMax[2]) // epsilon
|
||||
if(maxGroundHeight==0.0f || centroid[2] <= maxGroundHeight || centroid[2] <= max[2]) // epsilon
|
||||
{
|
||||
ground = util3d::concatenate(ground, clusteredFlatSurfaces.at(i));
|
||||
}
|
||||
|
||||
@@ -9,7 +9,6 @@
|
||||
#define CORELIB_INCLUDE_RTABMAP_CORE_IMPL_UTIL3D_SURFACE_HPP_
|
||||
|
||||
#include <pcl/search/kdtree.h>
|
||||
#include <pcl/conversions.h>
|
||||
#include <rtabmap/utilite/UConversion.h>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
@@ -78,7 +78,7 @@ private:
|
||||
Signature * map_;
|
||||
Signature * lastFrame_;
|
||||
int lastFrameOldestNewId_;
|
||||
std::vector<std::pair<pcl::PointCloud<pcl::PointXYZINormal>::Ptr, pcl::IndicesPtr> > scansBuffer_;
|
||||
std::vector<std::pair<pcl::PointCloud<pcl::PointNormal>::Ptr, pcl::IndicesPtr> > scansBuffer_;
|
||||
bool initGravity_;
|
||||
|
||||
std::map<int, std::map<int, FeatureBA> > bundleWordReferences_; //<WordId, <FrameId, pt2D+depth>>
|
||||
|
||||
@@ -154,8 +154,6 @@ cv::Mat RTABMAP_EXP brightnessAndContrastAuto(
|
||||
cv::Mat RTABMAP_EXP exposureFusion(
|
||||
const std::vector<cv::Mat> & images);
|
||||
|
||||
void RTABMAP_EXP HSVtoRGB( float *r, float *g, float *b, float h, float s, float v );
|
||||
|
||||
} // namespace util3d
|
||||
} // namespace rtabmap
|
||||
|
||||
|
||||
@@ -56,16 +56,7 @@ LaserScan RTABMAP_EXP commonFiltering(
|
||||
float voxelSize = 0.0f,
|
||||
int normalK = 0,
|
||||
float normalRadius = 0.0f,
|
||||
float groundNormalsUp = 0.0f);
|
||||
RTABMAP_DEPRECATED(LaserScan RTABMAP_EXP commonFiltering(
|
||||
const LaserScan & scan,
|
||||
int downsamplingStep,
|
||||
float rangeMin,
|
||||
float rangeMax,
|
||||
float voxelSize,
|
||||
int normalK,
|
||||
float normalRadius,
|
||||
bool forceGroundNormalsUp), "Use version with groundNormalsUp as float. For forceGroundNormalsUp=true, set groundNormalsUp=0.8, otherwise set groundNormalsUp=0.0.");
|
||||
bool forceGroundNormalsUp = false);
|
||||
|
||||
LaserScan RTABMAP_EXP rangeFiltering(
|
||||
const LaserScan & scan,
|
||||
@@ -297,12 +288,6 @@ pcl::PointCloud<pcl::PointXYZRGB>::Ptr RTABMAP_EXP cropBox(
|
||||
const Eigen::Vector4f & max,
|
||||
const Transform & transform = Transform::getIdentity(),
|
||||
bool negative = false);
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr RTABMAP_EXP cropBox(
|
||||
const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
|
||||
const Eigen::Vector4f & min,
|
||||
const Eigen::Vector4f & max,
|
||||
const Transform & transform = Transform::getIdentity(),
|
||||
bool negative = false);
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr RTABMAP_EXP cropBox(
|
||||
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
|
||||
const Eigen::Vector4f & min,
|
||||
@@ -466,12 +451,6 @@ pcl::IndicesPtr RTABMAP_EXP subtractFiltering(
|
||||
/**
|
||||
* For convenience.
|
||||
*/
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr RTABMAP_EXP subtractFiltering(
|
||||
const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
|
||||
const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & substractCloud,
|
||||
float radiusSearch,
|
||||
float maxAngle = M_PI/4.0f,
|
||||
int minNeighborsInRadius = 1);
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr RTABMAP_EXP subtractFiltering(
|
||||
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
|
||||
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & substractCloud,
|
||||
@@ -488,14 +467,6 @@ pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr RTABMAP_EXP subtractFiltering(
|
||||
* @param radiusSearch the radius in meter.
|
||||
* @return the indices of the points satisfying the parameters.
|
||||
*/
|
||||
pcl::IndicesPtr RTABMAP_EXP subtractFiltering(
|
||||
const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
|
||||
const pcl::IndicesPtr & indices,
|
||||
const pcl::PointCloud<pcl::PointXYZINormal>::Ptr & substractCloud,
|
||||
const pcl::IndicesPtr & substractIndices,
|
||||
float radiusSearch,
|
||||
float maxAngle = M_PI/4.0f,
|
||||
int minNeighborsInRadius = 1);
|
||||
pcl::IndicesPtr RTABMAP_EXP subtractFiltering(
|
||||
const pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
|
||||
const pcl::IndicesPtr & indices,
|
||||
|
||||
@@ -66,25 +66,12 @@ void RTABMAP_EXP computeVarianceAndCorrespondences(
|
||||
double maxCorrespondenceAngle, // <=0 means that we don't care about normal angle difference
|
||||
double & variance,
|
||||
int & correspondencesOut);
|
||||
void RTABMAP_EXP computeVarianceAndCorrespondences(
|
||||
const pcl::PointCloud<pcl::PointXYZINormal>::ConstPtr & cloudA,
|
||||
const pcl::PointCloud<pcl::PointXYZINormal>::ConstPtr & cloudB,
|
||||
double maxCorrespondenceDistance,
|
||||
double maxCorrespondenceAngle, // <=0 means that we don't care about normal angle difference
|
||||
double & variance,
|
||||
int & correspondencesOut);
|
||||
void RTABMAP_EXP computeVarianceAndCorrespondences(
|
||||
const pcl::PointCloud<pcl::PointXYZ>::ConstPtr & cloudA,
|
||||
const pcl::PointCloud<pcl::PointXYZ>::ConstPtr & cloudB,
|
||||
double maxCorrespondenceDistance,
|
||||
double & variance,
|
||||
int & correspondencesOut);
|
||||
void RTABMAP_EXP computeVarianceAndCorrespondences(
|
||||
const pcl::PointCloud<pcl::PointXYZI>::ConstPtr & cloudA,
|
||||
const pcl::PointCloud<pcl::PointXYZI>::ConstPtr & cloudB,
|
||||
double maxCorrespondenceDistance,
|
||||
double & variance,
|
||||
int & correspondencesOut);
|
||||
|
||||
Transform RTABMAP_EXP icp(
|
||||
const pcl::PointCloud<pcl::PointXYZ>::ConstPtr & cloud_source,
|
||||
@@ -95,15 +82,6 @@ Transform RTABMAP_EXP icp(
|
||||
pcl::PointCloud<pcl::PointXYZ> & cloud_source_registered,
|
||||
float epsilon = 0.0f,
|
||||
bool icp2D = false);
|
||||
Transform RTABMAP_EXP icp(
|
||||
const pcl::PointCloud<pcl::PointXYZI>::ConstPtr & cloud_source,
|
||||
const pcl::PointCloud<pcl::PointXYZI>::ConstPtr & cloud_target,
|
||||
double maxCorrespondenceDistance,
|
||||
int maximumIterations,
|
||||
bool & hasConverged,
|
||||
pcl::PointCloud<pcl::PointXYZI> & cloud_source_registered,
|
||||
float epsilon = 0.0f,
|
||||
bool icp2D = false);
|
||||
|
||||
Transform RTABMAP_EXP icpPointToPlane(
|
||||
const pcl::PointCloud<pcl::PointNormal>::ConstPtr & cloud_source,
|
||||
@@ -114,15 +92,6 @@ Transform RTABMAP_EXP icpPointToPlane(
|
||||
pcl::PointCloud<pcl::PointNormal> & cloud_source_registered,
|
||||
float epsilon = 0.0f,
|
||||
bool icp2D = false);
|
||||
Transform RTABMAP_EXP icpPointToPlane(
|
||||
const pcl::PointCloud<pcl::PointXYZINormal>::ConstPtr & cloud_source,
|
||||
const pcl::PointCloud<pcl::PointXYZINormal>::ConstPtr & cloud_target,
|
||||
double maxCorrespondenceDistance,
|
||||
int maximumIterations,
|
||||
bool & hasConverged,
|
||||
pcl::PointCloud<pcl::PointXYZINormal> & cloud_source_registered,
|
||||
float epsilon = 0.0f,
|
||||
bool icp2D = false);
|
||||
|
||||
} // namespace util3d
|
||||
} // namespace rtabmap
|
||||
|
||||
@@ -39,7 +39,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <rtabmap/core/CameraModel.h>
|
||||
#include <rtabmap/core/ProgressState.h>
|
||||
#include <rtabmap/core/LaserScan.h>
|
||||
#include <rtabmap/core/Version.h>
|
||||
#include <set>
|
||||
#include <list>
|
||||
|
||||
@@ -149,8 +148,7 @@ pcl::TextureMesh::Ptr RTABMAP_EXP createTextureMesh(
|
||||
int minClusterSize = 50, // minimum size of polygons clusters textured
|
||||
const std::vector<float> & roiRatios = std::vector<float>(), // [left, right, top, bottom] region of interest (in ratios) of the image projected.
|
||||
const ProgressState * state = 0,
|
||||
std::vector<std::map<int, pcl::PointXY> > * vertexToPixels = 0, // For each point, we have a list of cameras with corresponding pixel in it. Beware that the camera ids don't correspond to pose ids, they are indexes from 0 to total camera models and texture's materials.
|
||||
bool distanceToCamPolicy = false);
|
||||
std::vector<std::map<int, pcl::PointXY> > * vertexToPixels = 0);
|
||||
pcl::TextureMesh::Ptr RTABMAP_EXP createTextureMesh(
|
||||
const pcl::PolygonMesh::Ptr & mesh,
|
||||
const std::map<int, Transform> & poses,
|
||||
@@ -162,8 +160,7 @@ pcl::TextureMesh::Ptr RTABMAP_EXP createTextureMesh(
|
||||
int minClusterSize = 50, // minimum size of polygons clusters textured
|
||||
const std::vector<float> & roiRatios = std::vector<float>(), // [left, right, top, bottom] region of interest (in ratios) of the image projected.
|
||||
const ProgressState * state = 0,
|
||||
std::vector<std::map<int, pcl::PointXY> > * vertexToPixels = 0, // For each point, we have a list of cameras with corresponding pixel in it. Beware that the camera ids don't correspond to pose ids, they are indexes from 0 to total camera models and texture's materials.
|
||||
bool distanceToCamPolicy = false);
|
||||
std::vector<std::map<int, pcl::PointXY> > * vertexToPixels = 0);
|
||||
|
||||
/**
|
||||
* Remove not textured polygon clusters. If minClusterSize<0, only the largest cluster is kept.
|
||||
@@ -178,18 +175,18 @@ pcl::TextureMesh::Ptr RTABMAP_EXP concatenateTextureMeshes(
|
||||
void RTABMAP_EXP concatenateTextureMaterials(
|
||||
pcl::TextureMesh & mesh, const cv::Size & imageSize, int textureSize, int maxTextures, float & scale, std::vector<bool> * materialsKept=0);
|
||||
|
||||
std::vector<std::vector<RTABMAP_PCL_INDEX> > RTABMAP_EXP convertPolygonsFromPCL(
|
||||
std::vector<std::vector<unsigned int> > RTABMAP_EXP convertPolygonsFromPCL(
|
||||
const std::vector<pcl::Vertices> & polygons);
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > RTABMAP_EXP convertPolygonsFromPCL(
|
||||
std::vector<std::vector<std::vector<unsigned int> > > RTABMAP_EXP convertPolygonsFromPCL(
|
||||
const std::vector<std::vector<pcl::Vertices> > & polygons);
|
||||
std::vector<pcl::Vertices> RTABMAP_EXP convertPolygonsToPCL(
|
||||
const std::vector<std::vector<RTABMAP_PCL_INDEX> > & polygons);
|
||||
const std::vector<std::vector<unsigned int> > & polygons);
|
||||
std::vector<std::vector<pcl::Vertices> > RTABMAP_EXP convertPolygonsToPCL(
|
||||
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & tex_polygons);
|
||||
const std::vector<std::vector<std::vector<unsigned int> > > & tex_polygons);
|
||||
|
||||
pcl::TextureMesh::Ptr RTABMAP_EXP assembleTextureMesh(
|
||||
const cv::Mat & cloudMat,
|
||||
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons,
|
||||
const std::vector<std::vector<std::vector<unsigned int> > > & polygons,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
|
||||
#else
|
||||
@@ -200,7 +197,7 @@ pcl::TextureMesh::Ptr RTABMAP_EXP assembleTextureMesh(
|
||||
|
||||
pcl::PolygonMesh::Ptr RTABMAP_EXP assemblePolygonMesh(
|
||||
const cv::Mat & cloudMat,
|
||||
const std::vector<std::vector<RTABMAP_PCL_INDEX> > & polygons);
|
||||
const std::vector<std::vector<unsigned int> > & polygons);
|
||||
|
||||
/**
|
||||
* Merge all textures in the mesh into "textureCount" textures of size "textureSize".
|
||||
@@ -266,9 +263,8 @@ bool RTABMAP_EXP multiBandTexturing(
|
||||
int textureSize = 8192,
|
||||
const std::string & textureFormat = "jpg", // png, jpg
|
||||
const std::map<int, std::map<int, cv::Vec4d> > & gains = std::map<int, std::map<int, cv::Vec4d> >(), // optional output of util3d::mergeTextures()
|
||||
const std::map<int, std::map<int, cv::Mat> > & blendingGains = std::map<int, std::map<int, cv::Mat> >(), // optional output of util3d::mergeTextures()
|
||||
const std::pair<float, float> & contrastValues = std::pair<float, float>(0,0), // optional output of util3d::mergeTextures()
|
||||
bool gainRGB = true);
|
||||
const std::map<int, std::map<int, cv::Mat> > & blendingGains = std::map<int, std::map<int, cv::Mat> >(), // optional output of util3d::mergeTextures()
|
||||
const std::pair<float, float> & contrastValues = std::pair<float, float>(0,0)); // optional output of util3d::mergeTextures()
|
||||
|
||||
cv::Mat RTABMAP_EXP computeNormals(
|
||||
const cv::Mat & laserScan,
|
||||
@@ -358,12 +354,6 @@ float RTABMAP_EXP computeNormalsComplexity(
|
||||
bool is2d = false,
|
||||
cv::Mat * pcaEigenVectors = 0,
|
||||
cv::Mat * pcaEigenValues = 0);
|
||||
float RTABMAP_EXP computeNormalsComplexity(
|
||||
const pcl::PointCloud<pcl::PointXYZINormal> & cloud,
|
||||
const Transform & t = Transform::getIdentity(),
|
||||
bool is2d = false,
|
||||
cv::Mat * pcaEigenVectors = 0,
|
||||
cv::Mat * pcaEigenValues = 0);
|
||||
float RTABMAP_EXP computeNormalsComplexity(
|
||||
const pcl::PointCloud<pcl::PointXYZRGBNormal> & cloud,
|
||||
const Transform & t = Transform::getIdentity(),
|
||||
@@ -393,39 +383,18 @@ pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr RTABMAP_EXP mls(
|
||||
float dilationVoxelSize = 1.0f, // VOXEL_GRID_DILATION
|
||||
int dilationIterations = 0); // VOXEL_GRID_DILATION
|
||||
|
||||
RTABMAP_DEPRECATED(LaserScan RTABMAP_EXP adjustNormalsToViewPoint(
|
||||
const LaserScan & scan,
|
||||
const Eigen::Vector3f & viewpoint,
|
||||
bool forceGroundNormalsUp), "Use version with groundNormalsUp as float. For forceGroundNormalsUp=true, set groundNormalsUp to 0.8f, otherwise set groundNormalsUp to 0.0f.");
|
||||
LaserScan RTABMAP_EXP adjustNormalsToViewPoint(
|
||||
const LaserScan & scan,
|
||||
const Eigen::Vector3f & viewpoint = Eigen::Vector3f(0,0,0),
|
||||
float groundNormalsUp = 0.0f);
|
||||
RTABMAP_DEPRECATED(void RTABMAP_EXP adjustNormalsToViewPoint(
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
|
||||
const Eigen::Vector3f & viewpoint,
|
||||
bool forceGroundNormalsUp), "Use version with groundNormalsUp as float. For forceGroundNormalsUp=true, set groundNormalsUp to 0.8f, otherwise set groundNormalsUp to 0.0f.");
|
||||
bool forceGroundNormalsUp);
|
||||
void RTABMAP_EXP adjustNormalsToViewPoint(
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr & cloud,
|
||||
const Eigen::Vector3f & viewpoint = Eigen::Vector3f(0,0,0),
|
||||
float groundNormalsUp = 0.0f);
|
||||
RTABMAP_DEPRECATED(void RTABMAP_EXP adjustNormalsToViewPoint(
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
|
||||
const Eigen::Vector3f & viewpoint,
|
||||
bool forceGroundNormalsUp), "Use version with groundNormalsUp as float. For forceGroundNormalsUp=true, set groundNormalsUp to 0.8f, otherwise set groundNormalsUp to 0.0f.");
|
||||
bool forceGroundNormalsUp = false);
|
||||
void RTABMAP_EXP adjustNormalsToViewPoint(
|
||||
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
|
||||
const Eigen::Vector3f & viewpoint = Eigen::Vector3f(0,0,0),
|
||||
float groundNormalsUp = 0.0f);
|
||||
RTABMAP_DEPRECATED(void RTABMAP_EXP adjustNormalsToViewPoint(
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
|
||||
const Eigen::Vector3f & viewpoint,
|
||||
bool forceGroundNormalsUp), "Use version with groundNormalsUp as float. For forceGroundNormalsUp=true, set groundNormalsUp to 0.8f, otherwise set groundNormalsUp to 0.0f.");
|
||||
void RTABMAP_EXP adjustNormalsToViewPoint(
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr & cloud,
|
||||
const Eigen::Vector3f & viewpoint = Eigen::Vector3f(0,0,0),
|
||||
float groundNormalsUp = 0.0f);
|
||||
|
||||
bool forceGroundNormalsUp = false);
|
||||
void RTABMAP_EXP adjustNormalsToViewPoints(
|
||||
const std::map<int, Transform> & poses,
|
||||
const pcl::PointCloud<pcl::PointXYZ>::Ptr & rawCloud,
|
||||
|
||||
@@ -417,20 +417,6 @@ cv::Mat BayesFilter::generatePrediction(const Memory * memory, const std::vector
|
||||
return prediction;
|
||||
}
|
||||
|
||||
unsigned long BayesFilter::getMemoryUsed() const
|
||||
{
|
||||
long memoryUsage = sizeof(BayesFilter);
|
||||
memoryUsage += _posterior.size() * (sizeof(float)+sizeof(int)+sizeof(std::map<int, float>::iterator)) + sizeof(std::map<int, float>);
|
||||
memoryUsage += _prediction.total() * _prediction.elemSize();
|
||||
memoryUsage += _predictionLC.size() * sizeof(double);
|
||||
memoryUsage += _neighborsIndex.size() * (sizeof(int)+sizeof(std::map<int, int>)+sizeof(std::map<int, std::map<int, int> >::iterator)) + sizeof(std::map<int, std::map<int, int> >);
|
||||
for(std::map<int, std::map<int, int> >::const_iterator iter=_neighborsIndex.begin(); iter!=_neighborsIndex.end(); ++iter)
|
||||
{
|
||||
memoryUsage += iter->second.size() * (sizeof(int)*2+sizeof(std::map<int, int>::iterator)) + sizeof(std::map<int, int>);
|
||||
}
|
||||
return memoryUsage;
|
||||
}
|
||||
|
||||
void BayesFilter::normalize(cv::Mat & prediction, unsigned int index, float addedProbabilitiesSum, bool virtualPlaceUsed) const
|
||||
{
|
||||
UASSERT(index < (unsigned int)prediction.rows && index < (unsigned int)prediction.cols);
|
||||
|
||||
+10
-16
@@ -592,24 +592,18 @@ ENDIF(WITH_MADGWICK)
|
||||
####################################
|
||||
CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/resources/DatabaseSchema.sql.in ${CMAKE_CURRENT_SOURCE_DIR}/resources/DatabaseSchema.sql)
|
||||
|
||||
SET(RESOURCES
|
||||
SET(R
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources/DatabaseSchema.sql
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources/backward_compatibility/DatabaseSchema_0_18_3.sql
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources/backward_compatibility/DatabaseSchema_0_18_0.sql
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources/backward_compatibility/DatabaseSchema_0_17_0.sql
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources/backward_compatibility/DatabaseSchema_0_16_2.sql
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources/backward_compatibility/DatabaseSchema_0_16_1.sql
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/resources/backward_compatibility/DatabaseSchema_0_16_0.sql
|
||||
)
|
||||
|
||||
foreach(arg ${RESOURCES})
|
||||
get_filename_component(filename ${arg} NAME)
|
||||
string(REPLACE "." "_" output ${filename})
|
||||
set(RESOURCES_HEADERS "${RESOURCES_HEADERS}" "${CMAKE_CURRENT_BINARY_DIR}/${output}.h")
|
||||
endforeach(arg ${RESOURCES})
|
||||
#replace semicolons by spaces
|
||||
foreach(arg ${R})
|
||||
set(RESOURCES "${RESOURCES}" "${arg}")
|
||||
endforeach(arg ${R})
|
||||
|
||||
MESSAGE(STATUS "RESOURCES = ${RESOURCES}")
|
||||
MESSAGE(STATUS "RESOURCES_HEADERS = ${RESOURCES_HEADERS}")
|
||||
SET(RESOURCES_HEADERS
|
||||
${CMAKE_CURRENT_BINARY_DIR}/DatabaseSchema_sql.h
|
||||
)
|
||||
|
||||
IF(ANDROID)
|
||||
|
||||
@@ -624,14 +618,14 @@ IF(ANDROID)
|
||||
OUTPUT ${RESOURCES_HEADERS}
|
||||
COMMAND ${RTABMAP_RES_TOOL} -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${RESOURCES}
|
||||
COMMENT "[Creating resources]"
|
||||
DEPENDS ${RESOURCES}
|
||||
DEPENDS ${R}
|
||||
)
|
||||
ELSE()
|
||||
ADD_CUSTOM_COMMAND(
|
||||
OUTPUT ${RESOURCES_HEADERS}
|
||||
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/rtabmap-res_tool -n rtabmap -p ${CMAKE_CURRENT_BINARY_DIR} ${RESOURCES}
|
||||
COMMENT "[Creating resources]"
|
||||
DEPENDS ${RESOURCES} res_tool
|
||||
DEPENDS ${R} res_tool
|
||||
)
|
||||
ENDIF()
|
||||
|
||||
|
||||
@@ -765,16 +765,4 @@ bool CameraModel::inFrame(int u, int v) const
|
||||
return uIsInBounds(u, 0, imageWidth()) && uIsInBounds(v, 0, imageHeight());
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const CameraModel& model)
|
||||
{
|
||||
os << "Name: " << model.name() << std::endl
|
||||
<< "Size: " << model.imageWidth() << "x" << model.imageHeight() << std::endl
|
||||
<< "K= " << model.K_raw() << std::endl
|
||||
<< "D= " << model.D_raw() << std::endl
|
||||
<< "R= " << model.R() << std::endl
|
||||
<< "P= " << model.P() << std::endl
|
||||
<< "LocalTransform= " << model.localTransform();
|
||||
return os;
|
||||
}
|
||||
|
||||
} /* namespace rtabmap */
|
||||
|
||||
@@ -129,39 +129,6 @@ void CameraThread::disableIMUFiltering()
|
||||
_imuFilter = 0;
|
||||
}
|
||||
|
||||
void CameraThread::setScanParameters(
|
||||
bool fromDepth,
|
||||
int downsampleStep,
|
||||
float rangeMin,
|
||||
float rangeMax,
|
||||
float voxelSize,
|
||||
int normalsK,
|
||||
int normalsRadius,
|
||||
bool forceGroundNormalsUp)
|
||||
{
|
||||
setScanParameters(fromDepth, downsampleStep, rangeMin, rangeMax, voxelSize, normalsK, normalsRadius, forceGroundNormalsUp?0.8f:0.0f);
|
||||
}
|
||||
|
||||
void CameraThread::setScanParameters(
|
||||
bool fromDepth,
|
||||
int downsampleStep, // decimation of the depth image in case the scan is from depth image
|
||||
float rangeMin,
|
||||
float rangeMax,
|
||||
float voxelSize,
|
||||
int normalsK,
|
||||
int normalsRadius,
|
||||
float groundNormalsUp)
|
||||
{
|
||||
_scanFromDepth = fromDepth;
|
||||
_scanDownsampleStep=downsampleStep;
|
||||
_scanRangeMin = rangeMin;
|
||||
_scanRangeMax = rangeMax;
|
||||
_scanVoxelSize = voxelSize;
|
||||
_scanNormalsK = normalsK;
|
||||
_scanNormalsRadius = normalsRadius;
|
||||
_scanForceGroundNormalsUp = groundNormalsUp;
|
||||
}
|
||||
|
||||
void CameraThread::mainLoopBegin()
|
||||
{
|
||||
ULogger::registerCurrentThread("Camera");
|
||||
@@ -270,26 +237,7 @@ void CameraThread::postUpdate(SensorData * dataPtr, CameraInfo * info) const
|
||||
else
|
||||
{
|
||||
cv::Mat image = util2d::decimate(data.imageRaw(), _imageDecimation);
|
||||
|
||||
int depthDecimation = _imageDecimation;
|
||||
if(data.depthOrRightRaw().rows <= image.rows || data.depthOrRightRaw().cols <= image.cols)
|
||||
{
|
||||
depthDecimation = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
depthDecimation = 2;
|
||||
while(data.depthOrRightRaw().rows / depthDecimation > image.rows ||
|
||||
data.depthOrRightRaw().cols / depthDecimation > image.cols ||
|
||||
data.depthOrRightRaw().rows % depthDecimation != 0 ||
|
||||
data.depthOrRightRaw().cols % depthDecimation != 0)
|
||||
{
|
||||
++depthDecimation;
|
||||
}
|
||||
UDEBUG("depthDecimation=%d", depthDecimation);
|
||||
}
|
||||
cv::Mat depthOrRight = util2d::decimate(data.depthOrRightRaw(), depthDecimation);
|
||||
|
||||
cv::Mat depthOrRight = util2d::decimate(data.depthOrRightRaw(), _imageDecimation);
|
||||
std::vector<CameraModel> models = data.cameraModels();
|
||||
for(unsigned int i=0; i<models.size(); ++i)
|
||||
{
|
||||
|
||||
@@ -40,6 +40,7 @@ namespace rtabmap {
|
||||
|
||||
DBDriver * DBDriver::create(const ParametersMap & parameters)
|
||||
{
|
||||
// well, we only have Sqlite3 database type for now :P
|
||||
return new DBDriverSqlite3(parameters);
|
||||
}
|
||||
|
||||
@@ -58,7 +59,6 @@ DBDriver::~DBDriver()
|
||||
|
||||
void DBDriver::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
Parameters::parse(parameters, Parameters::kDbTargetVersion(), _targetVersion);
|
||||
}
|
||||
|
||||
void DBDriver::closeConnection(bool save, const std::string & outputUrl)
|
||||
@@ -107,9 +107,9 @@ bool DBDriver::isConnected() const
|
||||
}
|
||||
|
||||
// In bytes
|
||||
unsigned long DBDriver::getMemoryUsed() const
|
||||
long DBDriver::getMemoryUsed() const
|
||||
{
|
||||
unsigned long bytes;
|
||||
long bytes;
|
||||
_dbSafeAccessMutex.lock();
|
||||
bytes = getMemoryUsedQuery();
|
||||
_dbSafeAccessMutex.unlock();
|
||||
@@ -1209,7 +1209,7 @@ cv::Mat DBDriver::load2DMap(float & xMin, float & yMin, float & cellSize) const
|
||||
|
||||
void DBDriver::saveOptimizedMesh(
|
||||
const cv::Mat & cloud,
|
||||
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons,
|
||||
const std::vector<std::vector<std::vector<unsigned int> > > & polygons,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
|
||||
#else
|
||||
@@ -1223,7 +1223,7 @@ void DBDriver::saveOptimizedMesh(
|
||||
}
|
||||
|
||||
cv::Mat DBDriver::loadOptimizedMesh(
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > * polygons,
|
||||
std::vector<std::vector<std::vector<unsigned int> > > * polygons,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,
|
||||
#else
|
||||
|
||||
@@ -34,14 +34,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include "rtabmap/core/util3d.h"
|
||||
#include "rtabmap/core/Compression.h"
|
||||
#include "DatabaseSchema_sql.h"
|
||||
#include "DatabaseSchema_0_18_3_sql.h"
|
||||
#include "DatabaseSchema_0_18_0_sql.h"
|
||||
#include "DatabaseSchema_0_17_0_sql.h"
|
||||
#include "DatabaseSchema_0_16_2_sql.h"
|
||||
#include "DatabaseSchema_0_16_1_sql.h"
|
||||
#include "DatabaseSchema_0_16_0_sql.h"
|
||||
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "rtabmap/utilite/UtiLite.h"
|
||||
@@ -391,34 +383,6 @@ bool DBDriverSqlite3::connectDatabaseQuery(const std::string & url, bool overwri
|
||||
}
|
||||
// Create the database
|
||||
std::string schema = DATABASESCHEMA_SQL;
|
||||
std::string targetVersion = this->getTargetVersion();
|
||||
if(!targetVersion.empty())
|
||||
{
|
||||
// search for schema with version <= target version
|
||||
std::vector<std::pair<std::string, std::string> > schemas;
|
||||
schemas.push_back(std::make_pair("0.16.0", DATABASESCHEMA_0_16_0_SQL));
|
||||
schemas.push_back(std::make_pair("0.16.1", DATABASESCHEMA_0_16_1_SQL));
|
||||
schemas.push_back(std::make_pair("0.16.2", DATABASESCHEMA_0_16_2_SQL));
|
||||
schemas.push_back(std::make_pair("0.17.0", DATABASESCHEMA_0_17_0_SQL));
|
||||
schemas.push_back(std::make_pair("0.18.0", DATABASESCHEMA_0_18_0_SQL));
|
||||
schemas.push_back(std::make_pair("0.18.3", DATABASESCHEMA_0_18_3_SQL));
|
||||
schemas.push_back(std::make_pair(uNumber2Str(RTABMAP_VERSION_MAJOR)+"."+uNumber2Str(RTABMAP_VERSION_MINOR), DATABASESCHEMA_SQL));
|
||||
for(size_t i=0; i<schemas.size(); ++i)
|
||||
{
|
||||
if(uStrNumCmp(targetVersion, schemas[i].first) < 0)
|
||||
{
|
||||
if(i==0)
|
||||
{
|
||||
UERROR("Cannot create database with target version \"%s\" (not implemented), using latest version.", targetVersion.c_str());
|
||||
}
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
schema = schemas[i].second;
|
||||
}
|
||||
}
|
||||
}
|
||||
schema = uHex2Str(schema);
|
||||
this->executeNoResultQuery(schema.c_str());
|
||||
}
|
||||
@@ -522,7 +486,7 @@ void DBDriverSqlite3::executeNoResultQuery(const std::string & sql) const
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long DBDriverSqlite3::getMemoryUsedQuery() const
|
||||
long DBDriverSqlite3::getMemoryUsedQuery() const
|
||||
{
|
||||
if(_dbInMemory)
|
||||
{
|
||||
@@ -2413,7 +2377,6 @@ void DBDriverSqlite3::getAllNodeIdsQuery(std::set<int> & ids, bool ignoreChildre
|
||||
query << "INNER JOIN Link ";
|
||||
query << "ON id = to_id "; // use to_id to ignore all children (which don't have link pointing on them)
|
||||
query << "WHERE from_id != to_id "; // ignore self referring links
|
||||
query << "AND weight>-9 "; //ignore invalid nodes
|
||||
}
|
||||
|
||||
if(ignoreBadSignatures)
|
||||
@@ -3115,10 +3078,9 @@ void DBDriverSqlite3::loadSignaturesQuery(const std::list<int> & ids, std::list<
|
||||
const void * descriptor = 0;
|
||||
int dRealSize = 0;
|
||||
cv::KeyPoint kpt;
|
||||
std::multimap<int, int> visualWords;
|
||||
std::vector<cv::KeyPoint> visualWordsKpts;
|
||||
std::vector<cv::Point3f> visualWords3;
|
||||
cv::Mat descriptors;
|
||||
std::multimap<int, cv::KeyPoint> visualWords;
|
||||
std::multimap<int, cv::Point3f> visualWords3;
|
||||
std::multimap<int, cv::Mat> descriptors;
|
||||
bool allWords3NaN = true;
|
||||
cv::Point3f depth(0,0,0);
|
||||
|
||||
@@ -3168,9 +3130,8 @@ void DBDriverSqlite3::loadSignaturesQuery(const std::list<int> & ids, std::list<
|
||||
depth.z = sqlite3_column_double(ppStmt, index++);
|
||||
}
|
||||
|
||||
visualWordsKpts.push_back(kpt);
|
||||
visualWords.insert(visualWords.end(), std::make_pair(visualWordId, visualWordsKpts.size()-1));
|
||||
visualWords3.push_back(depth);
|
||||
visualWords.insert(visualWords.end(), std::make_pair(visualWordId, kpt));
|
||||
visualWords3.insert(visualWords3.end(), std::make_pair(visualWordId, depth));
|
||||
|
||||
if(allWords3NaN && util3d::isFinite(depth))
|
||||
{
|
||||
@@ -3203,7 +3164,7 @@ void DBDriverSqlite3::loadSignaturesQuery(const std::list<int> & ids, std::list<
|
||||
|
||||
memcpy(d.data, descriptor, dRealSize);
|
||||
|
||||
descriptors.push_back(d);
|
||||
descriptors.insert(descriptors.end(), std::make_pair(visualWordId, d));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3217,12 +3178,13 @@ void DBDriverSqlite3::loadSignaturesQuery(const std::list<int> & ids, std::list<
|
||||
}
|
||||
else
|
||||
{
|
||||
if(allWords3NaN)
|
||||
(*iter)->setWords(visualWords);
|
||||
if(!allWords3NaN)
|
||||
{
|
||||
visualWords3.clear();
|
||||
(*iter)->setWords3(visualWords3);
|
||||
}
|
||||
(*iter)->setWords(visualWords, visualWordsKpts, visualWords3, descriptors);
|
||||
ULOGGER_DEBUG("Add %d keypoints, %d 3d points and %d descriptors to node %d", (int)visualWords.size(), allWords3NaN?0:(int)visualWords3.size(), (int)descriptors.rows, (*iter)->id());
|
||||
(*iter)->setWordsDescriptors(descriptors);
|
||||
ULOGGER_DEBUG("Add %d keypoints, %d 3d points and %d descriptors to node %d", (int)visualWords.size(), allWords3NaN?0:(int)visualWords3.size(), (int)descriptors.size(), (*iter)->id());
|
||||
}
|
||||
|
||||
//reset
|
||||
@@ -3660,7 +3622,6 @@ void DBDriverSqlite3::loadWordsQuery(const std::set<int> & wordIds, std::list<Vi
|
||||
int descriptorSize;
|
||||
const void * descriptor;
|
||||
int dRealSize;
|
||||
unsigned long dRealSizeTotal = 0;
|
||||
for(std::set<int>::const_iterator iter=wordIds.begin(); iter!=wordIds.end(); ++iter)
|
||||
{
|
||||
// bind id
|
||||
@@ -3693,7 +3654,6 @@ void DBDriverSqlite3::loadWordsQuery(const std::set<int> & wordIds, std::list<Vi
|
||||
}
|
||||
|
||||
memcpy(d.data, descriptor, dRealSize);
|
||||
dRealSizeTotal+=dRealSize;
|
||||
VisualWord * vw = new VisualWord(*iter, d);
|
||||
if(vw)
|
||||
{
|
||||
@@ -3715,7 +3675,7 @@ void DBDriverSqlite3::loadWordsQuery(const std::set<int> & wordIds, std::list<Vi
|
||||
rc = sqlite3_finalize(ppStmt);
|
||||
UASSERT_MSG(rc == SQLITE_OK, uFormat("DB error (%s): %s", _version.c_str(), sqlite3_errmsg(_ppDb)).c_str());
|
||||
|
||||
UDEBUG("Time=%fs (%d words, %lu MB)", timer.ticks(), (int)vws.size(), dRealSizeTotal/1000000);
|
||||
ULOGGER_DEBUG("Time=%fs", timer.ticks());
|
||||
|
||||
if(wordIds.size() != loaded.size())
|
||||
{
|
||||
@@ -4312,25 +4272,30 @@ void DBDriverSqlite3::saveQuery(const std::list<Signature *> & signatures)
|
||||
float nanFloat = std::numeric_limits<float>::quiet_NaN ();
|
||||
for(std::list<Signature *>::const_iterator i=signatures.begin(); i!=signatures.end(); ++i)
|
||||
{
|
||||
UASSERT((*i)->getWords().size() == (*i)->getWordsKpts().size());
|
||||
UASSERT((*i)->getWords3().empty() || (*i)->getWords().size() == (*i)->getWords3().size());
|
||||
UASSERT((*i)->getWordsDescriptors().empty() || (int)(*i)->getWords().size() == (*i)->getWordsDescriptors().rows);
|
||||
UASSERT((*i)->getWordsDescriptors().empty() || (*i)->getWords().size() == (*i)->getWordsDescriptors().size());
|
||||
|
||||
for(std::multimap<int, int>::const_iterator w=(*i)->getWords().begin(); w!=(*i)->getWords().end(); ++w)
|
||||
std::multimap<int, cv::Point3f>::const_iterator p=(*i)->getWords3().begin();
|
||||
std::multimap<int, cv::Mat>::const_iterator d=(*i)->getWordsDescriptors().begin();
|
||||
for(std::multimap<int, cv::KeyPoint>::const_iterator w=(*i)->getWords().begin(); w!=(*i)->getWords().end(); ++w)
|
||||
{
|
||||
cv::Point3f pt(nanFloat,nanFloat,nanFloat);
|
||||
if(!(*i)->getWords3().empty())
|
||||
if(p!=(*i)->getWords3().end())
|
||||
{
|
||||
pt = (*i)->getWords3()[w->second];
|
||||
UASSERT(w->first == p->first); // must be same id!
|
||||
pt = p->second;
|
||||
++p;
|
||||
}
|
||||
|
||||
cv::Mat descriptor;
|
||||
if(!(*i)->getWordsDescriptors().empty())
|
||||
if(d!=(*i)->getWordsDescriptors().end())
|
||||
{
|
||||
descriptor = (*i)->getWordsDescriptors().row(w->second);
|
||||
UASSERT(w->first == d->first); // must be same id!
|
||||
descriptor = d->second;
|
||||
++d;
|
||||
}
|
||||
|
||||
stepKeypoint(ppStmt, (*i)->id(), w->first, (*i)->getWordsKpts()[w->second], pt, descriptor);
|
||||
stepKeypoint(ppStmt, (*i)->id(), w->first, w->second, pt, descriptor);
|
||||
}
|
||||
}
|
||||
// Finalize (delete) the statement
|
||||
@@ -5093,7 +5058,7 @@ cv::Mat DBDriverSqlite3::load2DMapQuery(float & xMin, float & yMin, float & cell
|
||||
|
||||
void DBDriverSqlite3::saveOptimizedMeshQuery(
|
||||
const cv::Mat & cloud,
|
||||
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons,
|
||||
const std::vector<std::vector<std::vector<unsigned int> > > & polygons,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
|
||||
#else
|
||||
@@ -5288,7 +5253,7 @@ void DBDriverSqlite3::saveOptimizedMeshQuery(
|
||||
}
|
||||
|
||||
cv::Mat DBDriverSqlite3::loadOptimizedMeshQuery(
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > * polygons,
|
||||
std::vector<std::vector<std::vector<unsigned int> > > * polygons,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,
|
||||
#else
|
||||
@@ -5350,7 +5315,7 @@ cv::Mat DBDriverSqlite3::loadOptimizedMeshQuery(
|
||||
for(int t=0; t<serializedPolygons.cols; ++t)
|
||||
{
|
||||
UASSERT(serializedPolygons.at<int>(t) > 0);
|
||||
std::vector<std::vector<RTABMAP_PCL_INDEX> > materialPolygons(serializedPolygons.at<int>(t), std::vector<RTABMAP_PCL_INDEX>(polygonSize));
|
||||
std::vector<std::vector<unsigned int> > materialPolygons(serializedPolygons.at<int>(t), std::vector<unsigned int>(polygonSize));
|
||||
++t;
|
||||
UASSERT(t < serializedPolygons.cols);
|
||||
UDEBUG("materialPolygons=%d", (int)materialPolygons.size());
|
||||
|
||||
+25
-11
@@ -47,16 +47,16 @@ DBReader::DBReader(const std::string & databasePath,
|
||||
bool odometryIgnored,
|
||||
bool ignoreGoalDelay,
|
||||
bool goalsIgnored,
|
||||
int startId,
|
||||
int stopId,
|
||||
int cameraIndex,
|
||||
int stopId) :
|
||||
int endId) :
|
||||
Camera(frameRate),
|
||||
_paths(uSplit(databasePath, ';')),
|
||||
_odometryIgnored(odometryIgnored),
|
||||
_ignoreGoalDelay(ignoreGoalDelay),
|
||||
_goalsIgnored(goalsIgnored),
|
||||
_startId(startId),
|
||||
_stopId(stopId),
|
||||
_startId(stopId),
|
||||
_stopId(endId),
|
||||
_cameraIndex(cameraIndex),
|
||||
_dbDriver(0),
|
||||
_currentId(_ids.end()),
|
||||
@@ -76,16 +76,16 @@ DBReader::DBReader(const std::list<std::string> & databasePaths,
|
||||
bool odometryIgnored,
|
||||
bool ignoreGoalDelay,
|
||||
bool goalsIgnored,
|
||||
int startId,
|
||||
int stopId,
|
||||
int cameraIndex,
|
||||
int stopId) :
|
||||
int endId) :
|
||||
Camera(frameRate),
|
||||
_paths(databasePaths),
|
||||
_odometryIgnored(odometryIgnored),
|
||||
_ignoreGoalDelay(ignoreGoalDelay),
|
||||
_goalsIgnored(goalsIgnored),
|
||||
_startId(startId),
|
||||
_stopId(stopId),
|
||||
_startId(stopId),
|
||||
_stopId(endId),
|
||||
_cameraIndex(cameraIndex),
|
||||
_dbDriver(0),
|
||||
_currentId(_ids.end()),
|
||||
@@ -510,9 +510,23 @@ SensorData DBReader::getNextData(CameraInfo * info)
|
||||
data.gps().stamp()!=0.0?1:0,
|
||||
gravityTransform.isNull()?0:1);
|
||||
|
||||
cv::Mat descriptors = s->getWordsDescriptors().clone();
|
||||
const std::vector<cv::KeyPoint> & keypoints = s->getWordsKpts();
|
||||
const std::vector<cv::Point3f> & keypoints3D = s->getWords3();
|
||||
cv::Mat descriptors;
|
||||
if(!s->getWordsDescriptors().empty())
|
||||
{
|
||||
descriptors = cv::Mat(
|
||||
s->getWordsDescriptors().size(),
|
||||
s->getWordsDescriptors().begin()->second.cols,
|
||||
s->getWordsDescriptors().begin()->second.type());
|
||||
int i=0;
|
||||
for(std::multimap<int, cv::Mat>::const_iterator iter=s->getWordsDescriptors().begin();
|
||||
iter!=s->getWordsDescriptors().end();
|
||||
++iter, ++i)
|
||||
{
|
||||
iter->second.copyTo(descriptors.row(i));
|
||||
}
|
||||
}
|
||||
std::vector<cv::KeyPoint> keypoints = uValues(s->getWords());
|
||||
std::vector<cv::Point3f> keypoints3D = uValues(s->getWords3());
|
||||
if(!keypoints.empty() &&
|
||||
(keypoints3D.empty() || keypoints.size() == keypoints3D.size()) &&
|
||||
(descriptors.empty() || (int)keypoints.size() == descriptors.rows))
|
||||
|
||||
@@ -70,21 +70,15 @@ bool EpipolarGeometry::check(const Signature * ssA, const Signature * ssB)
|
||||
}
|
||||
ULOGGER_DEBUG("id(%d,%d)", ssA->id(), ssB->id());
|
||||
|
||||
std::list<std::pair<int, std::pair<int, int> > > pairsId;
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > pairs;
|
||||
|
||||
findPairsUnique(ssA->getWords(), ssB->getWords(), pairsId);
|
||||
findPairsUnique(ssA->getWords(), ssB->getWords(), pairs);
|
||||
|
||||
if((int)pairsId.size()<_matchCountMinAccepted)
|
||||
if((int)pairs.size()<_matchCountMinAccepted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > pairs;
|
||||
for(std::list<std::pair<int, std::pair<int, int> > >::iterator iter = pairsId.begin(); iter!=pairsId.end(); ++iter)
|
||||
{
|
||||
pairs.push_back(std::make_pair(iter->first, std::make_pair(ssA->getWordsKpts()[iter->second.first], ssB->getWordsKpts()[iter->second.second])));
|
||||
}
|
||||
|
||||
std::vector<uchar> status;
|
||||
cv::Mat f = findFFromWords(pairs, status, _ransacParam1, _ransacParam2);
|
||||
|
||||
@@ -412,6 +406,136 @@ cv::Mat EpipolarGeometry::findFFromCalibratedStereoCameras(double fx, double fy,
|
||||
return K.inv().t()*E*K.inv();
|
||||
}
|
||||
|
||||
/**
|
||||
* if a=[1 2 3 4 6], b=[1 2 4 5 6], results= [(1,1) (2,2) (4,4) (6,6)]
|
||||
* realPairsCount = 4
|
||||
*/
|
||||
int EpipolarGeometry::findPairs(
|
||||
const std::map<int, cv::KeyPoint> & wordsA,
|
||||
const std::map<int, cv::KeyPoint> & wordsB,
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs,
|
||||
bool ignoreInvalidIds)
|
||||
{
|
||||
int realPairsCount = 0;
|
||||
pairs.clear();
|
||||
for(std::map<int, cv::KeyPoint>::const_iterator i=wordsA.begin(); i!=wordsA.end(); ++i)
|
||||
{
|
||||
if(!ignoreInvalidIds || (ignoreInvalidIds && i->first>=0))
|
||||
{
|
||||
std::map<int, cv::KeyPoint>::const_iterator ptB = wordsB.find(i->first);
|
||||
if(ptB != wordsB.end())
|
||||
{
|
||||
pairs.push_back(std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> >(i->first, std::pair<cv::KeyPoint, cv::KeyPoint>(i->second, ptB->second)));
|
||||
++realPairsCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
return realPairsCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(1,1a) (2,2) (4,4) (6a,6a) (6b,6b)]
|
||||
* realPairsCount = 5
|
||||
*/
|
||||
int EpipolarGeometry::findPairs(const std::multimap<int, cv::KeyPoint> & wordsA,
|
||||
const std::multimap<int, cv::KeyPoint> & wordsB,
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs,
|
||||
bool ignoreInvalidIds)
|
||||
{
|
||||
const std::list<int> & ids = uUniqueKeys(wordsA);
|
||||
std::multimap<int, cv::KeyPoint>::const_iterator iterA;
|
||||
std::multimap<int, cv::KeyPoint>::const_iterator iterB;
|
||||
pairs.clear();
|
||||
int realPairsCount = 0;
|
||||
for(std::list<int>::const_iterator i=ids.begin(); i!=ids.end(); ++i)
|
||||
{
|
||||
if(!ignoreInvalidIds || (ignoreInvalidIds && *i >= 0))
|
||||
{
|
||||
iterA = wordsA.find(*i);
|
||||
iterB = wordsB.find(*i);
|
||||
while(iterA != wordsA.end() && iterB != wordsB.end() && (*iterA).first == (*iterB).first && (*iterA).first == *i)
|
||||
{
|
||||
pairs.push_back(std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> >(*i, std::pair<cv::KeyPoint, cv::KeyPoint>((*iterA).second, (*iterB).second)));
|
||||
++iterA;
|
||||
++iterB;
|
||||
++realPairsCount;
|
||||
}
|
||||
}
|
||||
}
|
||||
return realPairsCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(2,2) (4,4)]
|
||||
* realPairsCount = 5
|
||||
*/
|
||||
int EpipolarGeometry::findPairsUnique(
|
||||
const std::multimap<int, cv::KeyPoint> & wordsA,
|
||||
const std::multimap<int, cv::KeyPoint> & wordsB,
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs,
|
||||
bool ignoreInvalidIds)
|
||||
{
|
||||
const std::list<int> & ids = uUniqueKeys(wordsA);
|
||||
int realPairsCount = 0;
|
||||
pairs.clear();
|
||||
for(std::list<int>::const_iterator i=ids.begin(); i!=ids.end(); ++i)
|
||||
{
|
||||
if(!ignoreInvalidIds || (ignoreInvalidIds && *i>=0))
|
||||
{
|
||||
std::list<cv::KeyPoint> ptsA = uValues(wordsA, *i);
|
||||
std::list<cv::KeyPoint> ptsB = uValues(wordsB, *i);
|
||||
if(ptsA.size() == 1 && ptsB.size() == 1)
|
||||
{
|
||||
pairs.push_back(std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> >(*i, std::pair<cv::KeyPoint, cv::KeyPoint>(ptsA.front(), ptsB.front())));
|
||||
++realPairsCount;
|
||||
}
|
||||
else if(ptsA.size()>1 && ptsB.size()>1)
|
||||
{
|
||||
// just update the count
|
||||
realPairsCount += ptsA.size() > ptsB.size() ? ptsB.size() : ptsA.size();
|
||||
}
|
||||
}
|
||||
}
|
||||
return realPairsCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(1,1a) (1,1b) (2,2) (4,4) (6a,6a) (6a,6b) (6b,6a) (6b,6b)]
|
||||
* realPairsCount = 5
|
||||
*/
|
||||
int EpipolarGeometry::findPairsAll(const std::multimap<int, cv::KeyPoint> & wordsA,
|
||||
const std::multimap<int, cv::KeyPoint> & wordsB,
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs,
|
||||
bool ignoreInvalidIds)
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
const std::list<int> & ids = uUniqueKeys(wordsA);
|
||||
pairs.clear();
|
||||
int realPairsCount = 0;;
|
||||
for(std::list<int>::const_iterator iter=ids.begin(); iter!=ids.end(); ++iter)
|
||||
{
|
||||
if(!ignoreInvalidIds || (ignoreInvalidIds && *iter>=0))
|
||||
{
|
||||
std::list<cv::KeyPoint> ptsA = uValues(wordsA, *iter);
|
||||
std::list<cv::KeyPoint> ptsB = uValues(wordsB, *iter);
|
||||
|
||||
realPairsCount += ptsA.size() > ptsB.size() ? ptsB.size() : ptsA.size();
|
||||
|
||||
for(std::list<cv::KeyPoint>::iterator jter=ptsA.begin(); jter!=ptsA.end(); ++jter)
|
||||
{
|
||||
for(std::list<cv::KeyPoint>::iterator kter=ptsB.begin(); kter!=ptsB.end(); ++kter)
|
||||
{
|
||||
pairs.push_back(std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> >(*iter, std::pair<cv::KeyPoint, cv::KeyPoint>(*jter, *kter)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
ULOGGER_DEBUG("time = %f", timer.ticks());
|
||||
return realPairsCount;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
source = SfM toy library: https://github.com/royshil/SfM-Toy-Library
|
||||
|
||||
+33
-212
@@ -509,69 +509,54 @@ Feature2D * Feature2D::create(const ParametersMap & parameters)
|
||||
Feature2D * Feature2D::create(Feature2D::Type type, const ParametersMap & parameters)
|
||||
{
|
||||
|
||||
// NONFREE checks
|
||||
#if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION <= 3) || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION < 4 || (CV_MINOR_VERSION==4 && CV_SUBMINOR_VERSION<11)))
|
||||
|
||||
#ifndef RTABMAP_NONFREE
|
||||
if(type == Feature2D::kFeatureSurf || type == Feature2D::kFeatureSift || type == Feature2D::kFeatureSurfFreak || type == Feature2D::kFeatureSurfDaisy)
|
||||
#ifndef RTABMAP_NONFREE
|
||||
if(type == Feature2D::kFeatureSurf || type == Feature2D::kFeatureSift)
|
||||
{
|
||||
#if CV_MAJOR_VERSION < 3
|
||||
#if CV_MAJOR_VERSION < 3
|
||||
UWARN("SURF and SIFT features cannot be used because OpenCV was not built with nonfree module. GFTT/ORB is used instead.");
|
||||
#else
|
||||
#else
|
||||
UWARN("SURF and SIFT features cannot be used because OpenCV was not built with xfeatures2d module. GFTT/ORB is used instead.");
|
||||
#endif
|
||||
#endif
|
||||
type = Feature2D::kFeatureGfttOrb;
|
||||
}
|
||||
#endif
|
||||
#if CV_MAJOR_VERSION == 3
|
||||
if(type == Feature2D::kFeatureFastBrief ||
|
||||
type == Feature2D::kFeatureFastFreak ||
|
||||
type == Feature2D::kFeatureGfttBrief ||
|
||||
type == Feature2D::kFeatureGfttFreak)
|
||||
{
|
||||
UWARN("BRIEF and FREAK features cannot be used because OpenCV was not built with xfeatures2d module. GFTT/ORB is used instead.");
|
||||
type = Feature2D::kFeatureGfttOrb;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#else // >= 4.4.0 >= 3.4.11
|
||||
|
||||
#ifndef RTABMAP_NONFREE
|
||||
#ifndef RTABMAP_NONFREE
|
||||
if(type == Feature2D::kFeatureSurf)
|
||||
{
|
||||
UWARN("SURF features cannot be used because OpenCV was not built with nonfree module. SIFT is used instead.");
|
||||
type = Feature2D::kFeatureSift;
|
||||
}
|
||||
else if(type == Feature2D::kFeatureSurfFreak || type == Feature2D::kFeatureSurfDaisy)
|
||||
{
|
||||
UWARN("SURF detector cannot be used because OpenCV was not built with nonfree module. GFTT/ORB is used instead.");
|
||||
type = Feature2D::kFeatureGfttOrb;
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // >= 4.4.0 >= 3.4.11
|
||||
|
||||
#if !defined(HAVE_OPENCV_XFEATURES2D) && CV_MAJOR_VERSION >= 3
|
||||
if(type == Feature2D::kFeatureFastBrief ||
|
||||
type == Feature2D::kFeatureFastFreak ||
|
||||
type == Feature2D::kFeatureGfttBrief ||
|
||||
type == Feature2D::kFeatureGfttFreak ||
|
||||
type == Feature2D::kFeatureSurfFreak ||
|
||||
type == Feature2D::kFeatureGfttDaisy ||
|
||||
type == Feature2D::kFeatureSurfDaisy)
|
||||
{
|
||||
UWARN("BRIEF, FREAK and DAISY features cannot be used because OpenCV was not built with xfeatures2d module. GFTT/ORB is used instead.");
|
||||
type = Feature2D::kFeatureGfttOrb;
|
||||
}
|
||||
#elif CV_MAJOR_VERSION < 3
|
||||
#if CV_MAJOR_VERSION < 3
|
||||
if(type == Feature2D::kFeatureKaze)
|
||||
{
|
||||
#ifdef RTABMAP_NONFREE
|
||||
#ifdef RTABMAP_NONFREE
|
||||
UWARN("KAZE detector/descriptor can be used only with OpenCV3. SURF is used instead.");
|
||||
type = Feature2D::kFeatureSurf;
|
||||
#else
|
||||
#else
|
||||
UWARN("KAZE detector/descriptor can be used only with OpenCV3. GFTT/ORB is used instead.");
|
||||
type = Feature2D::kFeatureGfttOrb;
|
||||
#endif
|
||||
}
|
||||
if(type == Feature2D::kFeatureGfttDaisy || type == Feature2D::kFeatureSurfDaisy)
|
||||
{
|
||||
UWARN("DAISY detector/descriptor can be used only with OpenCV3. GFTT/BRIEF is used instead.");
|
||||
type = Feature2D::kFeatureGfttBrief;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef RTABMAP_ORB_OCTREE
|
||||
if(type == Feature2D::kFeatureOrbOctree)
|
||||
{
|
||||
@@ -629,15 +614,6 @@ Feature2D * Feature2D::create(Feature2D::Type type, const ParametersMap & parame
|
||||
feature2D = new SuperPointTorch(parameters);
|
||||
break;
|
||||
#endif
|
||||
case Feature2D::kFeatureSurfFreak:
|
||||
feature2D = new SURF_FREAK(parameters);
|
||||
break;
|
||||
case Feature2D::kFeatureGfttDaisy:
|
||||
feature2D = new GFTT_DAISY(parameters);
|
||||
break;
|
||||
case Feature2D::kFeatureSurfDaisy:
|
||||
feature2D = new SURF_DAISY(parameters);
|
||||
break;
|
||||
#ifdef RTABMAP_NONFREE
|
||||
default:
|
||||
feature2D = new SURF(parameters);
|
||||
@@ -646,7 +622,7 @@ Feature2D * Feature2D::create(Feature2D::Type type, const ParametersMap & parame
|
||||
#else
|
||||
default:
|
||||
feature2D = new ORB(parameters);
|
||||
type = Feature2D::kFeatureGfttOrb;
|
||||
type = Feature2D::kFeatureOrb;
|
||||
break;
|
||||
#endif
|
||||
|
||||
@@ -997,7 +973,7 @@ void SIFT::parseParameters(const ParametersMap & parameters)
|
||||
#else
|
||||
UWARN("RTAB-Map is not built with OpenCV nonfree module so SIFT cannot be used!");
|
||||
#endif
|
||||
#else // >=4.4, >=3.4.11
|
||||
#else
|
||||
_sift = CV_SIFT::create(this->getMaxFeatures(), nOctaveLayers_, contrastThreshold_, edgeThreshold_, sigma_);
|
||||
#endif
|
||||
}
|
||||
@@ -1006,20 +982,16 @@ std::vector<cv::KeyPoint> SIFT::generateKeypointsImpl(const cv::Mat & image, con
|
||||
{
|
||||
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
#if defined(RTABMAP_NONFREE) || CV_MAJOR_VERSION > 4 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION >= 3)
|
||||
cv::Mat imgRoi(image, roi);
|
||||
cv::Mat maskRoi;
|
||||
if(!mask.empty())
|
||||
{
|
||||
maskRoi = cv::Mat(mask, roi);
|
||||
}
|
||||
#if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION <= 3) || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION < 4 || (CV_MINOR_VERSION==4 && CV_SUBMINOR_VERSION<11)))
|
||||
#ifdef RTABMAP_NONFREE
|
||||
_sift->detect(imgRoi, keypoints, maskRoi); // Opencv keypoints
|
||||
#else
|
||||
UWARN("RTAB-Map is not built with OpenCV nonfree module so SIFT cannot be used!");
|
||||
#endif
|
||||
#else // >=4.4, >=3.4.11
|
||||
_sift->detect(imgRoi, keypoints, maskRoi); // Opencv keypoints
|
||||
#endif
|
||||
return keypoints;
|
||||
}
|
||||
@@ -1028,15 +1000,9 @@ cv::Mat SIFT::generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::Key
|
||||
{
|
||||
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
|
||||
cv::Mat descriptors;
|
||||
#if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION <= 3) || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION < 4 || (CV_MINOR_VERSION==4 && CV_SUBMINOR_VERSION<11)))
|
||||
#ifdef RTABMAP_NONFREE
|
||||
#if defined(RTABMAP_NONFREE) || CV_MAJOR_VERSION > 4 || (CV_MAJOR_VERSION == 4 && CV_MINOR_VERSION >= 3)
|
||||
_sift->compute(image, keypoints, descriptors);
|
||||
#else
|
||||
UWARN("RTAB-Map is not built with OpenCV nonfree module so SIFT cannot be used!");
|
||||
#endif
|
||||
#else // >=4.4, >=3.4.11
|
||||
_sift->compute(image, keypoints, descriptors);
|
||||
#endif
|
||||
|
||||
if( rootSIFT_ && !descriptors.empty())
|
||||
{
|
||||
UDEBUG("Performing RootSIFT...");
|
||||
@@ -1052,6 +1018,10 @@ cv::Mat SIFT::generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::Key
|
||||
cv::sqrt(descriptors.row(i), descriptors.row(i));
|
||||
}
|
||||
}
|
||||
|
||||
#else
|
||||
UWARN("RTAB-Map is not built with OpenCV nonfree module so SIFT cannot be used!");
|
||||
#endif
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
@@ -1754,59 +1724,6 @@ cv::Mat GFTT_FREAK::generateDescriptorsImpl(const cv::Mat & image, std::vector<c
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//SURF-FREAK
|
||||
//////////////////////////
|
||||
SURF_FREAK::SURF_FREAK(const ParametersMap & parameters) :
|
||||
SURF(parameters),
|
||||
orientationNormalized_(Parameters::defaultFREAKOrientationNormalized()),
|
||||
scaleNormalized_(Parameters::defaultFREAKScaleNormalized()),
|
||||
patternScale_(Parameters::defaultFREAKPatternScale()),
|
||||
nOctaves_(Parameters::defaultFREAKNOctaves())
|
||||
{
|
||||
parseParameters(parameters);
|
||||
}
|
||||
|
||||
SURF_FREAK::~SURF_FREAK()
|
||||
{
|
||||
}
|
||||
|
||||
void SURF_FREAK::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
SURF::parseParameters(parameters);
|
||||
|
||||
Parameters::parse(parameters, Parameters::kFREAKOrientationNormalized(), orientationNormalized_);
|
||||
Parameters::parse(parameters, Parameters::kFREAKScaleNormalized(), scaleNormalized_);
|
||||
Parameters::parse(parameters, Parameters::kFREAKPatternScale(), patternScale_);
|
||||
Parameters::parse(parameters, Parameters::kFREAKNOctaves(), nOctaves_);
|
||||
|
||||
#if CV_MAJOR_VERSION < 3
|
||||
_freak = cv::Ptr<CV_FREAK>(new CV_FREAK(orientationNormalized_, scaleNormalized_, patternScale_, nOctaves_));
|
||||
#else
|
||||
#ifdef HAVE_OPENCV_XFEATURES2D
|
||||
_freak = CV_FREAK::create(orientationNormalized_, scaleNormalized_, patternScale_, nOctaves_);
|
||||
#else
|
||||
UWARN("RTAB-Map is not built with OpenCV xfeatures2d module so Freak cannot be used!");
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
|
||||
cv::Mat SURF_FREAK::generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
|
||||
cv::Mat descriptors;
|
||||
#if CV_MAJOR_VERSION < 3
|
||||
_freak->compute(image, keypoints, descriptors);
|
||||
#else
|
||||
#ifdef HAVE_OPENCV_XFEATURES2D
|
||||
_freak->compute(image, keypoints, descriptors);
|
||||
#else
|
||||
UWARN("RTAB-Map is not built with OpenCV xfeatures2d module so Freak cannot be used!");
|
||||
#endif
|
||||
#endif
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//GFTT-ORB
|
||||
//////////////////////////
|
||||
@@ -1959,10 +1876,7 @@ cv::Mat KAZE::generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::Key
|
||||
ORBOctree::ORBOctree(const ParametersMap & parameters) :
|
||||
scaleFactor_(Parameters::defaultORBScaleFactor()),
|
||||
nLevels_(Parameters::defaultORBNLevels()),
|
||||
patchSize_(Parameters::defaultORBPatchSize()),
|
||||
edgeThreshold_(Parameters::defaultORBEdgeThreshold()),
|
||||
fastThreshold_(Parameters::defaultFASTThreshold()),
|
||||
fastMinThreshold_(Parameters::defaultFASTMinThreshold())
|
||||
fastThreshold_(Parameters::defaultFASTThreshold())
|
||||
{
|
||||
parseParameters(parameters);
|
||||
}
|
||||
@@ -1977,14 +1891,12 @@ void ORBOctree::parseParameters(const ParametersMap & parameters)
|
||||
|
||||
Parameters::parse(parameters, Parameters::kORBScaleFactor(), scaleFactor_);
|
||||
Parameters::parse(parameters, Parameters::kORBNLevels(), nLevels_);
|
||||
Parameters::parse(parameters, Parameters::kORBPatchSize(), patchSize_);
|
||||
Parameters::parse(parameters, Parameters::kORBEdgeThreshold(), edgeThreshold_);
|
||||
|
||||
Parameters::parse(parameters, Parameters::kFASTThreshold(), fastThreshold_);
|
||||
Parameters::parse(parameters, Parameters::kFASTMinThreshold(), fastMinThreshold_);
|
||||
|
||||
#ifdef RTABMAP_ORB_OCTREE
|
||||
_orb = cv::Ptr<ORBextractor>(new ORBextractor(this->getMaxFeatures(), scaleFactor_, nLevels_, fastThreshold_, fastMinThreshold_, patchSize_, edgeThreshold_));
|
||||
_orb = cv::Ptr<ORBextractor>(new ORBextractor(this->getMaxFeatures(), scaleFactor_, nLevels_, fastThreshold_, fastMinThreshold_));
|
||||
#else
|
||||
UWARN("RTAB-Map is not built with ORB OcTree option enabled so ORB OcTree feature cannot be used!");
|
||||
#endif
|
||||
@@ -2095,95 +2007,4 @@ cv::Mat SuperPointTorch::generateDescriptorsImpl(const cv::Mat & image, std::vec
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
//////////////////////////
|
||||
//GFTT-DAISY
|
||||
//////////////////////////
|
||||
GFTT_DAISY::GFTT_DAISY(const ParametersMap & parameters) :
|
||||
GFTT(parameters),
|
||||
orientationNormalized_(Parameters::defaultFREAKOrientationNormalized()),
|
||||
scaleNormalized_(Parameters::defaultFREAKScaleNormalized()),
|
||||
patternScale_(Parameters::defaultFREAKPatternScale()),
|
||||
nOctaves_(Parameters::defaultFREAKNOctaves())
|
||||
{
|
||||
parseParameters(parameters);
|
||||
}
|
||||
|
||||
GFTT_DAISY::~GFTT_DAISY()
|
||||
{
|
||||
}
|
||||
|
||||
void GFTT_DAISY::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
GFTT::parseParameters(parameters);
|
||||
|
||||
Parameters::parse(parameters, Parameters::kFREAKOrientationNormalized(), orientationNormalized_);
|
||||
Parameters::parse(parameters, Parameters::kFREAKScaleNormalized(), scaleNormalized_);
|
||||
Parameters::parse(parameters, Parameters::kFREAKPatternScale(), patternScale_);
|
||||
Parameters::parse(parameters, Parameters::kFREAKNOctaves(), nOctaves_);
|
||||
|
||||
#ifdef HAVE_OPENCV_XFEATURES2D
|
||||
_daisy = CV_DAISY::create();
|
||||
#else
|
||||
UWARN("RTAB-Map is not built with OpenCV xfeatures2d module so DAISY cannot be used!");
|
||||
#endif
|
||||
}
|
||||
|
||||
cv::Mat GFTT_DAISY::generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
|
||||
cv::Mat descriptors;
|
||||
#ifdef HAVE_OPENCV_XFEATURES2D
|
||||
_daisy->compute(image, keypoints, descriptors);
|
||||
#else
|
||||
UWARN("RTAB-Map is not built with OpenCV xfeatures2d module so DAISY cannot be used!");
|
||||
#endif
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
//////////////////////////
|
||||
//SURF-DAISY
|
||||
//////////////////////////
|
||||
SURF_DAISY::SURF_DAISY(const ParametersMap & parameters) :
|
||||
SURF(parameters),
|
||||
orientationNormalized_(Parameters::defaultFREAKOrientationNormalized()),
|
||||
scaleNormalized_(Parameters::defaultFREAKScaleNormalized()),
|
||||
patternScale_(Parameters::defaultFREAKPatternScale()),
|
||||
nOctaves_(Parameters::defaultFREAKNOctaves())
|
||||
{
|
||||
parseParameters(parameters);
|
||||
}
|
||||
|
||||
SURF_DAISY::~SURF_DAISY()
|
||||
{
|
||||
}
|
||||
|
||||
void SURF_DAISY::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
SURF::parseParameters(parameters);
|
||||
|
||||
Parameters::parse(parameters, Parameters::kFREAKOrientationNormalized(), orientationNormalized_);
|
||||
Parameters::parse(parameters, Parameters::kFREAKScaleNormalized(), scaleNormalized_);
|
||||
Parameters::parse(parameters, Parameters::kFREAKPatternScale(), patternScale_);
|
||||
Parameters::parse(parameters, Parameters::kFREAKNOctaves(), nOctaves_);
|
||||
|
||||
#ifdef HAVE_OPENCV_XFEATURES2D
|
||||
_daisy = CV_DAISY::create();
|
||||
#else
|
||||
UWARN("RTAB-Map is not built with OpenCV xfeatures2d module so DAISY cannot be used!");
|
||||
#endif
|
||||
}
|
||||
|
||||
cv::Mat SURF_DAISY::generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
UASSERT(!image.empty() && image.channels() == 1 && image.depth() == CV_8U);
|
||||
cv::Mat descriptors;
|
||||
#ifdef HAVE_OPENCV_XFEATURES2D
|
||||
_daisy->compute(image, keypoints, descriptors);
|
||||
#else
|
||||
UWARN("RTAB-Map is not built with OpenCV xfeatures2d module so DAISY cannot be used!");
|
||||
#endif
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+28
-81
@@ -107,36 +107,32 @@ unsigned int FlannIndex::indexedFeatures() const
|
||||
}
|
||||
}
|
||||
|
||||
// return Bytes
|
||||
unsigned long FlannIndex::memoryUsed() const
|
||||
// return KB
|
||||
unsigned int FlannIndex::memoryUsed() const
|
||||
{
|
||||
if(!index_)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
unsigned long memoryUsage = sizeof(FlannIndex);
|
||||
memoryUsage += addedDescriptors_.size() * (sizeof(int) + sizeof(cv::Mat) + sizeof(std::map<int, cv::Mat>::iterator)) + sizeof(std::map<int, cv::Mat>);
|
||||
memoryUsage += sizeof(std::list<int>) + removedIndexes_.size() * sizeof(int);
|
||||
if(featuresType_ == CV_8UC1)
|
||||
{
|
||||
memoryUsage += ((const rtflann::Index<rtflann::Hamming<unsigned char> >*)index_)->usedMemory();
|
||||
return ((const rtflann::Index<rtflann::Hamming<unsigned char> >*)index_)->usedMemory()/1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
if(useDistanceL1_)
|
||||
{
|
||||
memoryUsage += ((const rtflann::Index<rtflann::L1<float> >*)index_)->usedMemory();
|
||||
return ((const rtflann::Index<rtflann::L1<float> >*)index_)->usedMemory()/1000;
|
||||
}
|
||||
else if(featuresDim_ <= 3)
|
||||
{
|
||||
memoryUsage += ((const rtflann::Index<rtflann::L2_Simple<float> >*)index_)->usedMemory();
|
||||
return ((const rtflann::Index<rtflann::L2_Simple<float> >*)index_)->usedMemory()/1000;
|
||||
}
|
||||
else
|
||||
{
|
||||
memoryUsage += ((const rtflann::Index<rtflann::L2<float> >*)index_)->usedMemory();
|
||||
return ((const rtflann::Index<rtflann::L2<float> >*)index_)->usedMemory()/1000;
|
||||
}
|
||||
}
|
||||
return memoryUsage;
|
||||
}
|
||||
|
||||
void FlannIndex::buildLinearIndex(
|
||||
@@ -181,21 +177,10 @@ void FlannIndex::buildLinearIndex(
|
||||
}
|
||||
}
|
||||
|
||||
// incremental FLANN: we should add all headers separately in case we remove
|
||||
// some indexes (to keep underlying matrix data allocated)
|
||||
if(rebalancingFactor_ > 1.0f)
|
||||
{
|
||||
for(int i=0; i<features.rows; ++i)
|
||||
{
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_++, features.row(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// tree won't ever be rebalanced, so just keep only one header for the data
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_, features));
|
||||
nextIndex_ += features.rows;
|
||||
}
|
||||
// incremental FLANN
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_, features));
|
||||
|
||||
nextIndex_ = features.rows;
|
||||
UDEBUG("");
|
||||
}
|
||||
|
||||
@@ -242,21 +227,10 @@ void FlannIndex::buildKDTreeIndex(
|
||||
}
|
||||
}
|
||||
|
||||
// incremental FLANN: we should add all headers separately in case we remove
|
||||
// some indexes (to keep underlying matrix data allocated)
|
||||
if(rebalancingFactor_ > 1.0f)
|
||||
{
|
||||
for(int i=0; i<features.rows; ++i)
|
||||
{
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_++, features.row(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// tree won't ever be rebalanced, so just keep only one header for the data
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_, features));
|
||||
nextIndex_ += features.rows;
|
||||
}
|
||||
// incremental FLANN
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_, features));
|
||||
|
||||
nextIndex_ = features.rows;
|
||||
UDEBUG("");
|
||||
}
|
||||
|
||||
@@ -304,21 +278,10 @@ void FlannIndex::buildKDTreeSingleIndex(
|
||||
}
|
||||
}
|
||||
|
||||
// incremental FLANN: we should add all headers separately in case we remove
|
||||
// some indexes (to keep underlying matrix data allocated)
|
||||
if(rebalancingFactor_ > 1.0f)
|
||||
{
|
||||
for(int i=0; i<features.rows; ++i)
|
||||
{
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_++, features.row(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// tree won't ever be rebalanced, so just keep only one header for the data
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_, features));
|
||||
nextIndex_ += features.rows;
|
||||
}
|
||||
// incremental FLANN
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_, features));
|
||||
|
||||
nextIndex_ = features.rows;
|
||||
UDEBUG("");
|
||||
}
|
||||
|
||||
@@ -342,21 +305,10 @@ void FlannIndex::buildLSHIndex(
|
||||
index_ = new rtflann::Index<rtflann::Hamming<unsigned char> >(dataset, rtflann::LshIndexParams(12, 20, 2));
|
||||
((rtflann::Index<rtflann::Hamming<unsigned char> >*)index_)->buildIndex();
|
||||
|
||||
// incremental FLANN: we should add all headers separately in case we remove
|
||||
// some indexes (to keep underlying matrix data allocated)
|
||||
if(rebalancingFactor_ > 1.0f)
|
||||
{
|
||||
for(int i=0; i<features.rows; ++i)
|
||||
{
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_++, features.row(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// tree won't ever be rebalanced, so just keep only one header for the data
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_, features));
|
||||
nextIndex_ += features.rows;
|
||||
}
|
||||
// incremental FLANN
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_, features));
|
||||
|
||||
nextIndex_ = features.rows;
|
||||
UDEBUG("");
|
||||
}
|
||||
|
||||
@@ -365,12 +317,12 @@ bool FlannIndex::isBuilt()
|
||||
return index_!=0;
|
||||
}
|
||||
|
||||
std::vector<unsigned int> FlannIndex::addPoints(const cv::Mat & features)
|
||||
unsigned int FlannIndex::addPoints(const cv::Mat & features)
|
||||
{
|
||||
if(!index_)
|
||||
{
|
||||
UERROR("Flann index not yet created!");
|
||||
return std::vector<unsigned int>();
|
||||
return 0;
|
||||
}
|
||||
UASSERT(features.type() == featuresType_);
|
||||
UASSERT(features.cols == featuresDim_);
|
||||
@@ -449,16 +401,11 @@ std::vector<unsigned int> FlannIndex::addPoints(const cv::Mat & features)
|
||||
removedIndexes_.clear();
|
||||
}
|
||||
|
||||
// incremental FLANN: we should add all headers separately in case we remove
|
||||
// some indexes (to keep underlying matrix data allocated)
|
||||
std::vector<unsigned int> indexes;
|
||||
for(int i=0; i<features.rows; ++i)
|
||||
{
|
||||
indexes.push_back(nextIndex_);
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_++, features.row(i)));
|
||||
}
|
||||
addedDescriptors_.insert(std::make_pair(nextIndex_, features));
|
||||
|
||||
return indexes;
|
||||
int r = nextIndex_;
|
||||
nextIndex_ += features.rows;
|
||||
return r;
|
||||
}
|
||||
|
||||
void FlannIndex::removePoint(unsigned int index)
|
||||
|
||||
+38
-64
@@ -169,7 +169,7 @@ bool exportPoses(
|
||||
|
||||
bool importPoses(
|
||||
const std::string & filePath,
|
||||
int format, // 0=Raw, 1=RGBD-SLAM motion capture (10=without change of coordinate frame), 2=KITTI, 3=TORO, 4=g2o, 5=NewCollege(t,x,y), 6=Malaga Urban GPS, 7=St Lucia INS, 8=Karlsruhe, 9=EuRoC MAV
|
||||
int format, // 0=Raw, 1=RGBD-SLAM motion capture (10=without change of coordinate frame), 2=KITTI, 3=TORO, 4=g2o, 5=NewCollege(t,x,y), 6=Malaga Urban GPS, 7=St Lucia INS, 8=Karlsruhe, 9=EuRoC MAC
|
||||
std::map<int, Transform> & poses,
|
||||
std::multimap<int, Link> * constraints, // optional for formats 3 and 4
|
||||
std::map<int, double> * stamps) // optional for format 1 and 9
|
||||
@@ -1129,22 +1129,19 @@ std::multimap<int, Link> filterDuplicateLinks(
|
||||
|
||||
std::multimap<int, Link> filterLinks(
|
||||
const std::multimap<int, Link> & links,
|
||||
Link::Type filteredType,
|
||||
bool inverted)
|
||||
Link::Type filteredType)
|
||||
{
|
||||
std::multimap<int, Link> output;
|
||||
for(std::multimap<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
if(filteredType == Link::kSelfRefLink)
|
||||
{
|
||||
if((!inverted && iter->second.from() != iter->second.to())||
|
||||
(inverted && iter->second.from() == iter->second.to()))
|
||||
if(iter->second.from() != iter->second.to())
|
||||
{
|
||||
output.insert(*iter);
|
||||
}
|
||||
}
|
||||
else if((!inverted && iter->second.type() != filteredType)||
|
||||
(inverted && iter->second.type() == filteredType))
|
||||
else if(iter->second.type() != filteredType)
|
||||
{
|
||||
output.insert(*iter);
|
||||
}
|
||||
@@ -1154,22 +1151,19 @@ std::multimap<int, Link> filterLinks(
|
||||
|
||||
std::map<int, Link> filterLinks(
|
||||
const std::map<int, Link> & links,
|
||||
Link::Type filteredType,
|
||||
bool inverted)
|
||||
Link::Type filteredType)
|
||||
{
|
||||
std::map<int, Link> output;
|
||||
for(std::map<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
if(filteredType == Link::kSelfRefLink)
|
||||
{
|
||||
if((!inverted && iter->second.from() != iter->second.to())||
|
||||
(inverted && iter->second.from() == iter->second.to()))
|
||||
if(iter->second.from() != iter->second.to())
|
||||
{
|
||||
output.insert(*iter);
|
||||
}
|
||||
}
|
||||
else if((!inverted && iter->second.type() != filteredType)||
|
||||
(inverted && iter->second.type() == filteredType))
|
||||
else if(iter->second.type() != filteredType)
|
||||
{
|
||||
output.insert(*iter);
|
||||
}
|
||||
@@ -2060,28 +2054,23 @@ std::list<std::pair<int, Transform> > computePath(
|
||||
|
||||
int findNearestNode(
|
||||
const std::map<int, rtabmap::Transform> & nodes,
|
||||
const rtabmap::Transform & targetPose,
|
||||
float * distance)
|
||||
const rtabmap::Transform & targetPose)
|
||||
{
|
||||
int id = 0;
|
||||
std::map<int, float> nearestNodes = findNearestNodes(nodes, targetPose, 1);
|
||||
if(!nearestNodes.empty())
|
||||
std::vector<int> nearestNodes = findNearestNodes(nodes, targetPose, 1);
|
||||
if(nearestNodes.size())
|
||||
{
|
||||
id = nearestNodes.begin()->first;
|
||||
if(distance)
|
||||
{
|
||||
*distance = nearestNodes.begin()->second;
|
||||
}
|
||||
id = nearestNodes[0];
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
std::map<int, float> findNearestNodes(
|
||||
std::vector<int> findNearestNodes(
|
||||
const std::map<int, rtabmap::Transform> & nodes,
|
||||
const rtabmap::Transform & targetPose,
|
||||
int k)
|
||||
{
|
||||
std::map<int, float> nearestIds;
|
||||
std::vector<int> nearestIds;
|
||||
if(nodes.size() && !targetPose.isNull())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
|
||||
@@ -2101,9 +2090,10 @@ std::map<int, float> findNearestNodes(
|
||||
pcl::PointXYZ pt(targetPose.x(), targetPose.y(), targetPose.z());
|
||||
kdTree->nearestKSearch(pt, k, ind, dist);
|
||||
|
||||
nearestIds.resize(ind.size());
|
||||
for(unsigned int i=0; i<ind.size(); ++i)
|
||||
{
|
||||
nearestIds.insert(std::make_pair(ids[ind[i]], dist[i]));
|
||||
nearestIds[i] = ids[ind[i]];
|
||||
}
|
||||
}
|
||||
return nearestIds;
|
||||
@@ -2116,21 +2106,8 @@ std::map<int, float> getNodesInRadius(
|
||||
float radius)
|
||||
{
|
||||
UASSERT(uContains(nodes, nodeId));
|
||||
|
||||
std::map<int, Transform> nodesMinusTarget = nodes;
|
||||
Transform targetPose = nodes.at(nodeId);
|
||||
nodesMinusTarget.erase(nodeId);
|
||||
return getNodesInRadius(targetPose, nodesMinusTarget, radius);
|
||||
}
|
||||
|
||||
// return <id, sqrd distance>, excluding query
|
||||
std::map<int, float> getNodesInRadius(
|
||||
const Transform & targetPose,
|
||||
const std::map<int, Transform> & nodes,
|
||||
float radius)
|
||||
{
|
||||
std::map<int, float> foundNodes;
|
||||
if(nodes.empty())
|
||||
if(nodes.size() <= 1)
|
||||
{
|
||||
return foundNodes;
|
||||
}
|
||||
@@ -2141,21 +2118,26 @@ std::map<int, float> getNodesInRadius(
|
||||
int oi = 0;
|
||||
for(std::map<int, Transform>::const_iterator iter = nodes.begin(); iter!=nodes.end(); ++iter)
|
||||
{
|
||||
(*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
|
||||
UASSERT_MSG(pcl::isFinite((*cloud)[oi]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
|
||||
ids[oi] = iter->first;
|
||||
++oi;
|
||||
if(iter->first != nodeId)
|
||||
{
|
||||
(*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
|
||||
UASSERT_MSG(pcl::isFinite((*cloud)[oi]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
|
||||
ids[oi] = iter->first;
|
||||
++oi;
|
||||
}
|
||||
}
|
||||
cloud->resize(oi);
|
||||
ids.resize(oi);
|
||||
|
||||
Transform fromT = nodes.at(nodeId);
|
||||
|
||||
if(cloud->size())
|
||||
{
|
||||
pcl::search::KdTree<pcl::PointXYZ>::Ptr kdTree(new pcl::search::KdTree<pcl::PointXYZ>);
|
||||
kdTree->setInputCloud(cloud);
|
||||
std::vector<int> ind;
|
||||
std::vector<float> sqrdDist;
|
||||
pcl::PointXYZ pt(targetPose.x(), targetPose.y(), targetPose.z());
|
||||
pcl::PointXYZ pt(fromT.x(), fromT.y(), fromT.z());
|
||||
kdTree->radiusSearch(pt, radius, ind, sqrdDist, 0);
|
||||
for(unsigned int i=0; i<ind.size(); ++i)
|
||||
{
|
||||
@@ -2177,21 +2159,8 @@ std::map<int, Transform> getPosesInRadius(
|
||||
float angle)
|
||||
{
|
||||
UASSERT(uContains(nodes, nodeId));
|
||||
|
||||
std::map<int, Transform> nodesMinusTarget = nodes;
|
||||
Transform targetPose = nodes.at(nodeId);
|
||||
nodesMinusTarget.erase(nodeId);
|
||||
return getPosesInRadius(targetPose, nodesMinusTarget, radius, angle);
|
||||
}
|
||||
// return <id, Transform>, excluding query
|
||||
std::map<int, Transform> getPosesInRadius(
|
||||
const Transform & targetPose,
|
||||
const std::map<int, Transform> & nodes,
|
||||
float radius,
|
||||
float angle)
|
||||
{
|
||||
std::map<int, Transform> foundNodes;
|
||||
if(nodes.empty())
|
||||
if(nodes.size() <= 1)
|
||||
{
|
||||
return foundNodes;
|
||||
}
|
||||
@@ -2202,24 +2171,29 @@ std::map<int, Transform> getPosesInRadius(
|
||||
int oi = 0;
|
||||
for(std::map<int, Transform>::const_iterator iter = nodes.begin(); iter!=nodes.end(); ++iter)
|
||||
{
|
||||
(*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
|
||||
UASSERT_MSG(pcl::isFinite((*cloud)[oi]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
|
||||
ids[oi] = iter->first;
|
||||
++oi;
|
||||
if(iter->first != nodeId)
|
||||
{
|
||||
(*cloud)[oi] = pcl::PointXYZ(iter->second.x(), iter->second.y(), iter->second.z());
|
||||
UASSERT_MSG(pcl::isFinite((*cloud)[oi]), uFormat("Invalid pose (%d) %s", iter->first, iter->second.prettyPrint().c_str()).c_str());
|
||||
ids[oi] = iter->first;
|
||||
++oi;
|
||||
}
|
||||
}
|
||||
cloud->resize(oi);
|
||||
ids.resize(oi);
|
||||
|
||||
Transform fromT = nodes.at(nodeId);
|
||||
|
||||
if(cloud->size())
|
||||
{
|
||||
pcl::search::KdTree<pcl::PointXYZ>::Ptr kdTree(new pcl::search::KdTree<pcl::PointXYZ>);
|
||||
kdTree->setInputCloud(cloud);
|
||||
std::vector<int> ind;
|
||||
std::vector<float> sqrdDist;
|
||||
pcl::PointXYZ pt(targetPose.x(), targetPose.y(), targetPose.z());
|
||||
pcl::PointXYZ pt(fromT.x(), fromT.y(), fromT.z());
|
||||
kdTree->radiusSearch(pt, radius, ind, sqrdDist, 0);
|
||||
|
||||
Eigen::Vector3f vA = targetPose.toEigen3f().linear()*Eigen::Vector3f(1,0,0);
|
||||
Eigen::Vector3f vA = fromT.toEigen3f().linear()*Eigen::Vector3f(1,0,0);
|
||||
|
||||
for(unsigned int i=0; i<ind.size(); ++i)
|
||||
{
|
||||
|
||||
@@ -36,8 +36,6 @@ MarkerDetector::MarkerDetector(const ParametersMap & parameters)
|
||||
#ifdef HAVE_OPENCV_ARUCO
|
||||
markerLength_ = Parameters::defaultMarkerLength();
|
||||
maxDepthError_ = Parameters::defaultMarkerMaxDepthError();
|
||||
maxRange_ = Parameters::defaultMarkerMaxRange();
|
||||
minRange_ = Parameters::defaultMarkerMinRange();
|
||||
dictionaryId_ = Parameters::defaultMarkerDictionary();
|
||||
#if CV_MAJOR_VERSION > 3 || (CV_MAJOR_VERSION == 3 && CV_MINOR_VERSION >=2)
|
||||
detectorParams_ = cv::aruco::DetectorParameters::create();
|
||||
@@ -89,8 +87,6 @@ void MarkerDetector::parseParameters(const ParametersMap & parameters)
|
||||
|
||||
Parameters::parse(parameters, Parameters::kMarkerLength(), markerLength_);
|
||||
Parameters::parse(parameters, Parameters::kMarkerMaxDepthError(), maxDepthError_);
|
||||
Parameters::parse(parameters, Parameters::kMarkerMaxRange(), maxRange_);
|
||||
Parameters::parse(parameters, Parameters::kMarkerMinRange(), minRange_);
|
||||
Parameters::parse(parameters, Parameters::kMarkerDictionary(), dictionaryId_);
|
||||
#if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 3 && (CV_MINOR_VERSION <4 || (CV_MINOR_VERSION ==4 && CV_SUBMINOR_VERSION<2)))
|
||||
if(dictionaryId_ >= 17)
|
||||
@@ -195,20 +191,15 @@ std::map<int, Transform> MarkerDetector::detect(const cv::Mat & image, const Cam
|
||||
}
|
||||
}
|
||||
|
||||
// Limit the detection range to be between the min / max range.
|
||||
// If the ranges are -1, allow any detection within that direction.
|
||||
if((maxRange_ <= 0 || tvecs[i].val[2] < maxRange_) &&
|
||||
(minRange_ <= 0 || tvecs[i].val[2] > minRange_))
|
||||
{
|
||||
cv::Mat R;
|
||||
cv::Rodrigues(rvecs[i], R);
|
||||
Transform t(R.at<double>(0,0), R.at<double>(0,1), R.at<double>(0,2), tvecs[i].val[0],
|
||||
R.at<double>(1,0), R.at<double>(1,1), R.at<double>(1,2), tvecs[i].val[1],
|
||||
R.at<double>(2,0), R.at<double>(2,1), R.at<double>(2,2), tvecs[i].val[2]);
|
||||
Transform pose = model.localTransform() * t;
|
||||
detections.insert(std::make_pair(ids[i], pose));
|
||||
UDEBUG("Marker %d detected at %s (%s)", ids[i], pose.prettyPrint().c_str(), t.prettyPrint().c_str());
|
||||
}
|
||||
cv::Mat R;
|
||||
cv::Rodrigues(rvecs[i], R);
|
||||
Transform t(R.at<double>(0,0), R.at<double>(0,1), R.at<double>(0,2), tvecs[i].val[0],
|
||||
R.at<double>(1,0), R.at<double>(1,1), R.at<double>(1,2), tvecs[i].val[1],
|
||||
R.at<double>(2,0), R.at<double>(2,1), R.at<double>(2,2), tvecs[i].val[2]);
|
||||
|
||||
Transform pose = model.localTransform() * t;
|
||||
detections.insert(std::make_pair(ids[i], pose));
|
||||
UDEBUG("Marker %d detected at %s (%s)", ids[i], pose.prettyPrint().c_str(), t.prettyPrint().c_str());
|
||||
}
|
||||
if(markerLength_ == 0)
|
||||
{
|
||||
@@ -270,3 +261,4 @@ std::map<int, Transform> MarkerDetector::detect(const cv::Mat & image, const Cam
|
||||
|
||||
|
||||
} /* namespace rtabmap */
|
||||
|
||||
|
||||
+139
-206
@@ -362,7 +362,7 @@ void Memory::loadDataFromDb(bool postInitClosingEvents)
|
||||
const std::map<int, Signature *> & signatures = this->getSignatures();
|
||||
for(std::map<int, Signature *>::const_iterator i=signatures.begin(); i!=signatures.end(); ++i)
|
||||
{
|
||||
const std::multimap<int, int> & words = i->second->getWords();
|
||||
const std::multimap<int, cv::KeyPoint> & words = i->second->getWords();
|
||||
std::list<int> keys = uUniqueKeys(words);
|
||||
for(std::list<int>::iterator iter=keys.begin(); iter!=keys.end(); ++iter)
|
||||
{
|
||||
@@ -413,11 +413,11 @@ void Memory::loadDataFromDb(bool postInitClosingEvents)
|
||||
Signature * s = this->_getSignature(i->first);
|
||||
UASSERT(s != 0);
|
||||
|
||||
const std::multimap<int, int> & words = s->getWords();
|
||||
const std::multimap<int, cv::KeyPoint> & words = s->getWords();
|
||||
if(words.size())
|
||||
{
|
||||
UDEBUG("node=%d, word references=%d", s->id(), words.size());
|
||||
for(std::multimap<int, int>::const_iterator iter = words.begin(); iter!=words.end(); ++iter)
|
||||
for(std::multimap<int, cv::KeyPoint>::const_iterator iter = words.begin(); iter!=words.end(); ++iter)
|
||||
{
|
||||
if(iter->first > 0)
|
||||
{
|
||||
@@ -886,7 +886,7 @@ void Memory::addSignatureToStm(Signature * signature, const cv::Mat & covariance
|
||||
// add signature on top of the short-term memory
|
||||
if(signature)
|
||||
{
|
||||
UDEBUG("adding %d (pose=%s)", signature->id(), signature->getPose().prettyPrint().c_str());
|
||||
UDEBUG("adding %d", signature->id());
|
||||
// Update neighbors
|
||||
if(_stMem.size())
|
||||
{
|
||||
@@ -1009,7 +1009,7 @@ void Memory::addSignatureToStm(Signature * signature, const cv::Mat & covariance
|
||||
|
||||
if(_vwd)
|
||||
{
|
||||
UDEBUG("%d words ref for the signature %d (weight=%d)", signature->getWords().size(), signature->id(), signature->getWeight());
|
||||
UDEBUG("%d words ref for the signature %d", signature->getWords().size(), signature->id());
|
||||
}
|
||||
if(signature->getWords().size())
|
||||
{
|
||||
@@ -1131,7 +1131,7 @@ void Memory::moveSignatureToWMFromSTM(int id, int * reducedTo)
|
||||
}
|
||||
}
|
||||
|
||||
this->moveToTrash(s, false);
|
||||
this->moveToTrash(s, _notLinkedNodesKeptInDb);
|
||||
s = 0;
|
||||
}
|
||||
}
|
||||
@@ -1536,7 +1536,7 @@ std::map<int, float> Memory::getNeighborsIdRadius(
|
||||
nextMargin.insert(signatureId);
|
||||
int m = 0;
|
||||
Transform referential = optimizedPoses.at(signatureId);
|
||||
UASSERT_MSG(!referential.isNull(), uFormat("signatureId=%d", signatureId).c_str());
|
||||
UASSERT(!referential.isNull());
|
||||
float radiusSqrd = radius*radius;
|
||||
while((maxGraphDepth == 0 || m < maxGraphDepth) && nextMargin.size())
|
||||
{
|
||||
@@ -2083,7 +2083,7 @@ cv::Mat Memory::load2DMap(float & xMin, float & yMin, float & cellSize) const
|
||||
|
||||
void Memory::saveOptimizedMesh(
|
||||
const cv::Mat & cloud,
|
||||
const std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > & polygons,
|
||||
const std::vector<std::vector<std::vector<unsigned int> > > & polygons,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
|
||||
#else
|
||||
@@ -2098,7 +2098,7 @@ void Memory::saveOptimizedMesh(
|
||||
}
|
||||
|
||||
cv::Mat Memory::loadOptimizedMesh(
|
||||
std::vector<std::vector<std::vector<RTABMAP_PCL_INDEX> > > * polygons,
|
||||
std::vector<std::vector<std::vector<unsigned int> > > * polygons,
|
||||
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
|
||||
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,
|
||||
#else
|
||||
@@ -2357,7 +2357,7 @@ void Memory::moveToTrash(Signature * s, bool keepLinkedToGraph, std::list<int> *
|
||||
}
|
||||
|
||||
// child
|
||||
if(iter->second.type() == Link::kGlobalClosure && s->id() > sTo->id() && s->getWeight()>0)
|
||||
if(iter->second.type() == Link::kGlobalClosure && s->id() > sTo->id())
|
||||
{
|
||||
sTo->setWeight(sTo->getWeight() + s->getWeight()); // copy weight
|
||||
}
|
||||
@@ -2368,7 +2368,7 @@ void Memory::moveToTrash(Signature * s, bool keepLinkedToGraph, std::list<int> *
|
||||
}
|
||||
s->removeLinks(true); // remove all links, but keep self referring link
|
||||
s->removeLandmarks(); // remove all landmarks
|
||||
s->setWeight(-9); // invalid
|
||||
s->setWeight(0);
|
||||
s->setLabel(""); // reset label
|
||||
}
|
||||
else
|
||||
@@ -2753,16 +2753,20 @@ Transform Memory::computeTransform(
|
||||
if(_reextractLoopClosureFeatures && _registrationPipeline->isImageRequired())
|
||||
{
|
||||
UDEBUG("");
|
||||
tmpFrom.removeAllWords();
|
||||
tmpFrom.setWords(std::multimap<int, cv::KeyPoint>());
|
||||
tmpFrom.setWords3(std::multimap<int, cv::Point3f>());
|
||||
tmpFrom.setWordsDescriptors(std::multimap<int, cv::Mat>());
|
||||
tmpFrom.sensorData().setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
|
||||
tmpTo.removeAllWords();
|
||||
tmpTo.setWords(std::multimap<int, cv::KeyPoint>());
|
||||
tmpTo.setWords3(std::multimap<int, cv::Point3f>());
|
||||
tmpTo.setWordsDescriptors(std::multimap<int, cv::Mat>());
|
||||
tmpTo.sensorData().setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
|
||||
}
|
||||
else if(useKnownCorrespondencesIfPossible)
|
||||
{
|
||||
// This will make RegistrationVis bypassing the correspondences computation
|
||||
tmpFrom.setWordsDescriptors(cv::Mat());
|
||||
tmpTo.setWordsDescriptors(cv::Mat());
|
||||
tmpFrom.setWordsDescriptors(std::multimap<int, cv::Mat>());
|
||||
tmpTo.setWordsDescriptors(std::multimap<int, cv::Mat>());
|
||||
}
|
||||
|
||||
bool isNeighborRefining = fromS.getLinks().find(toS.id()) != fromS.getLinks().end() && fromS.getLinks().find(toS.id())->second.type() == Link::kNeighbor;
|
||||
@@ -2791,28 +2795,23 @@ Transform Memory::computeTransform(
|
||||
!tmpTo.getWords().empty() &&
|
||||
!tmpFrom.getWordsDescriptors().empty() &&
|
||||
!tmpFrom.getWords().empty() &&
|
||||
!tmpFrom.getWords3().empty() &&
|
||||
fromS.hasLink(0, Link::kNeighbor)) // If doesn't have neighbors, skip bundle
|
||||
!tmpFrom.getWords3().empty())
|
||||
{
|
||||
std::multimap<int, int> words;
|
||||
std::vector<cv::Point3f> words3DMap;
|
||||
std::vector<cv::KeyPoint> wordsMap;
|
||||
cv::Mat wordsDescriptorsMap;
|
||||
std::multimap<int, cv::Point3f> words3DMap;
|
||||
std::multimap<int, cv::KeyPoint> wordsMap;
|
||||
std::multimap<int, cv::Mat> wordsDescriptorsMap;
|
||||
|
||||
const std::multimap<int, Link> & links = fromS.getLinks();
|
||||
if(!fromS.getWords3().empty())
|
||||
{
|
||||
const std::map<int, int> & wordsFrom = uMultimapToMapUnique(fromS.getWords());
|
||||
UDEBUG("fromS.getWords()=%d uniques=%d", (int)fromS.getWords().size(), (int)wordsFrom.size());
|
||||
for(std::map<int, int>::const_iterator jter=wordsFrom.begin(); jter!=wordsFrom.end(); ++jter)
|
||||
const std::map<int, cv::Point3f> & words3 = uMultimapToMapUnique(fromS.getWords3());
|
||||
UDEBUG("fromS.getWords3()=%d uniques=%d", (int)fromS.getWords3().size(), (int)words3.size());
|
||||
for(std::map<int, cv::Point3f>::const_iterator jter=words3.begin(); jter!=words3.end(); ++jter)
|
||||
{
|
||||
const cv::Point3f & pt = fromS.getWords3()[jter->second];
|
||||
if(util3d::isFinite(pt))
|
||||
if(util3d::isFinite(jter->second))
|
||||
{
|
||||
words.insert(std::make_pair(jter->first, words.size()));
|
||||
words3DMap.push_back(pt);
|
||||
wordsMap.push_back(fromS.getWordsKpts()[jter->second]);
|
||||
wordsDescriptorsMap.push_back(fromS.getWordsDescriptors().row(jter->second));
|
||||
words3DMap.insert(*jter);
|
||||
wordsMap.insert(*fromS.getWords().find(jter->first));
|
||||
wordsDescriptorsMap.insert(*fromS.getWordsDescriptors().find(jter->first));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2821,23 +2820,21 @@ Transform Memory::computeTransform(
|
||||
for(std::multimap<int, Link>::const_iterator iter=links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
int id = iter->first;
|
||||
if(id != fromS.id() && iter->second.type() == Link::kNeighbor) // assemble only neighbors for the local feature map
|
||||
if(id != fromS.id())
|
||||
{
|
||||
const Signature * s = this->getSignature(id);
|
||||
if(s && !s->getWords3().empty())
|
||||
if(s)
|
||||
{
|
||||
const std::map<int, int> & wordsTo = uMultimapToMapUnique(s->getWords());
|
||||
for(std::map<int, int>::const_iterator jter=wordsTo.begin(); jter!=wordsTo.end(); ++jter)
|
||||
const std::map<int, cv::Point3f> & words3 = uMultimapToMapUnique(s->getWords3());
|
||||
for(std::map<int, cv::Point3f>::const_iterator jter=words3.begin(); jter!=words3.end(); ++jter)
|
||||
{
|
||||
const cv::Point3f & pt = s->getWords3()[jter->second];
|
||||
if( jter->first > 0 &&
|
||||
util3d::isFinite(pt) &&
|
||||
words.find(jter->first) == words.end())
|
||||
util3d::isFinite(jter->second) &&
|
||||
words3DMap.find(jter->first) == words3DMap.end())
|
||||
{
|
||||
words.insert(words.end(), std::make_pair(jter->first, words.size()));
|
||||
words3DMap.push_back(util3d::transformPoint(pt, iter->second.transform()));
|
||||
wordsMap.push_back(s->getWordsKpts()[jter->second]);
|
||||
wordsDescriptorsMap.push_back(s->getWordsDescriptors().row(jter->second));
|
||||
words3DMap.insert(std::make_pair(jter->first, util3d::transformPoint(jter->second, iter->second.transform())));
|
||||
wordsMap.insert(*s->getWords().find(jter->first));
|
||||
wordsDescriptorsMap.insert(*s->getWordsDescriptors().find(jter->first));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2845,29 +2842,24 @@ Transform Memory::computeTransform(
|
||||
}
|
||||
UDEBUG("words3DMap=%d", (int)words3DMap.size());
|
||||
Signature tmpFrom2(fromS.id());
|
||||
tmpFrom2.setWords(words, wordsMap, words3DMap, wordsDescriptorsMap);
|
||||
tmpFrom2.setWords3(words3DMap);
|
||||
tmpFrom2.setWords(wordsMap);
|
||||
tmpFrom2.setWordsDescriptors(wordsDescriptorsMap);
|
||||
|
||||
transform = _registrationPipeline->computeTransformationMod(tmpFrom2, tmpTo, guess, info);
|
||||
|
||||
if(!transform.isNull() && info && !tmpFrom2.getWords3().empty())
|
||||
if(!transform.isNull() && info)
|
||||
{
|
||||
std::map<int, cv::Point3f> points3DMap;
|
||||
std::map<int, int> wordsMap = uMultimapToMapUnique(tmpFrom2.getWords());
|
||||
for(std::map<int, int>::iterator iter=wordsMap.begin(); iter!=wordsMap.end(); ++iter)
|
||||
{
|
||||
points3DMap.insert(std::make_pair(iter->first, tmpFrom2.getWords3()[iter->second]));
|
||||
}
|
||||
std::map<int, cv::Point3f> points3DMap = uMultimapToMapUnique(tmpFrom2.getWords3());
|
||||
std::map<int, Transform> bundlePoses;
|
||||
std::multimap<int, Link> bundleLinks;
|
||||
std::map<int, CameraModel> bundleModels;
|
||||
std::map<int, std::map<int, FeatureBA> > wordReferences;
|
||||
|
||||
std::multimap<int, Link> links = fromS.getLinks();
|
||||
links = graph::filterLinks(links, Link::kNeighbor, true); // assemble only neighbors for the local feature map
|
||||
links.insert(std::make_pair(toS.id(), Link(fromS.id(), toS.id(), Link::kGlobalClosure, transform, info->covariance.inv())));
|
||||
links.insert(std::make_pair(fromS.id(), Link()));
|
||||
|
||||
int totalWordReferences = 0;
|
||||
for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
int id = iter->first;
|
||||
@@ -2920,41 +2912,33 @@ Transform Memory::computeTransform(
|
||||
bundlePoses.insert(std::make_pair(id, iter->second.transform()));
|
||||
}
|
||||
|
||||
const std::map<int,int> & words = uMultimapToMapUnique(s->getWords());
|
||||
for(std::map<int, int>::const_iterator jter=words.begin(); jter!=words.end(); ++jter)
|
||||
const std::map<int,cv::KeyPoint> & words = uMultimapToMapUnique(s->getWords());
|
||||
for(std::map<int, cv::KeyPoint>::const_iterator jter=words.begin(); jter!=words.end(); ++jter)
|
||||
{
|
||||
if(points3DMap.find(jter->first)!=points3DMap.end() &&
|
||||
(id == tmpTo.id() || jter->first > 0)) // Since we added negative words of "from", only accept matches with current frame
|
||||
(id == tmpTo.id() || jter->first > 0))
|
||||
{
|
||||
//get depth
|
||||
float d = 0.0f;
|
||||
if( !s->getWords3().empty() &&
|
||||
util3d::isFinite(s->getWords3()[jter->second]))
|
||||
{
|
||||
//move back point in camera frame (to get depth along z)
|
||||
d = util3d::transformPoint(s->getWords3()[jter->second], invLocalTransform).z;
|
||||
}
|
||||
std::multimap<int, cv::Point3f>::const_iterator kter = s->getWords3().find(jter->first);
|
||||
cv::Point3f pt3d = util3d::transformPoint(kter->second, invLocalTransform);
|
||||
wordReferences.insert(std::make_pair(jter->first, std::map<int, FeatureBA>()));
|
||||
wordReferences.at(jter->first).insert(std::make_pair(id, FeatureBA(s->getWordsKpts()[jter->second], d)));
|
||||
++totalWordReferences;
|
||||
wordReferences.at(jter->first).insert(std::make_pair(id, FeatureBA(jter->second, pt3d.z)));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UDEBUG("sba...start");
|
||||
// set root negative to fix all other poses
|
||||
std::set<int> sbaOutliers;
|
||||
UTimer bundleTimer;
|
||||
OptimizerG2O sba(parameters_);
|
||||
OptimizerG2O sba;
|
||||
sba.setIterations(5);
|
||||
UTimer bundleTime;
|
||||
bundlePoses = sba.optimizeBA(-toS.id(), bundlePoses, bundleLinks, bundleModels, points3DMap, wordReferences, &sbaOutliers);
|
||||
UDEBUG("sba...end");
|
||||
|
||||
UDEBUG("bundleTime=%fs (poses=%d wordRef=%d outliers=%d)", bundleTime.ticks(), (int)bundlePoses.size(), totalWordReferences, (int)sbaOutliers.size());
|
||||
UDEBUG("bundleTime=%fs (poses=%d wordRef=%d outliers=%d)", bundleTime.ticks(), (int)bundlePoses.size(), (int)wordReferences.size(), (int)sbaOutliers.size());
|
||||
|
||||
UDEBUG("Local Bundle Adjustment Before: %s", transform.prettyPrint().c_str());
|
||||
if(!bundlePoses.rbegin()->second.isNull())
|
||||
@@ -2996,6 +2980,36 @@ Transform Memory::computeTransform(
|
||||
{
|
||||
transform = _registrationPipeline->computeTransformationMod(tmpFrom, tmpTo, guess, info);
|
||||
}
|
||||
|
||||
if(!transform.isNull() &&
|
||||
fromS.sensorData().cameraModels().size()<=1 &&
|
||||
toS.sensorData().cameraModels().size()<=1)
|
||||
{
|
||||
UDEBUG("");
|
||||
// verify if it is a 180 degree transform, well verify > 90
|
||||
float x,y,z, roll,pitch,yaw;
|
||||
if(guess.isNull())
|
||||
{
|
||||
transform.getTranslationAndEulerAngles(x,y,z, roll,pitch,yaw);
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform guessError = guess.inverse() * transform;
|
||||
guessError.getTranslationAndEulerAngles(x,y,z, roll,pitch,yaw);
|
||||
}
|
||||
if(fabs(pitch) > CV_PI/2 ||
|
||||
fabs(yaw) > CV_PI/2)
|
||||
{
|
||||
transform.setNull();
|
||||
std::string msg = uFormat("Too large rotation detected! (pitch=%f, yaw=%f) max is %f",
|
||||
roll, pitch, yaw, CV_PI/2);
|
||||
UINFO(msg.c_str());
|
||||
if(info)
|
||||
{
|
||||
info->rejectedMsg = msg;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return transform;
|
||||
}
|
||||
@@ -3422,25 +3436,21 @@ void Memory::dumpSignatures(const char * fileNameSign, bool words3D) const
|
||||
{
|
||||
if(words3D)
|
||||
{
|
||||
if(!ss->getWords3().empty())
|
||||
const std::multimap<int, cv::Point3f> & ref = ss->getWords3();
|
||||
for(std::multimap<int, cv::Point3f>::const_iterator jter=ref.begin(); jter!=ref.end(); ++jter)
|
||||
{
|
||||
const std::multimap<int, int> & ref = ss->getWords();
|
||||
for(std::multimap<int, int>::const_iterator jter=ref.begin(); jter!=ref.end(); ++jter)
|
||||
//show only valid point according to current parameters
|
||||
if(pcl::isFinite(jter->second) &&
|
||||
(jter->second.x != 0 || jter->second.y != 0 || jter->second.z != 0))
|
||||
{
|
||||
const cv::Point3f & pt = ss->getWords3()[jter->second];
|
||||
//show only valid point according to current parameters
|
||||
if(pcl::isFinite(pt) &&
|
||||
(pt.x != 0 || pt.y != 0 || pt.z != 0))
|
||||
{
|
||||
fprintf(foutSign, "%d ", (*jter).first);
|
||||
}
|
||||
fprintf(foutSign, "%d ", (*jter).first);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
const std::multimap<int, int> & ref = ss->getWords();
|
||||
for(std::multimap<int, int>::const_iterator jter=ref.begin(); jter!=ref.end(); ++jter)
|
||||
const std::multimap<int, cv::KeyPoint> & ref = ss->getWords();
|
||||
for(std::multimap<int, cv::KeyPoint>::const_iterator jter=ref.begin(); jter!=ref.end(); ++jter)
|
||||
{
|
||||
fprintf(foutSign, "%d ", (*jter).first);
|
||||
}
|
||||
@@ -3510,47 +3520,6 @@ void Memory::dumpMemoryTree(const char * fileNameTree) const
|
||||
|
||||
}
|
||||
|
||||
unsigned long Memory::getMemoryUsed() const
|
||||
{
|
||||
unsigned long memoryUsage = sizeof(Memory);
|
||||
memoryUsage += _signatures.size() * (sizeof(int)+sizeof(std::map<int, Signature *>::iterator)) + sizeof(std::map<int, Signature *>);
|
||||
for(std::map<int, Signature*>::const_iterator iter=_signatures.begin(); iter!=_signatures.end(); ++iter)
|
||||
{
|
||||
memoryUsage += iter->second->getMemoryUsed(true);
|
||||
}
|
||||
if(_vwd)
|
||||
{
|
||||
memoryUsage += _vwd->getMemoryUsed();
|
||||
}
|
||||
memoryUsage += _stMem.size() * (sizeof(int)+sizeof(std::set<int>::iterator)) + sizeof(std::set<int>);
|
||||
memoryUsage += _workingMem.size() * (sizeof(int)+sizeof(double)+sizeof(std::map<int, double>::iterator)) + sizeof(std::map<int, double>);
|
||||
memoryUsage += _groundTruths.size() * (sizeof(int)+sizeof(Transform)+12*sizeof(float) + sizeof(std::map<int, Transform>::iterator)) + sizeof(std::map<int, Transform>);
|
||||
memoryUsage += _labels.size() * (sizeof(int)+sizeof(std::string) + sizeof(std::map<int, std::string>::iterator)) + sizeof(std::map<int, std::string>);
|
||||
for(std::map<int, std::string>::const_iterator iter=_labels.begin(); iter!=_labels.end(); ++iter)
|
||||
{
|
||||
memoryUsage+=iter->second.size();
|
||||
}
|
||||
memoryUsage += _landmarksIndex.size() * (sizeof(int)+sizeof(std::set<int>) + sizeof(std::map<int, std::set<int> >::iterator)) + sizeof(std::map<int, std::set<int> >);
|
||||
memoryUsage += _landmarksInvertedIndex.size() * (sizeof(int)+sizeof(std::set<int>) + sizeof(std::map<int, std::set<int> >::iterator)) + sizeof(std::map<int, std::set<int> >);
|
||||
for(std::map<int, std::set<int>>::const_iterator iter=_landmarksIndex.begin(); iter!=_landmarksIndex.end(); ++iter)
|
||||
{
|
||||
memoryUsage+=iter->second.size()*(sizeof(int)+sizeof(std::set<int>::iterator)) + sizeof(std::set<int>);
|
||||
}
|
||||
for(std::map<int, std::set<int>>::const_iterator iter=_landmarksInvertedIndex.begin(); iter!=_landmarksInvertedIndex.end(); ++iter)
|
||||
{
|
||||
memoryUsage+=iter->second.size()*(sizeof(int)+sizeof(std::set<int>::iterator)) + sizeof(std::set<int>);
|
||||
}
|
||||
memoryUsage += parameters_.size()*(sizeof(std::string)*2+sizeof(ParametersMap::iterator)) + sizeof(ParametersMap);
|
||||
memoryUsage += sizeof(Feature2D) + _feature2D->getParameters().size()*(sizeof(std::string)*2+sizeof(ParametersMap::iterator)) + sizeof(ParametersMap);
|
||||
memoryUsage += sizeof(Registration);
|
||||
memoryUsage += sizeof(RegistrationIcp);
|
||||
memoryUsage += _occupancy->getMemoryUsed();
|
||||
memoryUsage += sizeof(MarkerDetector);
|
||||
memoryUsage += sizeof(DBDriver);
|
||||
|
||||
return memoryUsage;
|
||||
}
|
||||
|
||||
void Memory::rehearsal(Signature * signature, Statistics * stats)
|
||||
{
|
||||
UTimer timer;
|
||||
@@ -3660,10 +3629,6 @@ bool Memory::rehearsalMerge(int oldId, int newId)
|
||||
{
|
||||
fullMerge = newS->hasLink(oldS->id()) && newS->getLinks().begin()->second.transform().isNull();
|
||||
}
|
||||
UDEBUG("fullMerge=%s intermediateMerge=%s _idUpdatedToNewOneRehearsal=%s",
|
||||
fullMerge?"true":"false",
|
||||
intermediateMerge?"true":"false",
|
||||
_idUpdatedToNewOneRehearsal?"true":"false");
|
||||
|
||||
if(fullMerge)
|
||||
{
|
||||
@@ -3714,7 +3679,6 @@ bool Memory::rehearsalMerge(int oldId, int newId)
|
||||
{
|
||||
_lastGlobalLoopClosureId = newS->id();
|
||||
}
|
||||
oldS->setWeight(-9);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3727,9 +3691,7 @@ bool Memory::rehearsalMerge(int oldId, int newId)
|
||||
{
|
||||
_lastSignature = oldS;
|
||||
}
|
||||
newS->setWeight(-9);
|
||||
}
|
||||
UDEBUG("New weights: %d->%d %d->%d", oldS->id(), oldS->getWeight(), newS->id(), oldS->getWeight());
|
||||
|
||||
// remove location
|
||||
moveToTrash(_idUpdatedToNewOneRehearsal?oldS:newS, _notLinkedNodesKeptInDb);
|
||||
@@ -3949,10 +3911,9 @@ SensorData Memory::getNodeData(int locationId, bool images, bool scan, bool user
|
||||
}
|
||||
|
||||
void Memory::getNodeWordsAndGlobalDescriptors(int nodeId,
|
||||
std::multimap<int, int> & words,
|
||||
std::vector<cv::KeyPoint> & wordsKpts,
|
||||
std::vector<cv::Point3f> & words3,
|
||||
cv::Mat & wordsDescriptors,
|
||||
std::multimap<int, cv::KeyPoint> & words,
|
||||
std::multimap<int, cv::Point3f> & words3,
|
||||
std::multimap<int, cv::Mat> & wordsDescriptors,
|
||||
std::vector<GlobalDescriptor> & globalDescriptors) const
|
||||
{
|
||||
//UDEBUG("nodeId=%d", nodeId);
|
||||
@@ -3960,7 +3921,6 @@ void Memory::getNodeWordsAndGlobalDescriptors(int nodeId,
|
||||
if(s)
|
||||
{
|
||||
words = s->getWords();
|
||||
wordsKpts = s->getWordsKpts();
|
||||
words3 = s->getWords3();
|
||||
wordsDescriptors = s->getWordsDescriptors();
|
||||
globalDescriptors = s->sensorData().globalDescriptors();
|
||||
@@ -3976,7 +3936,6 @@ void Memory::getNodeWordsAndGlobalDescriptors(int nodeId,
|
||||
if(signatures.size())
|
||||
{
|
||||
words = signatures.front()->getWords();
|
||||
wordsKpts = signatures.front()->getWordsKpts();
|
||||
words3 = signatures.front()->getWords3();
|
||||
wordsDescriptors = signatures.front()->getWordsDescriptors();
|
||||
globalDescriptors = signatures.front()->sensorData().globalDescriptors();
|
||||
@@ -4046,7 +4005,7 @@ void Memory::copyData(const Signature * from, Signature * to)
|
||||
{
|
||||
// words 2d
|
||||
this->disableWordsRef(to->id());
|
||||
to->setWords(from->getWords(), from->getWordsKpts(), from->getWords3(), from->getWordsDescriptors());
|
||||
to->setWords(from->getWords());
|
||||
std::list<int> id;
|
||||
id.push_back(to->id());
|
||||
this->enableWordsRef(id);
|
||||
@@ -4063,6 +4022,8 @@ void Memory::copyData(const Signature * from, Signature * to)
|
||||
to->sensorData().setId(to->id());
|
||||
|
||||
to->setPose(from->getPose());
|
||||
to->setWords3(from->getWords3());
|
||||
to->setWordsDescriptors(from->getWordsDescriptors());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4258,8 +4219,6 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
|
||||
int preDecimation = 1;
|
||||
std::vector<cv::Point3f> keypoints3D;
|
||||
SensorData decimatedData;
|
||||
UDEBUG("Received kpts=%d kpts3D=%d, descriptors=%d _useOdometryFeatures=%s",
|
||||
(int)data.keypoints().size(), (int)data.keypoints3D().size(), data.descriptors().rows, _useOdometryFeatures?"true":"false");
|
||||
if(!_useOdometryFeatures ||
|
||||
data.keypoints().empty() ||
|
||||
(int)data.keypoints().size() != data.descriptors().rows ||
|
||||
@@ -4521,7 +4480,7 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
|
||||
keypoints3D[i] = data.keypoints3D()[keypoints[i].class_id];
|
||||
}
|
||||
}
|
||||
else if(useProvided3dPoints && keypoints.size() == data.keypoints3D().size())
|
||||
else if(keypoints.size() == data.keypoints3D().size())
|
||||
{
|
||||
UDEBUG("Using provided 3d points (%d)", (int)data.keypoints3D().size());
|
||||
keypoints3D = data.keypoints3D();
|
||||
@@ -4720,10 +4679,9 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
|
||||
UDEBUG("id %d is a bad signature", id);
|
||||
}
|
||||
|
||||
std::multimap<int, int> words;
|
||||
std::vector<cv::KeyPoint> wordsKpts;
|
||||
std::vector<cv::Point3f> words3D;
|
||||
cv::Mat wordsDescriptors;
|
||||
std::multimap<int, cv::KeyPoint> words;
|
||||
std::multimap<int, cv::Point3f> words3D;
|
||||
std::multimap<int, cv::Mat> wordsDescriptors;
|
||||
int words3DValid = 0;
|
||||
if(wordIds.size() > 0)
|
||||
{
|
||||
@@ -4743,12 +4701,11 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
|
||||
kpt.size *= decimationRatio;
|
||||
kpt.octave += log2value;
|
||||
}
|
||||
words.insert(std::make_pair(*iter, words.size()));
|
||||
wordsKpts.push_back(kpt);
|
||||
words.insert(std::pair<int, cv::KeyPoint>(*iter, kpt));
|
||||
|
||||
if(keypoints3D.size())
|
||||
{
|
||||
words3D.push_back(keypoints3D.at(i));
|
||||
words3D.insert(std::pair<int, cv::Point3f>(*iter, keypoints3D.at(i)));
|
||||
if(util3d::isFinite(keypoints3D.at(i)))
|
||||
{
|
||||
++words3DValid;
|
||||
@@ -4756,7 +4713,7 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
|
||||
}
|
||||
if(_rawDescriptorsKept)
|
||||
{
|
||||
wordsDescriptors.push_back(descriptors.row(i));
|
||||
wordsDescriptors.insert(std::pair<int, cv::Mat>(*iter, descriptors.row(i).clone()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -4876,32 +4833,18 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
|
||||
|
||||
Signature cpPrevious(2);
|
||||
// IDs should be unique so that registration doesn't override them
|
||||
std::map<int, int> uniqueWordsOld = uMultimapToMapUnique(previousS->getWords());
|
||||
std::vector<cv::KeyPoint> uniqueWordsKpts;
|
||||
cv::Mat uniqueWordsDescriptors;
|
||||
std::multimap<int, int> uniqueWords;
|
||||
for(std::map<int, int>::iterator iter=uniqueWordsOld.begin(); iter!=uniqueWordsOld.end(); ++iter)
|
||||
{
|
||||
uniqueWords.insert(std::make_pair(iter->first, uniqueWords.size()));
|
||||
uniqueWordsKpts.push_back(previousS->getWordsKpts()[iter->second]);
|
||||
uniqueWordsDescriptors.push_back(previousS->getWordsDescriptors().row(iter->second));
|
||||
}
|
||||
std::map<int, cv::KeyPoint> uniqueWords = uMultimapToMapUnique(previousS->getWords());
|
||||
std::map<int, cv::Mat> uniqueWordsDescriptors = uMultimapToMapUnique(previousS->getWordsDescriptors());
|
||||
cpPrevious.sensorData().setCameraModels(previousS->sensorData().cameraModels());
|
||||
cpPrevious.setWords(uniqueWords, uniqueWordsKpts, std::vector<cv::Point3f>(), uniqueWordsDescriptors);
|
||||
cpPrevious.setWords(std::multimap<int, cv::KeyPoint>(uniqueWords.begin(), uniqueWords.end()));
|
||||
cpPrevious.setWordsDescriptors(std::multimap<int, cv::Mat>(uniqueWordsDescriptors.begin(), uniqueWordsDescriptors.end()));
|
||||
Signature cpCurrent(1);
|
||||
uniqueWordsOld = uMultimapToMapUnique(words);
|
||||
uniqueWordsKpts.clear();
|
||||
uniqueWordsDescriptors = cv::Mat();
|
||||
uniqueWords.clear();
|
||||
for(std::map<int, int>::iterator iter=uniqueWordsOld.begin(); iter!=uniqueWordsOld.end(); ++iter)
|
||||
{
|
||||
uniqueWords.insert(std::make_pair(iter->first, uniqueWords.size()));
|
||||
uniqueWordsKpts.push_back(wordsKpts[iter->second]);
|
||||
uniqueWordsDescriptors.push_back(wordsDescriptors.row(iter->second));
|
||||
}
|
||||
uniqueWords = uMultimapToMapUnique(words);
|
||||
uniqueWordsDescriptors = uMultimapToMapUnique(wordsDescriptors);
|
||||
cpCurrent.sensorData().setCameraModels(cameraModels);
|
||||
// This will force comparing descriptors between both images directly
|
||||
cpCurrent.setWords(uniqueWords, uniqueWordsKpts, std::vector<cv::Point3f>(), uniqueWordsDescriptors);
|
||||
cpCurrent.setWords(std::multimap<int, cv::KeyPoint>(uniqueWords.begin(), uniqueWords.end()));
|
||||
cpCurrent.setWordsDescriptors(std::multimap<int, cv::Mat>(uniqueWordsDescriptors.begin(), uniqueWordsDescriptors.end()));
|
||||
|
||||
// The following is used only to re-estimate the correspondences, the returned transform is ignored
|
||||
Transform tmpt;
|
||||
@@ -4919,21 +4862,9 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
|
||||
UDEBUG("t=%s", tmpt.prettyPrint().c_str());
|
||||
|
||||
// compute 3D words by epipolar geometry with the previous signature using odometry motion
|
||||
std::map<int, int> currentUniqueWords = uMultimapToMapUnique(cpCurrent.getWords());
|
||||
std::map<int, int> previousUniqueWords = uMultimapToMapUnique(cpPrevious.getWords());
|
||||
std::map<int, cv::KeyPoint> currentWords;
|
||||
std::map<int, cv::KeyPoint> previousWords;
|
||||
for(std::map<int, int>::iterator iter=currentUniqueWords.begin(); iter!=currentUniqueWords.end(); ++iter)
|
||||
{
|
||||
currentWords.insert(std::make_pair(iter->first, cpCurrent.getWordsKpts()[iter->second]));
|
||||
}
|
||||
for(std::map<int, int>::iterator iter=previousUniqueWords.begin(); iter!=previousUniqueWords.end(); ++iter)
|
||||
{
|
||||
previousWords.insert(std::make_pair(iter->first, cpPrevious.getWordsKpts()[iter->second]));
|
||||
}
|
||||
std::map<int, cv::Point3f> inliers = util3d::generateWords3DMono(
|
||||
currentWords,
|
||||
previousWords,
|
||||
uMultimapToMapUnique(cpCurrent.getWords()),
|
||||
uMultimapToMapUnique(cpPrevious.getWords()),
|
||||
cameraModels[0],
|
||||
cameraTransform);
|
||||
|
||||
@@ -4944,26 +4875,32 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
|
||||
UASSERT(words3D.size() == 0 || words.size() == words3D.size());
|
||||
bool words3DWasEmpty = words3D.empty();
|
||||
int added3DPointsWithoutDepth = 0;
|
||||
for(std::multimap<int, int>::const_iterator iter=words.begin(); iter!=words.end(); ++iter)
|
||||
for(std::multimap<int, cv::KeyPoint>::const_iterator iter=words.begin(); iter!=words.end(); ++iter)
|
||||
{
|
||||
std::map<int, cv::Point3f>::iterator jter=inliers.find(iter->first);
|
||||
if(words3DWasEmpty)
|
||||
std::multimap<int, cv::Point3f>::iterator iter3D = words3D.find(iter->first);
|
||||
if(iter3D == words3D.end())
|
||||
{
|
||||
if(jter != inliers.end())
|
||||
{
|
||||
words3D.push_back(jter->second);
|
||||
words3D.insert(std::make_pair(iter->first, jter->second));
|
||||
++added3DPointsWithoutDepth;
|
||||
}
|
||||
else
|
||||
{
|
||||
words3D.push_back(cv::Point3f(bad_point,bad_point,bad_point));
|
||||
words3D.insert(std::make_pair(iter->first, cv::Point3f(bad_point,bad_point,bad_point)));
|
||||
}
|
||||
}
|
||||
else if(!util3d::isFinite(words3D[iter->second]) && jter != inliers.end())
|
||||
else if(!util3d::isFinite(iter3D->second) && jter != inliers.end())
|
||||
{
|
||||
words3D[iter->second] = jter->second;
|
||||
iter3D->second = jter->second;
|
||||
++added3DPointsWithoutDepth;
|
||||
}
|
||||
else if(words3DWasEmpty && jter == inliers.end())
|
||||
{
|
||||
// duplicate
|
||||
words3D.insert(std::make_pair(iter->first, cv::Point3f(bad_point,bad_point,bad_point)));
|
||||
}
|
||||
}
|
||||
UDEBUG("added3DPointsWithoutDepth=%d", added3DPointsWithoutDepth);
|
||||
if(stats) stats->addStatistic(Statistics::kMemoryTriangulated_points(), (float)added3DPointsWithoutDepth);
|
||||
@@ -5216,7 +5153,9 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
|
||||
compressedUserData));
|
||||
}
|
||||
|
||||
s->setWords(words, wordsKpts, words3D, wordsDescriptors);
|
||||
s->setWords(words);
|
||||
s->setWords3(words3D);
|
||||
s->setWordsDescriptors(wordsDescriptors);
|
||||
|
||||
// set raw data
|
||||
if(!cameraModels.empty())
|
||||
@@ -5283,22 +5222,16 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
|
||||
}
|
||||
else if(data.gps().stamp() > 0.0)
|
||||
{
|
||||
if(uIsFinite(data.gps().altitude()) &&
|
||||
uIsFinite(data.gps().latitude()) &&
|
||||
uIsFinite(data.gps().longitude()) &&
|
||||
uIsFinite(data.gps().bearing()) &&
|
||||
uIsFinite(data.gps().error()) &&
|
||||
data.gps().error() > 0.0)
|
||||
if(_gpsOrigin.stamp() <= 0.0)
|
||||
{
|
||||
_gpsOrigin = data.gps();
|
||||
UINFO("Added GPS origin: long=%f lat=%f alt=%f bearing=%f error=%f", data.gps().longitude(), data.gps().latitude(), data.gps().altitude(), data.gps().bearing(), data.gps().error());
|
||||
}
|
||||
cv::Point3f pt = data.gps().toGeodeticCoords().toENU_WGS84(_gpsOrigin.toGeodeticCoords());
|
||||
Transform gpsPose(pt.x, pt.y, pose.z(), 0, 0, -(data.gps().bearing()-90.0)*180.0/M_PI);
|
||||
cv::Mat gpsInfMatrix = cv::Mat::eye(6,6,CV_64FC1)/9999.0; // variance not used >= 9999
|
||||
if(data.gps().error() > 0.0)
|
||||
{
|
||||
if(_gpsOrigin.stamp() <= 0.0)
|
||||
{
|
||||
_gpsOrigin = data.gps();
|
||||
UINFO("Added GPS origin: long=%f lat=%f alt=%f bearing=%f error=%f", data.gps().longitude(), data.gps().latitude(), data.gps().altitude(), data.gps().bearing(), data.gps().error());
|
||||
}
|
||||
cv::Point3f pt = data.gps().toGeodeticCoords().toENU_WGS84(_gpsOrigin.toGeodeticCoords());
|
||||
Transform gpsPose(pt.x, pt.y, pose.z(), 0, 0, -(data.gps().bearing()-90.0)*180.0/M_PI);
|
||||
cv::Mat gpsInfMatrix = cv::Mat::eye(6,6,CV_64FC1)/9999.0; // variance not used >= 9999
|
||||
|
||||
UDEBUG("Added GPS prior: x=%f y=%f z=%f yaw=%f", gpsPose.x(), gpsPose.y(), gpsPose.z(), gpsPose.theta());
|
||||
// only set x, y as we don't know variance for other degrees of freedom.
|
||||
gpsInfMatrix.at<double>(0,0) = gpsInfMatrix.at<double>(1,1) = 1.0/data.gps().error();
|
||||
@@ -5307,7 +5240,7 @@ Signature * Memory::createSignature(const SensorData & inputData, const Transfor
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Invalid GPS value: long=%f lat=%f alt=%f bearing=%f error=%f", data.gps().longitude(), data.gps().latitude(), data.gps().altitude(), data.gps().bearing(), data.gps().error());
|
||||
UERROR("Invalid GPS error value (%f m), must be > 0 m.", data.gps().error());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5381,7 +5314,7 @@ void Memory::disableWordsRef(int signatureId)
|
||||
Signature * ss = this->_getSignature(signatureId);
|
||||
if(ss && ss->isEnabled())
|
||||
{
|
||||
const std::multimap<int, int> & words = ss->getWords();
|
||||
const std::multimap<int, cv::KeyPoint> & words = ss->getWords();
|
||||
const std::list<int> & keys = uUniqueKeys(words);
|
||||
int count = _vwd->getTotalActiveReferences();
|
||||
// First remove all references
|
||||
|
||||
@@ -1532,36 +1532,4 @@ bool OccupancyGrid::update(const std::map<int, Transform> & posesIn)
|
||||
return updated;
|
||||
}
|
||||
|
||||
unsigned long OccupancyGrid::getMemoryUsed() const
|
||||
{
|
||||
unsigned long memoryUsage = sizeof(OccupancyGrid);
|
||||
memoryUsage += parameters_.size()*(sizeof(std::string)*2+sizeof(ParametersMap::iterator)) + sizeof(ParametersMap);
|
||||
|
||||
memoryUsage += cache_.size()*(sizeof(int) + sizeof(std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat>) + sizeof(std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::iterator)) + sizeof(std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >);
|
||||
for(std::map<int, std::pair<std::pair<cv::Mat, cv::Mat>, cv::Mat> >::const_iterator iter=cache_.begin(); iter!=cache_.end(); ++iter)
|
||||
{
|
||||
memoryUsage += iter->second.first.first.total() * iter->second.first.first.elemSize();
|
||||
memoryUsage += iter->second.first.second.total() * iter->second.first.second.elemSize();
|
||||
memoryUsage += iter->second.second.total() * iter->second.second.elemSize();
|
||||
}
|
||||
memoryUsage += map_.total() * map_.elemSize();
|
||||
memoryUsage += mapInfo_.total() * mapInfo_.elemSize();
|
||||
memoryUsage += cellCount_.size()*(sizeof(int)*3 + sizeof(std::pair<int, int>) + sizeof(std::map<int, std::pair<int, int> >::iterator)) + sizeof(std::map<int, std::pair<int, int> >);
|
||||
memoryUsage += addedNodes_.size()*(sizeof(int) + sizeof(Transform)+ sizeof(float)*12 + sizeof(std::map<int, Transform>::iterator)) + sizeof(std::map<int, Transform>);
|
||||
|
||||
if(assembledGround_.get())
|
||||
{
|
||||
memoryUsage += assembledGround_->points.size() * sizeof(pcl::PointXYZRGB);
|
||||
}
|
||||
if(assembledObstacles_.get())
|
||||
{
|
||||
memoryUsage += assembledObstacles_->points.size() * sizeof(pcl::PointXYZRGB);
|
||||
}
|
||||
if(assembledEmptyCells_.get())
|
||||
{
|
||||
memoryUsage += assembledEmptyCells_->points.size() * sizeof(pcl::PointXYZRGB);
|
||||
}
|
||||
return memoryUsage;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+50
-2
@@ -32,7 +32,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <rtabmap/core/util3d_transforms.h>
|
||||
#include <rtabmap/core/util3d_filtering.h>
|
||||
#include <rtabmap/core/util3d_mapping.h>
|
||||
#include <rtabmap/core/util2d.h>
|
||||
#include <pcl/common/transforms.h>
|
||||
|
||||
namespace rtabmap {
|
||||
@@ -887,6 +886,55 @@ void OctoMap::updateMinMax(const octomap::point3d & point)
|
||||
}
|
||||
}
|
||||
|
||||
void OctoMap::HSVtoRGB( float *r, float *g, float *b, float h, float s, float v )
|
||||
{
|
||||
int i;
|
||||
float f, p, q, t;
|
||||
if( s == 0 ) {
|
||||
// achromatic (grey)
|
||||
*r = *g = *b = v;
|
||||
return;
|
||||
}
|
||||
h /= 60; // sector 0 to 5
|
||||
i = floor( h );
|
||||
f = h - i; // factorial part of h
|
||||
p = v * ( 1 - s );
|
||||
q = v * ( 1 - s * f );
|
||||
t = v * ( 1 - s * ( 1 - f ) );
|
||||
switch( i ) {
|
||||
case 0:
|
||||
*r = v;
|
||||
*g = t;
|
||||
*b = p;
|
||||
break;
|
||||
case 1:
|
||||
*r = q;
|
||||
*g = v;
|
||||
*b = p;
|
||||
break;
|
||||
case 2:
|
||||
*r = p;
|
||||
*g = v;
|
||||
*b = t;
|
||||
break;
|
||||
case 3:
|
||||
*r = p;
|
||||
*g = q;
|
||||
*b = v;
|
||||
break;
|
||||
case 4:
|
||||
*r = t;
|
||||
*g = p;
|
||||
*b = v;
|
||||
break;
|
||||
default: // case 5:
|
||||
*r = v;
|
||||
*g = p;
|
||||
*b = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pcl::PointCloud<pcl::PointXYZRGB>::Ptr OctoMap::createCloud(
|
||||
unsigned int treeDepth,
|
||||
std::vector<int> * obstacleIndices,
|
||||
@@ -955,7 +1003,7 @@ pcl::PointCloud<pcl::PointXYZRGB>::Ptr OctoMap::createCloud(
|
||||
// Gradiant color on z axis
|
||||
float H = (maxZ - pt.z())*299.0f/(maxZ-minZ);
|
||||
float r,g,b;
|
||||
util2d::HSVtoRGB(&r, &g, &b, H, 1, 1);
|
||||
HSVtoRGB(&r, &g, &b, H, 1, 1);
|
||||
(*cloud)[oi].r = r*255.0f;
|
||||
(*cloud)[oi].g = g*255.0f;
|
||||
(*cloud)[oi].b = b*255.0f;
|
||||
|
||||
@@ -308,11 +308,8 @@ Transform Odometry::process(SensorData & data, const Transform & guessIn, Odomet
|
||||
}
|
||||
if(stereoModel_.isRectificationMapInitialized())
|
||||
{
|
||||
data.setStereoImage(
|
||||
stereoModel_.left().rectifyImage(data.imageRaw()),
|
||||
stereoModel_.right().rectifyImage(data.rightRaw()),
|
||||
stereoModel_,
|
||||
false);
|
||||
data.setImageRaw(stereoModel_.left().rectifyImage(data.imageRaw()));
|
||||
data.setDepthOrRightRaw(stereoModel_.right().rectifyImage(data.rightRaw()));
|
||||
}
|
||||
}
|
||||
else
|
||||
|
||||
+45
-35
@@ -101,16 +101,16 @@ Optimizer * Optimizer::create(Optimizer::Type type, const ParametersMap & parame
|
||||
}
|
||||
if(!OptimizerG2O::available() && type == Optimizer::kTypeG2O)
|
||||
{
|
||||
if(OptimizerGTSAM::available())
|
||||
{
|
||||
UWARN("g2o optimizer not available. GTSAM will be used instead.");
|
||||
type = Optimizer::kTypeGTSAM;
|
||||
}
|
||||
else if(OptimizerTORO::available())
|
||||
if(OptimizerTORO::available())
|
||||
{
|
||||
UWARN("g2o optimizer not available. TORO will be used instead.");
|
||||
type = Optimizer::kTypeTORO;
|
||||
}
|
||||
else if(OptimizerGTSAM::available())
|
||||
{
|
||||
UWARN("g2o optimizer not available. GTSAM will be used instead.");
|
||||
type = Optimizer::kTypeGTSAM;
|
||||
}
|
||||
else if(OptimizerCeres::available())
|
||||
{
|
||||
UWARN("g2o optimizer not available. ceres will be used instead.");
|
||||
@@ -119,16 +119,16 @@ Optimizer * Optimizer::create(Optimizer::Type type, const ParametersMap & parame
|
||||
}
|
||||
if(!OptimizerGTSAM::available() && type == Optimizer::kTypeGTSAM)
|
||||
{
|
||||
if(OptimizerG2O::available())
|
||||
{
|
||||
UWARN("GTSAM optimizer not available. g2o will be used instead.");
|
||||
type = Optimizer::kTypeG2O;
|
||||
}
|
||||
else if(OptimizerTORO::available())
|
||||
if(OptimizerTORO::available())
|
||||
{
|
||||
UWARN("GTSAM optimizer not available. TORO will be used instead.");
|
||||
type = Optimizer::kTypeTORO;
|
||||
}
|
||||
else if(OptimizerG2O::available())
|
||||
{
|
||||
UWARN("GTSAM optimizer not available. g2o will be used instead.");
|
||||
type = Optimizer::kTypeG2O;
|
||||
}
|
||||
else if(OptimizerCeres::available())
|
||||
{
|
||||
UWARN("GTSAM optimizer not available. ceres will be used instead.");
|
||||
@@ -137,11 +137,26 @@ Optimizer * Optimizer::create(Optimizer::Type type, const ParametersMap & parame
|
||||
}
|
||||
if(!OptimizerCVSBA::available() && type == Optimizer::kTypeCVSBA)
|
||||
{
|
||||
if(OptimizerG2O::available())
|
||||
if(OptimizerTORO::available())
|
||||
{
|
||||
UWARN("CVSBA optimizer not available. TORO will be used instead.");
|
||||
type = Optimizer::kTypeTORO;
|
||||
}
|
||||
else if(OptimizerGTSAM::available())
|
||||
{
|
||||
UWARN("CVSBA optimizer not available. GTSAM will be used instead.");
|
||||
type = Optimizer::kTypeGTSAM;
|
||||
}
|
||||
else if(OptimizerG2O::available())
|
||||
{
|
||||
UWARN("CVSBA optimizer not available. g2o will be used instead.");
|
||||
type = Optimizer::kTypeG2O;
|
||||
}
|
||||
else if(OptimizerCeres::available())
|
||||
{
|
||||
UWARN("CVSBA optimizer not available. ceres will be used instead.");
|
||||
type = Optimizer::kTypeCeres;
|
||||
}
|
||||
}
|
||||
if(!OptimizerCeres::available() && type == Optimizer::kTypeCeres)
|
||||
{
|
||||
@@ -602,8 +617,8 @@ void Optimizer::computeBACorrespondences(
|
||||
|
||||
if(!rematchFeatures)
|
||||
{
|
||||
sFrom.setWordsDescriptors(cv::Mat());
|
||||
sTo.setWordsDescriptors(cv::Mat());
|
||||
sFrom.setWordsDescriptors(std::multimap<int, cv::Mat>());
|
||||
sTo.setWordsDescriptors(std::multimap<int, cv::Mat>());
|
||||
}
|
||||
|
||||
RegistrationInfo info;
|
||||
@@ -618,13 +633,13 @@ void Optimizer::computeBACorrespondences(
|
||||
// set descriptors for the output
|
||||
if(sFrom.getWords().size() &&
|
||||
sFrom.getWordsDescriptors().empty() &&
|
||||
(int)sFrom.getWords().size() == signatures.at(link.from()).getWordsDescriptors().rows)
|
||||
sFrom.getWords().size() == signatures.at(link.from()).getWordsDescriptors().size())
|
||||
{
|
||||
sFrom.setWordsDescriptors(signatures.at(link.from()).getWordsDescriptors());
|
||||
}
|
||||
if(sTo.getWords().size() &&
|
||||
sTo.getWordsDescriptors().empty() &&
|
||||
(int)sTo.getWords().size() == signatures.at(link.to()).getWordsDescriptors().rows)
|
||||
sTo.getWords().size() == signatures.at(link.to()).getWordsDescriptors().size())
|
||||
{
|
||||
sTo.setWordsDescriptors(signatures.at(link.to()).getWordsDescriptors());
|
||||
}
|
||||
@@ -634,13 +649,11 @@ void Optimizer::computeBACorrespondences(
|
||||
UASSERT(!pose.isNull());
|
||||
for(unsigned int i=0; i<info.inliersIDs.size(); ++i)
|
||||
{
|
||||
int indexFrom = sFrom.getWords().lower_bound(info.inliersIDs[i])->second;
|
||||
cv::Point3f p = sFrom.getWords3()[indexFrom];
|
||||
cv::Point3f p = sFrom.getWords3().lower_bound(info.inliersIDs[i])->second;
|
||||
if(p.x > 0.0f) // make sure the point is valid
|
||||
{
|
||||
cv::KeyPoint ptFrom = sFrom.getWordsKpts()[indexFrom];
|
||||
int indexTo = sTo.getWords().lower_bound(info.inliersIDs[i])->second;
|
||||
cv::KeyPoint ptTo = sTo.getWordsKpts()[indexTo];
|
||||
cv::KeyPoint ptFrom = sFrom.getWords().lower_bound(info.inliersIDs[i])->second;
|
||||
cv::KeyPoint ptTo = sTo.getWords().lower_bound(info.inliersIDs[i])->second;
|
||||
|
||||
int wordId = -1;
|
||||
|
||||
@@ -679,10 +692,10 @@ void Optimizer::computeBACorrespondences(
|
||||
if(!fromAlreadyAdded)
|
||||
{
|
||||
cv::Mat descriptorFrom;
|
||||
if(!sFrom.getWordsDescriptors().empty())
|
||||
if(sFrom.getWordsDescriptors().size())
|
||||
{
|
||||
UASSERT(indexFrom < sFrom.getWordsDescriptors().rows);
|
||||
descriptorFrom = sFrom.getWordsDescriptors().row(indexFrom);
|
||||
UASSERT(sFrom.getWordsDescriptors().find(info.inliersIDs[i]) != sFrom.getWordsDescriptors().end());
|
||||
descriptorFrom = sFrom.getWordsDescriptors().lower_bound(info.inliersIDs[i])->second;
|
||||
}
|
||||
wordReferences.at(wordId).insert(std::make_pair(sFrom.id(), FeatureBA(ptFrom, p.x, descriptorFrom)));
|
||||
frameToWordMap.insert(std::make_pair(sFrom.id(), std::map<cv::KeyPoint, int, KeyPointCompare>()));
|
||||
@@ -692,20 +705,17 @@ void Optimizer::computeBACorrespondences(
|
||||
if(!toAlreadyAdded)
|
||||
{
|
||||
cv::Mat descriptorTo;
|
||||
if(!sTo.getWordsDescriptors().empty())
|
||||
if(sTo.getWordsDescriptors().size())
|
||||
{
|
||||
UASSERT(indexTo < sTo.getWordsDescriptors().rows);
|
||||
descriptorTo = sTo.getWordsDescriptors().row(indexTo);
|
||||
UASSERT(sTo.getWordsDescriptors().find(info.inliersIDs[i]) != sTo.getWordsDescriptors().end());
|
||||
descriptorTo = sTo.getWordsDescriptors().lower_bound(info.inliersIDs[i])->second;
|
||||
}
|
||||
float depth = 0.0f;
|
||||
if(!sTo.getWords3().empty())
|
||||
std::multimap<int, cv::Point3f>::const_iterator iterTo = sTo.getWords3().lower_bound(info.inliersIDs[i]);
|
||||
if( iterTo!=sTo.getWords3().end() &&
|
||||
iterTo->second.x > 0)
|
||||
{
|
||||
UASSERT(indexTo < (int)sTo.getWords3().size());
|
||||
const cv::Point3f & pt = sTo.getWords3()[indexTo];
|
||||
if( pt.x > 0)
|
||||
{
|
||||
depth = pt.x;
|
||||
}
|
||||
depth = iterTo->second.x;
|
||||
}
|
||||
wordReferences.at(wordId).insert(std::make_pair(sTo.id(), FeatureBA(ptTo, depth, descriptorTo)));
|
||||
frameToWordMap.insert(std::make_pair(sTo.id(), std::map<cv::KeyPoint, int, KeyPointCompare>()));
|
||||
|
||||
@@ -706,12 +706,6 @@ ParametersMap Parameters::parseArguments(int argc, char * argv[], bool onlyParam
|
||||
std::cout << str << std::setw(spacing - str.size()) << "true" << std::endl;
|
||||
#else
|
||||
std::cout << str << std::setw(spacing - str.size()) << "false" << std::endl;
|
||||
#endif
|
||||
str = "With K4A:";
|
||||
#ifdef RTABMAP_K4A
|
||||
std::cout << str << std::setw(spacing - str.size()) << "true" << std::endl;
|
||||
#else
|
||||
std::cout << str << std::setw(spacing - str.size()) << "false" << std::endl;
|
||||
#endif
|
||||
str = "With DC1394:";
|
||||
#ifdef RTABMAP_DC1394
|
||||
|
||||
@@ -133,18 +133,6 @@ bool databaseRecovery(
|
||||
*errorMsg = uFormat("Failed renaming database file from \"%s\" to \"%s\". Is it opened by another app?", UFile::getName(databasePath).c_str(), UFile::getName(backupPath).c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
bool incrementalMemory = true;
|
||||
Parameters::parse(parameters, Parameters::kMemIncrementalMemory(), incrementalMemory);
|
||||
if(!incrementalMemory)
|
||||
{
|
||||
if(progressState)
|
||||
{
|
||||
progressState->callback("Database is in localization mode, setting it to mapping mode to recover...");
|
||||
}
|
||||
uInsert(parameters, ParametersPair(Parameters::kMemIncrementalMemory(), "true"));
|
||||
}
|
||||
|
||||
Rtabmap rtabmap;
|
||||
rtabmap.init(parameters, databasePath);
|
||||
|
||||
|
||||
+101
-273
@@ -38,12 +38,10 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <rtabmap/utilite/UTimer.h>
|
||||
#include <pcl/conversions.h>
|
||||
#include <pcl/common/pca.h>
|
||||
#include <pcl/common/io.h>
|
||||
|
||||
#ifdef RTABMAP_POINTMATCHER
|
||||
#include <fstream>
|
||||
#include "pointmatcher/PointMatcher.h"
|
||||
#include "nabo/nabo.h"
|
||||
typedef PointMatcher<float> PM;
|
||||
typedef PM::DataPoints DP;
|
||||
|
||||
@@ -183,7 +181,6 @@ DP laserScanToDP(const rtabmap::LaserScan & scan)
|
||||
descLabels.push_back(Label("intensity", 1));
|
||||
}
|
||||
|
||||
|
||||
// create cloud
|
||||
DP cloud(featLabels, descLabels, scan.size());
|
||||
cloud.getFeatureViewByName("pad").setConstant(1);
|
||||
@@ -362,110 +359,6 @@ typename PointMatcher<T>::TransformationParameters eigenMatrixToDim(const typena
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
struct KDTreeMatcherIntensity : public PointMatcher<T>::Matcher
|
||||
{
|
||||
typedef PointMatcherSupport::Parametrizable Parametrizable;
|
||||
typedef PointMatcherSupport::Parametrizable P;
|
||||
typedef Parametrizable::Parameters Parameters;
|
||||
typedef Parametrizable::ParameterDoc ParameterDoc;
|
||||
typedef Parametrizable::ParametersDoc ParametersDoc;
|
||||
|
||||
typedef typename Nabo::NearestNeighbourSearch<T> NNS;
|
||||
typedef typename NNS::SearchType NNSearchType;
|
||||
|
||||
typedef typename PointMatcher<T>::DataPoints DataPoints;
|
||||
typedef typename PointMatcher<T>::Matcher Matcher;
|
||||
typedef typename PointMatcher<T>::Matches Matches;
|
||||
typedef typename PointMatcher<T>::Matrix Matrix;
|
||||
|
||||
inline static const std::string description()
|
||||
{
|
||||
return "This matcher matches a point from the reading to its closest neighbors in the reference.";
|
||||
}
|
||||
inline static const ParametersDoc availableParameters()
|
||||
{
|
||||
return {
|
||||
{"knn", "number of nearest neighbors to consider it the reference", "1", "1", "2147483647", &P::Comp<unsigned>},
|
||||
{"epsilon", "approximation to use for the nearest-neighbor search", "0", "0", "inf", &P::Comp<T>},
|
||||
{"searchType", "Nabo search type. 0: brute force, check distance to every point in the data (very slow), 1: kd-tree with linear heap, good for small knn (~up to 30) and 2: kd-tree with tree heap, good for large knn (~from 30)", "1", "0", "2", &P::Comp<unsigned>},
|
||||
{"maxDist", "maximum distance to consider for neighbors", "inf", "0", "inf", &P::Comp<T>}
|
||||
};
|
||||
}
|
||||
|
||||
const int knn;
|
||||
const T epsilon;
|
||||
const NNSearchType searchType;
|
||||
const T maxDist;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<NNS> featureNNS;
|
||||
Matrix filteredReferenceIntensity;
|
||||
|
||||
public:
|
||||
KDTreeMatcherIntensity(const Parameters& params = Parameters()) :
|
||||
PointMatcher<T>::Matcher("KDTreeMatcherIntensity", KDTreeMatcherIntensity::availableParameters(), params),
|
||||
knn(Parametrizable::get<int>("knn")),
|
||||
epsilon(Parametrizable::get<T>("epsilon")),
|
||||
searchType(NNSearchType(Parametrizable::get<int>("searchType"))),
|
||||
maxDist(Parametrizable::get<T>("maxDist"))
|
||||
{
|
||||
UINFO("* KDTreeMatcherIntensity: initialized with knn=%d, epsilon=%f, searchType=%d and maxDist=%f", knn, epsilon, searchType, maxDist);
|
||||
}
|
||||
virtual ~KDTreeMatcherIntensity() {}
|
||||
virtual void init(const DataPoints& filteredReference)
|
||||
{
|
||||
// build and populate NNS
|
||||
if(knn>1)
|
||||
{
|
||||
filteredReferenceIntensity = filteredReference.getDescriptorCopyByName("intensity");
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("KDTreeMatcherIntensity: knn is not over 1 (%d), intensity re-ordering will be ignored.", knn);
|
||||
}
|
||||
featureNNS.reset( NNS::create(filteredReference.features, filteredReference.features.rows() - 1, searchType, NNS::TOUCH_STATISTICS));
|
||||
}
|
||||
virtual PM::Matches findClosests(const DP& filteredReading)
|
||||
{
|
||||
const int pointsCount(filteredReading.features.cols());
|
||||
Matches matches(
|
||||
typename Matches::Dists(knn, pointsCount),
|
||||
typename Matches::Ids(knn, pointsCount)
|
||||
);
|
||||
|
||||
const BOOST_AUTO(filteredReadingIntensity, filteredReading.getDescriptorViewByName("intensity"));
|
||||
|
||||
static_assert(NNS::InvalidIndex == PM::Matches::InvalidId, "");
|
||||
static_assert(NNS::InvalidValue == PM::Matches::InvalidDist, "");
|
||||
this->visitCounter += featureNNS->knn(filteredReading.features, matches.ids, matches.dists, knn, epsilon, NNS::ALLOW_SELF_MATCH, maxDist);
|
||||
|
||||
if(knn > 1)
|
||||
{
|
||||
Matches matchesOrderedByIntensity(
|
||||
typename Matches::Dists(1, pointsCount),
|
||||
typename Matches::Ids(1, pointsCount)
|
||||
);
|
||||
#pragma omp parallel for
|
||||
for (int i = 0; i < pointsCount; ++i)
|
||||
{
|
||||
float minDistance = std::numeric_limits<float>::max();
|
||||
for(int k=0; k<knn && k<filteredReferenceIntensity.rows(); ++k)
|
||||
{
|
||||
float distIntensity = fabs(filteredReadingIntensity(0,i) - filteredReferenceIntensity(0, matches.ids.coeff(k, i)));
|
||||
if(distIntensity < minDistance)
|
||||
{
|
||||
matchesOrderedByIntensity.ids.coeffRef(0, i) = matches.ids.coeff(k, i);
|
||||
matchesOrderedByIntensity.dists.coeffRef(0, i) = matches.dists.coeff(k, i);
|
||||
minDistance = distIntensity;
|
||||
}
|
||||
}
|
||||
}
|
||||
matches = matchesOrderedByIntensity;
|
||||
}
|
||||
return matches;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace rtabmap {
|
||||
@@ -485,14 +378,11 @@ RegistrationIcp::RegistrationIcp(const ParametersMap & parameters, Registration
|
||||
_pointToPlane(Parameters::defaultIcpPointToPlane()),
|
||||
_pointToPlaneK(Parameters::defaultIcpPointToPlaneK()),
|
||||
_pointToPlaneRadius(Parameters::defaultIcpPointToPlaneRadius()),
|
||||
_pointToPlaneGroundNormalsUp(Parameters::defaultIcpPointToPlaneGroundNormalsUp()),
|
||||
_pointToPlaneMinComplexity(Parameters::defaultIcpPointToPlaneMinComplexity()),
|
||||
_pointToPlaneLowComplexityStrategy(Parameters::defaultIcpPointToPlaneLowComplexityStrategy()),
|
||||
_libpointmatcher(Parameters::defaultIcpPM()),
|
||||
_libpointmatcherConfig(Parameters::defaultIcpPMConfig()),
|
||||
_libpointmatcherKnn(Parameters::defaultIcpPMMatcherKnn()),
|
||||
_libpointmatcherEpsilon(Parameters::defaultIcpPMMatcherEpsilon()),
|
||||
_libpointmatcherIntensity(Parameters::defaultIcpPMMatcherIntensity()),
|
||||
_libpointmatcherOutlierRatio(Parameters::defaultIcpPMOutlierRatio()),
|
||||
_libpointmatcherICP(0)
|
||||
{
|
||||
@@ -523,10 +413,7 @@ void RegistrationIcp::parseParameters(const ParametersMap & parameters)
|
||||
Parameters::parse(parameters, Parameters::kIcpPointToPlane(), _pointToPlane);
|
||||
Parameters::parse(parameters, Parameters::kIcpPointToPlaneK(), _pointToPlaneK);
|
||||
Parameters::parse(parameters, Parameters::kIcpPointToPlaneRadius(), _pointToPlaneRadius);
|
||||
Parameters::parse(parameters, Parameters::kIcpPointToPlaneGroundNormalsUp(), _pointToPlaneGroundNormalsUp);
|
||||
Parameters::parse(parameters, Parameters::kIcpPointToPlaneMinComplexity(), _pointToPlaneMinComplexity);
|
||||
Parameters::parse(parameters, Parameters::kIcpPointToPlaneLowComplexityStrategy(), _pointToPlaneLowComplexityStrategy);
|
||||
UASSERT(_pointToPlaneGroundNormalsUp >= 0.0f && _pointToPlaneGroundNormalsUp <= 1.0f);
|
||||
UASSERT(_pointToPlaneMinComplexity >= 0.0f && _pointToPlaneMinComplexity <= 1.0f);
|
||||
|
||||
Parameters::parse(parameters, Parameters::kIcpPM(), _libpointmatcher);
|
||||
@@ -534,7 +421,6 @@ void RegistrationIcp::parseParameters(const ParametersMap & parameters)
|
||||
Parameters::parse(parameters, Parameters::kIcpPMOutlierRatio(), _libpointmatcherOutlierRatio);
|
||||
Parameters::parse(parameters, Parameters::kIcpPMMatcherKnn(), _libpointmatcherKnn);
|
||||
Parameters::parse(parameters, Parameters::kIcpPMMatcherEpsilon(), _libpointmatcherEpsilon);
|
||||
Parameters::parse(parameters, Parameters::kIcpPMMatcherIntensity(), _libpointmatcherIntensity);
|
||||
|
||||
#ifndef RTABMAP_POINTMATCHER
|
||||
if(_libpointmatcher)
|
||||
@@ -587,19 +473,11 @@ void RegistrationIcp::parseParameters(const ParametersMap & parameters)
|
||||
params["maxDist"] = uNumber2Str(_maxCorrespondenceDistance);
|
||||
params["knn"] = uNumber2Str(_libpointmatcherKnn);
|
||||
params["epsilon"] = uNumber2Str(_libpointmatcherEpsilon);
|
||||
|
||||
if(_libpointmatcherIntensity)
|
||||
{
|
||||
icp->matcher.reset(new KDTreeMatcherIntensity<float>(params));
|
||||
}
|
||||
else
|
||||
{
|
||||
#if POINTMATCHER_VERSION_INT >= 10300
|
||||
icp->matcher = PM::get().MatcherRegistrar.create("KDTreeMatcher", params);
|
||||
icp->matcher = PM::get().MatcherRegistrar.create("KDTreeMatcher", params);
|
||||
#else
|
||||
icp->matcher.reset(PM::get().MatcherRegistrar.create("KDTreeMatcher", params));
|
||||
icp->matcher.reset(PM::get().MatcherRegistrar.create("KDTreeMatcher", params));
|
||||
#endif
|
||||
}
|
||||
params.clear();
|
||||
|
||||
params["ratio"] = uNumber2Str(_libpointmatcherOutlierRatio);
|
||||
@@ -712,7 +590,6 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
double variance = 1.0;
|
||||
bool transformComputed = false;
|
||||
bool tooLowComplexityForPlaneToPlane = false;
|
||||
float secondEigenValue = 1.0f;
|
||||
cv::Mat complexityVectors;
|
||||
|
||||
if( _pointToPlane &&
|
||||
@@ -732,29 +609,19 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
if(complexity < _pointToPlaneMinComplexity)
|
||||
{
|
||||
tooLowComplexityForPlaneToPlane = true;
|
||||
if(complexity > 0.0f)
|
||||
{
|
||||
complexityVectors = fromComplexity<toComplexity?complexityVectorsFrom:complexityVectorsTo;
|
||||
complexityVectors = fromComplexity<toComplexity?complexityVectorsFrom:complexityVectorsTo;
|
||||
|
||||
UASSERT((complexityVectors.rows == 2 && complexityVectors.cols == 2)||
|
||||
(complexityVectors.rows == 3 && complexityVectors.cols == 3));
|
||||
UWARN("ICP PointToPlane ignored as structural complexity is too low (corridor-like environment): (from=%f || to=%f) < %f (%s). "
|
||||
"PointToPoint is done instead, orientation is still optimized but translation will be limited to "
|
||||
"direction of normals (%s: %s).",
|
||||
fromComplexity, toComplexity, _pointToPlaneMinComplexity, Parameters::kIcpPointToPlaneMinComplexity().c_str(),
|
||||
fromComplexity<toComplexity?"From":"To",
|
||||
complexityVectors.rows==2?
|
||||
uFormat("n=%f,%f", complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1)).c_str():
|
||||
uFormat("n1=%f,%f,%f n2=%f,%f,%f", complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1), complexityVectors.at<float>(0,2), complexityVectors.at<float>(1,0), complexityVectors.at<float>(1,1), complexityVectors.at<float>(1,2)).c_str());
|
||||
|
||||
UASSERT((complexityVectors.rows == 2 && complexityVectors.cols == 2)||
|
||||
(complexityVectors.rows == 3 && complexityVectors.cols == 3));
|
||||
secondEigenValue = complexityValuesFrom.at<float>(1,0)<complexityValuesTo.at<float>(1,0)?complexityValuesFrom.at<float>(1,0):complexityValuesTo.at<float>(1,0);
|
||||
UWARN("ICP PointToPlane ignored as structural complexity is too low (corridor-like environment): (from=%f || to=%f) < %f (%s). Second eigen value=%f. "
|
||||
"PointToPoint is done instead, orientation is still optimized but translation will be limited to "
|
||||
"direction of normals (%s: %s).",
|
||||
fromComplexity, toComplexity, _pointToPlaneMinComplexity, Parameters::kIcpPointToPlaneMinComplexity().c_str(),
|
||||
secondEigenValue,
|
||||
fromComplexity<toComplexity?"From":"To",
|
||||
complexityVectors.rows==2?
|
||||
uFormat("n=%f,%f", complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1)).c_str():
|
||||
secondEigenValue<_pointToPlaneMinComplexity?
|
||||
uFormat("n=%f,%f,%f", complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1), complexityVectors.at<float>(0,2)).c_str():
|
||||
uFormat("n1=%f,%f,%f n2=%f,%f,%f", complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1), complexityVectors.at<float>(0,2), complexityVectors.at<float>(1,0), complexityVectors.at<float>(1,1), complexityVectors.at<float>(1,2)).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("ICP PointToPlane ignored as structural complexity cannot be computed (from=%f to=%f)!? PointToPoint is done instead.", fromComplexity, toComplexity);
|
||||
}
|
||||
if(ULogger::level() == ULogger::kDebug)
|
||||
{
|
||||
std::cout << "complexityVectorsFrom = " << std::endl << complexityVectorsFrom << std::endl;
|
||||
@@ -765,15 +632,15 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
}
|
||||
else
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr fromCloudNormals = util3d::laserScanToPointCloudINormal(fromScan, fromScan.localTransform());
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr toCloudNormals = util3d::laserScanToPointCloudINormal(toScan, guess * toScan.localTransform());
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr fromCloudNormals = util3d::laserScanToPointCloudNormal(fromScan, fromScan.localTransform());
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr toCloudNormals = util3d::laserScanToPointCloudNormal(toScan, guess * toScan.localTransform());
|
||||
|
||||
fromCloudNormals = util3d::removeNaNNormalsFromPointCloud(fromCloudNormals);
|
||||
toCloudNormals = util3d::removeNaNNormalsFromPointCloud(toCloudNormals);
|
||||
|
||||
if(fromCloudNormals->size() > 2 && toCloudNormals->size() > 2)
|
||||
{
|
||||
pcl::PCA<pcl::PointXYZINormal> pca;
|
||||
pcl::PCA<pcl::PointNormal> pca;
|
||||
pca.setInputCloud(fromCloudNormals);
|
||||
Eigen::Vector3f valuesFrom = pca.getEigenValues();
|
||||
pca.setInputCloud(toCloudNormals);
|
||||
@@ -789,7 +656,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
}
|
||||
|
||||
UDEBUG("Conversion time = %f s", timer.ticks());
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr fromCloudNormalsRegistered(new pcl::PointCloud<pcl::PointXYZINormal>());
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr fromCloudNormalsRegistered(new pcl::PointCloud<pcl::PointNormal>());
|
||||
#ifdef RTABMAP_POINTMATCHER
|
||||
if(_libpointmatcher)
|
||||
{
|
||||
@@ -854,13 +721,13 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
int maxLaserScansTo = toScan.maxPoints();
|
||||
if(!transformComputed)
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZI>::Ptr fromCloud = util3d::laserScanToPointCloudI(fromScan, fromScan.localTransform());
|
||||
pcl::PointCloud<pcl::PointXYZI>::Ptr toCloud = util3d::laserScanToPointCloudI(toScan, guess * toScan.localTransform());
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr fromCloud = util3d::laserScanToPointCloud(fromScan, fromScan.localTransform());
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr toCloud = util3d::laserScanToPointCloud(toScan, guess * toScan.localTransform());
|
||||
UDEBUG("Conversion time = %f s", timer.ticks());
|
||||
|
||||
if(fromCloud->size() > 2 && toCloud->size() > 2)
|
||||
{
|
||||
pcl::PCA<pcl::PointXYZI> pca;
|
||||
pcl::PCA<pcl::PointXYZ> pca;
|
||||
pca.setInputCloud(fromCloud);
|
||||
Eigen::Vector3f valuesFrom = pca.getEigenValues();
|
||||
pca.setInputCloud(toCloud);
|
||||
@@ -873,11 +740,10 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
{
|
||||
info.icpStructuralDistribution = sqrt(valuesTo[0]/toCloud->size());
|
||||
}
|
||||
UDEBUG("Computed icpStructuralDistribution %f s",timer.ticks());
|
||||
}
|
||||
|
||||
pcl::PointCloud<pcl::PointXYZI>::Ptr fromCloudFiltered = fromCloud;
|
||||
pcl::PointCloud<pcl::PointXYZI>::Ptr toCloudFiltered = toCloud;
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr fromCloudFiltered = fromCloud;
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr toCloudFiltered = toCloud;
|
||||
if(_voxelSize > 0.0f)
|
||||
{
|
||||
float pointsBeforeFiltering = (float)fromCloudFiltered->size();
|
||||
@@ -901,7 +767,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
timer.ticks());
|
||||
}
|
||||
|
||||
pcl::PointCloud<pcl::PointXYZI>::Ptr fromCloudRegistered(new pcl::PointCloud<pcl::PointXYZI>());
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr fromCloudRegistered(new pcl::PointCloud<pcl::PointXYZ>());
|
||||
if(_pointToPlane && // ICP Point To Plane
|
||||
!tooLowComplexityForPlaneToPlane && // if previously rejected above
|
||||
!((fromScan.is2d()|| toScan.is2d()) && !_libpointmatcher)) // PCL crashes if 2D
|
||||
@@ -968,24 +834,18 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
if(complexity < _pointToPlaneMinComplexity)
|
||||
{
|
||||
tooLowComplexityForPlaneToPlane = true;
|
||||
if(complexity > 0.0f)
|
||||
{
|
||||
complexityVectors = fromComplexity<toComplexity?complexityVectorsFrom:complexityVectorsTo;
|
||||
UASSERT((complexityVectors.rows == 2 && complexityVectors.cols == 2)||
|
||||
(complexityVectors.rows == 3 && complexityVectors.cols == 3));
|
||||
UWARN("ICP PointToPlane ignored as structural complexity is too low (corridor-like environment): (from=%f || to=%f) < %f (%s). "
|
||||
"PointToPoint is done instead, orientation is still optimized but translation will be limited to "
|
||||
"direction of normals (%s: %s).",
|
||||
fromComplexity, toComplexity, _pointToPlaneMinComplexity, Parameters::kIcpPointToPlaneMinComplexity().c_str(),
|
||||
fromComplexity<toComplexity?"From":"To",
|
||||
complexityVectors.rows==2?
|
||||
uFormat("n=%f,%f", complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1)).c_str():
|
||||
uFormat("n1=%f,%f,%f n2=%f,%f,%f", complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1), complexityVectors.at<float>(0,2), complexityVectors.at<float>(1,0), complexityVectors.at<float>(1,1), complexityVectors.at<float>(1,2)).c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("ICP PointToPlane ignored as structural complexity cannot be computed (from=%f to=%f)!? PointToPoint is done instead.", fromComplexity, toComplexity);
|
||||
}
|
||||
complexityVectors = fromComplexity<toComplexity?complexityVectorsFrom:complexityVectorsTo;
|
||||
UASSERT((complexityVectors.rows == 2 && complexityVectors.cols == 2)||
|
||||
(complexityVectors.rows == 3 && complexityVectors.cols == 3));
|
||||
UWARN("ICP PointToPlane ignored as structural complexity is too low (corridor-like environment): (from=%f || to=%f) < %f (%s). "
|
||||
"PointToPoint is done instead, orientation is still optimized but translation will be limited to "
|
||||
"direction of normals (%s: %s).",
|
||||
fromComplexity, toComplexity, _pointToPlaneMinComplexity, Parameters::kIcpPointToPlaneMinComplexity().c_str(),
|
||||
fromComplexity<toComplexity?"From":"To",
|
||||
complexityVectors.rows==2?
|
||||
uFormat("n=%f,%f", complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1)).c_str():
|
||||
uFormat("n1=%f,%f,%f n2=%f,%f,%f", complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1), complexityVectors.at<float>(0,2), complexityVectors.at<float>(1,0), complexityVectors.at<float>(1,1), complexityVectors.at<float>(1,2)).c_str());
|
||||
|
||||
if(ULogger::level() == ULogger::kDebug)
|
||||
{
|
||||
std::cout << "complexityVectorsFrom = " << std::endl << complexityVectorsFrom << std::endl;
|
||||
@@ -996,31 +856,16 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
}
|
||||
else
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr fromCloudNormals(new pcl::PointCloud<pcl::PointXYZINormal>);
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr fromCloudNormals(new pcl::PointCloud<pcl::PointNormal>);
|
||||
pcl::concatenateFields(*fromCloudFiltered, *normalsFrom, *fromCloudNormals);
|
||||
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr toCloudNormals(new pcl::PointCloud<pcl::PointXYZINormal>);
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr toCloudNormals(new pcl::PointCloud<pcl::PointNormal>);
|
||||
pcl::concatenateFields(*toCloudFiltered, *normalsTo, *toCloudNormals);
|
||||
|
||||
std::vector<int> indices;
|
||||
toCloudNormals = util3d::removeNaNNormalsFromPointCloud(toCloudNormals);
|
||||
fromCloudNormals = util3d::removeNaNNormalsFromPointCloud(fromCloudNormals);
|
||||
|
||||
if(!fromCloudNormals->empty() && !fromScan.is2d() && _pointToPlaneGroundNormalsUp>0.0f)
|
||||
{
|
||||
util3d::adjustNormalsToViewPoint(fromCloudNormals,
|
||||
Eigen::Vector3f(fromScan.localTransform().x(),fromScan.localTransform().y(),fromScan.localTransform().z()+10),
|
||||
_pointToPlaneGroundNormalsUp);
|
||||
}
|
||||
if(!toCloudNormals->empty() && !toScan.is2d() && _pointToPlaneGroundNormalsUp>0.0f)
|
||||
{
|
||||
Transform toT = guess * toScan.localTransform();
|
||||
Eigen::Vector3f viewpointTo(toT.x(), toT.y(), toT.z()+10);
|
||||
util3d::adjustNormalsToViewPoint(toCloudNormals,
|
||||
viewpointTo,
|
||||
_pointToPlaneGroundNormalsUp);
|
||||
}
|
||||
|
||||
// update output scans
|
||||
if(fromScan.is2d())
|
||||
{
|
||||
@@ -1029,7 +874,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
util3d::laserScan2dFromPointCloud(*fromCloudNormals, fromScan.localTransform().inverse()),
|
||||
maxLaserScansFrom,
|
||||
fromScan.rangeMax(),
|
||||
LaserScan::kXYINormal,
|
||||
LaserScan::kXYNormal,
|
||||
fromScan.localTransform()));
|
||||
}
|
||||
else
|
||||
@@ -1039,7 +884,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
util3d::laserScanFromPointCloud(*fromCloudNormals, fromScan.localTransform().inverse()),
|
||||
maxLaserScansFrom,
|
||||
fromScan.rangeMax(),
|
||||
LaserScan::kXYZINormal,
|
||||
LaserScan::kXYZNormal,
|
||||
fromScan.localTransform()));
|
||||
}
|
||||
if(toScan.is2d())
|
||||
@@ -1049,7 +894,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
util3d::laserScan2dFromPointCloud(*toCloudNormals, (guess*toScan.localTransform()).inverse()),
|
||||
maxLaserScansTo,
|
||||
toScan.rangeMax(),
|
||||
LaserScan::kXYINormal,
|
||||
LaserScan::kXYNormal,
|
||||
toScan.localTransform()));
|
||||
}
|
||||
else
|
||||
@@ -1059,7 +904,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
util3d::laserScanFromPointCloud(*toCloudNormals, (guess*toScan.localTransform()).inverse()),
|
||||
maxLaserScansTo,
|
||||
toScan.rangeMax(),
|
||||
LaserScan::kXYZINormal,
|
||||
LaserScan::kXYZNormal,
|
||||
toScan.localTransform()));
|
||||
}
|
||||
UDEBUG("Compute normals (%d,%d) time = %f s", (int)fromCloudNormals->size(), (int)toCloudNormals->size(), timer.ticks());
|
||||
@@ -1068,7 +913,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
|
||||
if(toCloudNormals->size() && fromCloudNormals->size())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr fromCloudNormalsRegistered(new pcl::PointCloud<pcl::PointXYZINormal>());
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr fromCloudNormalsRegistered(new pcl::PointCloud<pcl::PointNormal>());
|
||||
|
||||
#ifdef RTABMAP_POINTMATCHER
|
||||
if(_libpointmatcher)
|
||||
@@ -1148,7 +993,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
util3d::laserScan2dFromPointCloud(*fromCloudFiltered, fromScan.localTransform().inverse()),
|
||||
maxLaserScansFrom,
|
||||
fromScan.rangeMax(),
|
||||
LaserScan::kXYI,
|
||||
LaserScan::kXY,
|
||||
fromScan.localTransform()));
|
||||
}
|
||||
else
|
||||
@@ -1158,7 +1003,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
util3d::laserScanFromPointCloud(*fromCloudFiltered, fromScan.localTransform().inverse()),
|
||||
maxLaserScansFrom,
|
||||
fromScan.rangeMax(),
|
||||
LaserScan::kXYZI,
|
||||
LaserScan::kXYZ,
|
||||
fromScan.localTransform()));
|
||||
}
|
||||
if(toScan.is2d())
|
||||
@@ -1168,7 +1013,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
util3d::laserScan2dFromPointCloud(*toCloudFiltered, (guess*toScan.localTransform()).inverse()),
|
||||
maxLaserScansTo,
|
||||
toScan.rangeMax(),
|
||||
LaserScan::kXYI,
|
||||
LaserScan::kXY,
|
||||
toScan.localTransform()));
|
||||
}
|
||||
else
|
||||
@@ -1178,7 +1023,7 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
util3d::laserScanFromPointCloud(*toCloudFiltered, (guess*toScan.localTransform()).inverse()),
|
||||
maxLaserScansTo,
|
||||
toScan.rangeMax(),
|
||||
LaserScan::kXYZI,
|
||||
LaserScan::kXYZ,
|
||||
toScan.localTransform()));
|
||||
}
|
||||
fromScan = fromSignature.sensorData().laserScanRaw();
|
||||
@@ -1271,86 +1116,70 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
|
||||
if(!icpT.isNull() && hasConverged)
|
||||
{
|
||||
if(tooLowComplexityForPlaneToPlane && _pointToPlaneLowComplexityStrategy<2)
|
||||
if(tooLowComplexityForPlaneToPlane)
|
||||
{
|
||||
if(complexityVectors.empty() || _pointToPlaneLowComplexityStrategy == 0)
|
||||
Transform guessInv = guess.inverse();
|
||||
Transform t = guessInv * icpT.inverse() * guess;
|
||||
Eigen::Vector3f v(t.x(), t.y(), t.z());
|
||||
if(complexityVectors.cols == 2)
|
||||
{
|
||||
msg = uFormat("Rejecting transform because too low complexity (%s=0)", Parameters::kIcpPointToPlaneLowComplexityStrategy().c_str());
|
||||
icpT.setNull();
|
||||
UWARN(msg.c_str());
|
||||
// limit translation in direction of the first eigen vector
|
||||
Eigen::Vector3f n(complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1), 0.0f);
|
||||
float a = v.dot(n);
|
||||
Eigen::Vector3f vp = n*a;
|
||||
UWARN("Normals low complexity: Limiting translation from (%f,%f) to (%f,%f)",
|
||||
v[0], v[1], vp[0], vp[1]);
|
||||
v= vp;
|
||||
}
|
||||
else //if(_pointToPlaneLowComplexityStrategy == 1)
|
||||
else if(complexityVectors.rows == 3)
|
||||
{
|
||||
Transform guessInv = guess.inverse();
|
||||
Transform t = guessInv * icpT.inverse() * guess;
|
||||
Eigen::Vector3f v(t.x(), t.y(), t.z());
|
||||
if(complexityVectors.cols == 2)
|
||||
{
|
||||
// limit translation in direction of the first eigen vector
|
||||
Eigen::Vector3f n(complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1), 0.0f);
|
||||
float a = v.dot(n);
|
||||
Eigen::Vector3f vp = n*a;
|
||||
UWARN("Normals low complexity: Limiting translation from (%f,%f) to (%f,%f)",
|
||||
v[0], v[1], vp[0], vp[1]);
|
||||
v= vp;
|
||||
}
|
||||
else if(complexityVectors.rows == 3)
|
||||
{
|
||||
// limit translation in direction of the first and second eigen vectors
|
||||
Eigen::Vector3f n1(complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1), complexityVectors.at<float>(0,2));
|
||||
Eigen::Vector3f n2(complexityVectors.at<float>(1,0), complexityVectors.at<float>(1,1), complexityVectors.at<float>(1,2));
|
||||
float a = v.dot(n1);
|
||||
float b = v.dot(n2);
|
||||
Eigen::Vector3f vp = n1*a;
|
||||
if(secondEigenValue >= _pointToPlaneMinComplexity)
|
||||
{
|
||||
vp += n2*b;
|
||||
}
|
||||
UWARN("Normals low complexity: Limiting translation from (%f,%f,%f) to (%f,%f,%f)",
|
||||
v[0], v[1], v[2], vp[0], vp[1], vp[2]);
|
||||
v = vp;
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("not supposed to be here!");
|
||||
v = Eigen::Vector3f(0,0,0);
|
||||
}
|
||||
float roll, pitch, yaw;
|
||||
t.getEulerAngles(roll, pitch, yaw);
|
||||
t = Transform(v[0], v[1], v[2], roll, pitch, yaw);
|
||||
icpT = guess * t.inverse() * guessInv;
|
||||
// limit translation in direction of the first and second eigen vectors
|
||||
Eigen::Vector3f n1(complexityVectors.at<float>(0,0), complexityVectors.at<float>(0,1), complexityVectors.at<float>(0,2));
|
||||
Eigen::Vector3f n2(complexityVectors.at<float>(1,0), complexityVectors.at<float>(1,1), complexityVectors.at<float>(1,2));
|
||||
float a = v.dot(n1);
|
||||
float b = v.dot(n2);
|
||||
Eigen::Vector3f vp = n1*a;
|
||||
vp += n2*b;
|
||||
UWARN("Normals low complexity: Limiting translation from (%f,%f,%f) to (%f,%f,%f)",
|
||||
v[0], v[1], v[2], vp[0], vp[1], vp[2]);
|
||||
v = vp;
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("not supposed to be here!");
|
||||
v = Eigen::Vector3f(0,0,0);
|
||||
}
|
||||
float roll, pitch, yaw;
|
||||
t.getEulerAngles(roll, pitch, yaw);
|
||||
t = Transform(v[0], v[1], v[2], roll, pitch, yaw);
|
||||
icpT = guess * t.inverse() * guessInv;
|
||||
|
||||
if(fromScan.hasNormals() && toScan.hasNormals())
|
||||
{
|
||||
// we were using normals, so compute correspondences using normals
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr fromCloudNormalsRegistered = util3d::laserScanToPointCloudINormal(fromScan, icpT * fromScan.localTransform());
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr toCloudNormals = util3d::laserScanToPointCloudINormal(toScan, guess * toScan.localTransform());
|
||||
if(fromScan.hasNormals() && toScan.hasNormals())
|
||||
{
|
||||
// we were using normals, so compute correspondences using normals
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr fromCloudNormalsRegistered = util3d::laserScanToPointCloudNormal(fromScan, icpT * fromScan.localTransform());
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr toCloudNormals = util3d::laserScanToPointCloudNormal(toScan, guess * toScan.localTransform());
|
||||
|
||||
util3d::computeVarianceAndCorrespondences(
|
||||
fromCloudNormalsRegistered,
|
||||
toCloudNormals,
|
||||
_maxCorrespondenceDistance,
|
||||
_maxRotation,
|
||||
variance,
|
||||
correspondences);
|
||||
}
|
||||
else
|
||||
{
|
||||
util3d::computeVarianceAndCorrespondences(
|
||||
fromCloudRegistered,
|
||||
toCloudFiltered,
|
||||
_maxCorrespondenceDistance,
|
||||
variance,
|
||||
correspondences);
|
||||
}
|
||||
util3d::computeVarianceAndCorrespondences(
|
||||
fromCloudNormalsRegistered,
|
||||
toCloudNormals,
|
||||
_maxCorrespondenceDistance,
|
||||
_maxRotation,
|
||||
variance,
|
||||
correspondences);
|
||||
}
|
||||
else
|
||||
{
|
||||
util3d::computeVarianceAndCorrespondences(
|
||||
fromCloudRegistered,
|
||||
toCloudFiltered,
|
||||
_maxCorrespondenceDistance,
|
||||
variance,
|
||||
correspondences);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(tooLowComplexityForPlaneToPlane)
|
||||
{
|
||||
UWARN("Even if complexity is low , PointToPoint transformation is accepted \"as is\" (%s=2)", Parameters::kIcpPointToPlaneLowComplexityStrategy().c_str());
|
||||
}
|
||||
util3d::computeVarianceAndCorrespondences(
|
||||
fromCloudRegistered,
|
||||
toCloudFiltered,
|
||||
@@ -1425,7 +1254,6 @@ Transform RegistrationIcp::computeTransformationImpl(
|
||||
else
|
||||
{
|
||||
info.covariance = cv::Mat::eye(6,6,CV_64FC1)*variance;
|
||||
info.covariance(cv::Range(3,6),cv::Range(3,6))/=10.0; //orientation error
|
||||
}
|
||||
info.icpInliersRatio = correspondencesRatio;
|
||||
info.icpCorrespondences = correspondences;
|
||||
|
||||
+145
-217
@@ -213,10 +213,6 @@ void RegistrationVis::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
uInsert(_featureParameters, ParametersPair(Parameters::kKpNndrRatio(), parameters.at(Parameters::kVisCorNNDR())));
|
||||
}
|
||||
if(uContains(parameters, Parameters::kKpByteToFloat()))
|
||||
{
|
||||
uInsert(_featureParameters, ParametersPair(Parameters::kKpByteToFloat(), parameters.at(Parameters::kKpByteToFloat())));
|
||||
}
|
||||
if(uContains(parameters, Parameters::kVisFeatureType()))
|
||||
{
|
||||
uInsert(_featureParameters, ParametersPair(Parameters::kKpDetectorStrategy(), parameters.at(Parameters::kVisFeatureType())));
|
||||
@@ -303,7 +299,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
fromSignature.id(),
|
||||
(int)fromSignature.getWords().size(),
|
||||
(int)fromSignature.getWords3().size(),
|
||||
(int)fromSignature.getWordsDescriptors().rows,
|
||||
(int)fromSignature.getWordsDescriptors().size(),
|
||||
(int)fromSignature.sensorData().keypoints().size(),
|
||||
(int)fromSignature.sensorData().keypoints3D().size(),
|
||||
fromSignature.sensorData().descriptors().rows,
|
||||
@@ -316,7 +312,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
toSignature.id(),
|
||||
(int)toSignature.getWords().size(),
|
||||
(int)toSignature.getWords3().size(),
|
||||
(int)toSignature.getWordsDescriptors().rows,
|
||||
(int)toSignature.getWordsDescriptors().size(),
|
||||
(int)toSignature.sensorData().keypoints().size(),
|
||||
(int)toSignature.sensorData().keypoints3D().size(),
|
||||
toSignature.sensorData().descriptors().rows,
|
||||
@@ -349,16 +345,16 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
fromSignature.getWords3().empty() ||
|
||||
(fromSignature.getWords().size() == fromSignature.getWords3().size()));
|
||||
UASSERT((int)fromSignature.sensorData().keypoints().size() == fromSignature.sensorData().descriptors().rows ||
|
||||
(int)fromSignature.getWords().size() == fromSignature.getWordsDescriptors().rows ||
|
||||
fromSignature.sensorData().descriptors().empty() ||
|
||||
fromSignature.getWordsDescriptors().empty() == 0);
|
||||
fromSignature.getWords().size() == fromSignature.getWordsDescriptors().size() ||
|
||||
fromSignature.sensorData().descriptors().rows == 0 ||
|
||||
fromSignature.getWordsDescriptors().size() == 0);
|
||||
UASSERT((toSignature.getWords().empty() && toSignature.getWords3().empty())||
|
||||
(toSignature.getWords().size() && toSignature.getWords3().empty())||
|
||||
(toSignature.getWords().size() == toSignature.getWords3().size()));
|
||||
UASSERT((int)toSignature.sensorData().keypoints().size() == toSignature.sensorData().descriptors().rows ||
|
||||
(int)toSignature.getWords().size() == toSignature.getWordsDescriptors().rows ||
|
||||
toSignature.sensorData().descriptors().empty() ||
|
||||
toSignature.getWordsDescriptors().empty());
|
||||
toSignature.getWords().size() == toSignature.getWordsDescriptors().size() ||
|
||||
toSignature.sensorData().descriptors().rows == 0 ||
|
||||
toSignature.getWordsDescriptors().size() == 0);
|
||||
UASSERT(fromSignature.sensorData().imageRaw().empty() ||
|
||||
fromSignature.sensorData().imageRaw().type() == CV_8UC1 ||
|
||||
fromSignature.sensorData().imageRaw().type() == CV_8UC3);
|
||||
@@ -371,7 +367,6 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
cv::Mat imageTo = toSignature.sensorData().imageRaw();
|
||||
|
||||
std::vector<int> orignalWordsFromIds;
|
||||
int kptsFromSource = 0;
|
||||
if(fromSignature.getWords().empty())
|
||||
{
|
||||
if(fromSignature.sensorData().keypoints().empty())
|
||||
@@ -404,26 +399,22 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
else
|
||||
{
|
||||
kptsFrom = fromSignature.sensorData().keypoints();
|
||||
kptsFromSource = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kptsFromSource = 2;
|
||||
kptsFrom.resize(fromSignature.getWords().size());
|
||||
orignalWordsFromIds.resize(fromSignature.getWords().size());
|
||||
int i=0;
|
||||
bool allUniques = true;
|
||||
int previousIdAdded = 0;
|
||||
kptsFrom = fromSignature.getWordsKpts();
|
||||
for(std::multimap<int, int>::const_iterator iter=fromSignature.getWords().begin(); iter!=fromSignature.getWords().end(); ++iter)
|
||||
for(std::multimap<int, cv::KeyPoint>::const_iterator iter=fromSignature.getWords().begin(); iter!=fromSignature.getWords().end(); ++iter)
|
||||
{
|
||||
UASSERT(iter->second>=0 && iter->second<(int)orignalWordsFromIds.size());
|
||||
orignalWordsFromIds[iter->second] = iter->first;
|
||||
if(i>0 && iter->first==previousIdAdded)
|
||||
kptsFrom[i] = iter->second;
|
||||
orignalWordsFromIds[i] = iter->first;
|
||||
if(i>0 && iter->first==orignalWordsFromIds[i-1])
|
||||
{
|
||||
allUniques = false;
|
||||
}
|
||||
previousIdAdded = iter->first;
|
||||
++i;
|
||||
}
|
||||
if(!allUniques)
|
||||
@@ -433,14 +424,12 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
}
|
||||
}
|
||||
|
||||
std::multimap<int, int> wordsFrom;
|
||||
std::multimap<int, int> wordsTo;
|
||||
std::vector<cv::KeyPoint> wordsKptsFrom;
|
||||
std::vector<cv::KeyPoint> wordsKptsTo;
|
||||
std::vector<cv::Point3f> words3From;
|
||||
std::vector<cv::Point3f> words3To;
|
||||
cv::Mat wordsDescFrom;
|
||||
cv::Mat wordsDescTo;
|
||||
std::multimap<int, cv::KeyPoint> wordsFrom;
|
||||
std::multimap<int, cv::KeyPoint> wordsTo;
|
||||
std::multimap<int, cv::Point3f> words3From;
|
||||
std::multimap<int, cv::Point3f> words3To;
|
||||
std::multimap<int, cv::Mat> wordsDescFrom;
|
||||
std::multimap<int, cv::Mat> wordsDescTo;
|
||||
if(_correspondencesApproach == 1) //Optical Flow
|
||||
{
|
||||
UDEBUG("");
|
||||
@@ -461,7 +450,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
std::vector<cv::Point3f> kptsFrom3D;
|
||||
if(kptsFrom.size() == fromSignature.getWords3().size())
|
||||
{
|
||||
kptsFrom3D = fromSignature.getWords3();
|
||||
kptsFrom3D = uValues(fromSignature.getWords3());
|
||||
}
|
||||
else if(kptsFrom.size() == fromSignature.sensorData().keypoints3D().size())
|
||||
{
|
||||
@@ -551,16 +540,13 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
UASSERT(kptsTo3D.size() == 0 || kptsTo.size() == kptsTo3D.size());
|
||||
for(unsigned int i=0; i< kptsFrom3DKept.size(); ++i)
|
||||
{
|
||||
int id = !orignalWordsFromIds.empty()?orignalWordsFromIds[i]:i;
|
||||
wordsFrom.insert(wordsFrom.end(), std::make_pair(id, wordsFrom.size()));
|
||||
wordsKptsFrom.push_back(kptsFrom[i]);
|
||||
words3From.push_back(kptsFrom3DKept[i]);
|
||||
|
||||
wordsTo.insert(wordsTo.end(), std::make_pair(id, wordsTo.size()));
|
||||
wordsKptsTo.push_back(kptsTo[i]);
|
||||
if(!kptsTo3D.empty())
|
||||
int id = orignalWordsFromIds.size()?orignalWordsFromIds[i]:i;
|
||||
wordsFrom.insert(std::make_pair(id, kptsFrom[i]));
|
||||
words3From.insert(std::make_pair(id, kptsFrom3DKept[i]));
|
||||
wordsTo.insert(std::make_pair(id, kptsTo[i]));
|
||||
if(kptsTo3D.size())
|
||||
{
|
||||
words3To.push_back(kptsTo3D[i]);
|
||||
words3To.insert(std::make_pair(id, kptsTo3D[i]));
|
||||
}
|
||||
}
|
||||
toSignature.sensorData().setFeatures(kptsTo, kptsTo3D, cv::Mat());
|
||||
@@ -576,10 +562,9 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
{
|
||||
if(util3d::isFinite(kptsFrom3D[i]))
|
||||
{
|
||||
int id = !orignalWordsFromIds.empty()?orignalWordsFromIds[i]:i;
|
||||
wordsFrom.insert(wordsFrom.end(), std::make_pair(id, wordsFrom.size()));
|
||||
wordsKptsFrom.push_back(kptsFrom[i]);
|
||||
words3From.push_back(kptsFrom3D[i]);
|
||||
int id = orignalWordsFromIds.size()?orignalWordsFromIds[i]:i;
|
||||
wordsFrom.insert(std::make_pair(id, kptsFrom[i]));
|
||||
words3From.insert(std::make_pair(id, kptsFrom3D[i]));
|
||||
}
|
||||
}
|
||||
toSignature.sensorData().setFeatures(std::vector<cv::KeyPoint>(), std::vector<cv::Point3f>(), cv::Mat());
|
||||
@@ -591,7 +576,6 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
{
|
||||
UDEBUG("");
|
||||
std::vector<cv::KeyPoint> kptsTo;
|
||||
int kptsToSource = 0;
|
||||
if(toSignature.getWords().empty())
|
||||
{
|
||||
if(toSignature.sensorData().keypoints().empty() &&
|
||||
@@ -622,28 +606,33 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
else
|
||||
{
|
||||
kptsTo = toSignature.sensorData().keypoints();
|
||||
kptsToSource = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
kptsTo = toSignature.getWordsKpts();
|
||||
kptsToSource = 2;
|
||||
kptsTo = uValues(toSignature.getWords());
|
||||
}
|
||||
|
||||
// extract descriptors
|
||||
UDEBUG("kptsFrom=%d kptsFromSource=%d", (int)kptsFrom.size(), kptsFromSource);
|
||||
UDEBUG("kptsTo=%d kptsToSource=%d", (int)kptsTo.size(), kptsToSource);
|
||||
UDEBUG("kptsFrom=%d", (int)kptsFrom.size());
|
||||
UDEBUG("kptsTo=%d", (int)kptsTo.size());
|
||||
cv::Mat descriptorsFrom;
|
||||
if(kptsFromSource == 2 &&
|
||||
fromSignature.getWordsDescriptors().rows &&
|
||||
((kptsFrom.empty() && fromSignature.getWordsDescriptors().rows) ||
|
||||
fromSignature.getWordsDescriptors().rows == (int)kptsFrom.size()))
|
||||
if(fromSignature.getWordsDescriptors().size() &&
|
||||
((kptsFrom.empty() && fromSignature.getWordsDescriptors().size()) ||
|
||||
fromSignature.getWordsDescriptors().size() == kptsFrom.size()))
|
||||
{
|
||||
descriptorsFrom = fromSignature.getWordsDescriptors();
|
||||
descriptorsFrom = cv::Mat(fromSignature.getWordsDescriptors().size(),
|
||||
fromSignature.getWordsDescriptors().begin()->second.cols,
|
||||
fromSignature.getWordsDescriptors().begin()->second.type());
|
||||
int i=0;
|
||||
for(std::multimap<int, cv::Mat>::const_iterator iter=fromSignature.getWordsDescriptors().begin();
|
||||
iter!=fromSignature.getWordsDescriptors().end();
|
||||
++iter, ++i)
|
||||
{
|
||||
iter->second.copyTo(descriptorsFrom.row(i));
|
||||
}
|
||||
}
|
||||
else if(kptsFromSource == 1 &&
|
||||
fromSignature.sensorData().descriptors().rows == (int)kptsFrom.size())
|
||||
else if(fromSignature.sensorData().descriptors().rows == (int)kptsFrom.size())
|
||||
{
|
||||
descriptorsFrom = fromSignature.sensorData().descriptors();
|
||||
}
|
||||
@@ -663,13 +652,20 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
cv::Mat descriptorsTo;
|
||||
if(kptsTo.size())
|
||||
{
|
||||
if(kptsToSource == 2 &&
|
||||
toSignature.getWordsDescriptors().rows == (int)kptsTo.size())
|
||||
if(toSignature.getWordsDescriptors().size() == kptsTo.size())
|
||||
{
|
||||
descriptorsTo = toSignature.getWordsDescriptors();
|
||||
descriptorsTo = cv::Mat(toSignature.getWordsDescriptors().size(),
|
||||
toSignature.getWordsDescriptors().begin()->second.cols,
|
||||
toSignature.getWordsDescriptors().begin()->second.type());
|
||||
int i=0;
|
||||
for(std::multimap<int, cv::Mat>::const_iterator iter=toSignature.getWordsDescriptors().begin();
|
||||
iter!=toSignature.getWordsDescriptors().end();
|
||||
++iter, ++i)
|
||||
{
|
||||
iter->second.copyTo(descriptorsTo.row(i));
|
||||
}
|
||||
}
|
||||
else if(kptsToSource == 1 &&
|
||||
toSignature.sensorData().descriptors().rows == (int)kptsTo.size())
|
||||
else if(toSignature.sensorData().descriptors().rows == (int)kptsTo.size())
|
||||
{
|
||||
descriptorsTo = toSignature.sensorData().descriptors();
|
||||
}
|
||||
@@ -689,13 +685,11 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
// create 3D keypoints
|
||||
std::vector<cv::Point3f> kptsFrom3D;
|
||||
std::vector<cv::Point3f> kptsTo3D;
|
||||
if(kptsFromSource == 2 &&
|
||||
kptsFrom.size() == fromSignature.getWords3().size())
|
||||
if(kptsFrom.size() == fromSignature.getWords3().size())
|
||||
{
|
||||
kptsFrom3D = fromSignature.getWords3();
|
||||
kptsFrom3D = uValues(fromSignature.getWords3());
|
||||
}
|
||||
else if(kptsFromSource == 1 &&
|
||||
kptsFrom.size() == fromSignature.sensorData().keypoints3D().size())
|
||||
else if(kptsFrom.size() == fromSignature.sensorData().keypoints3D().size())
|
||||
{
|
||||
kptsFrom3D = fromSignature.sensorData().keypoints3D();
|
||||
}
|
||||
@@ -726,12 +720,11 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
_detectorFrom->filterKeypointsByDepth(kptsFrom, descriptorsFrom, kptsFrom3D, _detectorFrom->getMinDepth(), _detectorFrom->getMaxDepth());
|
||||
}
|
||||
|
||||
if(kptsToSource == 2 && kptsTo.size() == toSignature.getWords3().size())
|
||||
if(kptsTo.size() == toSignature.getWords3().size())
|
||||
{
|
||||
kptsTo3D = toSignature.getWords3();
|
||||
kptsTo3D = uValues(toSignature.getWords3());
|
||||
}
|
||||
else if(kptsToSource == 1 &&
|
||||
kptsTo.size() == toSignature.sensorData().keypoints3D().size())
|
||||
else if(kptsTo.size() == toSignature.sensorData().keypoints3D().size())
|
||||
{
|
||||
kptsTo3D = toSignature.sensorData().keypoints3D();
|
||||
}
|
||||
@@ -861,7 +854,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
UDEBUG("radius search done for guess");
|
||||
|
||||
// Process results (Nearest Neighbor Distance Ratio)
|
||||
int newToId = !orignalWordsFromIds.empty()?fromSignature.getWords().rbegin()->first+1:descriptorsFrom.rows;
|
||||
int newToId = orignalWordsFromIds.size()?orignalWordsFromIds.back():descriptorsFrom.rows;
|
||||
std::map<int,int> addedWordsFrom; //<id, index>
|
||||
std::map<int, int> duplicates; //<fromId, toId>
|
||||
int newWords = 0;
|
||||
@@ -915,7 +908,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
if(matchedIndex >= 0)
|
||||
{
|
||||
matchedIndex = projectedIndexToDescIndex[matchedIndex];
|
||||
int id = !orignalWordsFromIds.empty()?orignalWordsFromIds[matchedIndex]:matchedIndex;
|
||||
int id = orignalWordsFromIds.size()?orignalWordsFromIds[matchedIndex]:matchedIndex;
|
||||
|
||||
if(addedWordsFrom.find(matchedIndex) != addedWordsFrom.end())
|
||||
{
|
||||
@@ -926,32 +919,29 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
{
|
||||
addedWordsFrom.insert(std::make_pair(matchedIndex, id));
|
||||
|
||||
wordsFrom.insert(wordsFrom.end(), std::make_pair(id, wordsFrom.size()));
|
||||
if(!kptsFrom.empty())
|
||||
if(kptsFrom.size())
|
||||
{
|
||||
wordsKptsFrom.push_back(kptsFrom[matchedIndex]);
|
||||
wordsFrom.insert(std::make_pair(id, kptsFrom[matchedIndex]));
|
||||
}
|
||||
words3From.push_back(kptsFrom3D[matchedIndex]);
|
||||
wordsDescFrom.push_back(descriptorsFrom.row(matchedIndex));
|
||||
words3From.insert(std::make_pair(id, kptsFrom3D[matchedIndex]));
|
||||
wordsDescFrom.insert(std::make_pair(id, descriptorsFrom.row(matchedIndex)));
|
||||
}
|
||||
|
||||
wordsTo.insert(wordsTo.end(), std::make_pair(id, wordsTo.size()));
|
||||
wordsKptsTo.push_back(kptsTo[i]);
|
||||
wordsDescTo.push_back(descriptorsTo.row(i));
|
||||
if(!kptsTo3D.empty())
|
||||
wordsTo.insert(std::make_pair(id, kptsTo[i]));
|
||||
wordsDescTo.insert(std::make_pair(id, descriptorsTo.row(i)));
|
||||
if(kptsTo3D.size())
|
||||
{
|
||||
words3To.push_back(kptsTo3D[i]);
|
||||
words3To.insert(std::make_pair(id, kptsTo3D[i]));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// gen fake ids
|
||||
wordsTo.insert(wordsTo.end(), std::make_pair(newToId, wordsTo.size()));
|
||||
wordsKptsTo.push_back(kptsTo[i]);
|
||||
wordsDescTo.push_back(descriptorsTo.row(i));
|
||||
if(!kptsTo3D.empty())
|
||||
wordsTo.insert(wordsTo.end(), std::make_pair(newToId, kptsTo[i]));
|
||||
wordsDescTo.insert(wordsDescTo.end(), std::make_pair(newToId, descriptorsTo.row(i)));
|
||||
if(kptsTo3D.size())
|
||||
{
|
||||
words3To.push_back(kptsTo3D[i]);
|
||||
words3To.insert(words3To.end(), std::make_pair(newToId, kptsTo3D[i]));
|
||||
}
|
||||
|
||||
++newToId;
|
||||
@@ -968,11 +958,10 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
{
|
||||
if(util3d::isFinite(kptsFrom3D[i]) && addedWordsFrom.find(i) == addedWordsFrom.end())
|
||||
{
|
||||
int id = !orignalWordsFromIds.empty()?orignalWordsFromIds[i]:i;
|
||||
wordsFrom.insert(wordsFrom.end(), std::make_pair(id, wordsFrom.size()));
|
||||
wordsKptsFrom.push_back(kptsFrom[i]);
|
||||
wordsDescFrom.push_back(descriptorsFrom.row(i));
|
||||
words3From.push_back(kptsFrom3D[i]);
|
||||
int id = orignalWordsFromIds.size()?orignalWordsFromIds[i]:i;
|
||||
wordsFrom.insert(wordsFrom.end(), std::make_pair(id, kptsFrom[i]));
|
||||
wordsDescFrom.insert(wordsDescFrom.end(), std::make_pair(id, descriptorsFrom.row(i)));
|
||||
words3From.insert(words3From.end(), std::make_pair(id, kptsFrom3D[i]));
|
||||
|
||||
++addWordsFromNotMatched;
|
||||
}
|
||||
@@ -1014,7 +1003,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
|
||||
if(indices[i].size())
|
||||
{
|
||||
info.projectedIDs.push_back(!orignalWordsFromIds.empty()?orignalWordsFromIds[matchedIndexFrom]:matchedIndexFrom);
|
||||
info.projectedIDs.push_back(orignalWordsFromIds.size()?orignalWordsFromIds[matchedIndexFrom]:matchedIndexFrom);
|
||||
}
|
||||
|
||||
if(util3d::isFinite(kptsFrom3D[matchedIndexFrom]))
|
||||
@@ -1065,28 +1054,26 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
matchedIndexTo = indices[i].at(0);
|
||||
}
|
||||
|
||||
int id = !orignalWordsFromIds.empty()?orignalWordsFromIds[matchedIndexFrom]:matchedIndexFrom;
|
||||
int id = orignalWordsFromIds.size()?orignalWordsFromIds[matchedIndexFrom]:matchedIndexFrom;
|
||||
addedWordsFrom.insert(addedWordsFrom.end(), matchedIndexFrom);
|
||||
|
||||
wordsFrom.insert(wordsFrom.end(), std::make_pair(id, wordsFrom.size()));
|
||||
if(!kptsFrom.empty())
|
||||
if(kptsFrom.size())
|
||||
{
|
||||
wordsKptsFrom.push_back(kptsFrom[matchedIndexFrom]);
|
||||
wordsFrom.insert(wordsFrom.end(), std::make_pair(id, kptsFrom[matchedIndexFrom]));
|
||||
}
|
||||
words3From.push_back(kptsFrom3D[matchedIndexFrom]);
|
||||
wordsDescFrom.push_back(descriptorsFrom.row(matchedIndexFrom));
|
||||
words3From.insert(words3From.end(), std::make_pair(id, kptsFrom3D[matchedIndexFrom]));
|
||||
wordsDescFrom.insert(wordsDescFrom.end(), std::make_pair(id, descriptorsFrom.row(matchedIndexFrom)));
|
||||
|
||||
if( matchedIndexTo >= 0 &&
|
||||
addedWordsTo.find(matchedIndexTo) == addedWordsTo.end())
|
||||
{
|
||||
addedWordsTo.insert(matchedIndexTo);
|
||||
|
||||
wordsTo.insert(wordsTo.end(), std::make_pair(id, wordsTo.size()));
|
||||
wordsKptsTo.push_back(kptsTo[matchedIndexTo]);
|
||||
wordsDescTo.push_back(descriptorsTo.row(matchedIndexTo));
|
||||
if(!kptsTo3D.empty())
|
||||
wordsTo.insert(wordsTo.end(), std::make_pair(id, kptsTo[matchedIndexTo]));
|
||||
wordsDescTo.insert(wordsDescTo.end(), std::make_pair(id, descriptorsTo.row(matchedIndexTo)));
|
||||
if(kptsTo3D.size())
|
||||
{
|
||||
words3To.push_back(kptsTo3D[matchedIndexTo]);
|
||||
words3To.insert(words3To.end(), std::make_pair(id, kptsTo3D[matchedIndexTo]));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1098,25 +1085,23 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
{
|
||||
if(util3d::isFinite(kptsFrom3D[i]) && addedWordsFrom.find(i) == addedWordsFrom.end())
|
||||
{
|
||||
int id = !orignalWordsFromIds.empty()?orignalWordsFromIds[i]:i;
|
||||
wordsFrom.insert(wordsFrom.end(), std::make_pair(id, wordsFrom.size()));
|
||||
wordsKptsFrom.push_back(kptsFrom[i]);
|
||||
wordsDescFrom.push_back(descriptorsFrom.row(i));
|
||||
words3From.push_back(kptsFrom3D[i]);
|
||||
int id = orignalWordsFromIds.size()?orignalWordsFromIds[i]:i;
|
||||
wordsFrom.insert(wordsFrom.end(), std::make_pair(id, kptsFrom[i]));
|
||||
wordsDescFrom.insert(wordsDescFrom.end(), std::make_pair(id, descriptorsFrom.row(i)));
|
||||
words3From.insert(words3From.end(), std::make_pair(id, kptsFrom3D[i]));
|
||||
}
|
||||
}
|
||||
|
||||
int newToId = !orignalWordsFromIds.empty()?fromSignature.getWords().rbegin()->first+1:descriptorsFrom.rows;
|
||||
int newToId = orignalWordsFromIds.size()?orignalWordsFromIds.back():descriptorsFrom.rows;
|
||||
for(unsigned int i = 0; i < kptsTo.size(); ++i)
|
||||
{
|
||||
if(addedWordsTo.find(i) == addedWordsTo.end())
|
||||
{
|
||||
wordsTo.insert(wordsTo.end(), std::make_pair(newToId, wordsTo.size()));
|
||||
wordsKptsTo.push_back(kptsTo[i]);
|
||||
wordsDescTo.push_back(descriptorsTo.row(i));
|
||||
if(!kptsTo3D.empty())
|
||||
wordsTo.insert(wordsTo.end(), std::make_pair(newToId, kptsTo[i]));
|
||||
wordsDescTo.insert(wordsDescTo.end(), std::make_pair(newToId, descriptorsTo.row(i)));
|
||||
if(kptsTo3D.size())
|
||||
{
|
||||
words3To.push_back(kptsTo3D[i]);
|
||||
words3To.insert(words3To.end(), std::make_pair(newToId, kptsTo3D[i]));
|
||||
}
|
||||
++newToId;
|
||||
}
|
||||
@@ -1282,16 +1267,15 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
{
|
||||
if(fromWordIdsSet.count(*iter) == 1)
|
||||
{
|
||||
wordsFrom.insert(wordsFrom.end(), std::make_pair(*iter, wordsFrom.size()));
|
||||
if (!kptsFrom.empty())
|
||||
if (kptsFrom.size())
|
||||
{
|
||||
wordsKptsFrom.push_back(kptsFrom[i]);
|
||||
wordsFrom.insert(std::make_pair(*iter, kptsFrom[i]));
|
||||
}
|
||||
if(!kptsFrom3D.empty())
|
||||
if(kptsFrom3D.size())
|
||||
{
|
||||
words3From.push_back(kptsFrom3D[i]);
|
||||
words3From.insert(std::make_pair(*iter, kptsFrom3D[i]));
|
||||
}
|
||||
wordsDescFrom.push_back(descriptorsFrom.row(i));
|
||||
wordsDescFrom.insert(std::make_pair(*iter, descriptorsFrom.row(i)));
|
||||
}
|
||||
++i;
|
||||
}
|
||||
@@ -1303,12 +1287,11 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
{
|
||||
if(toWordIdsSet.count(*iter) == 1)
|
||||
{
|
||||
wordsTo.insert(wordsTo.end(), std::make_pair(*iter, wordsTo.size()));
|
||||
wordsKptsTo.push_back(kptsTo[i]);
|
||||
wordsDescTo.push_back(descriptorsTo.row(i));
|
||||
if(!kptsTo3D.empty())
|
||||
wordsTo.insert(std::make_pair(*iter, kptsTo[i]));
|
||||
wordsDescTo.insert(std::make_pair(*iter, descriptorsTo.row(i)));
|
||||
if(kptsTo3D.size())
|
||||
{
|
||||
words3To.push_back(kptsTo3D[i]);
|
||||
words3To.insert(std::make_pair(*iter, kptsTo3D[i]));
|
||||
}
|
||||
}
|
||||
++i;
|
||||
@@ -1321,19 +1304,21 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
UASSERT(kptsFrom3D.empty() || int(kptsFrom3D.size()) == descriptorsFrom.rows);
|
||||
for(int i=0; i<descriptorsFrom.rows; ++i)
|
||||
{
|
||||
wordsFrom.insert(wordsFrom.end(), std::make_pair(i, wordsFrom.size()));
|
||||
wordsKptsFrom.push_back(kptsFrom[i]);
|
||||
wordsDescFrom.push_back(descriptorsFrom.row(i));
|
||||
if(!kptsFrom3D.empty())
|
||||
wordsFrom.insert(std::make_pair(i, kptsFrom[i]));
|
||||
wordsDescFrom.insert(std::make_pair(i, descriptorsFrom.row(i)));
|
||||
if(kptsFrom3D.size())
|
||||
{
|
||||
words3From.push_back(kptsFrom3D[i]);
|
||||
words3From.insert(std::make_pair(i, kptsFrom3D[i]));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fromSignature.setWords(wordsFrom, wordsKptsFrom, words3From, wordsDescFrom);
|
||||
toSignature.setWords(wordsTo, wordsKptsTo, words3To, wordsDescTo);
|
||||
fromSignature.setWords(wordsFrom);
|
||||
fromSignature.setWords3(words3From);
|
||||
fromSignature.setWordsDescriptors(wordsDescFrom);
|
||||
toSignature.setWords(wordsTo);
|
||||
toSignature.setWords3(words3To);
|
||||
toSignature.setWordsDescriptors(wordsDescTo);
|
||||
}
|
||||
|
||||
/////////////////////
|
||||
@@ -1387,31 +1372,14 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
Transform cameraTransform;
|
||||
double variance = 1.0f;
|
||||
std::vector<int> matchesV;
|
||||
std::map<int, int> uniqueWordsA = uMultimapToMapUnique(signatureA->getWords());
|
||||
std::map<int, int> uniqueWordsB = uMultimapToMapUnique(signatureB->getWords());
|
||||
std::map<int, cv::KeyPoint> wordsA;
|
||||
std::map<int, cv::Point3f> words3A;
|
||||
std::map<int, cv::KeyPoint> wordsB;
|
||||
for(std::map<int, int>::iterator iter=uniqueWordsA.begin(); iter!=uniqueWordsA.end(); ++iter)
|
||||
{
|
||||
wordsA.insert(std::make_pair(iter->first, signatureA->getWordsKpts()[iter->second]));
|
||||
if(!signatureA->getWords3().empty())
|
||||
{
|
||||
words3A.insert(std::make_pair(iter->first, signatureA->getWords3()[iter->second]));
|
||||
}
|
||||
}
|
||||
for(std::map<int, int>::iterator iter=uniqueWordsB.begin(); iter!=uniqueWordsB.end(); ++iter)
|
||||
{
|
||||
wordsB.insert(std::make_pair(iter->first, signatureB->getWordsKpts()[iter->second]));
|
||||
}
|
||||
std::map<int, cv::Point3f> inliers3D = util3d::generateWords3DMono(
|
||||
wordsA,
|
||||
wordsB,
|
||||
uMultimapToMapUnique(signatureA->getWords()),
|
||||
uMultimapToMapUnique(signatureB->getWords()),
|
||||
cameraModel,
|
||||
cameraTransform,
|
||||
_PnPReprojError,
|
||||
0.99f,
|
||||
words3A, // for scale estimation
|
||||
uMultimapToMapUnique(signatureA->getWords3()), // for scale estimation
|
||||
&variance,
|
||||
&matchesV);
|
||||
covariances[dir] *= variance;
|
||||
@@ -1487,26 +1455,9 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
|
||||
std::vector<int> inliersV;
|
||||
std::vector<int> matchesV;
|
||||
std::map<int, int> uniqueWordsA = uMultimapToMapUnique(signatureA->getWords());
|
||||
std::map<int, int> uniqueWordsB = uMultimapToMapUnique(signatureB->getWords());
|
||||
std::map<int, cv::Point3f> words3A;
|
||||
std::map<int, cv::Point3f> words3B;
|
||||
std::map<int, cv::KeyPoint> wordsB;
|
||||
for(std::map<int, int>::iterator iter=uniqueWordsA.begin(); iter!=uniqueWordsA.end(); ++iter)
|
||||
{
|
||||
words3A.insert(std::make_pair(iter->first, signatureA->getWords3()[iter->second]));
|
||||
}
|
||||
for(std::map<int, int>::iterator iter=uniqueWordsB.begin(); iter!=uniqueWordsB.end(); ++iter)
|
||||
{
|
||||
wordsB.insert(std::make_pair(iter->first, signatureB->getWordsKpts()[iter->second]));
|
||||
if(!signatureB->getWords3().empty())
|
||||
{
|
||||
words3B.insert(std::make_pair(iter->first, signatureB->getWords3()[iter->second]));
|
||||
}
|
||||
}
|
||||
transforms[dir] = util3d::estimateMotion3DTo2D(
|
||||
words3A,
|
||||
wordsB,
|
||||
uMultimapToMapUnique(signatureA->getWords3()),
|
||||
uMultimapToMapUnique(signatureB->getWords()),
|
||||
cameraModel,
|
||||
_minInliers,
|
||||
_iterations,
|
||||
@@ -1514,7 +1465,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
_PnPFlags,
|
||||
_PnPRefineIterations,
|
||||
dir==0?(!guess.isNull()?guess:Transform::getIdentity()):!transforms[0].isNull()?transforms[0].inverse():(!guess.isNull()?guess.inverse():Transform::getIdentity()),
|
||||
words3B,
|
||||
uMultimapToMapUnique(signatureB->getWords3()),
|
||||
&covariances[dir],
|
||||
&matchesV,
|
||||
&inliersV);
|
||||
@@ -1550,21 +1501,9 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
{
|
||||
std::vector<int> inliersV;
|
||||
std::vector<int> matchesV;
|
||||
std::map<int, int> uniqueWordsA = uMultimapToMapUnique(signatureA->getWords());
|
||||
std::map<int, int> uniqueWordsB = uMultimapToMapUnique(signatureB->getWords());
|
||||
std::map<int, cv::Point3f> words3A;
|
||||
std::map<int, cv::Point3f> words3B;
|
||||
for(std::map<int, int>::iterator iter=uniqueWordsA.begin(); iter!=uniqueWordsA.end(); ++iter)
|
||||
{
|
||||
words3A.insert(std::make_pair(iter->first, signatureA->getWords3()[iter->second]));
|
||||
}
|
||||
for(std::map<int, int>::iterator iter=uniqueWordsB.begin(); iter!=uniqueWordsB.end(); ++iter)
|
||||
{
|
||||
words3B.insert(std::make_pair(iter->first, signatureB->getWords3()[iter->second]));
|
||||
}
|
||||
transforms[dir] = util3d::estimateMotion3DTo3D(
|
||||
words3A,
|
||||
words3B,
|
||||
uMultimapToMapUnique(signatureA->getWords3()),
|
||||
uMultimapToMapUnique(signatureB->getWords3()),
|
||||
_minInliers,
|
||||
_inlierDistance,
|
||||
_iterations,
|
||||
@@ -1732,37 +1671,27 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
models.insert(std::make_pair(2, cameraModelTo));
|
||||
|
||||
std::map<int, std::map<int, FeatureBA> > wordReferences;
|
||||
std::set<int> sbaOutliers;
|
||||
for(unsigned int i=0; i<allInliers.size(); ++i)
|
||||
{
|
||||
int wordId = allInliers[i];
|
||||
int indexFrom = fromSignature.getWords().find(wordId)->second;
|
||||
const cv::Point3f & pt3D = fromSignature.getWords3()[indexFrom];
|
||||
if(!util3d::isFinite(pt3D))
|
||||
{
|
||||
UASSERT_MSG(!_forwardEstimateOnly, uFormat("3D point %d is not finite!?", wordId).c_str());
|
||||
sbaOutliers.insert(wordId);
|
||||
continue;
|
||||
}
|
||||
|
||||
const cv::Point3f & pt3D = fromSignature.getWords3().find(wordId)->second;
|
||||
points3DMap.insert(std::make_pair(wordId, pt3D));
|
||||
|
||||
std::map<int, FeatureBA> ptMap;
|
||||
if(!fromSignature.getWordsKpts().empty() && cameraModelFrom.isValidForProjection())
|
||||
if(fromSignature.getWords().size() && cameraModelFrom.isValidForProjection())
|
||||
{
|
||||
float depthFrom = util3d::transformPoint(pt3D, invLocalTransformFrom).z;
|
||||
const cv::KeyPoint & kpt = fromSignature.getWordsKpts()[indexFrom];
|
||||
const cv::KeyPoint & kpt = fromSignature.getWords().find(wordId)->second;
|
||||
ptMap.insert(std::make_pair(1,FeatureBA(kpt, depthFrom)));
|
||||
}
|
||||
if(!toSignature.getWordsKpts().empty() && cameraModelTo.isValidForProjection())
|
||||
if(toSignature.getWords().size() && cameraModelTo.isValidForProjection())
|
||||
{
|
||||
int indexTo = toSignature.getWords().find(wordId)->second;
|
||||
float depthTo = 0.0f;
|
||||
if(!toSignature.getWords3().empty())
|
||||
if(toSignature.getWords3().find(wordId) != toSignature.getWords3().end())
|
||||
{
|
||||
depthTo = util3d::transformPoint(toSignature.getWords3()[indexTo], invLocalTransformTo).z;
|
||||
depthTo = util3d::transformPoint(toSignature.getWords3().find(wordId)->second, invLocalTransformTo).z;
|
||||
}
|
||||
const cv::KeyPoint & kpt = toSignature.getWordsKpts()[indexTo];
|
||||
const cv::KeyPoint & kpt = toSignature.getWords().find(wordId)->second;
|
||||
ptMap.insert(std::make_pair(2,FeatureBA(kpt, depthTo)));
|
||||
}
|
||||
|
||||
@@ -1775,6 +1704,7 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
//}
|
||||
}
|
||||
|
||||
std::set<int> sbaOutliers;
|
||||
optimizedPoses = sba->optimizeBA(1, poses, links, models, points3DMap, wordReferences, &sbaOutliers);
|
||||
delete sba;
|
||||
|
||||
@@ -1900,25 +1830,24 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
{
|
||||
if(_maxInliersMeanDistance>0.0f)
|
||||
{
|
||||
std::multimap<int, int>::const_iterator wordsIter = fromSignature.getWords().find(allInliers[i]);
|
||||
if(wordsIter != fromSignature.getWords().end() && !fromSignature.getWords3().empty())
|
||||
std::multimap<int, cv::Point3f>::const_iterator words3Iter = fromSignature.getWords3().find(allInliers[i]);
|
||||
if(words3Iter != fromSignature.getWords3().end())
|
||||
{
|
||||
const cv::Point3f & pt = fromSignature.getWords3()[wordsIter->second];
|
||||
if(uIsFinite(pt.x))
|
||||
if(uIsFinite(words3Iter->second.x))
|
||||
{
|
||||
distances.push_back(util3d::transformPoint(pt, transformInv).x);
|
||||
cv::Point3f pt = util3d::transformPoint(words3Iter->second, transformInv);
|
||||
distances.push_back(pt.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!pcaData.empty())
|
||||
{
|
||||
std::multimap<int, int>::const_iterator wordsIter = fromSignature.getWords().find(allInliers[i]);
|
||||
UASSERT(wordsIter != fromSignature.getWords().end() && !fromSignature.getWordsKpts().empty());
|
||||
std::multimap<int, cv::KeyPoint>::const_iterator wordsIter = fromSignature.getWords().find(allInliers[i]);
|
||||
UASSERT(wordsIter != fromSignature.getWords().end());
|
||||
float * ptr = pcaData.ptr<float>(i, 0);
|
||||
const cv::KeyPoint & kpt = fromSignature.getWordsKpts()[wordsIter->second];
|
||||
ptr[0] = (kpt.pt.x-cx) / w;
|
||||
ptr[1] = (kpt.pt.y-cy) / h;
|
||||
ptr[0] = (wordsIter->second.pt.x-cx) / w;
|
||||
ptr[1] = (wordsIter->second.pt.y-cy) / h;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1959,7 +1888,6 @@ Transform RegistrationVis::computeTransformationImpl(
|
||||
}
|
||||
|
||||
info.inliers = inliersCount;
|
||||
info.inliersRatio = !toSignature.getWords().empty()?float(inliersCount)/float(toSignature.getWords().size()):0;
|
||||
info.matches = matchesCount;
|
||||
info.rejectedMsg = msg;
|
||||
info.covariance = covariance;
|
||||
|
||||
+47
-144
@@ -134,7 +134,6 @@ Rtabmap::Rtabmap() :
|
||||
_lastProcessTime(0.0),
|
||||
_someNodesHaveBeenTransferred(false),
|
||||
_distanceTravelled(0.0f),
|
||||
_distanceTravelledSinceLastLocalization(0.0f),
|
||||
_optimizeFromGraphEndChanged(false),
|
||||
_epipolarGeometry(0),
|
||||
_bayesFilter(0),
|
||||
@@ -351,17 +350,6 @@ void Rtabmap::init(const ParametersMap & parameters, const std::string & databas
|
||||
std::map<int, Transform> tmp;
|
||||
// Get just the links
|
||||
_memory->getMetricConstraints(uKeysSet(_optimizedPoses), tmp, _constraints, false, true);
|
||||
|
||||
// Initialize Bayes' prediction matrix
|
||||
UTimer time;
|
||||
std::map<int, float> likelihood;
|
||||
likelihood.insert(std::make_pair(Memory::kIdVirtual, 1));
|
||||
for(std::map<int, Transform>::iterator iter=_optimizedPoses.begin(); iter!=_optimizedPoses.end(); ++iter)
|
||||
{
|
||||
likelihood.insert(std::make_pair(iter->first, 0));
|
||||
}
|
||||
_bayesFilter->computePosterior(_memory, likelihood);
|
||||
UINFO("Time initializing Bayes' prediction with %ld nodes: %fs", _optimizedPoses.size(), time.ticks());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -405,7 +393,6 @@ void Rtabmap::close(bool databaseSaved, const std::string & ouputDatabasePath)
|
||||
_odomCacheConstraints.clear();
|
||||
_odomCorrectionAcc = std::vector<float>(6,0);
|
||||
_distanceTravelled = 0.0f;
|
||||
_distanceTravelledSinceLastLocalization = 0.0f;
|
||||
_optimizeFromGraphEndChanged = false;
|
||||
this->clearPath(0);
|
||||
_gpsGeocentricCache.clear();
|
||||
@@ -432,16 +419,6 @@ void Rtabmap::close(bool databaseSaved, const std::string & ouputDatabasePath)
|
||||
{
|
||||
if(databaseSaved)
|
||||
{
|
||||
if(_memory->isGraphReduced() && _memory->isIncremental())
|
||||
{
|
||||
// Force reducing graph, then remove filtered nodes from the optimized poses
|
||||
std::map<int, int> reducedIds;
|
||||
_memory->incrementMapId(&reducedIds);
|
||||
for(std::map<int, int>::iterator iter=reducedIds.begin(); iter!=reducedIds.end(); ++iter)
|
||||
{
|
||||
_optimizedPoses.erase(iter->first);
|
||||
}
|
||||
}
|
||||
_memory->saveOptimizedPoses(_optimizedPoses, _lastLocalizationPose);
|
||||
}
|
||||
_memory->close(databaseSaved, true, ouputDatabasePath);
|
||||
@@ -678,6 +655,19 @@ int Rtabmap::getTotalMemSize() const
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::multimap<int, cv::KeyPoint> Rtabmap::getWords(int locationId) const
|
||||
{
|
||||
if(_memory)
|
||||
{
|
||||
const Signature * s = _memory->getSignature(locationId);
|
||||
if(s)
|
||||
{
|
||||
return s->getWords();
|
||||
}
|
||||
}
|
||||
return std::multimap<int, cv::KeyPoint>();
|
||||
}
|
||||
|
||||
bool Rtabmap::isInSTM(int locationId) const
|
||||
{
|
||||
if(_memory)
|
||||
@@ -700,7 +690,25 @@ const Statistics & Rtabmap::getStatistics() const
|
||||
{
|
||||
return statistics_;
|
||||
}
|
||||
|
||||
/*
|
||||
bool Rtabmap::getMetricData(int locationId, cv::Mat & rgb, cv::Mat & depth, float & depthConstant, Transform & pose, Transform & localTransform) const
|
||||
{
|
||||
if(_memory)
|
||||
{
|
||||
const Signature * s = _memory->getSignature(locationId);
|
||||
if(s && _optimizedPoses.find(s->id()) != _optimizedPoses.end())
|
||||
{
|
||||
rgb = s->getImage();
|
||||
depth = s->getDepth();
|
||||
depthConstant = s->getDepthConstant();
|
||||
pose = _optimizedPoses.at(s->id());
|
||||
localTransform = s->getLocalTransform();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
Transform Rtabmap::getPose(int locationId) const
|
||||
{
|
||||
return uValue(_optimizedPoses, locationId, Transform());
|
||||
@@ -743,8 +751,6 @@ int Rtabmap::triggerNewMap()
|
||||
_odomCachePoses.clear();
|
||||
_odomCacheConstraints.clear();
|
||||
_odomCorrectionAcc = std::vector<float>(6,0);
|
||||
_distanceTravelled = 0.0f;
|
||||
_distanceTravelledSinceLastLocalization = 0.0f;
|
||||
|
||||
if(!_memory->isIncremental())
|
||||
{
|
||||
@@ -911,7 +917,6 @@ void Rtabmap::resetMemory()
|
||||
_odomCacheConstraints.clear();
|
||||
_odomCorrectionAcc = std::vector<float>(6,0);
|
||||
_distanceTravelled = 0.0f;
|
||||
_distanceTravelledSinceLastLocalization = 0.0f;
|
||||
_optimizeFromGraphEndChanged = false;
|
||||
this->clearPath(0);
|
||||
|
||||
@@ -1071,43 +1076,6 @@ bool Rtabmap::process(
|
||||
bool fakeOdom = false;
|
||||
if(_rgbdSlamMode)
|
||||
{
|
||||
if(!odomPose.isNull())
|
||||
{
|
||||
// this will make sure that all inverse operations will work!
|
||||
if(!odomPose.isInvertible())
|
||||
{
|
||||
UWARN("Input odometry is not invertible! pose = %s\n"
|
||||
"[%f %f %f %f;\n"
|
||||
" %f %f %f %f;\n"
|
||||
" %f %f %f %f;\n"
|
||||
" 0 0 0 1]\n"
|
||||
"Trying to normalize rotation to see if it makes it invertible...",
|
||||
odomPose.prettyPrint().c_str(),
|
||||
odomPose.r11(), odomPose.r12(), odomPose.r13(), odomPose.o14(),
|
||||
odomPose.r21(), odomPose.r22(), odomPose.r23(), odomPose.o24(),
|
||||
odomPose.r31(), odomPose.r32(), odomPose.r33(), odomPose.o34());
|
||||
odomPose.normalizeRotation();
|
||||
UASSERT_MSG(odomPose.isInvertible(), uFormat("Odometry pose is not invertible!\n"
|
||||
"[%f %f %f %f;\n"
|
||||
" %f %f %f %f;\n"
|
||||
" %f %f %f %f;\n"
|
||||
" 0 0 0 1]", odomPose.prettyPrint().c_str(),
|
||||
odomPose.r11(), odomPose.r12(), odomPose.r13(), odomPose.o14(),
|
||||
odomPose.r21(), odomPose.r22(), odomPose.r23(), odomPose.o24(),
|
||||
odomPose.r31(), odomPose.r32(), odomPose.r33(), odomPose.o34()).c_str());
|
||||
UWARN("Normalizing rotation succeeded! fixed pose = %s\n"
|
||||
"[%f %f %f %f;\n"
|
||||
" %f %f %f %f;\n"
|
||||
" %f %f %f %f;\n"
|
||||
" 0 0 0 1]\n"
|
||||
"If the resulting rotation is very different from original one, try to fix the odometry or TF.",
|
||||
odomPose.prettyPrint().c_str(),
|
||||
odomPose.r11(), odomPose.r12(), odomPose.r13(), odomPose.o14(),
|
||||
odomPose.r21(), odomPose.r22(), odomPose.r23(), odomPose.o24(),
|
||||
odomPose.r31(), odomPose.r32(), odomPose.r33(), odomPose.o34());
|
||||
}
|
||||
}
|
||||
|
||||
if(!_memory->isIncremental() &&
|
||||
!odomPose.isNull() &&
|
||||
_optimizedPoses.size() &&
|
||||
@@ -1275,7 +1243,6 @@ bool Rtabmap::process(
|
||||
// This will disable global loop closure detection, only retrieval will be done.
|
||||
// The location will also be deleted at the end.
|
||||
smallDisplacement = true;
|
||||
UDEBUG("smallDisplacement: %f %f %f %f %f %f", x,y,z, roll,pitch,yaw);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1391,9 +1358,7 @@ bool Rtabmap::process(
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Neighbor link refining is activated but there are intermediate nodes (%d=%d %d=%d), aborting refining...",
|
||||
signature->id(), signature->getWeight(), oldS->id(), oldS->getWeight());
|
||||
newPose = _mapCorrection * signature->getPose();
|
||||
UWARN("Neighbor link refining is activated but there are intermediate nodes, aborting refining...");
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -1415,9 +1380,6 @@ bool Rtabmap::process(
|
||||
_constraints.insert(std::make_pair(iter->first, iter->second.inverse()));
|
||||
}
|
||||
}
|
||||
|
||||
float distanceTravelledOld = _distanceTravelled;
|
||||
|
||||
// only in mapping mode we add a neighbor link
|
||||
if(signature->getLinks().size() &&
|
||||
signature->getLinks().begin()->second.type() == Link::kNeighbor)
|
||||
@@ -1490,7 +1452,6 @@ bool Rtabmap::process(
|
||||
}
|
||||
}
|
||||
}
|
||||
_distanceTravelledSinceLastLocalization += _distanceTravelled - distanceTravelledOld;
|
||||
|
||||
//============================================================
|
||||
// Reduced graph
|
||||
@@ -2223,7 +2184,6 @@ bool Rtabmap::process(
|
||||
// Landmark
|
||||
//============================================================
|
||||
int landmarkDetected = 0;
|
||||
bool rejectedLandmark = false;
|
||||
std::set<int> landmarkDetectedNodesRef;
|
||||
if(!signature->getLandmarks().empty())
|
||||
{
|
||||
@@ -2245,7 +2205,6 @@ bool Rtabmap::process(
|
||||
//============================================================
|
||||
std::list<std::pair<int, int> > loopClosureLinksAdded;
|
||||
int loopClosureVisualInliers = 0; // for statistics
|
||||
float loopClosureVisualInliersRatio = 0.0f;
|
||||
int loopClosureVisualMatches = 0;
|
||||
float loopClosureLinearVariance = 0.0f;
|
||||
float loopClosureAngularVariance = 0.0f;
|
||||
@@ -2397,7 +2356,6 @@ bool Rtabmap::process(
|
||||
lastProximitySpaceClosureId = nearestId;
|
||||
|
||||
loopClosureVisualInliers = info.inliers;
|
||||
loopClosureVisualInliersRatio = info.inliersRatio;
|
||||
loopClosureVisualMatches = info.matches;
|
||||
|
||||
loopClosureLinearVariance = 1.0/information.at<double>(0,0);
|
||||
@@ -2601,7 +2559,6 @@ bool Rtabmap::process(
|
||||
loopClosureVisualInliersDistribution = info.inliersDistribution;
|
||||
|
||||
loopClosureVisualInliers = info.inliers;
|
||||
loopClosureVisualInliersRatio = info.inliersRatio;
|
||||
loopClosureVisualMatches = info.matches;
|
||||
rejectedGlobalLoopClosure = transform.isNull();
|
||||
if(rejectedGlobalLoopClosure)
|
||||
@@ -2954,7 +2911,6 @@ bool Rtabmap::process(
|
||||
_loopClosureHypothesis.first = 0;
|
||||
lastProximitySpaceClosureId = 0;
|
||||
rejectedGlobalLoopClosure = true;
|
||||
rejectedLandmark = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -2990,7 +2946,6 @@ bool Rtabmap::process(
|
||||
_loopClosureHypothesis.first = 0;
|
||||
lastProximitySpaceClosureId = 0;
|
||||
rejectedGlobalLoopClosure = true;
|
||||
rejectedLandmark = true;
|
||||
}
|
||||
else if(_memory->isIncremental() &&
|
||||
_optimizationMaxError > 0.0f &&
|
||||
@@ -3076,7 +3031,6 @@ bool Rtabmap::process(
|
||||
_loopClosureHypothesis.first = 0;
|
||||
lastProximitySpaceClosureId = 0;
|
||||
rejectedGlobalLoopClosure = true;
|
||||
rejectedLandmark = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3098,7 +3052,7 @@ bool Rtabmap::process(
|
||||
previousMapCorrection = _mapCorrection;
|
||||
_mapCorrection = _optimizedPoses.at(signature->id()) * signature->getPose().inverse();
|
||||
_lastLocalizationPose = _optimizedPoses.at(signature->id()); // update
|
||||
if(_mapCorrection.getNormSquared() > 0.1f && _optimizeFromGraphEnd)
|
||||
if(_mapCorrection.getNormSquared() > 0.001f && _optimizeFromGraphEnd)
|
||||
{
|
||||
bool hasPrior = signature->hasLink(signature->id());
|
||||
if(!_graphOptimizer->priorsIgnored())
|
||||
@@ -3183,7 +3137,6 @@ bool Rtabmap::process(
|
||||
statistics_.addStatistic(Statistics::kLoopReactivate_id(), retrievalId);
|
||||
statistics_.addStatistic(Statistics::kLoopHypothesis_ratio(), hypothesisRatio);
|
||||
statistics_.addStatistic(Statistics::kLoopVisual_inliers(), loopClosureVisualInliers);
|
||||
statistics_.addStatistic(Statistics::kLoopVisual_inliers_ratio(), loopClosureVisualInliersRatio);
|
||||
statistics_.addStatistic(Statistics::kLoopVisual_matches(), loopClosureVisualMatches);
|
||||
statistics_.addStatistic(Statistics::kLoopLinear_variance(), loopClosureLinearVariance);
|
||||
statistics_.addStatistic(Statistics::kLoopAngular_variance(), loopClosureAngularVariance);
|
||||
@@ -3207,9 +3160,7 @@ bool Rtabmap::process(
|
||||
statistics_.setProximityDetectionId(lastProximitySpaceClosureId);
|
||||
statistics_.setProximityDetectionMapId(_memory->getMapId(lastProximitySpaceClosureId));
|
||||
|
||||
int loopId = _loopClosureHypothesis.first>0?_loopClosureHypothesis.first:lastProximitySpaceClosureId;
|
||||
statistics_.addStatistic(Statistics::kLoopId(), loopId);
|
||||
statistics_.addStatistic(Statistics::kLoopMap_id(), (loopId>0 && sLoop)?sLoop->mapId():-1);
|
||||
statistics_.addStatistic(Statistics::kLoopId(), _loopClosureHypothesis.first>0?_loopClosureHypothesis.first:lastProximitySpaceClosureId);
|
||||
|
||||
float x,y,z,roll,pitch,yaw;
|
||||
if(_loopClosureHypothesis.first || lastProximitySpaceClosureId)
|
||||
@@ -3221,9 +3172,8 @@ bool Rtabmap::process(
|
||||
UINFO("Set loop closure transform = %s", loopIter->second.transform().prettyPrint().c_str());
|
||||
statistics_.setLoopClosureTransform(loopIter->second.transform());
|
||||
|
||||
statistics_.addStatistic(Statistics::kLoopMap_id(), sLoop->mapId());
|
||||
statistics_.addStatistic(Statistics::kLoopVisual_words(), sLoop->getWords().size());
|
||||
statistics_.addStatistic(Statistics::kLoopDistance_since_last_loc(), _distanceTravelledSinceLastLocalization);
|
||||
_distanceTravelledSinceLastLocalization = 0.0f;
|
||||
|
||||
// if ground truth exists, compute localization error
|
||||
if(!sLoop->getGroundTruthPose().isNull() && !signature->getGroundTruthPose().isNull())
|
||||
@@ -3331,16 +3281,7 @@ bool Rtabmap::process(
|
||||
statistics_.addStatistic(Statistics::kMemoryFast_movement(), tooFastMovement?1.0f:0);
|
||||
if(_publishRAMUsage)
|
||||
{
|
||||
UTimer ramTimer;
|
||||
statistics_.addStatistic(Statistics::kMemoryRAM_usage(), UProcessInfo::getMemoryUsage()/(1024*1024));
|
||||
long estimatedMemoryUsage = sizeof(Rtabmap);
|
||||
estimatedMemoryUsage += _optimizedPoses.size() * (sizeof(int) + sizeof(Transform) + 12 * sizeof(float) + sizeof(std::map<int, Transform>::iterator)) + sizeof(std::map<int, Transform>);
|
||||
estimatedMemoryUsage += _constraints.size() * (sizeof(int) + sizeof(Transform) + 12 * sizeof(float) + sizeof(cv::Mat) + 36 * sizeof(double) + sizeof(std::map<int, Link>::iterator)) + sizeof(std::map<int, Link>);
|
||||
estimatedMemoryUsage += _memory->getMemoryUsed();
|
||||
estimatedMemoryUsage += _bayesFilter->getMemoryUsed();
|
||||
estimatedMemoryUsage += _parameters.size()*(sizeof(std::string)*2+sizeof(ParametersMap::iterator)) + sizeof(ParametersMap);
|
||||
statistics_.addStatistic(Statistics::kMemoryRAM_estimated(), (float)(estimatedMemoryUsage/(1024*1024)));//MB
|
||||
statistics_.addStatistic(Statistics::kTimingRAM_estimation(), ramTimer.ticks()*1000);
|
||||
}
|
||||
|
||||
if(_publishLikelihood || _publishPdf)
|
||||
@@ -3405,7 +3346,7 @@ bool Rtabmap::process(
|
||||
if(_startNewMapOnLoopClosure &&
|
||||
_memory->isIncremental() && // only in mapping mode
|
||||
graph::filterLinks(signature->getLinks(), Link::kSelfRefLink).size() == 0 && // alone in the current map
|
||||
(landmarkDetected == 0 || rejectedLandmark) && // if we re not seeing a landmark from a previous map
|
||||
(landmarkDetected == 0 || rejectedGlobalLoopClosure) && // if we re not seeing a landmark from a previous map
|
||||
_memory->getWorkingMem().size()>=2) // The working memory should not be empty (beside virtual signature)
|
||||
{
|
||||
UWARN("Ignoring location %d because a global loop closure is required before starting a new map!",
|
||||
@@ -4489,30 +4430,18 @@ Signature Rtabmap::getSignatureCopy(int id, bool images, bool scan, bool userDat
|
||||
groundTruth,
|
||||
data);
|
||||
|
||||
std::multimap<int, Link> links = _memory->getLinks(id, true, true);
|
||||
for(std::multimap<int, Link>::iterator iter=links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
if(iter->second.type() == Link::kLandmark)
|
||||
{
|
||||
s.addLandmark(iter->second);
|
||||
}
|
||||
else
|
||||
{
|
||||
s.addLink(iter->second);
|
||||
}
|
||||
}
|
||||
|
||||
if(withWords || withGlobalDescriptors)
|
||||
{
|
||||
std::multimap<int, int> words;
|
||||
std::vector<cv::KeyPoint> wordsKpts;
|
||||
std::vector<cv::Point3f> words3;
|
||||
cv::Mat wordsDescriptors;
|
||||
std::multimap<int, cv::KeyPoint> words;
|
||||
std::multimap<int, cv::Point3f> words3;
|
||||
std::multimap<int, cv::Mat> wordsDescriptors;
|
||||
std::vector<rtabmap::GlobalDescriptor> globalDescriptors;
|
||||
_memory->getNodeWordsAndGlobalDescriptors(id, words, wordsKpts, words3, wordsDescriptors, globalDescriptors);
|
||||
_memory->getNodeWordsAndGlobalDescriptors(id, words, words3, wordsDescriptors, globalDescriptors);
|
||||
if(withWords)
|
||||
{
|
||||
s.setWords(words, wordsKpts, words3, wordsDescriptors);
|
||||
s.setWords(words);
|
||||
s.setWords3(words3);
|
||||
s.setWordsDescriptors(wordsDescriptors);
|
||||
}
|
||||
if(withGlobalDescriptors)
|
||||
{
|
||||
@@ -4606,26 +4535,6 @@ void Rtabmap::getGraph(
|
||||
}
|
||||
}
|
||||
|
||||
std::map<int, Transform> Rtabmap::getNodesInRadius(const Transform & pose, float radius)
|
||||
{
|
||||
return graph::getPosesInRadius(pose, _optimizedPoses, radius<=0?_localRadius:radius);
|
||||
}
|
||||
|
||||
std::map<int, Transform> Rtabmap::getNodesInRadius(int nodeId, float radius)
|
||||
{
|
||||
UDEBUG("nodeId=%d, radius=%f", nodeId, radius);
|
||||
std::map<int, Transform> nearNodes;
|
||||
if(nodeId==0 && !_optimizedPoses.empty())
|
||||
{
|
||||
nodeId = _optimizedPoses.rbegin()->first;
|
||||
}
|
||||
if(_optimizedPoses.find(nodeId) != _optimizedPoses.end())
|
||||
{
|
||||
nearNodes = graph::getPosesInRadius(nodeId, _optimizedPoses, radius<=0?_localRadius:radius);
|
||||
}
|
||||
return nearNodes;
|
||||
}
|
||||
|
||||
int Rtabmap::detectMoreLoopClosures(
|
||||
float clusterRadius,
|
||||
float clusterAngle,
|
||||
@@ -4658,7 +4567,7 @@ int Rtabmap::detectMoreLoopClosures(
|
||||
std::map<int, Transform> posesToCheckLoopClosures;
|
||||
std::map<int, Transform> poses;
|
||||
std::multimap<int, Link> links;
|
||||
std::map<int, Signature> signatures; // some signatures may be in LTM, get them all
|
||||
std::map<int, Signature> signatures;
|
||||
this->getGraph(poses, links, true, true, &signatures);
|
||||
|
||||
std::map<int, int> mapIds;
|
||||
@@ -4696,7 +4605,7 @@ int Rtabmap::detectMoreLoopClosures(
|
||||
|
||||
int from = iter->first;
|
||||
int to = iter->second;
|
||||
if(from > to)
|
||||
if(iter->first < iter->second)
|
||||
{
|
||||
from = iter->second;
|
||||
to = iter->first;
|
||||
@@ -4732,15 +4641,9 @@ int Rtabmap::detectMoreLoopClosures(
|
||||
UASSERT(signatures.find(from) != signatures.end());
|
||||
UASSERT(signatures.find(to) != signatures.end());
|
||||
|
||||
Transform guess;
|
||||
if(_proximityOdomGuess && uContains(poses, from) && uContains(poses, to))
|
||||
{
|
||||
guess = poses.at(from).inverse() * poses.at(to);
|
||||
}
|
||||
|
||||
RegistrationInfo info;
|
||||
// use signatures instead of IDs because some signatures may not be in WM
|
||||
Transform t = _memory->computeTransform(signatures.at(from), signatures.at(to), guess, &info);
|
||||
Transform t = _memory->computeTransform(signatures.at(from), signatures.at(to), Transform(), &info);
|
||||
|
||||
if(!t.isNull())
|
||||
{
|
||||
|
||||
@@ -763,10 +763,9 @@ void SensorData::setFeatures(const std::vector<cv::KeyPoint> & keypoints, const
|
||||
_descriptors = descriptors;
|
||||
}
|
||||
|
||||
unsigned long SensorData::getMemoryUsed() const // Return memory usage in Bytes
|
||||
long SensorData::getMemoryUsed() const // Return memory usage in Bytes
|
||||
{
|
||||
return sizeof(SensorData) +
|
||||
_imageCompressed.total()*_imageCompressed.elemSize() +
|
||||
return _imageCompressed.total()*_imageCompressed.elemSize() +
|
||||
_imageRaw.total()*_imageRaw.elemSize() +
|
||||
_depthOrRightCompressed.total()*_depthOrRightCompressed.elemSize() +
|
||||
_depthOrRightRaw.total()*_depthOrRightRaw.elemSize() +
|
||||
@@ -780,8 +779,8 @@ unsigned long SensorData::getMemoryUsed() const // Return memory usage in Bytes
|
||||
_obstacleCellsRaw.total()*_obstacleCellsRaw.elemSize()+
|
||||
_emptyCellsCompressed.total()*_emptyCellsCompressed.elemSize() +
|
||||
_emptyCellsRaw.total()*_emptyCellsRaw.elemSize()+
|
||||
_keypoints.size() * sizeof(cv::KeyPoint) +
|
||||
_keypoints3D.size() * sizeof(cv::Point3f) +
|
||||
_keypoints.size() * sizeof(float) * 7 +
|
||||
_keypoints3D.size() * sizeof(float)*3 +
|
||||
_descriptors.total()*_descriptors.elemSize();
|
||||
}
|
||||
|
||||
|
||||
+47
-72
@@ -132,24 +132,11 @@ bool Signature::hasLink(int idTo, Link::Type type) const
|
||||
{
|
||||
return _links.find(idTo) != _links.end();
|
||||
}
|
||||
if(idTo==0)
|
||||
for(std::multimap<int, Link>::const_iterator iter=_links.find(idTo); iter!=_links.end() && iter->first == idTo; ++iter)
|
||||
{
|
||||
for(std::multimap<int, Link>::const_iterator iter=_links.begin(); iter!=_links.end(); ++iter)
|
||||
if(type == iter->second.type())
|
||||
{
|
||||
if(type == iter->second.type())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for(std::multimap<int, Link>::const_iterator iter=_links.find(idTo); iter!=_links.end() && iter->first == idTo; ++iter)
|
||||
{
|
||||
if(type == iter->second.type())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
@@ -222,11 +209,11 @@ void Signature::removeVirtualLinks()
|
||||
float Signature::compareTo(const Signature & s) const
|
||||
{
|
||||
float similarity = 0.0f;
|
||||
const std::multimap<int, int> & words = s.getWords();
|
||||
const std::multimap<int, cv::KeyPoint> & words = s.getWords();
|
||||
|
||||
if(!s.isBadSignature() && !this->isBadSignature())
|
||||
{
|
||||
std::list<std::pair<int, std::pair<int, int> > > pairs;
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > pairs;
|
||||
int totalWords = ((int)_words.size()-_invalidWordsCount)>((int)words.size()-s.getInvalidWordsCount())?((int)_words.size()-_invalidWordsCount):((int)words.size()-s.getInvalidWordsCount());
|
||||
UASSERT(totalWords > 0);
|
||||
EpipolarGeometry::findPairs(words, _words, pairs);
|
||||
@@ -238,9 +225,11 @@ float Signature::compareTo(const Signature & s) const
|
||||
|
||||
void Signature::changeWordsRef(int oldWordId, int activeWordId)
|
||||
{
|
||||
std::list<int> words = uValues(_words, oldWordId);
|
||||
if(words.size())
|
||||
std::list<cv::KeyPoint> kps = uValues(_words, oldWordId);
|
||||
if(kps.size())
|
||||
{
|
||||
std::list<cv::Point3f> pts = uValues(_words3, oldWordId);
|
||||
std::list<cv::Mat> descriptors = uValues(_wordsDescriptors, oldWordId);
|
||||
if(oldWordId<=0)
|
||||
{
|
||||
_invalidWordsCount-=(int)_words.erase(oldWordId);
|
||||
@@ -250,41 +239,37 @@ void Signature::changeWordsRef(int oldWordId, int activeWordId)
|
||||
{
|
||||
_words.erase(oldWordId);
|
||||
}
|
||||
|
||||
_words3.erase(oldWordId);
|
||||
_wordsDescriptors.erase(oldWordId);
|
||||
_wordsChanged.insert(std::make_pair(oldWordId, activeWordId));
|
||||
for(std::list<int>::const_iterator iter=words.begin(); iter!=words.end(); ++iter)
|
||||
for(std::list<cv::KeyPoint>::const_iterator iter=kps.begin(); iter!=kps.end(); ++iter)
|
||||
{
|
||||
_words.insert(std::pair<int, int>(activeWordId, (*iter)));
|
||||
_words.insert(std::pair<int, cv::KeyPoint>(activeWordId, (*iter)));
|
||||
}
|
||||
for(std::list<cv::Point3f>::const_iterator iter=pts.begin(); iter!=pts.end(); ++iter)
|
||||
{
|
||||
_words3.insert(std::pair<int, cv::Point3f>(activeWordId, (*iter)));
|
||||
}
|
||||
for(std::list<cv::Mat>::const_iterator iter=descriptors.begin(); iter!=descriptors.end(); ++iter)
|
||||
{
|
||||
_wordsDescriptors.insert(std::pair<int, cv::Mat>(activeWordId, (*iter)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Signature::setWords(const std::multimap<int, int> & words,
|
||||
const std::vector<cv::KeyPoint> & keypoints,
|
||||
const std::vector<cv::Point3f> & points,
|
||||
const cv::Mat & descriptors)
|
||||
void Signature::setWords(const std::multimap<int, cv::KeyPoint> & words)
|
||||
{
|
||||
UASSERT_MSG(descriptors.empty() || descriptors.rows == (int)words.size(), uFormat("words=%d, descriptors=%d", (int)words.size(), descriptors.rows).c_str());
|
||||
UASSERT_MSG(points.empty() || points.size() == words.size(), uFormat("words=%d, points=%d", (int)words.size(), (int)points.size()).c_str());
|
||||
UASSERT_MSG(keypoints.empty() || keypoints.size() == words.size(), uFormat("words=%d, descriptors=%d", (int)words.size(), (int)keypoints.size()).c_str());
|
||||
UASSERT(words.empty() || !keypoints.empty() || !points.empty() || !descriptors.empty());
|
||||
|
||||
_invalidWordsCount = 0;
|
||||
for(std::multimap<int, int>::const_iterator iter=words.begin(); iter!=words.end(); ++iter)
|
||||
{
|
||||
if(iter->first<=0)
|
||||
{
|
||||
++_invalidWordsCount;
|
||||
}
|
||||
// make sure indexes are all valid!
|
||||
UASSERT_MSG(iter->second >=0 && iter->second < (int)words.size(), uFormat("iter->second=%d words.size()=%d", iter->second, (int)words.size()).c_str());
|
||||
}
|
||||
|
||||
_enabled = false;
|
||||
_words = words;
|
||||
_wordsKpts = keypoints;
|
||||
_words3 = points;
|
||||
_wordsDescriptors = descriptors.clone();
|
||||
_invalidWordsCount = 0;
|
||||
for(std::multimap<int, cv::KeyPoint>::iterator iter=_words.begin(); iter!=_words.end(); ++iter)
|
||||
{
|
||||
if(iter->first>0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
++_invalidWordsCount;
|
||||
}
|
||||
}
|
||||
|
||||
bool Signature::isBadSignature() const
|
||||
@@ -295,30 +280,24 @@ bool Signature::isBadSignature() const
|
||||
void Signature::removeAllWords()
|
||||
{
|
||||
_words.clear();
|
||||
_wordsKpts.clear();
|
||||
_words3.clear();
|
||||
_wordsDescriptors = cv::Mat();
|
||||
_wordsDescriptors.clear();
|
||||
_invalidWordsCount = 0;
|
||||
}
|
||||
|
||||
void Signature::setWordsDescriptors(const cv::Mat & descriptors)
|
||||
void Signature::removeWord(int wordId)
|
||||
{
|
||||
if(descriptors.empty())
|
||||
if(wordId<=0)
|
||||
{
|
||||
if(_wordsKpts.empty() && _words3.empty())
|
||||
{
|
||||
removeAllWords();
|
||||
}
|
||||
else
|
||||
{
|
||||
_wordsDescriptors = cv::Mat();
|
||||
}
|
||||
_invalidWordsCount-=(int)_words.erase(wordId);
|
||||
UASSERT(_invalidWordsCount>=0);
|
||||
}
|
||||
else
|
||||
{
|
||||
UASSERT(descriptors.rows == (int)_words.size());
|
||||
_wordsDescriptors = descriptors.clone();
|
||||
_words.erase(wordId);
|
||||
}
|
||||
_words3.erase(wordId);
|
||||
_wordsDescriptors.clear();
|
||||
}
|
||||
|
||||
cv::Mat Signature::getPoseCovariance() const
|
||||
@@ -342,23 +321,19 @@ cv::Mat Signature::getPoseCovariance() const
|
||||
return covariance;
|
||||
}
|
||||
|
||||
unsigned long Signature::getMemoryUsed(bool withSensorData) const // Return memory usage in Bytes
|
||||
long Signature::getMemoryUsed(bool withSensorData) const // Return memory usage in Bytes
|
||||
{
|
||||
unsigned long total = sizeof(Signature);
|
||||
total += _words.size() * (sizeof(int)*2+sizeof(std::multimap<int, cv::KeyPoint>::iterator)) + sizeof(std::multimap<int, cv::KeyPoint>);
|
||||
total += _wordsKpts.size() * sizeof(cv::KeyPoint) + sizeof(std::vector<cv::KeyPoint>);
|
||||
total += _words3.size() * sizeof(cv::Point3f) + sizeof(std::vector<cv::Point3f>);
|
||||
total += _wordsDescriptors.total() * _wordsDescriptors.elemSize() + sizeof(cv::Mat);
|
||||
total += _wordsChanged.size() * (sizeof(int)*2+sizeof(std::map<int, int>::iterator)) + sizeof(std::map<int, int>);
|
||||
long total = _words.size() * sizeof(float) * 8 +
|
||||
_words3.size() * sizeof(float) * 4;
|
||||
if(!_wordsDescriptors.empty())
|
||||
{
|
||||
total += _wordsDescriptors.size() * sizeof(int);
|
||||
total += _wordsDescriptors.size() * _wordsDescriptors.begin()->second.total() * _wordsDescriptors.begin()->second.elemSize();
|
||||
}
|
||||
if(withSensorData)
|
||||
{
|
||||
total+=_sensorData.getMemoryUsed();
|
||||
}
|
||||
total += _pose.size() * (sizeof(Transform) + sizeof(float)*12);
|
||||
total += _groundTruthPose.size() * (sizeof(Transform) + sizeof(float)*12);
|
||||
total += _velocity.size() * sizeof(float);
|
||||
total += _links.size() * (sizeof(int) + sizeof(Transform) + 12 * sizeof(float) + sizeof(cv::Mat) + 36 * sizeof(double)+sizeof(std::multimap<int, Link>::iterator)) + sizeof(std::multimap<int, Link>);
|
||||
total += _landmarks.size() * (sizeof(int) + sizeof(Transform) + 12 * sizeof(float) + sizeof(cv::Mat) + 36 * sizeof(double)+sizeof(std::map<int, Link>::iterator)) + sizeof(std::map<int, Link>);
|
||||
return total;
|
||||
}
|
||||
|
||||
|
||||
@@ -166,30 +166,9 @@ float Transform::theta() const
|
||||
return yaw;
|
||||
}
|
||||
|
||||
bool Transform::isInvertible() const
|
||||
{
|
||||
bool invertible = false;
|
||||
Eigen::Matrix4f inverse;
|
||||
Eigen::Matrix4f::RealScalar det;
|
||||
toEigen4f().computeInverseAndDetWithCheck(inverse, det, invertible);
|
||||
return invertible;
|
||||
}
|
||||
|
||||
Transform Transform::inverse() const
|
||||
{
|
||||
bool invertible = false;
|
||||
Eigen::Matrix4f inverse;
|
||||
Eigen::Matrix4f::RealScalar det;
|
||||
toEigen4f().computeInverseAndDetWithCheck(inverse, det, invertible);
|
||||
UASSERT_MSG(invertible, uFormat("This transform is not invertible! %s \n"
|
||||
"[%f %f %f %f;\n"
|
||||
" %f %f %f %f;\n"
|
||||
" %f %f %f %f;\n"
|
||||
" 0 0 0 1]", prettyPrint().c_str(),
|
||||
r11(), r12(), r13(), o14(),
|
||||
r21(), r22(), r23(), o24(),
|
||||
r31(), r32(), r33(), o34()).c_str());
|
||||
return fromEigen4f(inverse);
|
||||
return fromEigen4f(toEigen4f().inverse());
|
||||
}
|
||||
|
||||
Transform Transform::rotation() const
|
||||
@@ -332,9 +311,14 @@ bool Transform::operator!=(const Transform & t) const
|
||||
|
||||
std::ostream& operator<<(std::ostream& os, const Transform& s)
|
||||
{
|
||||
os << "[" << s.data()[0] << ", " << s.data()[1] << ", " << s.data()[2] << ", " << s.data()[3] << ";" << std::endl
|
||||
<< " " << s.data()[4] << ", " << s.data()[5] << ", " << s.data()[6] << ", " << s.data()[7] << ";" << std::endl
|
||||
<< " " << s.data()[8] << ", " << s.data()[9] << ", " << s.data()[10]<< ", " << s.data()[11] << "]";
|
||||
for(int i = 0; i < 3; ++i)
|
||||
{
|
||||
for(int j = 0; j < 4; ++j)
|
||||
{
|
||||
os << std::left << std::setw(12) << s.data()[i*4 + j] << " ";
|
||||
}
|
||||
os << std::endl;
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
+53
-119
@@ -65,7 +65,6 @@ VWDictionary::VWDictionary(const ParametersMap & parameters) :
|
||||
_incrementalDictionary(Parameters::defaultKpIncrementalDictionary()),
|
||||
_incrementalFlann(Parameters::defaultKpIncrementalFlann()),
|
||||
_rebalancingFactor(Parameters::defaultKpFlannRebalancingFactor()),
|
||||
_byteToFloat(Parameters::defaultKpByteToFloat()),
|
||||
_nndrRatio(Parameters::defaultKpNndrRatio()),
|
||||
_newDictionaryPath(Parameters::defaultKpDictionaryPath()),
|
||||
_newWordsComparedTogether(Parameters::defaultKpNewWordsComparedTogether()),
|
||||
@@ -91,8 +90,6 @@ void VWDictionary::parseParameters(const ParametersMap & parameters)
|
||||
Parameters::parse(parameters, Parameters::kKpNewWordsComparedTogether(), _newWordsComparedTogether);
|
||||
Parameters::parse(parameters, Parameters::kKpIncrementalFlann(), _incrementalFlann);
|
||||
Parameters::parse(parameters, Parameters::kKpFlannRebalancingFactor(), _rebalancingFactor);
|
||||
bool byteToFloat = _byteToFloat;
|
||||
Parameters::parse(parameters, Parameters::kKpByteToFloat(), _byteToFloat);
|
||||
|
||||
UASSERT_MSG(_nndrRatio > 0.0f, uFormat("String=%s value=%f", uContains(parameters, Parameters::kKpNndrRatio())?parameters.at(Parameters::kKpNndrRatio()).c_str():"", _nndrRatio).c_str());
|
||||
|
||||
@@ -107,19 +104,10 @@ void VWDictionary::parseParameters(const ParametersMap & parameters)
|
||||
}
|
||||
|
||||
// Verifying hypotheses strategy
|
||||
bool treeUpdated = false;
|
||||
if((iter=parameters.find(Parameters::kKpNNStrategy())) != parameters.end())
|
||||
{
|
||||
NNStrategy nnStrategy = (NNStrategy)std::atoi((*iter).second.c_str());
|
||||
treeUpdated = this->setNNStrategy(nnStrategy);
|
||||
}
|
||||
if(!treeUpdated && byteToFloat!=_byteToFloat && _strategy == kNNFlannKdTree)
|
||||
{
|
||||
UINFO("KDTree: Binary to Float conversion approach has changed, re-initialize kd-tree.");
|
||||
_dataTree = cv::Mat();
|
||||
_notIndexedWords = uKeysSet(_visualWords);
|
||||
_removedIndexedWords.clear();
|
||||
this->update();
|
||||
this->setNNStrategy(nnStrategy);
|
||||
}
|
||||
|
||||
if(incrementalDictionary)
|
||||
@@ -289,7 +277,7 @@ void VWDictionary::setFixedDictionary(const std::string & dictionaryPath)
|
||||
_newDictionaryPath = dictionaryPath;
|
||||
}
|
||||
|
||||
bool VWDictionary::setNNStrategy(NNStrategy strategy)
|
||||
void VWDictionary::setNNStrategy(NNStrategy strategy)
|
||||
{
|
||||
#if CV_MAJOR_VERSION < 3
|
||||
#ifdef HAVE_OPENCV_GPU
|
||||
@@ -331,17 +319,11 @@ bool VWDictionary::setNNStrategy(NNStrategy strategy)
|
||||
_strategy = strategy;
|
||||
if(update)
|
||||
{
|
||||
if(_notIndexedWords.size() != _visualWords.size() || !_dataTree.empty())
|
||||
{
|
||||
UINFO("Nearest neighbor strategy has changed, re-initialize search tree.");
|
||||
}
|
||||
_dataTree = cv::Mat();
|
||||
_notIndexedWords = uKeysSet(_visualWords);
|
||||
_removedIndexedWords.clear();
|
||||
this->update();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int VWDictionary::getLastIndexedWordId() const
|
||||
@@ -366,103 +348,59 @@ unsigned int VWDictionary::getIndexMemoryUsed() const
|
||||
return _flannIndex->memoryUsed();
|
||||
}
|
||||
|
||||
unsigned long VWDictionary::getMemoryUsed() const
|
||||
cv::Mat VWDictionary::convertBinTo32F(const cv::Mat & descriptorsIn)
|
||||
{
|
||||
long memoryUsage = sizeof(VWDictionary);
|
||||
memoryUsage += getIndexMemoryUsed();
|
||||
memoryUsage += _dataTree.total()*_dataTree.elemSize();
|
||||
if(!_visualWords.empty())
|
||||
// Old approach
|
||||
//cv::Mat descriptorsOut;
|
||||
//descriptorsIn.convertTo(descriptorsOut, CV_32F);
|
||||
//return descriptorsOut;
|
||||
|
||||
// New approach
|
||||
UASSERT(descriptorsIn.type() == CV_8UC1);
|
||||
cv::Mat descriptorsOut(descriptorsIn.rows, descriptorsIn.cols*8, CV_32FC1);
|
||||
for(int i=0; i<descriptorsIn.rows; ++i)
|
||||
{
|
||||
memoryUsage += _visualWords.size()*(sizeof(int) + _visualWords.rbegin()->second->getMemoryUsed() + sizeof(std::map<int, VisualWord *>::iterator)) + sizeof(std::map<int, VisualWord *>);
|
||||
if(_dataTree.empty() &&
|
||||
_visualWords.begin()->second->getDescriptor().type() == CV_8U &&
|
||||
_strategy == kNNFlannKdTree)
|
||||
const unsigned char * ptrIn = descriptorsIn.ptr(i);
|
||||
float * ptrOut = descriptorsOut.ptr<float>(i);
|
||||
for(int j=0; j<descriptorsIn.cols; ++j)
|
||||
{
|
||||
// Binary descriptors were converted to float, and not included in _dataTree
|
||||
memoryUsage += _visualWords.size() * _visualWords.begin()->second->getDescriptor().total() * sizeof(float) * (_byteToFloat?1:8);
|
||||
int jo = j*8;
|
||||
ptrOut[jo] = (ptrIn[j] & 1) == 1?1.0f:0.0f;
|
||||
ptrOut[jo+1] = (ptrIn[j] & (1<<1)) != 0?1.0f:0.0f;
|
||||
ptrOut[jo+2] = (ptrIn[j] & (1<<2)) != 0?1.0f:0.0f;
|
||||
ptrOut[jo+3] = (ptrIn[j] & (1<<3)) != 0?1.0f:0.0f;
|
||||
ptrOut[jo+4] = (ptrIn[j] & (1<<4)) != 0?1.0f:0.0f;
|
||||
ptrOut[jo+5] = (ptrIn[j] & (1<<5)) != 0?1.0f:0.0f;
|
||||
ptrOut[jo+6] = (ptrIn[j] & (1<<6)) != 0?1.0f:0.0f;
|
||||
ptrOut[jo+7] = (ptrIn[j] & (1<<7)) != 0?1.0f:0.0f;
|
||||
}
|
||||
}
|
||||
if(!_unusedWords.empty())
|
||||
{
|
||||
// they are the same words than in _visualWords, so just add the pointer size
|
||||
memoryUsage += _unusedWords.size()*(sizeof(int) + sizeof(VisualWord *)+sizeof(std::map<int, VisualWord *>::iterator)) + sizeof(std::map<int, VisualWord *>);
|
||||
}
|
||||
memoryUsage += _mapIndexId.size() * (sizeof(int)*2+sizeof(std::map<int ,int>::iterator)) + sizeof(std::map<int ,int>);
|
||||
memoryUsage += _mapIdIndex.size() * (sizeof(int)*2+sizeof(std::map<int ,int>::iterator)) + sizeof(std::map<int ,int>);
|
||||
memoryUsage += _notIndexedWords.size() * (sizeof(int)+sizeof(std::set<int>::iterator)) + sizeof(std::set<int>);
|
||||
memoryUsage += _removedIndexedWords.size() * (sizeof(int)+sizeof(std::set<int>::iterator)) + sizeof(std::set<int>);
|
||||
return memoryUsage;
|
||||
return descriptorsOut;
|
||||
}
|
||||
|
||||
cv::Mat VWDictionary::convertBinTo32F(const cv::Mat & descriptorsIn, bool byteToFloat)
|
||||
cv::Mat VWDictionary::convert32FToBin(const cv::Mat & descriptorsIn)
|
||||
{
|
||||
if(byteToFloat)
|
||||
UASSERT(descriptorsIn.type() == CV_32FC1 && descriptorsIn.cols % 8 == 0);
|
||||
cv::Mat descriptorsOut(descriptorsIn.rows, descriptorsIn.cols/8, CV_8UC1);
|
||||
for(int i=0; i<descriptorsIn.rows; ++i)
|
||||
{
|
||||
// Old approach
|
||||
cv::Mat descriptorsOut;
|
||||
descriptorsIn.convertTo(descriptorsOut, CV_32F);
|
||||
return descriptorsOut;
|
||||
}
|
||||
else
|
||||
{
|
||||
// New approach
|
||||
UASSERT(descriptorsIn.type() == CV_8UC1);
|
||||
cv::Mat descriptorsOut(descriptorsIn.rows, descriptorsIn.cols*8, CV_32FC1);
|
||||
for(int i=0; i<descriptorsIn.rows; ++i)
|
||||
const float * ptrIn = descriptorsIn.ptr<float>(i);
|
||||
unsigned char * ptrOut = descriptorsOut.ptr(i);
|
||||
for(int j=0; j<descriptorsOut.cols; ++j)
|
||||
{
|
||||
const unsigned char * ptrIn = descriptorsIn.ptr(i);
|
||||
float * ptrOut = descriptorsOut.ptr<float>(i);
|
||||
for(int j=0; j<descriptorsIn.cols; ++j)
|
||||
{
|
||||
int jo = j*8;
|
||||
ptrOut[jo] = (ptrIn[j] & 1) == 1?1.0f:0.0f;
|
||||
ptrOut[jo+1] = (ptrIn[j] & (1<<1)) != 0?1.0f:0.0f;
|
||||
ptrOut[jo+2] = (ptrIn[j] & (1<<2)) != 0?1.0f:0.0f;
|
||||
ptrOut[jo+3] = (ptrIn[j] & (1<<3)) != 0?1.0f:0.0f;
|
||||
ptrOut[jo+4] = (ptrIn[j] & (1<<4)) != 0?1.0f:0.0f;
|
||||
ptrOut[jo+5] = (ptrIn[j] & (1<<5)) != 0?1.0f:0.0f;
|
||||
ptrOut[jo+6] = (ptrIn[j] & (1<<6)) != 0?1.0f:0.0f;
|
||||
ptrOut[jo+7] = (ptrIn[j] & (1<<7)) != 0?1.0f:0.0f;
|
||||
}
|
||||
int jo = j*8;
|
||||
ptrOut[j] =
|
||||
(unsigned char)(ptrIn[jo] == 0?0:1) |
|
||||
(ptrIn[jo+1] == 0?0:(1<<1)) |
|
||||
(ptrIn[jo+2] == 0?0:(1<<2)) |
|
||||
(ptrIn[jo+3] == 0?0:(1<<3)) |
|
||||
(ptrIn[jo+4] == 0?0:(1<<4)) |
|
||||
(ptrIn[jo+5] == 0?0:(1<<5)) |
|
||||
(ptrIn[jo+6] == 0?0:(1<<6)) |
|
||||
(ptrIn[jo+7] == 0?0:(1<<7));
|
||||
}
|
||||
return descriptorsOut;
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat VWDictionary::convert32FToBin(const cv::Mat & descriptorsIn, bool byteToFloat)
|
||||
{
|
||||
if(byteToFloat)
|
||||
{
|
||||
// Old approach
|
||||
cv::Mat descriptorsOut;
|
||||
descriptorsIn.convertTo(descriptorsOut, CV_8UC1);
|
||||
return descriptorsOut;
|
||||
}
|
||||
else
|
||||
{
|
||||
// New approach
|
||||
UASSERT(descriptorsIn.type() == CV_32FC1 && descriptorsIn.cols % 8 == 0);
|
||||
cv::Mat descriptorsOut(descriptorsIn.rows, descriptorsIn.cols/8, CV_8UC1);
|
||||
for(int i=0; i<descriptorsIn.rows; ++i)
|
||||
{
|
||||
const float * ptrIn = descriptorsIn.ptr<float>(i);
|
||||
unsigned char * ptrOut = descriptorsOut.ptr(i);
|
||||
for(int j=0; j<descriptorsOut.cols; ++j)
|
||||
{
|
||||
int jo = j*8;
|
||||
ptrOut[j] =
|
||||
(unsigned char)(ptrIn[jo] == 0?0:1) |
|
||||
(ptrIn[jo+1] == 0?0:(1<<1)) |
|
||||
(ptrIn[jo+2] == 0?0:(1<<2)) |
|
||||
(ptrIn[jo+3] == 0?0:(1<<3)) |
|
||||
(ptrIn[jo+4] == 0?0:(1<<4)) |
|
||||
(ptrIn[jo+5] == 0?0:(1<<5)) |
|
||||
(ptrIn[jo+6] == 0?0:(1<<6)) |
|
||||
(ptrIn[jo+7] == 0?0:(1<<7));
|
||||
}
|
||||
}
|
||||
return descriptorsOut;
|
||||
}
|
||||
return descriptorsOut;
|
||||
}
|
||||
|
||||
void VWDictionary::update()
|
||||
@@ -513,7 +451,7 @@ void VWDictionary::update()
|
||||
useDistanceL1_ = true;
|
||||
if(_strategy == kNNFlannKdTree)
|
||||
{
|
||||
descriptor = convertBinTo32F(w->getDescriptor(), _byteToFloat);
|
||||
descriptor = convertBinTo32F(w->getDescriptor());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -552,8 +490,7 @@ void VWDictionary::update()
|
||||
{
|
||||
UASSERT(descriptor.cols == _flannIndex->featuresDim());
|
||||
UASSERT(descriptor.type() == _flannIndex->featuresType());
|
||||
UASSERT(descriptor.rows == 1);
|
||||
index = _flannIndex->addPoints(descriptor).front();
|
||||
index = _flannIndex->addPoints(descriptor);
|
||||
}
|
||||
std::pair<std::map<int, int>::iterator, bool> inserted;
|
||||
inserted = _mapIndexId.insert(std::pair<int, int>(index, w->id()));
|
||||
@@ -606,10 +543,7 @@ void VWDictionary::update()
|
||||
if(_strategy == kNNFlannKdTree)
|
||||
{
|
||||
type = CV_32F;
|
||||
if(!_byteToFloat)
|
||||
{
|
||||
dim *= 8;
|
||||
}
|
||||
dim *= 8;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -634,7 +568,7 @@ void VWDictionary::update()
|
||||
{
|
||||
if(_strategy == kNNFlannKdTree)
|
||||
{
|
||||
descriptor = convertBinTo32F(iter->second->getDescriptor(), _byteToFloat);
|
||||
descriptor = convertBinTo32F(iter->second->getDescriptor());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -660,15 +594,15 @@ void VWDictionary::update()
|
||||
switch(_strategy)
|
||||
{
|
||||
case kNNFlannNaive:
|
||||
_flannIndex->buildLinearIndex(_dataTree, useDistanceL1_, _incrementalDictionary&&_incrementalFlann?_rebalancingFactor:1);
|
||||
_flannIndex->buildLinearIndex(_dataTree, useDistanceL1_, _rebalancingFactor);
|
||||
break;
|
||||
case kNNFlannKdTree:
|
||||
UASSERT_MSG(type == CV_32F, "To use KdTree dictionary, float descriptors are required!");
|
||||
_flannIndex->buildKDTreeIndex(_dataTree, KDTREE_SIZE, useDistanceL1_, _incrementalDictionary&&_incrementalFlann?_rebalancingFactor:1);
|
||||
_flannIndex->buildKDTreeIndex(_dataTree, KDTREE_SIZE, useDistanceL1_, _rebalancingFactor);
|
||||
break;
|
||||
case kNNFlannLSH:
|
||||
UASSERT_MSG(type == CV_8U, "To use LSH dictionary, binary descriptors are required!");
|
||||
_flannIndex->buildLSHIndex(_dataTree, 12, 20, 2, _incrementalDictionary&&_incrementalFlann?_rebalancingFactor:1);
|
||||
_flannIndex->buildLSHIndex(_dataTree, 12, 20, 2, _rebalancingFactor);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@@ -802,7 +736,7 @@ std::list<int> VWDictionary::addNewWords(
|
||||
useDistanceL1_ = true;
|
||||
if(_strategy == kNNFlannKdTree)
|
||||
{
|
||||
descriptors = convertBinTo32F(descriptorsIn, _byteToFloat);
|
||||
descriptors = convertBinTo32F(descriptorsIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1140,7 +1074,7 @@ std::vector<int> VWDictionary::findNN(const cv::Mat & queryIn) const
|
||||
{
|
||||
if(_strategy == kNNFlannKdTree)
|
||||
{
|
||||
query = convertBinTo32F(queryIn, _byteToFloat);
|
||||
query = convertBinTo32F(queryIn);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1268,7 +1202,7 @@ std::vector<int> VWDictionary::findNN(const cv::Mat & queryIn) const
|
||||
{
|
||||
if(_strategy == kNNFlannKdTree)
|
||||
{
|
||||
descriptor = convertBinTo32F(vw->getDescriptor(), _byteToFloat);
|
||||
descriptor = convertBinTo32F(vw->getDescriptor());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -69,13 +69,4 @@ int VisualWord::removeAllRef(int signatureId)
|
||||
return removed;
|
||||
}
|
||||
|
||||
unsigned long VisualWord::getMemoryUsed() const
|
||||
{
|
||||
unsigned long memoryUsage = sizeof(VisualWord);
|
||||
memoryUsage += _references.size() * (sizeof(int)*2+sizeof(std::map<int ,int>::iterator)) + sizeof(std::map<int ,int>);
|
||||
memoryUsage += _oldReferences.size() * (sizeof(int)*2+sizeof(std::map<int ,int>::iterator)) + sizeof(std::map<int ,int>);
|
||||
memoryUsage += _descriptor.total() * _descriptor.elemSize();
|
||||
return memoryUsage;
|
||||
}
|
||||
|
||||
} // namespace rtabmap
|
||||
|
||||
@@ -29,7 +29,6 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
#include <rtabmap/utilite/UConversion.h>
|
||||
#include <rtabmap/utilite/UDirectory.h>
|
||||
#include <rtabmap/utilite/UStl.h>
|
||||
#include <rtabmap/utilite/UFile.h>
|
||||
#include <rtabmap/utilite/UThreadC.h>
|
||||
#include <rtabmap/core/util3d.h>
|
||||
#include <rtabmap/core/util3d_filtering.h>
|
||||
@@ -59,7 +58,6 @@ CameraImages::CameraImages() :
|
||||
_depthFromScanFillHoles(1),
|
||||
_depthFromScanFillHolesFromBorder(false),
|
||||
_filenamesAreTimestamps(false),
|
||||
_hasConfigForEachFrame(false),
|
||||
_syncImageRateWithStamps(true),
|
||||
_odometryFormat(0),
|
||||
_groundTruthFormat(0),
|
||||
@@ -89,7 +87,6 @@ CameraImages::CameraImages(const std::string & path,
|
||||
_depthFromScanFillHoles(1),
|
||||
_depthFromScanFillHolesFromBorder(false),
|
||||
_filenamesAreTimestamps(false),
|
||||
_hasConfigForEachFrame(false),
|
||||
_syncImageRateWithStamps(true),
|
||||
_odometryFormat(0),
|
||||
_groundTruthFormat(0),
|
||||
@@ -114,9 +111,6 @@ bool CameraImages::init(const std::string & calibrationFolder, const std::string
|
||||
_countScan = 0;
|
||||
_captureDelay = 0.0;
|
||||
_framesPublished=0;
|
||||
_model = cameraModel();
|
||||
_models.clear();
|
||||
covariances_.clear();
|
||||
|
||||
UDEBUG("");
|
||||
if(_dir)
|
||||
@@ -219,108 +213,7 @@ bool CameraImages::init(const std::string & calibrationFolder, const std::string
|
||||
groundTruth_.clear();
|
||||
if(success)
|
||||
{
|
||||
if(_hasConfigForEachFrame)
|
||||
{
|
||||
#if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 3 && CV_MAJOR_VERSION < 2)
|
||||
UDirectory dirJson(_path, "yaml xml");
|
||||
#else
|
||||
UDirectory dirJson(_path, "yaml xml json");
|
||||
#endif
|
||||
if(dirJson.getFileNames().size() == _dir->getFileNames().size())
|
||||
{
|
||||
bool modelsWarned = false;
|
||||
bool firstFrame = true;
|
||||
for(std::list<std::string>::const_iterator iter=dirJson.getFileNames().begin(); iter!=dirJson.getFileNames().end() && success; ++iter)
|
||||
{
|
||||
// Assuming 3DScannerApp(iOS) format (only this one supported...)
|
||||
std::string filePath = _path+"/"+*iter;
|
||||
cv::FileStorage fs(filePath, 0);
|
||||
cv::FileNode poseNode = fs["cameraPoseARFrame"];
|
||||
cv::FileNode timeNode = fs["time"];
|
||||
cv::FileNode intrinsicsNode = fs["intrinsics"];
|
||||
if(poseNode.isNone() || poseNode.size() != 16)
|
||||
{
|
||||
UERROR("Failed reading \"cameraPoseARFrame\" parameter, it should have 16 values (file=%s)", filePath.c_str());
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
else if(timeNode.isNone() || !timeNode.isReal())
|
||||
{
|
||||
UERROR("Failed reading \"time\" parameter (file=%s)", filePath.c_str());
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
else if(intrinsicsNode.isNone() || intrinsicsNode.size()!=9)
|
||||
{
|
||||
UERROR("Failed reading \"intrinsics\" parameter (file=%s)", filePath.c_str());
|
||||
success = false;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
_stamps.push_back((double)timeNode);
|
||||
if(_model.isValidForProjection() && !modelsWarned)
|
||||
{
|
||||
UWARN("Camera model loaded for each frame is overridden by "
|
||||
"general calibration file provided. Remove general calibration "
|
||||
"file to use camera model of each frame. This warning will "
|
||||
"be shown only one time.");
|
||||
modelsWarned = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
_models.push_back(CameraModel(
|
||||
(double)intrinsicsNode[0], //fx
|
||||
(double)intrinsicsNode[4], //fy
|
||||
(double)intrinsicsNode[2], //cx
|
||||
(double)intrinsicsNode[5], //cy
|
||||
CameraModel::opticalRotation()));
|
||||
}
|
||||
// we need to rotate from opengl world to rtabmap world
|
||||
Transform pose(
|
||||
(float)poseNode[0], (float)poseNode[1], (float)poseNode[2], (float)poseNode[3],
|
||||
(float)poseNode[4], (float)poseNode[5], (float)poseNode[6], (float)poseNode[7],
|
||||
(float)poseNode[8], (float)poseNode[9], (float)poseNode[10], (float)poseNode[11]);
|
||||
pose = Transform::rtabmap_T_opengl() * pose * Transform::opengl_T_rtabmap();
|
||||
odometry_.push_back(pose);
|
||||
// linear cov = 0.0001
|
||||
cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1) * (firstFrame?9999.0:0.0001);
|
||||
if(!firstFrame)
|
||||
{
|
||||
// angular cov = 0.000001
|
||||
covariance.at<double>(3,3) *= 0.01;
|
||||
covariance.at<double>(4,4) *= 0.01;
|
||||
covariance.at<double>(5,5) *= 0.01;
|
||||
}
|
||||
firstFrame = false;
|
||||
covariances_.push_back(covariance);
|
||||
}
|
||||
}
|
||||
if(!success)
|
||||
{
|
||||
odometry_.clear();
|
||||
_stamps.clear();
|
||||
_models.clear();
|
||||
covariances_.clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
std::string opencv32warn;
|
||||
#if CV_MAJOR_VERSION < 3 || (CV_MAJOR_VERSION == 3 && CV_MAJOR_VERSION < 2)
|
||||
opencv32warn = " RTAB-Map is currently built with OpenCV < 3.2, only xml and yaml files are supported (not json).";
|
||||
#endif
|
||||
UERROR("Parameter \"Config for each frame\" is true, but the "
|
||||
"number of config files (%d) is not equal to number "
|
||||
"of images (%d) in this directory \"%s\".%s",
|
||||
(int)dirJson.getFileNames().size(),
|
||||
(int)_dir->getFileNames().size(),
|
||||
_path.c_str(),
|
||||
opencv32warn.c_str());
|
||||
success = false;
|
||||
}
|
||||
}
|
||||
else if(_filenamesAreTimestamps)
|
||||
if(_filenamesAreTimestamps)
|
||||
{
|
||||
const std::list<std::string> & filenames = _dir->getFileNames();
|
||||
for(std::list<std::string>::const_iterator iter=filenames.begin(); iter!=filenames.end(); ++iter)
|
||||
@@ -423,7 +316,7 @@ bool CameraImages::init(const std::string & calibrationFolder, const std::string
|
||||
}
|
||||
}
|
||||
|
||||
if(success && _odometryPath.size() && odometry_.empty())
|
||||
if(success && _odometryPath.size())
|
||||
{
|
||||
success = readPoses(odometry_, _stamps, _odometryPath, _odometryFormat, _maxPoseTimeDiff);
|
||||
}
|
||||
@@ -439,12 +332,7 @@ bool CameraImages::init(const std::string & calibrationFolder, const std::string
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CameraImages::readPoses(
|
||||
std::list<Transform> & outputPoses,
|
||||
std::list<double> & inOutStamps,
|
||||
const std::string & filePath,
|
||||
int format,
|
||||
double maxTimeDiff) const
|
||||
bool CameraImages::readPoses(std::list<Transform> & outputPoses, std::list<double> & inOutStamps, const std::string & filePath, int format, double maxTimeDiff) const
|
||||
{
|
||||
outputPoses.clear();
|
||||
std::map<int, Transform> poses;
|
||||
@@ -548,11 +436,6 @@ bool CameraImages::readPoses(
|
||||
UERROR("With Karlsruhe format, timestamps (%d) and poses (%d) should match!", (int)stamps.size(), (int)poses.size());
|
||||
return false;
|
||||
}
|
||||
else if(!outputPoses.empty() && inOutStamps.empty() && stamps.empty())
|
||||
{
|
||||
UERROR("Timestamps are empty (poses=%d)! Forgot the set a timestamp file?", (int)outputPoses.size());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
UASSERT_MSG(outputPoses.size() == inOutStamps.size(), uFormat("%d vs %d", (int)outputPoses.size(), (int)inOutStamps.size()).c_str());
|
||||
return true;
|
||||
@@ -560,7 +443,7 @@ bool CameraImages::readPoses(
|
||||
|
||||
bool CameraImages::isCalibrated() const
|
||||
{
|
||||
return _model.isValidForProjection() || (_models.size() && _models.front().isValidForProjection());
|
||||
return _model.isValidForProjection();
|
||||
}
|
||||
|
||||
std::string CameraImages::getSerial() const
|
||||
@@ -623,10 +506,8 @@ SensorData CameraImages::captureImage(CameraInfo * info)
|
||||
LaserScan scan(cv::Mat(), _scanMaxPts, 0, LaserScan::kUnknown, _scanLocalTransform);
|
||||
double stamp = UTimer::now();
|
||||
Transform odometryPose;
|
||||
cv::Mat covariance;
|
||||
Transform groundTruthPose;
|
||||
cv::Mat depthFromScan;
|
||||
CameraModel model = _model;
|
||||
UDEBUG("");
|
||||
if(_dir->isValid())
|
||||
{
|
||||
@@ -672,26 +553,16 @@ SensorData CameraImages::captureImage(CameraInfo * info)
|
||||
{
|
||||
_captureDelay = _stamps.front() - stamp;
|
||||
}
|
||||
}
|
||||
if(odometry_.size())
|
||||
{
|
||||
odometryPose = odometry_.front();
|
||||
odometry_.pop_front();
|
||||
if(covariances_.size())
|
||||
if(odometry_.size())
|
||||
{
|
||||
covariance = covariances_.front();
|
||||
covariances_.pop_front();
|
||||
odometryPose = odometry_.front();
|
||||
odometry_.pop_front();
|
||||
}
|
||||
if(groundTruth_.size())
|
||||
{
|
||||
groundTruthPose = groundTruth_.front();
|
||||
groundTruth_.pop_front();
|
||||
}
|
||||
}
|
||||
if(groundTruth_.size())
|
||||
{
|
||||
groundTruthPose = groundTruth_.front();
|
||||
groundTruth_.pop_front();
|
||||
}
|
||||
if(_models.size() && !model.isValidForProjection())
|
||||
{
|
||||
model = _models.front();
|
||||
_models.pop_front();
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -709,26 +580,16 @@ SensorData CameraImages::captureImage(CameraInfo * info)
|
||||
{
|
||||
_captureDelay = _stamps.front() - stamp;
|
||||
}
|
||||
}
|
||||
if(odometry_.size())
|
||||
{
|
||||
odometryPose = odometry_.front();
|
||||
odometry_.pop_front();
|
||||
if(covariances_.size())
|
||||
if(odometry_.size())
|
||||
{
|
||||
covariance = covariances_.front();
|
||||
covariances_.pop_front();
|
||||
odometryPose = odometry_.front();
|
||||
odometry_.pop_front();
|
||||
}
|
||||
if(groundTruth_.size())
|
||||
{
|
||||
groundTruthPose = groundTruth_.front();
|
||||
groundTruth_.pop_front();
|
||||
}
|
||||
}
|
||||
if(groundTruth_.size())
|
||||
{
|
||||
groundTruthPose = groundTruth_.front();
|
||||
groundTruth_.pop_front();
|
||||
}
|
||||
if(_models.size() && !model.isValidForProjection())
|
||||
{
|
||||
model = _models.front();
|
||||
_models.pop_front();
|
||||
}
|
||||
|
||||
while(_count++ < _startAt && (fileName = _dir->getNextFileName()).size())
|
||||
@@ -742,26 +603,16 @@ SensorData CameraImages::captureImage(CameraInfo * info)
|
||||
{
|
||||
_captureDelay = _stamps.front() - stamp;
|
||||
}
|
||||
}
|
||||
if(odometry_.size())
|
||||
{
|
||||
odometryPose = odometry_.front();
|
||||
odometry_.pop_front();
|
||||
if(covariances_.size())
|
||||
if(odometry_.size())
|
||||
{
|
||||
covariance = covariances_.front();
|
||||
covariances_.pop_front();
|
||||
odometryPose = odometry_.front();
|
||||
odometry_.pop_front();
|
||||
}
|
||||
if(groundTruth_.size())
|
||||
{
|
||||
groundTruthPose = groundTruth_.front();
|
||||
groundTruth_.pop_front();
|
||||
}
|
||||
}
|
||||
if(groundTruth_.size())
|
||||
{
|
||||
groundTruthPose = groundTruth_.front();
|
||||
groundTruth_.pop_front();
|
||||
}
|
||||
if(_models.size() && !model.isValidForProjection())
|
||||
{
|
||||
model = _models.front();
|
||||
_models.pop_front();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -842,11 +693,12 @@ SensorData CameraImages::captureImage(CameraInfo * info)
|
||||
UWARN("Error debayering images: \"%s\". Please set bayer mode to -1 if images are not bayered!", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(!img.empty() && model.isValidForRectification() && _rectifyImages)
|
||||
if(!img.empty() && _model.isValidForRectification() && _rectifyImages)
|
||||
{
|
||||
img = model.rectifyImage(img);
|
||||
img = _model.rectifyImage(img);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -859,7 +711,7 @@ SensorData CameraImages::captureImage(CameraInfo * info)
|
||||
if(_depthFromScan && !img.empty())
|
||||
{
|
||||
UDEBUG("Computing depth from scan...");
|
||||
if(!model.isValidForProjection())
|
||||
if(!_model.isValidForProjection())
|
||||
{
|
||||
UWARN("Depth from laser scan: Camera model should be valid.");
|
||||
}
|
||||
@@ -870,7 +722,7 @@ SensorData CameraImages::captureImage(CameraInfo * info)
|
||||
else
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud = util3d::laserScanToPointCloud(scan, scan.localTransform());
|
||||
depthFromScan = util3d::projectCloudToCamera(img.size(), model.K(), cloud, model.localTransform());
|
||||
depthFromScan = util3d::projectCloudToCamera(img.size(), _model.K(), cloud, _model.localTransform());
|
||||
if(_depthFromScanFillHoles!=0)
|
||||
{
|
||||
util3d::fillProjectedCloudHoles(depthFromScan, _depthFromScanFillHoles>0, _depthFromScanFillHolesFromBorder);
|
||||
@@ -885,18 +737,18 @@ SensorData CameraImages::captureImage(CameraInfo * info)
|
||||
UWARN("Directory is not set, camera must be initialized.");
|
||||
}
|
||||
|
||||
if(model.imageHeight() == 0 || model.imageWidth() == 0)
|
||||
if(_model.imageHeight() == 0 || _model.imageWidth() == 0)
|
||||
{
|
||||
model.setImageSize(img.size());
|
||||
_model.setImageSize(img.size());
|
||||
}
|
||||
|
||||
SensorData data(scan, _isDepth?cv::Mat():img, _isDepth?img:depthFromScan, model, this->getNextSeqID(), stamp);
|
||||
SensorData data(scan, _isDepth?cv::Mat():img, _isDepth?img:depthFromScan, _model, this->getNextSeqID(), stamp);
|
||||
data.setGroundTruth(groundTruthPose);
|
||||
|
||||
if(info && !odometryPose.isNull())
|
||||
{
|
||||
info->odomPose = odometryPose;
|
||||
info->odomCovariance = covariance.empty()?cv::Mat::eye(6,6,CV_64FC1):covariance; // Note that with TORO and g2o file formats, we could get the covariance
|
||||
info->odomCovariance = cv::Mat::eye(6,6,CV_64FC1); // Note that with TORO and g2o file formats, we could get the covariance
|
||||
}
|
||||
|
||||
return data;
|
||||
|
||||
+390
-295
@@ -55,11 +55,12 @@ CameraK4A::CameraK4A(
|
||||
Camera(imageRate, localTransform)
|
||||
#ifdef RTABMAP_K4A
|
||||
,
|
||||
deviceHandle_(NULL),
|
||||
device_(NULL),
|
||||
config_(K4A_DEVICE_CONFIG_INIT_DISABLE_ALL),
|
||||
transformationHandle_(NULL),
|
||||
captureHandle_(NULL),
|
||||
transformation_(NULL),
|
||||
capture_(NULL),
|
||||
playbackHandle_(NULL),
|
||||
transformationHandle_(NULL),
|
||||
deviceId_(deviceId),
|
||||
rgb_resolution_(0),
|
||||
framerate_(2),
|
||||
@@ -77,10 +78,11 @@ CameraK4A::CameraK4A(
|
||||
Camera(imageRate, localTransform)
|
||||
#ifdef RTABMAP_K4A
|
||||
,
|
||||
deviceHandle_(NULL),
|
||||
transformationHandle_(NULL),
|
||||
captureHandle_(NULL),
|
||||
device_(NULL),
|
||||
transformation_(NULL),
|
||||
capture_(NULL),
|
||||
playbackHandle_(NULL),
|
||||
transformationHandle_(NULL),
|
||||
deviceId_(-1),
|
||||
fileName_(fileName),
|
||||
rgb_resolution_(0),
|
||||
@@ -100,25 +102,37 @@ CameraK4A::~CameraK4A()
|
||||
void CameraK4A::close()
|
||||
{
|
||||
#ifdef RTABMAP_K4A
|
||||
if (playbackHandle_ != NULL)
|
||||
if (!fileName_.empty())
|
||||
{
|
||||
k4a_playback_close((k4a_playback_t)playbackHandle_);
|
||||
playbackHandle_ = NULL;
|
||||
}
|
||||
else if (deviceHandle_ != NULL)
|
||||
{
|
||||
k4a_device_stop_imu(deviceHandle_);
|
||||
if (playbackHandle_ != NULL)
|
||||
{
|
||||
k4a_playback_close((k4a_playback_t)playbackHandle_);
|
||||
playbackHandle_ = NULL;
|
||||
}
|
||||
|
||||
k4a_device_stop_cameras(deviceHandle_);
|
||||
k4a_device_close(deviceHandle_);
|
||||
deviceHandle_ = NULL;
|
||||
config_ = K4A_DEVICE_CONFIG_INIT_DISABLE_ALL;
|
||||
if (transformationHandle_ != NULL)
|
||||
{
|
||||
k4a_transformation_destroy((k4a_transformation_t)transformationHandle_);
|
||||
transformationHandle_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (transformationHandle_ != NULL)
|
||||
else
|
||||
{
|
||||
k4a_transformation_destroy((k4a_transformation_t)transformationHandle_);
|
||||
transformationHandle_ = NULL;
|
||||
if (device_ != NULL)
|
||||
{
|
||||
k4a_device_stop_imu(device_);
|
||||
|
||||
if (transformation_ != NULL)
|
||||
{
|
||||
k4a_transformation_destroy(transformation_);
|
||||
transformation_ = NULL;
|
||||
}
|
||||
|
||||
k4a_device_stop_cameras(device_);
|
||||
k4a_device_close(device_);
|
||||
device_ = NULL;
|
||||
config_ = K4A_DEVICE_CONFIG_INIT_DISABLE_ALL;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -157,17 +171,50 @@ bool CameraK4A::init(const std::string & calibrationFolder, const std::string &
|
||||
uint64_t recording_length = k4a_playback_get_last_timestamp_usec((k4a_playback_t)playbackHandle_);
|
||||
UINFO("Recording is %lld seconds long", recording_length / 1000000);
|
||||
|
||||
if (k4a_playback_get_calibration((k4a_playback_t)playbackHandle_, &calibration_))
|
||||
k4a_calibration_t calibration;
|
||||
if (k4a_playback_get_calibration((k4a_playback_t)playbackHandle_, &calibration))
|
||||
{
|
||||
UERROR("Failed to get calibration");
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
if (ir_)
|
||||
{
|
||||
model_ = CameraModel(
|
||||
calibration.depth_camera_calibration.intrinsics.parameters.param.fx,
|
||||
calibration.depth_camera_calibration.intrinsics.parameters.param.fy,
|
||||
calibration.depth_camera_calibration.intrinsics.parameters.param.cx,
|
||||
calibration.depth_camera_calibration.intrinsics.parameters.param.cy,
|
||||
this->getLocalTransform(),
|
||||
0,
|
||||
cv::Size(calibration.depth_camera_calibration.resolution_width, calibration.depth_camera_calibration.resolution_height));
|
||||
}
|
||||
else
|
||||
{
|
||||
model_ = CameraModel(
|
||||
calibration.color_camera_calibration.intrinsics.parameters.param.fx,
|
||||
calibration.color_camera_calibration.intrinsics.parameters.param.fy,
|
||||
calibration.color_camera_calibration.intrinsics.parameters.param.cx,
|
||||
calibration.color_camera_calibration.intrinsics.parameters.param.cy,
|
||||
this->getLocalTransform(),
|
||||
0,
|
||||
cv::Size(calibration.color_camera_calibration.resolution_width, calibration.color_camera_calibration.resolution_height));
|
||||
|
||||
transformationHandle_ = k4a_transformation_create(&calibration);
|
||||
}
|
||||
|
||||
k4a_record_configuration_t config;
|
||||
|
||||
if (k4a_playback_get_record_configuration((k4a_playback_t)playbackHandle_, &config))
|
||||
{
|
||||
UERROR("Failed to getting recording configuration");
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (deviceId_ >= 0)
|
||||
{
|
||||
if(deviceHandle_!=NULL)
|
||||
if(device_!=NULL)
|
||||
{
|
||||
this->close();
|
||||
}
|
||||
@@ -218,7 +265,7 @@ bool CameraK4A::init(const std::string & calibrationFolder, const std::string &
|
||||
UINFO("CameraK4A found %d k4a device(s) attached", device_count);
|
||||
|
||||
// Open the first plugged in Kinect device
|
||||
if (K4A_FAILED(k4a_device_open(deviceId_, &deviceHandle_)))
|
||||
if (K4A_FAILED(k4a_device_open(deviceId_, &device_)))
|
||||
{
|
||||
UERROR("Failed to open k4a device!");
|
||||
return false;
|
||||
@@ -226,18 +273,18 @@ bool CameraK4A::init(const std::string & calibrationFolder, const std::string &
|
||||
|
||||
// Get the size of the serial number
|
||||
size_t serial_size = 0;
|
||||
k4a_device_get_serialnum(deviceHandle_, NULL, &serial_size);
|
||||
k4a_device_get_serialnum(device_, NULL, &serial_size);
|
||||
|
||||
// Allocate memory for the serial, then acquire it
|
||||
char *serial = (char*)(malloc(serial_size));
|
||||
k4a_device_get_serialnum(deviceHandle_, serial, &serial_size);
|
||||
k4a_device_get_serialnum(device_, serial, &serial_size);
|
||||
serial_number_.assign(serial, serial_size);
|
||||
free(serial);
|
||||
|
||||
UINFO("Opened K4A device: %s", serial_number_.c_str());
|
||||
|
||||
// Start the camera with the given configuration
|
||||
if (K4A_FAILED(k4a_device_start_cameras(deviceHandle_, &config_)))
|
||||
if (K4A_FAILED(k4a_device_start_cameras(device_, &config_)))
|
||||
{
|
||||
UERROR("Failed to start cameras!");
|
||||
close();
|
||||
@@ -246,121 +293,59 @@ bool CameraK4A::init(const std::string & calibrationFolder, const std::string &
|
||||
|
||||
UINFO("K4A camera started successfully");
|
||||
|
||||
if (K4A_FAILED(k4a_device_get_calibration(deviceHandle_, config_.depth_mode, config_.color_resolution, &calibration_)))
|
||||
if (K4A_FAILED(k4a_device_get_calibration(device_, config_.depth_mode, config_.color_resolution, &calibration_)))
|
||||
{
|
||||
UERROR("k4a_device_get_calibration() failed!");
|
||||
close();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("k4a_device_get_calibration() no file and no valid device id!");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (ir_)
|
||||
{
|
||||
cv::Mat K = cv::Mat::eye(3, 3, CV_64FC1);
|
||||
K.at<double>(0,0) = calibration_.depth_camera_calibration.intrinsics.parameters.param.fx;
|
||||
K.at<double>(1,1) = calibration_.depth_camera_calibration.intrinsics.parameters.param.fy;
|
||||
K.at<double>(0,2) = calibration_.depth_camera_calibration.intrinsics.parameters.param.cx;
|
||||
K.at<double>(1,2) = calibration_.depth_camera_calibration.intrinsics.parameters.param.cy;
|
||||
cv::Mat D = cv::Mat::eye(1, 8, CV_64FC1);
|
||||
D.at<double>(0,0) = calibration_.depth_camera_calibration.intrinsics.parameters.param.k1;
|
||||
D.at<double>(0,1) = calibration_.depth_camera_calibration.intrinsics.parameters.param.k2;
|
||||
D.at<double>(0,2) = calibration_.depth_camera_calibration.intrinsics.parameters.param.p1;
|
||||
D.at<double>(0,3) = calibration_.depth_camera_calibration.intrinsics.parameters.param.p2;
|
||||
D.at<double>(0,4) = calibration_.depth_camera_calibration.intrinsics.parameters.param.k3;
|
||||
D.at<double>(0,5) = calibration_.depth_camera_calibration.intrinsics.parameters.param.k4;
|
||||
D.at<double>(0,6) = calibration_.depth_camera_calibration.intrinsics.parameters.param.k5;
|
||||
D.at<double>(0,7) = calibration_.depth_camera_calibration.intrinsics.parameters.param.k6;
|
||||
cv::Mat R = cv::Mat::eye(3, 3, CV_64FC1);
|
||||
cv::Mat P = cv::Mat::eye(3, 4, CV_64FC1);
|
||||
P.at<double>(0,0) = K.at<double>(0,0);
|
||||
P.at<double>(1,1) = K.at<double>(1,1);
|
||||
P.at<double>(0,2) = K.at<double>(0,2);
|
||||
P.at<double>(1,2) = K.at<double>(1,2);
|
||||
model_ = CameraModel(
|
||||
"k4a_ir",
|
||||
cv::Size(calibration_.depth_camera_calibration.resolution_width, calibration_.depth_camera_calibration.resolution_height),
|
||||
K,D,R,P,
|
||||
this->getLocalTransform());
|
||||
UASSERT(model_.isValidForRectification());
|
||||
model_.initRectificationMap();
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::Mat K = cv::Mat::eye(3, 3, CV_64FC1);
|
||||
K.at<double>(0,0) = calibration_.color_camera_calibration.intrinsics.parameters.param.fx;
|
||||
K.at<double>(1,1) = calibration_.color_camera_calibration.intrinsics.parameters.param.fy;
|
||||
K.at<double>(0,2) = calibration_.color_camera_calibration.intrinsics.parameters.param.cx;
|
||||
K.at<double>(1,2) = calibration_.color_camera_calibration.intrinsics.parameters.param.cy;
|
||||
cv::Mat D = cv::Mat::eye(1, 8, CV_64FC1);
|
||||
D.at<double>(0,0) = calibration_.color_camera_calibration.intrinsics.parameters.param.k1;
|
||||
D.at<double>(0,1) = calibration_.color_camera_calibration.intrinsics.parameters.param.k2;
|
||||
D.at<double>(0,2) = calibration_.color_camera_calibration.intrinsics.parameters.param.p1;
|
||||
D.at<double>(0,3) = calibration_.color_camera_calibration.intrinsics.parameters.param.p2;
|
||||
D.at<double>(0,4) = calibration_.color_camera_calibration.intrinsics.parameters.param.k3;
|
||||
D.at<double>(0,5) = calibration_.color_camera_calibration.intrinsics.parameters.param.k4;
|
||||
D.at<double>(0,6) = calibration_.color_camera_calibration.intrinsics.parameters.param.k5;
|
||||
D.at<double>(0,7) = calibration_.color_camera_calibration.intrinsics.parameters.param.k6;
|
||||
cv::Mat R = cv::Mat::eye(3, 3, CV_64FC1);
|
||||
cv::Mat P = cv::Mat::eye(3, 4, CV_64FC1);
|
||||
P.at<double>(0,0) = K.at<double>(0,0);
|
||||
P.at<double>(1,1) = K.at<double>(1,1);
|
||||
P.at<double>(0,2) = K.at<double>(0,2);
|
||||
P.at<double>(1,2) = K.at<double>(1,2);
|
||||
model_ = CameraModel(
|
||||
"k4a_color",
|
||||
cv::Size(calibration_.color_camera_calibration.resolution_width, calibration_.color_camera_calibration.resolution_height),
|
||||
K,D,R,P,
|
||||
this->getLocalTransform());
|
||||
}
|
||||
|
||||
if (ULogger::level() <= ULogger::kInfo)
|
||||
{
|
||||
UINFO("K4A calibration:");
|
||||
std::cout << model_ << std::endl;
|
||||
}
|
||||
|
||||
transformationHandle_ = k4a_transformation_create(&calibration_);
|
||||
|
||||
// Get imu transform
|
||||
k4a_calibration_extrinsics_t* imu_extrinsics;
|
||||
if(ir_)
|
||||
{
|
||||
imu_extrinsics = &calibration_.extrinsics[K4A_CALIBRATION_TYPE_ACCEL][K4A_CALIBRATION_TYPE_DEPTH];
|
||||
}
|
||||
else
|
||||
{
|
||||
imu_extrinsics = &calibration_.extrinsics[K4A_CALIBRATION_TYPE_ACCEL][K4A_CALIBRATION_TYPE_COLOR];
|
||||
}
|
||||
imuLocalTransform_ = Transform(
|
||||
imu_extrinsics->rotation[0], imu_extrinsics->rotation[1], imu_extrinsics->rotation[2], imu_extrinsics->translation[0] / 1000.0f,
|
||||
imu_extrinsics->rotation[3], imu_extrinsics->rotation[4], imu_extrinsics->rotation[5], imu_extrinsics->translation[1] / 1000.0f,
|
||||
imu_extrinsics->rotation[6], imu_extrinsics->rotation[7], imu_extrinsics->rotation[8], imu_extrinsics->translation[2] / 1000.0f);
|
||||
|
||||
UINFO("camera to imu=%s", imuLocalTransform_.prettyPrint().c_str());
|
||||
UINFO("base to camera=%s", this->getLocalTransform().prettyPrint().c_str());
|
||||
imuLocalTransform_ = this->getLocalTransform()*imuLocalTransform_;
|
||||
UINFO("base to imu=%s", imuLocalTransform_.prettyPrint().c_str());
|
||||
|
||||
|
||||
// Start playback or camera
|
||||
if (!fileName_.empty())
|
||||
{
|
||||
k4a_record_configuration_t config;
|
||||
if (k4a_playback_get_record_configuration((k4a_playback_t)playbackHandle_, &config))
|
||||
if (ir_)
|
||||
{
|
||||
UERROR("Failed to getting recording configuration");
|
||||
close();
|
||||
return false;
|
||||
model_ = CameraModel(
|
||||
calibration_.depth_camera_calibration.intrinsics.parameters.param.fx,
|
||||
calibration_.depth_camera_calibration.intrinsics.parameters.param.fy,
|
||||
calibration_.depth_camera_calibration.intrinsics.parameters.param.cx,
|
||||
calibration_.depth_camera_calibration.intrinsics.parameters.param.cy,
|
||||
this->getLocalTransform(),
|
||||
0,
|
||||
cv::Size(calibration_.depth_camera_calibration.resolution_width, calibration_.depth_camera_calibration.resolution_height));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (K4A_FAILED(k4a_device_start_imu(deviceHandle_)))
|
||||
else
|
||||
{
|
||||
model_ = CameraModel(
|
||||
calibration_.color_camera_calibration.intrinsics.parameters.param.fx,
|
||||
calibration_.color_camera_calibration.intrinsics.parameters.param.fy,
|
||||
calibration_.color_camera_calibration.intrinsics.parameters.param.cx,
|
||||
calibration_.color_camera_calibration.intrinsics.parameters.param.cy,
|
||||
this->getLocalTransform(),
|
||||
0,
|
||||
cv::Size(calibration_.color_camera_calibration.resolution_width, calibration_.color_camera_calibration.resolution_height));
|
||||
}
|
||||
|
||||
transformation_ = k4a_transformation_create(&calibration_);
|
||||
|
||||
// Get imu transform
|
||||
k4a_calibration_extrinsics_t* imu_extrinsics;
|
||||
if(ir_)
|
||||
{
|
||||
imu_extrinsics = &calibration_.extrinsics[K4A_CALIBRATION_TYPE_ACCEL][K4A_CALIBRATION_TYPE_DEPTH];
|
||||
}
|
||||
else
|
||||
{
|
||||
imu_extrinsics = &calibration_.extrinsics[K4A_CALIBRATION_TYPE_ACCEL][K4A_CALIBRATION_TYPE_COLOR];
|
||||
}
|
||||
imuLocalTransform_ = Transform(
|
||||
imu_extrinsics->rotation[0], imu_extrinsics->rotation[1], imu_extrinsics->rotation[2], imu_extrinsics->translation[0] / 1000.0f,
|
||||
imu_extrinsics->rotation[3], imu_extrinsics->rotation[4], imu_extrinsics->rotation[5], imu_extrinsics->translation[1] / 1000.0f,
|
||||
imu_extrinsics->rotation[6], imu_extrinsics->rotation[7], imu_extrinsics->rotation[8], imu_extrinsics->translation[2] / 1000.0f);
|
||||
|
||||
UINFO("camera to imu=%s", imuLocalTransform_.prettyPrint().c_str());
|
||||
UINFO("base to camera=%s", this->getLocalTransform().prettyPrint().c_str());
|
||||
imuLocalTransform_ = this->getLocalTransform()*imuLocalTransform_;
|
||||
UINFO("base to imu=%s", imuLocalTransform_.prettyPrint().c_str());
|
||||
|
||||
if (K4A_FAILED(k4a_device_start_imu(device_)))
|
||||
{
|
||||
UERROR("Failed to start K4A IMU");
|
||||
close();
|
||||
@@ -370,9 +355,9 @@ bool CameraK4A::init(const std::string & calibrationFolder, const std::string &
|
||||
UINFO("K4a IMU started successfully");
|
||||
|
||||
// Get an initial capture to put the camera in the right state
|
||||
if (K4A_WAIT_RESULT_SUCCEEDED == k4a_device_get_capture(deviceHandle_, &captureHandle_, K4A_WAIT_INFINITE))
|
||||
if (K4A_WAIT_RESULT_SUCCEEDED == k4a_device_get_capture(device_, &capture_, K4A_WAIT_INFINITE))
|
||||
{
|
||||
k4a_capture_release(captureHandle_);
|
||||
k4a_capture_release(capture_);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -410,23 +395,197 @@ SensorData CameraK4A::captureImage(CameraInfo * info)
|
||||
|
||||
#ifdef RTABMAP_K4A
|
||||
|
||||
k4a_image_t ir_image_ = NULL;
|
||||
k4a_image_t rgb_image_ = NULL;
|
||||
k4a_imu_sample_t imu_sample_;
|
||||
|
||||
double t = UTimer::now();
|
||||
|
||||
bool captured = false;
|
||||
if(playbackHandle_)
|
||||
if (playbackHandle_ != NULL)
|
||||
{
|
||||
k4a_stream_result_t result = K4A_STREAM_RESULT_FAILED;
|
||||
while((UTimer::now()-t < 0.1) &&
|
||||
(K4A_STREAM_RESULT_SUCCEEDED != (result=k4a_playback_get_next_capture(playbackHandle_, &captureHandle_)) ||
|
||||
((ir_ && (ir_image_=k4a_capture_get_ir_image(captureHandle_)) == NULL) || (!ir_ && (rgb_image_=k4a_capture_get_color_image(captureHandle_)) == NULL))))
|
||||
k4a_capture_t capture = NULL;
|
||||
k4a_stream_result_t result = K4A_STREAM_RESULT_SUCCEEDED;
|
||||
|
||||
// wait to get all frames
|
||||
UTimer time;
|
||||
while (result == K4A_STREAM_RESULT_SUCCEEDED && time.elapsed() < 5.0)
|
||||
{
|
||||
k4a_capture_release(captureHandle_);
|
||||
// the first frame may be null, just retry for 1 second
|
||||
result = k4a_playback_get_next_capture((k4a_playback_t)playbackHandle_, &capture);
|
||||
|
||||
if (result == K4A_STREAM_RESULT_SUCCEEDED)
|
||||
{
|
||||
cv::Mat bgrCV;
|
||||
cv::Mat depthCV;
|
||||
double stamp = 0;
|
||||
|
||||
// Process capture here
|
||||
if (ir_)
|
||||
{
|
||||
k4a_image_t ir = k4a_capture_get_ir_image(capture);
|
||||
if (ir != NULL)
|
||||
{
|
||||
/*UDEBUG("ir res:%4dx%4d stride:%5d format:%d stamp=%f",
|
||||
k4a_image_get_height_pixels(ir),
|
||||
k4a_image_get_width_pixels(ir),
|
||||
k4a_image_get_stride_bytes(ir),
|
||||
k4a_image_get_format(ir),
|
||||
double(k4a_image_get_timestamp_usec(ir)) / 1000000.0);*/
|
||||
|
||||
UASSERT(k4a_image_get_format(ir) == K4A_IMAGE_FORMAT_IR16);
|
||||
|
||||
cv::Mat bgrCV16(k4a_image_get_height_pixels(ir), k4a_image_get_width_pixels(ir), CV_16UC1, (void*)k4a_image_get_buffer(ir));
|
||||
bgrCV16.convertTo(bgrCV, CV_8U);
|
||||
|
||||
// Release the image
|
||||
k4a_image_release(ir);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
k4a_image_t color = k4a_capture_get_color_image(capture);
|
||||
if (color != NULL)
|
||||
{
|
||||
/*UDEBUG("Color res:%4dx%4d stride:%5d format:%d stamp=%f",
|
||||
k4a_image_get_height_pixels(color),
|
||||
k4a_image_get_width_pixels(color),
|
||||
k4a_image_get_stride_bytes(color),
|
||||
k4a_image_get_format(color),
|
||||
double(k4a_image_get_timestamp_usec(color)) / 1000000.0);*/
|
||||
|
||||
UASSERT(k4a_image_get_format(color) == K4A_IMAGE_FORMAT_COLOR_MJPG || k4a_image_get_format(color) == K4A_IMAGE_FORMAT_COLOR_BGRA32);
|
||||
|
||||
if (k4a_image_get_format(color) == K4A_IMAGE_FORMAT_COLOR_MJPG)
|
||||
{
|
||||
bgrCV = uncompressImage(cv::Mat(1, (int)k4a_image_get_size(color), CV_8UC1, (void*)k4a_image_get_buffer(color)));
|
||||
//UDEBUG("Uncompressed = %d %d %d", bgrCV.rows, bgrCV.cols, bgrCV.channels());
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::Mat bgra(k4a_image_get_height_pixels(color), k4a_image_get_width_pixels(color), CV_8UC4, (void*)k4a_image_get_buffer(color));
|
||||
cv::cvtColor(bgra, bgrCV, CV_BGRA2BGR);
|
||||
}
|
||||
|
||||
// Release the image
|
||||
k4a_image_release(color);
|
||||
}
|
||||
}
|
||||
|
||||
if (!bgrCV.empty())
|
||||
{
|
||||
k4a_image_t depth = k4a_capture_get_depth_image(capture);
|
||||
if (depth != NULL)
|
||||
{
|
||||
/*UDEBUG("Depth16 res:%4dx%4d stride:%5d format:%d stamp=%f",
|
||||
k4a_image_get_height_pixels(depth),
|
||||
k4a_image_get_width_pixels(depth),
|
||||
k4a_image_get_stride_bytes(depth),
|
||||
k4a_image_get_format(depth),
|
||||
double(k4a_image_get_timestamp_usec(depth)) / 1000000.0);*/
|
||||
|
||||
UASSERT(k4a_image_get_format(depth) == K4A_IMAGE_FORMAT_DEPTH16);
|
||||
|
||||
stamp = ((double)k4a_image_get_timestamp_usec(depth)) / 1000000;
|
||||
|
||||
if (ir_)
|
||||
{
|
||||
depthCV = cv::Mat(k4a_image_get_height_pixels(depth), k4a_image_get_width_pixels(depth), CV_16UC1, (void*)k4a_image_get_buffer(depth)).clone();
|
||||
}
|
||||
else
|
||||
{
|
||||
k4a_image_t transformedDepth;
|
||||
if (k4a_image_create(k4a_image_get_format(depth), bgrCV.cols, bgrCV.rows, bgrCV.cols * 2, &transformedDepth) == K4A_RESULT_SUCCEEDED)
|
||||
{
|
||||
if (k4a_transformation_depth_image_to_color_camera((k4a_transformation_t)transformationHandle_, depth, transformedDepth) == K4A_RESULT_SUCCEEDED)
|
||||
{
|
||||
depthCV = cv::Mat(k4a_image_get_height_pixels(transformedDepth), k4a_image_get_width_pixels(transformedDepth), CV_16UC1, (void*)k4a_image_get_buffer(transformedDepth)).clone();
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Failed registration!");
|
||||
}
|
||||
k4a_image_release(transformedDepth);
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Failed allocating depth registered! (%d %d %d)", bgrCV.cols, bgrCV.rows, bgrCV.cols * 2);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Release the image
|
||||
k4a_image_release(depth);
|
||||
}
|
||||
}
|
||||
|
||||
k4a_capture_release(capture);
|
||||
|
||||
IMU imu;
|
||||
// FIXME: local imu transform missing
|
||||
/*k4a_imu_sample_t imuSample;
|
||||
if (k4a_playback_get_next_imu_sample((k4a_playback_t)playbackHandle_, &imuSample) == K4A_STREAM_RESULT_SUCCEEDED)
|
||||
{
|
||||
// K4A IMU Co-ordinates
|
||||
// x+ = "backwards"
|
||||
// y+ = "left"
|
||||
// z+ = "down"
|
||||
//
|
||||
// ROS Standard co-ordinates:
|
||||
// x+ = "forward"
|
||||
// y+ = "left"
|
||||
// z+ = "up"
|
||||
//
|
||||
// Remap K4A IMU to ROS co-ordinate system:
|
||||
// ROS_X+ = K4A_X-
|
||||
// ROS_Y+ = K4A_Y+
|
||||
// ROS_Z+ = K4A_Z-
|
||||
|
||||
imu = IMU(
|
||||
cv::Vec3d(-1*imuSample.gyro_sample.xyz.x, imuSample.gyro_sample.xyz.y, -1 * imuSample.gyro_sample.xyz.z),
|
||||
cv::Mat::eye(3, 3, CV_64FC1),
|
||||
cv::Vec3d(-1 * imuSample.acc_sample.xyz.x, imuSample.acc_sample.xyz.y, -1 * imuSample.acc_sample.xyz.z),
|
||||
cv::Mat::eye(3, 3, CV_64FC1),
|
||||
Transform::getIdentity());
|
||||
}*/
|
||||
|
||||
if (!bgrCV.empty() && !depthCV.empty())
|
||||
{
|
||||
data = SensorData(bgrCV, depthCV, model_, this->getNextSeqID(), stamp);
|
||||
data.setIMU(imu);
|
||||
|
||||
// Frame rate
|
||||
if (this->getImageRate() < 0.0f)
|
||||
{
|
||||
if (stamp == 0)
|
||||
{
|
||||
UWARN("The option to use mkv stamps is set (framerate<0), but there are no stamps saved in the file! Aborting...");
|
||||
}
|
||||
else if (previousStamp_ > 0)
|
||||
{
|
||||
float ratio = -this->getImageRate();
|
||||
int sleepTime = 1000.0*(stamp - previousStamp_) / ratio - 1000.0*timer_.getElapsedTime();
|
||||
if (sleepTime > 10000)
|
||||
{
|
||||
UWARN("Detected long delay (%d sec, stamps = %f vs %f). Waiting a maximum of 10 seconds.",
|
||||
sleepTime / 1000, previousStamp_, stamp);
|
||||
sleepTime = 10000;
|
||||
}
|
||||
if (sleepTime > 2)
|
||||
{
|
||||
uSleep(sleepTime - 2);
|
||||
}
|
||||
|
||||
// Add precision at the cost of a small overhead
|
||||
while (timer_.getElapsedTime() < (stamp - previousStamp_) / ratio - 0.000001)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
double slept = timer_.getElapsedTime();
|
||||
timer_.start();
|
||||
UDEBUG("slept=%fs vs target=%fs (ratio=%f)", slept, (stamp - previousStamp_) / ratio, ratio);
|
||||
}
|
||||
previousStamp_ = stamp;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (result == K4A_STREAM_RESULT_EOF)
|
||||
{
|
||||
// End of file reached
|
||||
@@ -436,138 +595,112 @@ SensorData CameraK4A::captureImage(CameraInfo * info)
|
||||
{
|
||||
UERROR("Failed to read entire recording");
|
||||
}
|
||||
captured = result == K4A_STREAM_RESULT_SUCCEEDED;
|
||||
}
|
||||
else // device
|
||||
else
|
||||
{
|
||||
k4a_image_t ir_image_ = NULL;
|
||||
k4a_image_t rgb_image_ = NULL;
|
||||
k4a_imu_sample_t imu_sample_;
|
||||
|
||||
double t = UTimer::now();
|
||||
k4a_wait_result_t result = K4A_WAIT_RESULT_FAILED;
|
||||
while((UTimer::now()-t < 5.0) &&
|
||||
(K4A_WAIT_RESULT_SUCCEEDED != (result=k4a_device_get_capture(deviceHandle_, &captureHandle_, K4A_WAIT_INFINITE)) ||
|
||||
((ir_ && (ir_image_=k4a_capture_get_ir_image(captureHandle_)) == NULL) || (!ir_ && (rgb_image_=k4a_capture_get_color_image(captureHandle_)) == NULL))))
|
||||
(K4A_WAIT_RESULT_SUCCEEDED != (result=k4a_device_get_capture(device_, &capture_, K4A_WAIT_INFINITE)) ||
|
||||
((ir_ && (ir_image_=k4a_capture_get_ir_image(capture_)) == NULL) || (!ir_ && (rgb_image_=k4a_capture_get_color_image(capture_)) == NULL))))
|
||||
{
|
||||
k4a_capture_release(captureHandle_);
|
||||
k4a_capture_release(capture_);
|
||||
// the first frame may be null, just retry for 5 seconds
|
||||
}
|
||||
captured = result == K4A_WAIT_RESULT_SUCCEEDED;
|
||||
}
|
||||
|
||||
if (captured && (rgb_image_!=NULL || ir_image_!=NULL))
|
||||
{
|
||||
cv::Mat bgrCV;
|
||||
cv::Mat depthCV;
|
||||
IMU imu;
|
||||
|
||||
if (ir_image_ != NULL)
|
||||
if (result == K4A_WAIT_RESULT_SUCCEEDED && (rgb_image_!=NULL || ir_image_!=NULL))
|
||||
{
|
||||
// Convert IR image
|
||||
cv::Mat bgrCV16(k4a_image_get_height_pixels(ir_image_),
|
||||
k4a_image_get_width_pixels(ir_image_),
|
||||
CV_16UC1,
|
||||
(void*)k4a_image_get_buffer(ir_image_));
|
||||
cv::Mat bgrCV;
|
||||
cv::Mat depthCV;
|
||||
IMU imu;
|
||||
|
||||
bgrCV16.convertTo(bgrCV, CV_8U);
|
||||
|
||||
bgrCV = model_.rectifyImage(bgrCV);
|
||||
|
||||
// Release the image
|
||||
k4a_image_release(ir_image_);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Convert RGB image
|
||||
if (k4a_image_get_format(rgb_image_) == K4A_IMAGE_FORMAT_COLOR_MJPG)
|
||||
if (ir_image_ != NULL)
|
||||
{
|
||||
bgrCV = uncompressImage(cv::Mat(1, (int)k4a_image_get_size(rgb_image_),
|
||||
CV_8UC1,
|
||||
(void*)k4a_image_get_buffer(rgb_image_)));
|
||||
// Convert IR image
|
||||
cv::Mat bgrCV16(k4a_image_get_height_pixels(ir_image_),
|
||||
k4a_image_get_width_pixels(ir_image_),
|
||||
CV_16UC1,
|
||||
(void*)k4a_image_get_buffer(ir_image_));
|
||||
|
||||
bgrCV16.convertTo(bgrCV, CV_8U);
|
||||
|
||||
// Release the image
|
||||
k4a_image_release(ir_image_);
|
||||
}
|
||||
else
|
||||
{
|
||||
cv::Mat bgra(k4a_image_get_height_pixels(rgb_image_),
|
||||
k4a_image_get_width_pixels(rgb_image_),
|
||||
CV_8UC4,
|
||||
(void*)k4a_image_get_buffer(rgb_image_));
|
||||
|
||||
cv::cvtColor(bgra, bgrCV, CV_BGRA2BGR);
|
||||
}
|
||||
|
||||
// Release the image
|
||||
k4a_image_release(rgb_image_);
|
||||
}
|
||||
|
||||
double stamp = UTimer::now();
|
||||
if(!bgrCV.empty())
|
||||
{
|
||||
// Retrieve depth image from capture
|
||||
k4a_image_t depth_image_ = k4a_capture_get_depth_image(captureHandle_);
|
||||
|
||||
if (depth_image_ != NULL)
|
||||
{
|
||||
stamp = ((double)k4a_image_get_timestamp_usec(depth_image_)) / 1000000;
|
||||
|
||||
if (ir_)
|
||||
// Convert RGB image
|
||||
if (k4a_image_get_format(rgb_image_) == K4A_IMAGE_FORMAT_COLOR_MJPG)
|
||||
{
|
||||
depthCV = cv::Mat(k4a_image_get_height_pixels(depth_image_),
|
||||
k4a_image_get_width_pixels(depth_image_),
|
||||
CV_16UC1,
|
||||
(void*)k4a_image_get_buffer(depth_image_));
|
||||
|
||||
depthCV = model_.rectifyDepth(depthCV);
|
||||
bgrCV = uncompressImage(cv::Mat(1, (int)k4a_image_get_size(rgb_image_),
|
||||
CV_8UC1,
|
||||
(void*)k4a_image_get_buffer(rgb_image_)));
|
||||
}
|
||||
else
|
||||
{
|
||||
k4a_image_t transformedDepth = NULL;
|
||||
if (k4a_image_create(k4a_image_get_format(depth_image_),
|
||||
bgrCV.cols, bgrCV.rows, bgrCV.cols * 2, &transformedDepth) == K4A_RESULT_SUCCEEDED)
|
||||
{
|
||||
if(k4a_transformation_depth_image_to_color_camera(transformationHandle_, depth_image_, transformedDepth) == K4A_RESULT_SUCCEEDED)
|
||||
{
|
||||
depthCV = cv::Mat(k4a_image_get_height_pixels(transformedDepth),
|
||||
k4a_image_get_width_pixels(transformedDepth),
|
||||
CV_16UC1,
|
||||
(void*)k4a_image_get_buffer(transformedDepth)).clone();
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("K4A failed to register depth image");
|
||||
}
|
||||
cv::Mat bgra(k4a_image_get_height_pixels(rgb_image_),
|
||||
k4a_image_get_width_pixels(rgb_image_),
|
||||
CV_8UC4,
|
||||
(void*)k4a_image_get_buffer(rgb_image_));
|
||||
|
||||
k4a_image_release(transformedDepth);
|
||||
cv::cvtColor(bgra, bgrCV, CV_BGRA2BGR);
|
||||
}
|
||||
|
||||
// Release the image
|
||||
k4a_image_release(rgb_image_);
|
||||
}
|
||||
|
||||
if(!bgrCV.empty())
|
||||
{
|
||||
// Retrieve depth image from capture
|
||||
k4a_image_t depth_image_ = k4a_capture_get_depth_image(capture_);
|
||||
|
||||
if (depth_image_ != NULL)
|
||||
{
|
||||
if (ir_)
|
||||
{
|
||||
depthCV = cv::Mat(k4a_image_get_height_pixels(depth_image_),
|
||||
k4a_image_get_width_pixels(depth_image_),
|
||||
CV_16UC1,
|
||||
(void*)k4a_image_get_buffer(depth_image_)).clone();
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("K4A failed to allocate registered depth image");
|
||||
k4a_image_t transformedDepth = NULL;
|
||||
if (k4a_image_create(k4a_image_get_format(depth_image_),
|
||||
bgrCV.cols, bgrCV.rows, bgrCV.cols * 2, &transformedDepth) == K4A_RESULT_SUCCEEDED)
|
||||
{
|
||||
if(k4a_transformation_depth_image_to_color_camera(transformation_, depth_image_, transformedDepth) == K4A_RESULT_SUCCEEDED)
|
||||
{
|
||||
depthCV = cv::Mat(k4a_image_get_height_pixels(transformedDepth),
|
||||
k4a_image_get_width_pixels(transformedDepth),
|
||||
CV_16UC1,
|
||||
(void*)k4a_image_get_buffer(transformedDepth)).clone();
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("K4A failed to register depth image");
|
||||
}
|
||||
|
||||
k4a_image_release(transformedDepth);
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("K4A failed to allocate registered depth image");
|
||||
}
|
||||
}
|
||||
k4a_image_release(depth_image_);
|
||||
}
|
||||
k4a_image_release(depth_image_);
|
||||
}
|
||||
}
|
||||
|
||||
k4a_capture_release(captureHandle_);
|
||||
k4a_capture_release(capture_);
|
||||
|
||||
if(playbackHandle_)
|
||||
{
|
||||
// Get IMU sample, clear buffer
|
||||
// FIXME: not tested, uncomment when tested.
|
||||
k4a_playback_seek_timestamp(playbackHandle_, stamp* 1000000+1, K4A_PLAYBACK_SEEK_BEGIN);
|
||||
if(K4A_STREAM_RESULT_SUCCEEDED == k4a_playback_get_previous_imu_sample(playbackHandle_, &imu_sample_))
|
||||
{
|
||||
double stmp = ((double)imu_sample_.acc_timestamp_usec) / 1000000;
|
||||
imu = IMU(cv::Vec3d(imu_sample_.gyro_sample.xyz.x, imu_sample_.gyro_sample.xyz.y, imu_sample_.gyro_sample.xyz.z),
|
||||
cv::Mat::eye(3, 3, CV_64FC1),
|
||||
cv::Vec3d(imu_sample_.acc_sample.xyz.x, imu_sample_.acc_sample.xyz.y, imu_sample_.acc_sample.xyz.z),
|
||||
cv::Mat::eye(3, 3, CV_64FC1),
|
||||
imuLocalTransform_);
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("IMU data NULL");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Get IMU sample, clear buffer
|
||||
if(K4A_WAIT_RESULT_SUCCEEDED == k4a_device_get_imu_sample(deviceHandle_, &imu_sample_, 60))
|
||||
if(K4A_WAIT_RESULT_SUCCEEDED == k4a_device_get_imu_sample(device_, &imu_sample_, 60))
|
||||
{
|
||||
imu = IMU(cv::Vec3d(imu_sample_.gyro_sample.xyz.x, imu_sample_.gyro_sample.xyz.y, imu_sample_.gyro_sample.xyz.z),
|
||||
cv::Mat::eye(3, 3, CV_64FC1),
|
||||
@@ -579,51 +712,13 @@ SensorData CameraK4A::captureImage(CameraInfo * info)
|
||||
{
|
||||
UERROR("IMU data NULL");
|
||||
}
|
||||
}
|
||||
|
||||
// Relay the data to rtabmap
|
||||
if (!bgrCV.empty() && !depthCV.empty())
|
||||
{
|
||||
data = SensorData(bgrCV, depthCV, model_, this->getNextSeqID(), stamp);
|
||||
if(!imu.empty())
|
||||
// Relay the data to rtabmap
|
||||
if (!bgrCV.empty() && !depthCV.empty())
|
||||
{
|
||||
data = SensorData(bgrCV, depthCV, model_, this->getNextSeqID(), UTimer::now());
|
||||
data.setIMU(imu);
|
||||
}
|
||||
|
||||
// Frame rate
|
||||
if (playbackHandle_ && this->getImageRate() < 0.0f)
|
||||
{
|
||||
if (stamp == 0)
|
||||
{
|
||||
UWARN("The option to use mkv stamps is set (framerate<0), but there are no stamps saved in the file! Aborting...");
|
||||
}
|
||||
else if (previousStamp_ > 0)
|
||||
{
|
||||
float ratio = -this->getImageRate();
|
||||
int sleepTime = 1000.0*(stamp - previousStamp_) / ratio - 1000.0*timer_.getElapsedTime();
|
||||
if (sleepTime > 10000)
|
||||
{
|
||||
UWARN("Detected long delay (%d sec, stamps = %f vs %f). Waiting a maximum of 10 seconds.",
|
||||
sleepTime / 1000, previousStamp_, stamp);
|
||||
sleepTime = 10000;
|
||||
}
|
||||
if (sleepTime > 2)
|
||||
{
|
||||
uSleep(sleepTime - 2);
|
||||
}
|
||||
|
||||
// Add precision at the cost of a small overhead
|
||||
while (timer_.getElapsedTime() < (stamp - previousStamp_) / ratio - 0.000001)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
double slept = timer_.getElapsedTime();
|
||||
timer_.start();
|
||||
UDEBUG("slept=%fs vs target=%fs (ratio=%f)", slept, (stamp - previousStamp_) / ratio, ratio);
|
||||
}
|
||||
previousStamp_ = stamp;
|
||||
}
|
||||
}
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -70,6 +70,16 @@ bool CameraRGBDImages::init(const std::string & calibrationFolder, const std::st
|
||||
return success;
|
||||
}
|
||||
|
||||
bool CameraRGBDImages::isCalibrated() const
|
||||
{
|
||||
return this->cameraModel().isValidForProjection();
|
||||
}
|
||||
|
||||
std::string CameraRGBDImages::getSerial() const
|
||||
{
|
||||
return this->cameraModel().name();
|
||||
}
|
||||
|
||||
SensorData CameraRGBDImages::captureImage(CameraInfo * info)
|
||||
{
|
||||
SensorData data;
|
||||
|
||||
@@ -68,7 +68,6 @@ CameraRealSense2::CameraRealSense2(
|
||||
depthToRGBExtrinsics_(new rs2_extrinsics),
|
||||
lastImuStamp_(0.0),
|
||||
clockSyncWarningShown_(false),
|
||||
imuGlobalSyncWarningShown_(false),
|
||||
emitterEnabled_(true),
|
||||
ir_(false),
|
||||
irDepth_(true),
|
||||
@@ -77,11 +76,9 @@ CameraRealSense2::CameraRealSense2(
|
||||
cameraWidth_(640),
|
||||
cameraHeight_(480),
|
||||
cameraFps_(30),
|
||||
globalTimeSync_(true),
|
||||
publishInterIMU_(false),
|
||||
dualMode_(false),
|
||||
closing_(false),
|
||||
isL500_(false)
|
||||
closing_(false)
|
||||
#endif
|
||||
{
|
||||
UDEBUG("");
|
||||
@@ -232,7 +229,7 @@ void CameraRealSense2::getPoseAndIMU(
|
||||
Transform & pose,
|
||||
unsigned int & poseConfidence,
|
||||
IMU & imu,
|
||||
int maxWaitTimeMs)
|
||||
int maxWaitTimeMs) const
|
||||
{
|
||||
pose.setNull();
|
||||
imu = IMU();
|
||||
@@ -299,18 +296,15 @@ void CameraRealSense2::getPoseAndIMU(
|
||||
cv::Vec3d acc;
|
||||
{
|
||||
imuMutex_.lock();
|
||||
if(globalTimeSync_)
|
||||
int waitTry = 0;
|
||||
while(maxWaitTimeMs > 0 && accBuffer_.rbegin()->first < stamp && waitTry < maxWaitTimeMs)
|
||||
{
|
||||
int waitTry = 0;
|
||||
while(maxWaitTimeMs > 0 && accBuffer_.rbegin()->first < stamp && waitTry < maxWaitTimeMs)
|
||||
{
|
||||
imuMutex_.unlock();
|
||||
++waitTry;
|
||||
uSleep(1);
|
||||
imuMutex_.lock();
|
||||
}
|
||||
imuMutex_.unlock();
|
||||
++waitTry;
|
||||
uSleep(1);
|
||||
imuMutex_.lock();
|
||||
}
|
||||
if(globalTimeSync_ && accBuffer_.rbegin()->first < stamp)
|
||||
if(accBuffer_.rbegin()->first < stamp)
|
||||
{
|
||||
if(maxWaitTimeMs>0)
|
||||
{
|
||||
@@ -346,34 +340,16 @@ void CameraRealSense2::getPoseAndIMU(
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!imuGlobalSyncWarningShown_)
|
||||
if(stamp < iterA->first)
|
||||
{
|
||||
if(stamp < iterA->first)
|
||||
{
|
||||
UWARN("Could not find acc data to interpolate at image time %f (earliest is %f). Are sensors synchronized?", stamp, iterA->first);
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Could not find acc data to interpolate at image time %f (between %f and %f). Are sensors synchronized?", stamp, iterA->first, iterB->first);
|
||||
}
|
||||
}
|
||||
if(!globalTimeSync_)
|
||||
{
|
||||
if(!imuGlobalSyncWarningShown_)
|
||||
{
|
||||
UWARN("As globalTimeSync option is off, the received gyro and accelerometer will be re-stamped with image time. This message is only shown once.");
|
||||
imuGlobalSyncWarningShown_ = true;
|
||||
}
|
||||
std::map<double, cv::Vec3f>::const_reverse_iterator iterC = accBuffer_.rbegin();
|
||||
acc[0] = iterC->second[0];
|
||||
acc[1] = iterC->second[1];
|
||||
acc[2] = iterC->second[2];
|
||||
UWARN("Could not find acc data to interpolate at image time %f (earliest is %f). Are sensors synchronized?", stamp, iterA->first);
|
||||
}
|
||||
else
|
||||
{
|
||||
imuMutex_.unlock();
|
||||
return;
|
||||
UWARN("Could not find acc data to interpolate at image time %f (between %f and %f). Are sensors synchronized?", stamp, iterA->first, iterB->first);
|
||||
}
|
||||
imuMutex_.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
imuMutex_.unlock();
|
||||
@@ -383,18 +359,15 @@ void CameraRealSense2::getPoseAndIMU(
|
||||
cv::Vec3d gyro;
|
||||
{
|
||||
imuMutex_.lock();
|
||||
if(globalTimeSync_)
|
||||
int waitTry = 0;
|
||||
while(maxWaitTimeMs>0 && gyroBuffer_.rbegin()->first < stamp && waitTry < maxWaitTimeMs)
|
||||
{
|
||||
int waitTry = 0;
|
||||
while(maxWaitTimeMs>0 && gyroBuffer_.rbegin()->first < stamp && waitTry < maxWaitTimeMs)
|
||||
{
|
||||
imuMutex_.unlock();
|
||||
++waitTry;
|
||||
uSleep(1);
|
||||
imuMutex_.lock();
|
||||
}
|
||||
imuMutex_.unlock();
|
||||
++waitTry;
|
||||
uSleep(1);
|
||||
imuMutex_.lock();
|
||||
}
|
||||
if(globalTimeSync_ && gyroBuffer_.rbegin()->first < stamp)
|
||||
if(gyroBuffer_.rbegin()->first < stamp)
|
||||
{
|
||||
if(maxWaitTimeMs>0)
|
||||
{
|
||||
@@ -430,34 +403,16 @@ void CameraRealSense2::getPoseAndIMU(
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!imuGlobalSyncWarningShown_)
|
||||
if(stamp < iterA->first)
|
||||
{
|
||||
if(stamp < iterA->first)
|
||||
{
|
||||
UWARN("Could not find gyro data to interpolate at image time %f (earliest is %f). Are sensors synchronized?", stamp, iterA->first);
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Could not find gyro data to interpolate at image time %f (between %f and %f). Are sensors synchronized?", stamp, iterA->first, iterB->first);
|
||||
}
|
||||
}
|
||||
if(!globalTimeSync_)
|
||||
{
|
||||
if(!imuGlobalSyncWarningShown_)
|
||||
{
|
||||
UWARN("As globalTimeSync option is off, the latest received gyro and accelerometer will be re-stamped with image time. This message is only shown once.");
|
||||
imuGlobalSyncWarningShown_ = true;
|
||||
}
|
||||
std::map<double, cv::Vec3f>::const_reverse_iterator iterC = gyroBuffer_.rbegin();
|
||||
gyro[0] = iterC->second[0];
|
||||
gyro[1] = iterC->second[1];
|
||||
gyro[2] = iterC->second[2];
|
||||
UWARN("Could not find gyro data to interpolate at image time %f (earliest is %f). Are sensors synchronized?", stamp, iterA->first);
|
||||
}
|
||||
else
|
||||
{
|
||||
imuMutex_.unlock();
|
||||
return;
|
||||
UWARN("Could not find gyro data to interpolate at image time %f (between %f and %f). Are sensors synchronized?", stamp, iterA->first, iterB->first);
|
||||
}
|
||||
imuMutex_.unlock();
|
||||
return;
|
||||
}
|
||||
}
|
||||
imuMutex_.unlock();
|
||||
@@ -480,7 +435,6 @@ bool CameraRealSense2::init(const std::string & calibrationFolder, const std::st
|
||||
dev_[i] = 0;
|
||||
}
|
||||
clockSyncWarningShown_ = false;
|
||||
imuGlobalSyncWarningShown_ = false;
|
||||
|
||||
auto list = ctx_->query_devices();
|
||||
if (0 == list.size())
|
||||
@@ -606,7 +560,6 @@ bool CameraRealSense2::init(const std::string & calibrationFolder, const std::st
|
||||
UINFO("Device Sensors: ");
|
||||
std::vector<rs2::sensor> sensors(2); //0=rgb 1=depth 2=(pose in dualMode_)
|
||||
bool stereo = false;
|
||||
isL500_ = false;
|
||||
for(auto&& elem : dev_sensors)
|
||||
{
|
||||
std::string module_name = elem.get_info(RS2_CAMERA_INFO_NAME);
|
||||
@@ -651,11 +604,6 @@ bool CameraRealSense2::init(const std::string & calibrationFolder, const std::st
|
||||
sensors.back().set_option(rs2_option::RS2_OPTION_ENABLE_POSE_JUMPING, 0);
|
||||
sensors.back().set_option(rs2_option::RS2_OPTION_ENABLE_RELOCALIZATION, 0);
|
||||
}
|
||||
else if ("L500 Depth Sensor" == module_name)
|
||||
{
|
||||
sensors[1] = elem;
|
||||
isL500_ = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Module Name \"%s\" isn't supported!", module_name.c_str());
|
||||
@@ -685,14 +633,12 @@ bool CameraRealSense2::init(const std::string & calibrationFolder, const std::st
|
||||
for (auto& profile : profiles)
|
||||
{
|
||||
auto video_profile = profile.as<rs2::video_stream_profile>();
|
||||
UINFO("%s %d %d %d %d %s type=%d", rs2_format_to_string(
|
||||
UINFO("%s %d %d %d %d", rs2_format_to_string(
|
||||
video_profile.format()),
|
||||
video_profile.width(),
|
||||
video_profile.height(),
|
||||
video_profile.fps(),
|
||||
video_profile.stream_index(),
|
||||
video_profile.stream_name().c_str(),
|
||||
video_profile.stream_type());
|
||||
video_profile.stream_index());
|
||||
}
|
||||
}
|
||||
int pi = 0;
|
||||
@@ -701,43 +647,15 @@ bool CameraRealSense2::init(const std::string & calibrationFolder, const std::st
|
||||
auto video_profile = profile.as<rs2::video_stream_profile>();
|
||||
if(!stereo)
|
||||
{
|
||||
if(isL500_ &&
|
||||
(video_profile.width() == 640 &&
|
||||
video_profile.height() == 480 &&
|
||||
video_profile.fps() == 30))
|
||||
{
|
||||
if( i==0 // rgb
|
||||
&& video_profile.format() == RS2_FORMAT_RGB8 && video_profile.stream_type() == RS2_STREAM_COLOR)
|
||||
{
|
||||
auto intrinsic = video_profile.get_intrinsics();
|
||||
profilesPerSensor[i].push_back(profile);
|
||||
rgbBuffer_ = cv::Mat(cv::Size(video_profile.width(), video_profile.height()), CV_8UC3, cv::Scalar(0, 0, 0));
|
||||
model_ = CameraModel(camera_name, intrinsic.fx, intrinsic.fy, intrinsic.ppx, intrinsic.ppy, this->getLocalTransform(), 0, cv::Size(intrinsic.width, intrinsic.height));
|
||||
rgbStreamProfile = profile;
|
||||
*rgbIntrinsics_ = intrinsic;
|
||||
added = true;
|
||||
}
|
||||
else if( i==1 // depth
|
||||
&& video_profile.format() == RS2_FORMAT_Z16 && video_profile.stream_type() == RS2_STREAM_DEPTH)
|
||||
{
|
||||
auto intrinsic = video_profile.get_intrinsics();
|
||||
profilesPerSensor[i].push_back(profile);
|
||||
depthBuffer_ = cv::Mat(cv::Size(video_profile.width(), video_profile.height()), CV_16UC1, cv::Scalar(0));
|
||||
depthStreamProfile = profile;
|
||||
*depthIntrinsics_ = intrinsic;
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
//D400 series:
|
||||
else if (!isL500_ &&
|
||||
(video_profile.width() == cameraWidth_ &&
|
||||
video_profile.height() == cameraHeight_ &&
|
||||
video_profile.fps() == cameraFps_))
|
||||
if (video_profile.width() == cameraWidth_ &&
|
||||
video_profile.height() == cameraHeight_ &&
|
||||
video_profile.fps() == cameraFps_)
|
||||
{
|
||||
auto intrinsic = video_profile.get_intrinsics();
|
||||
|
||||
// rgb or ir left
|
||||
if((!ir_ && video_profile.format() == RS2_FORMAT_RGB8 && video_profile.stream_type() == RS2_STREAM_COLOR) ||
|
||||
if((!ir_ && video_profile.format() == RS2_FORMAT_RGB8) ||
|
||||
(ir_ && video_profile.format() == RS2_FORMAT_Y8 && video_profile.stream_index() == 1))
|
||||
{
|
||||
if(!profilesPerSensor[i].empty())
|
||||
@@ -778,35 +696,15 @@ bool CameraRealSense2::init(const std::string & calibrationFolder, const std::st
|
||||
else if(video_profile.format() == RS2_FORMAT_MOTION_XYZ32F || video_profile.format() == RS2_FORMAT_6DOF)
|
||||
{
|
||||
//D435i:
|
||||
//MOTION_XYZ32F 0 0 200 (gyro)
|
||||
//MOTION_XYZ32F 0 0 400 (gyro)
|
||||
//MOTION_XYZ32F 0 0 63 6 (accel)
|
||||
//MOTION_XYZ32F 0 0 250 6 (accel)
|
||||
//MOTION_XYZ32F 0 0 200
|
||||
//MOTION_XYZ32F 0 0 400
|
||||
//MOTION_XYZ32F 0 0 63
|
||||
//MOTION_XYZ32F 0 0 250
|
||||
// or dualMode_ T265:
|
||||
//MOTION_XYZ32F 0 0 200 5 (gyro)
|
||||
//MOTION_XYZ32F 0 0 62 6 (accel)
|
||||
//6DOF 0 0 200 4 (pose)
|
||||
bool modified = false;
|
||||
for (size_t j= 0; j < profilesPerSensor[i].size(); ++j)
|
||||
{
|
||||
if (profilesPerSensor[i][j].stream_type() == profile.stream_type())
|
||||
{
|
||||
if (profile.stream_type() == RS2_STREAM_ACCEL)
|
||||
{
|
||||
if(profile.fps() > profilesPerSensor[i][j].fps())
|
||||
profilesPerSensor[i][j] = profile;
|
||||
modified = true;
|
||||
}
|
||||
else if (profile.stream_type() == RS2_STREAM_GYRO)
|
||||
{
|
||||
if(profile.fps() < profilesPerSensor[i][j].fps())
|
||||
profilesPerSensor[i][j] = profile;
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!modified)
|
||||
profilesPerSensor[i].push_back(profile);
|
||||
//MOTION_XYZ32F 0 0 200
|
||||
//MOTION_XYZ32F 0 0 62
|
||||
//6DOF 0 0 200
|
||||
profilesPerSensor[i].push_back(profile);
|
||||
added = true;
|
||||
}
|
||||
}
|
||||
@@ -857,14 +755,12 @@ bool CameraRealSense2::init(const std::string & calibrationFolder, const std::st
|
||||
for (auto& profile : profiles)
|
||||
{
|
||||
auto video_profile = profile.as<rs2::video_stream_profile>();
|
||||
UERROR("%s %d %d %d %d %s type=%d", rs2_format_to_string(
|
||||
UERROR("%s %d %d %d %d", rs2_format_to_string(
|
||||
video_profile.format()),
|
||||
video_profile.width(),
|
||||
video_profile.height(),
|
||||
video_profile.fps(),
|
||||
video_profile.stream_index(),
|
||||
video_profile.stream_name().c_str(),
|
||||
video_profile.stream_type());
|
||||
video_profile.stream_index());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1040,37 +936,18 @@ bool CameraRealSense2::init(const std::string & calibrationFolder, const std::st
|
||||
if(profilesPerSensor[i].size())
|
||||
{
|
||||
UINFO("Starting sensor %d with %d profiles", (int)i, (int)profilesPerSensor[i].size());
|
||||
for (size_t j = 0; j < profilesPerSensor[i].size(); ++j)
|
||||
{
|
||||
auto video_profile = profilesPerSensor[i][j].as<rs2::video_stream_profile>();
|
||||
UINFO("Opening: %s %d %d %d %d %s type=%d", rs2_format_to_string(
|
||||
video_profile.format()),
|
||||
video_profile.width(),
|
||||
video_profile.height(),
|
||||
video_profile.fps(),
|
||||
video_profile.stream_index(),
|
||||
video_profile.stream_name().c_str(),
|
||||
video_profile.stream_type());
|
||||
}
|
||||
if(globalTimeSync_ && sensors[i].supports(rs2_option::RS2_OPTION_GLOBAL_TIME_ENABLED))
|
||||
{
|
||||
float value = sensors[i].get_option(rs2_option::RS2_OPTION_GLOBAL_TIME_ENABLED);
|
||||
UINFO("Set RS2_OPTION_GLOBAL_TIME_ENABLED=1 (was %f) for sensor %d", value, (int)i);
|
||||
sensors[i].set_option(rs2_option::RS2_OPTION_GLOBAL_TIME_ENABLED, 1);
|
||||
}
|
||||
sensors[i].open(profilesPerSensor[i]);
|
||||
if(sensors[i].is<rs2::depth_sensor>())
|
||||
{
|
||||
auto depth_sensor = sensors[i].as<rs2::depth_sensor>();
|
||||
depth_scale_meters_ = depth_sensor.get_depth_scale();
|
||||
UINFO("Depth scale %f for sensor %d", depth_scale_meters_, (int)i);
|
||||
}
|
||||
sensors[i].start(multiple_message_callback_function);
|
||||
}
|
||||
}
|
||||
|
||||
uSleep(1000); // ignore the first frames
|
||||
UINFO("Enabling streams...done!");
|
||||
uSleep(1000); // ignore the first frames
|
||||
UINFO("Enabling streams...done!");
|
||||
|
||||
return true;
|
||||
|
||||
@@ -1133,13 +1010,6 @@ void CameraRealSense2::setResolution(int width, int height, int fps)
|
||||
#endif
|
||||
}
|
||||
|
||||
void CameraRealSense2::setGlobalTimeSync(bool enabled)
|
||||
{
|
||||
#ifdef RTABMAP_REALSENSE2
|
||||
globalTimeSync_ = enabled;
|
||||
#endif
|
||||
}
|
||||
|
||||
void CameraRealSense2::publishInterIMU(bool enabled)
|
||||
{
|
||||
#ifdef RTABMAP_REALSENSE2
|
||||
@@ -1194,15 +1064,12 @@ SensorData CameraRealSense2::captureImage(CameraInfo * info)
|
||||
try{
|
||||
auto frameset = syncer_->wait_for_frames(5000);
|
||||
UTimer timer;
|
||||
int desiredFramesetSize = 2;
|
||||
if(isL500_ && globalTimeSync_)
|
||||
desiredFramesetSize = 3;
|
||||
while ((int)frameset.size() != desiredFramesetSize && timer.elapsed() < 2.0)
|
||||
while (frameset.size() != 2 && timer.elapsed() < 2.0)
|
||||
{
|
||||
// maybe there is a latency with the USB, try again in 100 ms (for the next 2 seconds)
|
||||
frameset = syncer_->wait_for_frames(100);
|
||||
}
|
||||
if ((int)frameset.size() == desiredFramesetSize)
|
||||
if (frameset.size() == 2)
|
||||
{
|
||||
double now = UTimer::now();
|
||||
bool is_rgb_arrived = false;
|
||||
@@ -1222,15 +1089,7 @@ SensorData CameraRealSense2::captureImage(CameraInfo * info)
|
||||
auto stream_type = f.get_profile().stream_type();
|
||||
if (stream_type == RS2_STREAM_COLOR || stream_type == RS2_STREAM_INFRARED)
|
||||
{
|
||||
if(isL500_)
|
||||
{
|
||||
if(stream_type == RS2_STREAM_COLOR)
|
||||
{
|
||||
rgb_frame = f;
|
||||
is_rgb_arrived = true;
|
||||
}
|
||||
}
|
||||
else if(ir_ && !irDepth_)
|
||||
if(ir_ && !irDepth_)
|
||||
{
|
||||
//stereo D435
|
||||
if(!is_depth_arrived)
|
||||
@@ -1288,6 +1147,7 @@ SensorData CameraRealSense2::captureImage(CameraInfo * info)
|
||||
|
||||
if(is_rgb_arrived && is_depth_arrived)
|
||||
{
|
||||
auto from_image_frame = depth_frame.as<rs2::video_frame>();
|
||||
cv::Mat depth;
|
||||
if(ir_)
|
||||
{
|
||||
@@ -1299,19 +1159,6 @@ SensorData CameraRealSense2::captureImage(CameraInfo * info)
|
||||
rs2::frameset processed = frameset.apply_filter(align);
|
||||
rs2::depth_frame aligned_depth_frame = processed.get_depth_frame();
|
||||
depth = cv::Mat(depthBuffer_.size(), depthBuffer_.type(), (void*)aligned_depth_frame.get_data()).clone();
|
||||
if(depth_scale_meters_ != 0.001f)
|
||||
{ // convert to mm
|
||||
if(depth.type() == CV_16UC1)
|
||||
{
|
||||
float scale = depth_scale_meters_ / 0.001f;
|
||||
uint16_t *p = depth.ptr<uint16_t>();
|
||||
int buffSize = depth.rows * depth.cols;
|
||||
#pragma omp parallel for
|
||||
for(int i = 0; i < buffSize; ++i) {
|
||||
p[i] *= scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat rgb = cv::Mat(rgbBuffer_.size(), rgbBuffer_.type(), (void*)rgb_frame.get_data());
|
||||
@@ -1365,13 +1212,13 @@ SensorData CameraRealSense2::captureImage(CameraInfo * info)
|
||||
IMU imu;
|
||||
unsigned int confidence = 0;
|
||||
double imuStamp = stamp*1000.0;
|
||||
Transform pose;
|
||||
getPoseAndIMU(imuStamp, pose, confidence, imu);
|
||||
UASSERT(info!=0);
|
||||
getPoseAndIMU(imuStamp, info->odomPose, confidence, imu);
|
||||
|
||||
if(info && odometryProvided_ && !pose.isNull())
|
||||
if(odometryProvided_ && !info->odomPose.isNull())
|
||||
{
|
||||
// Transform in base frame (local transform should contain base to pose transform)
|
||||
info->odomPose = this->getLocalTransform() * pose * this->getLocalTransform().inverse();
|
||||
info->odomPose = this->getLocalTransform() * info->odomPose * this->getLocalTransform().inverse();
|
||||
|
||||
info->odomCovariance = cv::Mat::eye(6,6,CV_64FC1) * 0.0001;
|
||||
info->odomCovariance.rowRange(0,3) *= pow(10, 3-(int)confidence);
|
||||
@@ -1422,13 +1269,9 @@ SensorData CameraRealSense2::captureImage(CameraInfo * info)
|
||||
lastImuStamp_ = imuStamp;
|
||||
}
|
||||
}
|
||||
else if(isL500_ && globalTimeSync_)
|
||||
{
|
||||
UERROR("Missing frames (received %d, needed=%d). L500 camera is used and global time sync is enabled, try disabling global time sync for the RealSense2 driver.", (int)frameset.size(), desiredFramesetSize);
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Missing frames (received %d, needed=%d)", (int)frameset.size(), desiredFramesetSize);
|
||||
UERROR("Missing frames (received %d)", (int)frameset.size());
|
||||
}
|
||||
}
|
||||
catch(const std::exception& ex)
|
||||
|
||||
@@ -310,11 +310,9 @@ void MadgwickFilter::updateImpl(
|
||||
A[0] = ax;
|
||||
A[1] = ay;
|
||||
A[2] = az;
|
||||
if(computeOrientation(A,orientation))
|
||||
{
|
||||
reset(orientation.x(), orientation.y(), orientation.z(), orientation.w());
|
||||
initialized_ = true;
|
||||
}
|
||||
computeOrientation(A,orientation);
|
||||
reset(orientation.x(), orientation.y(), orientation.z(), orientation.w());
|
||||
initialized_ = true;
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -137,7 +137,9 @@ Transform OdometryF2F::computeTransform(
|
||||
{
|
||||
tmpRefFrame = refFrame_;
|
||||
// reset matches, but keep already extracted features in newFrame.sensorData()
|
||||
newFrame.removeAllWords();
|
||||
newFrame.setWords(std::multimap<int, cv::KeyPoint>());
|
||||
newFrame.setWords3(std::multimap<int, cv::Point3f>());
|
||||
newFrame.setWordsDescriptors(std::multimap<int, cv::Mat>());
|
||||
UWARN("Failed to find a transformation with the provided guess (%s), trying again without a guess.", guess.prettyPrint().c_str());
|
||||
// If optical flow is used, switch temporary to feature matching
|
||||
int visCorTypeBackup = Parameters::defaultVisCorType();
|
||||
@@ -174,18 +176,18 @@ Transform OdometryF2F::computeTransform(
|
||||
|
||||
if(info && this->isInfoDataFilled())
|
||||
{
|
||||
std::list<std::pair<int, std::pair<int, int> > > pairs;
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > pairs;
|
||||
EpipolarGeometry::findPairsUnique(tmpRefFrame.getWords(), newFrame.getWords(), pairs);
|
||||
info->refCorners.resize(pairs.size());
|
||||
info->newCorners.resize(pairs.size());
|
||||
std::map<int, int> idToIndex;
|
||||
int i=0;
|
||||
for(std::list<std::pair<int, std::pair<int, int> > >::iterator iter=pairs.begin();
|
||||
for(std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > >::iterator iter=pairs.begin();
|
||||
iter!=pairs.end();
|
||||
++iter)
|
||||
{
|
||||
info->refCorners[i] = tmpRefFrame.getWordsKpts()[iter->second.first].pt;
|
||||
info->newCorners[i] = newFrame.getWordsKpts()[iter->second.second].pt;
|
||||
info->refCorners[i] = iter->second.first.pt;
|
||||
info->newCorners[i] = iter->second.second.pt;
|
||||
idToIndex.insert(std::make_pair(iter->first, i));
|
||||
++i;
|
||||
}
|
||||
@@ -197,21 +199,12 @@ Transform OdometryF2F::computeTransform(
|
||||
}
|
||||
|
||||
Transform t = this->getPose()*motionSinceLastKeyFrame.inverse();
|
||||
if(!tmpRefFrame.getWords3().empty())
|
||||
for(std::multimap<int, cv::Point3f>::const_iterator iter=tmpRefFrame.getWords3().begin(); iter!=tmpRefFrame.getWords3().end(); ++iter)
|
||||
{
|
||||
for(std::multimap<int, int>::const_iterator iter=tmpRefFrame.getWords().begin(); iter!=tmpRefFrame.getWords().end(); ++iter)
|
||||
{
|
||||
info->localMap.insert(std::make_pair(iter->first, util3d::transformPoint(tmpRefFrame.getWords3()[iter->second], t)));
|
||||
}
|
||||
info->localMap.insert(std::make_pair(iter->first, util3d::transformPoint(iter->second, t)));
|
||||
}
|
||||
info->localMapSize = tmpRefFrame.getWords3().size();
|
||||
if(!newFrame.getWordsKpts().empty())
|
||||
{
|
||||
for(std::multimap<int, int>::const_iterator iter=newFrame.getWords().begin(); iter!=newFrame.getWords().end(); ++iter)
|
||||
{
|
||||
info->words.insert(std::make_pair(iter->first, newFrame.getWordsKpts()[iter->second]));
|
||||
}
|
||||
}
|
||||
info->words = newFrame.getWords();
|
||||
|
||||
info->localScanMapSize = tmpRefFrame.sensorData().laserScanRaw().size();
|
||||
|
||||
@@ -239,7 +232,7 @@ Transform OdometryF2F::computeTransform(
|
||||
(registrationPipeline_->isScanRequired() && (scanKeyFrameThr_ == 0.0f || regInfo.icpInliersRatio <= scanKeyFrameThr_)))
|
||||
{
|
||||
UDEBUG("Update key frame");
|
||||
int features = newFrame.getWordsDescriptors().rows;
|
||||
int features = newFrame.getWordsDescriptors().size();
|
||||
if(registrationPipeline_->isImageRequired() && features == 0)
|
||||
{
|
||||
newFrame = Signature(data);
|
||||
@@ -258,7 +251,9 @@ Transform OdometryF2F::computeTransform(
|
||||
{
|
||||
refFrame_ = newFrame;
|
||||
|
||||
refFrame_.removeAllWords();
|
||||
refFrame_.setWords(std::multimap<int, cv::KeyPoint>());
|
||||
refFrame_.setWords3(std::multimap<int, cv::Point3f>());
|
||||
refFrame_.setWordsDescriptors(std::multimap<int, cv::Mat>());
|
||||
|
||||
//reset motion
|
||||
lastKeyFramePose_.setNull();
|
||||
|
||||
@@ -133,27 +133,6 @@ OdometryF2M::OdometryF2M(const ParametersMap & parameters) :
|
||||
}
|
||||
uInsert(bundleParameters, ParametersPair(Parameters::kVisCorType(), uNumber2Str(corType)));
|
||||
|
||||
int estType = Parameters::defaultVisEstimationType();
|
||||
Parameters::parse(parameters, Parameters::kVisEstimationType(), estType);
|
||||
if(estType > 1)
|
||||
{
|
||||
UWARN("%s=%d is not supported by OdometryF2M, using 2D->3D approach instead (type=1).",
|
||||
Parameters::kVisEstimationType().c_str(),
|
||||
estType);
|
||||
estType = 1;
|
||||
}
|
||||
uInsert(bundleParameters, ParametersPair(Parameters::kVisEstimationType(), uNumber2Str(estType)));
|
||||
|
||||
bool forwardEst = Parameters::defaultVisForwardEstOnly();
|
||||
Parameters::parse(parameters, Parameters::kVisForwardEstOnly(), forwardEst);
|
||||
if(!forwardEst)
|
||||
{
|
||||
UWARN("%s=false is not supported by OdometryF2M, setting to true.",
|
||||
Parameters::kVisForwardEstOnly().c_str());
|
||||
forwardEst = true;
|
||||
}
|
||||
uInsert(bundleParameters, ParametersPair(Parameters::kVisForwardEstOnly(), uBool2Str(forwardEst)));
|
||||
|
||||
regPipeline_ = Registration::create(bundleParameters);
|
||||
if(bundleAdjustment_>0 && regPipeline_->isScanRequired())
|
||||
{
|
||||
@@ -293,7 +272,9 @@ Transform OdometryF2M::computeTransform(
|
||||
{
|
||||
tmpMap = *map_;
|
||||
// reset matches, but keep already extracted features in lastFrame_->sensorData()
|
||||
lastFrame_->removeAllWords();
|
||||
lastFrame_->setWords(std::multimap<int, cv::KeyPoint>());
|
||||
lastFrame_->setWords3(std::multimap<int, cv::Point3f>());
|
||||
lastFrame_->setWordsDescriptors(std::multimap<int, cv::Mat>());
|
||||
|
||||
points3DMap.clear();
|
||||
bundlePoses.clear();
|
||||
@@ -412,9 +393,11 @@ Transform OdometryF2M::computeTransform(
|
||||
int wordId =regInfo.inliersIDs[i];
|
||||
|
||||
// 3D point
|
||||
std::multimap<int, int>::const_iterator iter3D = tmpMap.getWords().find(wordId);
|
||||
UASSERT(iter3D!=tmpMap.getWords().end() && !tmpMap.getWords3().empty());
|
||||
points3DMap.insert(std::make_pair(wordId, tmpMap.getWords3()[iter3D->second]));
|
||||
std::multimap<int, cv::Point3f>::const_iterator iter3D = tmpMap.getWords3().find(wordId);
|
||||
UASSERT(iter3D!=tmpMap.getWords3().end());
|
||||
points3DMap.insert(*iter3D);
|
||||
|
||||
std::multimap<int, cv::KeyPoint>::const_iterator iter2D = lastFrame_->getWords().find(wordId);
|
||||
|
||||
// all other references
|
||||
std::map<int, std::map<int, FeatureBA> >::iterator refIter = bundleWordReferences_.find(wordId);
|
||||
@@ -444,19 +427,12 @@ Transform OdometryF2M::computeTransform(
|
||||
}
|
||||
}
|
||||
|
||||
std::multimap<int, int>::const_iterator iter2D = lastFrame_->getWords().find(wordId);
|
||||
if(iter2D!=lastFrame_->getWords().end())
|
||||
{
|
||||
UASSERT(!lastFrame_->getWordsKpts().empty());
|
||||
//get depth
|
||||
float d = 0.0f;
|
||||
if( !lastFrame_->getWords3().empty() &&
|
||||
util3d::isFinite(lastFrame_->getWords3()[iter2D->second]))
|
||||
{
|
||||
//move back point in camera frame (to get depth along z)
|
||||
d = util3d::transformPoint(lastFrame_->getWords3()[iter2D->second], invLocalTransform).z;
|
||||
}
|
||||
references.insert(std::make_pair(lastFrame_->id(), FeatureBA(lastFrame_->getWordsKpts()[iter2D->second], d)));
|
||||
UASSERT(lastFrame_->getWords3().find(wordId) != lastFrame_->getWords3().end());
|
||||
//move back point in camera frame (to get depth along z)
|
||||
cv::Point3f pt3d = util3d::transformPoint(lastFrame_->getWords3().find(wordId)->second, invLocalTransform);
|
||||
references.insert(std::make_pair(lastFrame_->id(), FeatureBA(iter2D->second, pt3d.z)));
|
||||
}
|
||||
wordReferences.insert(std::make_pair(wordId, references));
|
||||
|
||||
@@ -581,19 +557,23 @@ Transform OdometryF2M::computeTransform(
|
||||
|
||||
// fields to update
|
||||
LaserScan mapScan = tmpMap.sensorData().laserScanRaw();
|
||||
std::multimap<int, int> mapWords = tmpMap.getWords();
|
||||
std::vector<cv::KeyPoint> mapWordsKpts = tmpMap.getWordsKpts();
|
||||
std::vector<cv::Point3f> mapPoints = tmpMap.getWords3();
|
||||
cv::Mat mapDescriptors = tmpMap.getWordsDescriptors();
|
||||
std::multimap<int, cv::KeyPoint> mapWords = tmpMap.getWords();
|
||||
std::multimap<int, cv::Point3f> mapPoints = tmpMap.getWords3();
|
||||
std::multimap<int, cv::Mat> mapDescriptors = tmpMap.getWordsDescriptors();
|
||||
|
||||
bool addVisualKeyFrame = regPipeline_->isImageRequired() &&
|
||||
(keyFrameThr_ == 0.0f ||
|
||||
visKeyFrameThr_ == 0 ||
|
||||
float(regInfo.inliers) <= (keyFrameThr_*float(lastFrame_->getWords().size())) ||
|
||||
regInfo.inliers <= visKeyFrameThr_);
|
||||
|
||||
bool addGeometricKeyFrame = regPipeline_->isScanRequired() &&
|
||||
(scanKeyFrameThr_==0 || regInfo.icpInliersRatio <= scanKeyFrameThr_);
|
||||
float minComplexity = Parameters::defaultIcpPointToPlaneMinComplexity();
|
||||
bool p2n = Parameters::defaultIcpPointToPlane();
|
||||
Parameters::parse(parameters_, Parameters::kIcpPointToPlane(), p2n);
|
||||
Parameters::parse(parameters_, Parameters::kIcpPointToPlaneMinComplexity(), minComplexity);
|
||||
bool addGeometricKeyFrame =
|
||||
regPipeline_->isScanRequired() &&
|
||||
(scanKeyFrameThr_==0 || regInfo.icpInliersRatio <= scanKeyFrameThr_) &&
|
||||
(addVisualKeyFrame || !p2n || regInfo.icpStructuralComplexity>=minComplexity);
|
||||
|
||||
addKeyFrame = false;//bundleLinks.rbegin()->second.transform().getNorm() > 5.0f*0.075f;
|
||||
addKeyFrame = addKeyFrame || addVisualKeyFrame || addGeometricKeyFrame;
|
||||
@@ -610,9 +590,8 @@ Transform OdometryF2M::computeTransform(
|
||||
|
||||
// update local map
|
||||
UASSERT(mapWords.size() == mapPoints.size());
|
||||
UASSERT(mapWords.size() == mapWordsKpts.size());
|
||||
UASSERT((int)mapPoints.size() == mapDescriptors.rows);
|
||||
UASSERT_MSG(lastFrame_->getWordsDescriptors().rows == (int)lastFrame_->getWords3().size(), uFormat("%d vs %d", lastFrame_->getWordsDescriptors().rows, (int)lastFrame_->getWords3().size()).c_str());
|
||||
UASSERT(mapPoints.size() == mapDescriptors.size());
|
||||
UASSERT_MSG(lastFrame_->getWordsDescriptors().size() == lastFrame_->getWords3().size(), uFormat("%d vs %d", lastFrame_->getWordsDescriptors().size(), lastFrame_->getWords3().size()).c_str());
|
||||
|
||||
std::map<int, int>::iterator iterBundlePosesRef = bundlePoseReferences_.end();
|
||||
if(bundleAdjustment_>0)
|
||||
@@ -634,15 +613,17 @@ Transform OdometryF2M::computeTransform(
|
||||
// update local map 3D points (if bundle adjustment was done)
|
||||
for(std::map<int, cv::Point3f>::iterator iter=points3DMap.begin(); iter!=points3DMap.end(); ++iter)
|
||||
{
|
||||
UASSERT(mapWords.count(iter->first) == 1);
|
||||
//UDEBUG("Updated %d (%f,%f,%f) -> (%f,%f,%f)", iter->first, mapPoints[mapWords.find(iter->first)->second].x, mapPoints[mapWords.find(iter->first)->second].y, mapPoints[mapWords.find(iter->first)->second].z, iter->second.x, iter->second.y, iter->second.z);
|
||||
mapPoints[mapWords.find(iter->first)->second] = iter->second;
|
||||
UASSERT(mapPoints.count(iter->first) == 1);
|
||||
//UDEBUG("Updated %d (%f,%f,%f) -> (%f,%f,%f)", iter->first, mapPoints.find(origin)->second.x, mapPoints.find(origin)->second.y, mapPoints.find(origin)->second.z, iter->second.x, iter->second.y, iter->second.z);
|
||||
mapPoints.find(iter->first)->second = iter->second;
|
||||
}
|
||||
}
|
||||
|
||||
// sort by feature response
|
||||
std::multimap<float, std::pair<int, std::pair<cv::KeyPoint, std::pair<cv::Point3f, cv::Mat> > > > newIds;
|
||||
UASSERT(lastFrame_->getWords3().size() == lastFrame_->getWords().size());
|
||||
std::multimap<int, cv::KeyPoint>::const_iterator iter2D = lastFrame_->getWords().begin();
|
||||
std::multimap<int, cv::Mat>::const_iterator iterDesc = lastFrame_->getWordsDescriptors().begin();
|
||||
UDEBUG("new frame words3=%d", (int)lastFrame_->getWords3().size());
|
||||
std::set<int> seenStatusUpdated;
|
||||
Transform invLocalTransform;
|
||||
@@ -667,11 +648,11 @@ Transform OdometryF2M::computeTransform(
|
||||
if(!visDepthAsMask && validDepthRatio_ < 1.0f)
|
||||
{
|
||||
int ptsWithDepth = 0;
|
||||
for (std::vector<cv::Point3f>::const_iterator iter = lastFrame_->getWords3().begin();
|
||||
for (std::multimap<int, cv::Point3f>::const_iterator iter = lastFrame_->getWords3().begin();
|
||||
iter != lastFrame_->getWords3().end();
|
||||
++iter)
|
||||
{
|
||||
if(util3d::isFinite(*iter))
|
||||
if(util3d::isFinite(iter->second))
|
||||
{
|
||||
++ptsWithDepth;
|
||||
}
|
||||
@@ -685,29 +666,27 @@ Transform OdometryF2M::computeTransform(
|
||||
}
|
||||
}
|
||||
|
||||
for(std::multimap<int, int>::const_iterator iter = lastFrame_->getWords().begin(); iter!=lastFrame_->getWords().end(); ++iter)
|
||||
for(std::multimap<int, cv::Point3f>::const_iterator iter = lastFrame_->getWords3().begin(); iter!=lastFrame_->getWords3().end(); ++iter, ++iter2D, ++iterDesc)
|
||||
{
|
||||
const cv::Point3f & pt = lastFrame_->getWords3()[iter->second];
|
||||
const cv::KeyPoint & kpt = lastFrame_->getWordsKpts()[iter->second];
|
||||
if(mapWords.find(iter->first) == mapWords.end()) // Point not in map
|
||||
if(mapPoints.find(iter->first) == mapPoints.end()) // Point not in map
|
||||
{
|
||||
if(util3d::isFinite(pt) || addPointsWithoutDepth)
|
||||
if(util3d::isFinite(iter->second) || addPointsWithoutDepth)
|
||||
{
|
||||
newIds.insert(
|
||||
std::make_pair(kpt.response>0?1.0f/kpt.response:0.0f,
|
||||
std::make_pair(iter2D->second.response>0?1.0f/iter2D->second.response:0.0f,
|
||||
std::make_pair(iter->first,
|
||||
std::make_pair(kpt,
|
||||
std::make_pair(pt, lastFrame_->getWordsDescriptors().row(iter->second))))));
|
||||
std::make_pair(iter2D->second,
|
||||
std::make_pair(iter->second, iterDesc->second)))));
|
||||
}
|
||||
}
|
||||
else if(bundleAdjustment_>0)
|
||||
{
|
||||
if(lastFrame_->getWords().count(iter->first) == 1)
|
||||
{
|
||||
std::multimap<int, int>::iterator iterKpts = mapWords.find(iter->first);
|
||||
if(iterKpts!=mapWords.end() && !mapWordsKpts.empty())
|
||||
std::multimap<int, cv::KeyPoint>::iterator iterKpts = mapWords.find(iter->first);
|
||||
if(iterKpts!=mapWords.end())
|
||||
{
|
||||
mapWordsKpts[iterKpts->second].octave = kpt.octave;
|
||||
iterKpts->second.octave = iter2D->second.octave;
|
||||
}
|
||||
|
||||
UASSERT(iterBundlePosesRef!=bundlePoseReferences_.end());
|
||||
@@ -715,19 +694,19 @@ Transform OdometryF2M::computeTransform(
|
||||
|
||||
//move back point in camera frame (to get depth along z)
|
||||
float depth = 0.0f;
|
||||
if(util3d::isFinite(pt))
|
||||
if(util3d::isFinite(iter->second))
|
||||
{
|
||||
depth = util3d::transformPoint(pt, invLocalTransform).z;
|
||||
depth = util3d::transformPoint(iter->second, invLocalTransform).z;
|
||||
}
|
||||
if(bundleWordReferences_.find(iter->first) == bundleWordReferences_.end())
|
||||
{
|
||||
std::map<int, FeatureBA> framePt;
|
||||
framePt.insert(std::make_pair(lastFrame_->id(), FeatureBA(kpt, depth)));
|
||||
framePt.insert(std::make_pair(lastFrame_->id(), FeatureBA(iter2D->second, depth)));
|
||||
bundleWordReferences_.insert(std::make_pair(iter->first, framePt));
|
||||
}
|
||||
else
|
||||
{
|
||||
bundleWordReferences_.find(iter->first)->second.insert(std::make_pair(lastFrame_->id(), FeatureBA(kpt, depth)));
|
||||
bundleWordReferences_.find(iter->first)->second.insert(std::make_pair(lastFrame_->id(), FeatureBA(iter2D->second, depth)));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -768,8 +747,7 @@ Transform OdometryF2M::computeTransform(
|
||||
}
|
||||
}
|
||||
|
||||
mapWords.insert(mapWords.end(), std::make_pair(iter->second.first, mapWords.size()));
|
||||
mapWordsKpts.push_back(iter->second.second.first);
|
||||
mapWords.insert(std::make_pair(iter->second.first, iter->second.second.first));
|
||||
cv::Point3f pt = iter->second.second.second.first;
|
||||
if(!util3d::isFinite(pt))
|
||||
{
|
||||
@@ -805,8 +783,8 @@ Transform OdometryF2M::computeTransform(
|
||||
float scaleInf = (0.05 * model.fx()) / 0.01;
|
||||
pt = util3d::transformPoint(cv::Point3f(ray[0]*scaleInf, ray[1]*scaleInf, ray[2]*scaleInf), model.localTransform()); // in base_link frame
|
||||
}
|
||||
mapPoints.push_back(util3d::transformPoint(pt, newFramePose));
|
||||
mapDescriptors.push_back(iter->second.second.second.second);
|
||||
mapPoints.insert(std::make_pair(iter->second.first, util3d::transformPoint(pt, newFramePose)));
|
||||
mapDescriptors.insert(std::make_pair(iter->second.first, iter->second.second.second.second));
|
||||
if(lastFrameOldestNewId_ > iter->second.first)
|
||||
{
|
||||
lastFrameOldestNewId_ = iter->second.first;
|
||||
@@ -816,7 +794,7 @@ Transform OdometryF2M::computeTransform(
|
||||
}
|
||||
|
||||
// remove words in map if max size is reached
|
||||
if((int)mapWords.size() > maximumMapSize_)
|
||||
if((int)mapPoints.size() > maximumMapSize_)
|
||||
{
|
||||
// remove oldest outliers first
|
||||
std::set<int> inliers(regInfo.inliersIDs.begin(), regInfo.inliersIDs.end());
|
||||
@@ -835,7 +813,7 @@ Transform OdometryF2M::computeTransform(
|
||||
ids.resize(regInfo.matchesIDs.size()+oi);
|
||||
UDEBUG("projected added=%d/%d minLastFrameId=%d", oi, (int)regInfo.projectedIDs.size(), lastFrameOldestNewId);
|
||||
}
|
||||
for(unsigned int i=0; i<ids.size() && (int)mapWords.size() > maximumMapSize_ && mapWords.size() >= newIds.size(); ++i)
|
||||
for(unsigned int i=0; i<ids.size() && (int)mapPoints.size() > maximumMapSize_ && mapPoints.size() >= newIds.size(); ++i)
|
||||
{
|
||||
int id = ids.at(i);
|
||||
if(inliers.find(id) == inliers.end())
|
||||
@@ -853,14 +831,18 @@ Transform OdometryF2M::computeTransform(
|
||||
bundleWordReferences_.erase(iterRef);
|
||||
}
|
||||
|
||||
mapPoints.erase(id);
|
||||
mapDescriptors.erase(id);
|
||||
mapWords.erase(id);
|
||||
++removed;
|
||||
}
|
||||
}
|
||||
|
||||
// remove oldest first
|
||||
for(std::multimap<int, int>::iterator iter = mapWords.begin();
|
||||
iter!=mapWords.end() && (int)mapWords.size() > maximumMapSize_ && mapWords.size() >= newIds.size();)
|
||||
std::multimap<int, cv::Mat>::iterator iterMapDescriptors = mapDescriptors.begin();
|
||||
std::multimap<int, cv::KeyPoint>::iterator iterMapWords = mapWords.begin();
|
||||
for(std::multimap<int, cv::Point3f>::iterator iter = mapPoints.begin();
|
||||
iter!=mapPoints.end() && (int)mapPoints.size() > maximumMapSize_ && mapPoints.size() >= newIds.size();)
|
||||
{
|
||||
if(inliers.find(iter->first) == inliers.end())
|
||||
{
|
||||
@@ -877,36 +859,19 @@ Transform OdometryF2M::computeTransform(
|
||||
bundleWordReferences_.erase(iterRef);
|
||||
}
|
||||
|
||||
mapWords.erase(iter++);
|
||||
mapPoints.erase(iter++);
|
||||
mapDescriptors.erase(iterMapDescriptors++);
|
||||
mapWords.erase(iterMapWords++);
|
||||
++removed;
|
||||
}
|
||||
else
|
||||
{
|
||||
++iter;
|
||||
++iterMapDescriptors;
|
||||
++iterMapWords;
|
||||
}
|
||||
}
|
||||
|
||||
if(mapWords.size() != mapPoints.size())
|
||||
{
|
||||
UDEBUG("Remove points");
|
||||
std::vector<cv::KeyPoint> mapWordsKptsClean(mapWords.size());
|
||||
std::vector<cv::Point3f> mapPointsClean(mapWords.size());
|
||||
cv::Mat mapDescriptorsClean(mapWords.size(), mapDescriptors.cols, mapDescriptors.type());
|
||||
int index = 0;
|
||||
for(std::multimap<int, int>::iterator iter = mapWords.begin(); iter!=mapWords.end(); ++iter, ++index)
|
||||
{
|
||||
mapWordsKptsClean[index] = mapWordsKpts[iter->second];
|
||||
mapPointsClean[index] = mapPoints[iter->second];
|
||||
mapDescriptors.row(iter->second).copyTo(mapDescriptorsClean.row(index));
|
||||
iter->second = index;
|
||||
}
|
||||
mapWordsKpts = mapWordsKptsClean;
|
||||
mapWordsKptsClean.clear();
|
||||
mapPoints = mapPointsClean;
|
||||
mapPointsClean.clear();
|
||||
mapDescriptors = mapDescriptorsClean;
|
||||
}
|
||||
|
||||
Link * previousLink = 0;
|
||||
for(std::map<int, int>::iterator iter=bundlePoseReferences_.begin(); iter!=bundlePoseReferences_.end();)
|
||||
{
|
||||
@@ -950,13 +915,14 @@ Transform OdometryF2M::computeTransform(
|
||||
|
||||
if(lastFrame_->sensorData().laserScanRaw().size())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr mapCloudNormals = util3d::laserScanToPointCloudINormal(mapScan, tmpMap.sensorData().laserScanRaw().localTransform());
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr mapCloudNormals = util3d::laserScanToPointCloudNormal(mapScan, tmpMap.sensorData().laserScanRaw().localTransform());
|
||||
Transform viewpoint = newFramePose * lastFrame_->sensorData().laserScanRaw().localTransform();
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr frameCloudNormals (new pcl::PointCloud<pcl::PointXYZINormal>());
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr frameCloudNormals (new pcl::PointCloud<pcl::PointNormal>());
|
||||
|
||||
if(scanMapMaxRange_ > 0)
|
||||
{
|
||||
frameCloudNormals = util3d::laserScanToPointCloudINormal(lastFrame_->sensorData().laserScanRaw());
|
||||
frameCloudNormals = util3d::laserScanToPointCloudNormal(
|
||||
lastFrame_->sensorData().laserScanRaw());
|
||||
frameCloudNormals = util3d::cropBox(frameCloudNormals,
|
||||
Eigen::Vector4f(-scanMapMaxRange_ / 2, -scanMapMaxRange_ / 2,-scanMapMaxRange_ / 2, 0),
|
||||
Eigen::Vector4f(scanMapMaxRange_ / 2,scanMapMaxRange_ / 2,scanMapMaxRange_ / 2, 0)
|
||||
@@ -964,7 +930,8 @@ Transform OdometryF2M::computeTransform(
|
||||
frameCloudNormals = util3d::transformPointCloud(frameCloudNormals, viewpoint);
|
||||
} else
|
||||
{
|
||||
frameCloudNormals = util3d::laserScanToPointCloudINormal(lastFrame_->sensorData().laserScanRaw(), viewpoint);
|
||||
frameCloudNormals = util3d::laserScanToPointCloudNormal(
|
||||
lastFrame_->sensorData().laserScanRaw(), viewpoint);
|
||||
}
|
||||
|
||||
pcl::IndicesPtr frameCloudNormalsIndices(new std::vector<int>);
|
||||
@@ -991,7 +958,7 @@ Transform OdometryF2M::computeTransform(
|
||||
if (scanMapMaxRange_ > 0) {
|
||||
// Copying new points to tmp cloud
|
||||
// These are the points that have no overlap between mapScan and lastFrame
|
||||
pcl::PointCloud<pcl::PointXYZINormal> tmp;
|
||||
pcl::PointCloud<pcl::PointNormal> tmp;
|
||||
pcl::copyPointCloud(*frameCloudNormals, *frameCloudNormalsIndices, tmp);
|
||||
|
||||
if (int(mapCloudNormals->size() + newPoints) > scanMaximumMapSize_) // 20 000 points
|
||||
@@ -1051,7 +1018,7 @@ Transform OdometryF2M::computeTransform(
|
||||
{
|
||||
if(scansBuffer_[i].second->size())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZINormal> tmp;
|
||||
pcl::PointCloud<pcl::PointNormal> tmp;
|
||||
pcl::copyPointCloud(*scansBuffer_[i].first, *scansBuffer_[i].second, tmp);
|
||||
*mapCloudNormals += tmp;
|
||||
}
|
||||
@@ -1064,7 +1031,7 @@ Transform OdometryF2M::computeTransform(
|
||||
// remove old clouds
|
||||
if(i > 0)
|
||||
{
|
||||
std::vector<std::pair<pcl::PointCloud<pcl::PointXYZINormal>::Ptr, pcl::IndicesPtr> > scansTmp(scansBuffer_.size()-i);
|
||||
std::vector<std::pair<pcl::PointCloud<pcl::PointNormal>::Ptr, pcl::IndicesPtr> > scansTmp(scansBuffer_.size()-i);
|
||||
int oi = 0;
|
||||
for(; i<(int)scansBuffer_.size(); ++i)
|
||||
{
|
||||
@@ -1079,7 +1046,7 @@ Transform OdometryF2M::computeTransform(
|
||||
// just append the last cloud
|
||||
if(scansBuffer_.back().second->size())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZINormal> tmp;
|
||||
pcl::PointCloud<pcl::PointNormal> tmp;
|
||||
pcl::copyPointCloud(*scansBuffer_.back().first, *scansBuffer_.back().second, tmp);
|
||||
*mapCloudNormals += tmp;
|
||||
}
|
||||
@@ -1093,12 +1060,12 @@ Transform OdometryF2M::computeTransform(
|
||||
if(mapScan.is2d())
|
||||
{
|
||||
Transform mapViewpoint(-newFramePose.x(), -newFramePose.y(),0,0,0,0);
|
||||
mapScan = LaserScan(util3d::laserScan2dFromPointCloud(*mapCloudNormals, mapViewpoint), 0, 0.0f, LaserScan::kXYINormal);
|
||||
mapScan = LaserScan(util3d::laserScan2dFromPointCloud(*mapCloudNormals, mapViewpoint), 0, 0.0f, LaserScan::kXYNormal);
|
||||
}
|
||||
else
|
||||
{
|
||||
Transform mapViewpoint(-newFramePose.x(), -newFramePose.y(), -newFramePose.z(),0,0,0);
|
||||
mapScan = LaserScan(util3d::laserScanFromPointCloud(*mapCloudNormals, mapViewpoint), 0, 0.0f, LaserScan::kXYZINormal);
|
||||
mapScan = LaserScan(util3d::laserScanFromPointCloud(*mapCloudNormals, mapViewpoint), 0, 0.0f, LaserScan::kXYZNormal);
|
||||
}
|
||||
modified=true;
|
||||
}
|
||||
@@ -1132,7 +1099,9 @@ Transform OdometryF2M::computeTransform(
|
||||
newFramePose.translation()));
|
||||
}
|
||||
|
||||
map_->setWords(mapWords, mapWordsKpts, mapPoints, mapDescriptors);
|
||||
map_->setWords(mapWords);
|
||||
map_->setWords3(mapPoints);
|
||||
map_->setWordsDescriptors(mapDescriptors);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1143,14 +1112,7 @@ Transform OdometryF2M::computeTransform(
|
||||
info->localScanMapSize = tmpMap.sensorData().laserScanRaw().size();
|
||||
if(this->isInfoDataFilled())
|
||||
{
|
||||
info->localMap.clear();
|
||||
if(!tmpMap.getWords3().empty())
|
||||
{
|
||||
for(std::multimap<int, int>::const_iterator iter=tmpMap.getWords().begin(); iter!=tmpMap.getWords().end(); ++iter)
|
||||
{
|
||||
info->localMap.insert(std::make_pair(iter->first, tmpMap.getWords3()[iter->second]));
|
||||
}
|
||||
}
|
||||
info->localMap = uMultimapToMap(tmpMap.getWords3());
|
||||
info->localScanMap = tmpMap.sensorData().laserScanRaw();
|
||||
}
|
||||
}
|
||||
@@ -1177,12 +1139,11 @@ Transform OdometryF2M::computeTransform(
|
||||
if(regPipeline_->isImageRequired())
|
||||
{
|
||||
int ptsWithDepth = 0;
|
||||
for (std::multimap<int, int>::const_iterator iter = lastFrame_->getWords().begin();
|
||||
iter != lastFrame_->getWords().end();
|
||||
for (std::multimap<int, cv::Point3f>::const_iterator iter = lastFrame_->getWords3().begin();
|
||||
iter != lastFrame_->getWords3().end();
|
||||
++iter)
|
||||
{
|
||||
if(!lastFrame_->getWords3().empty() &&
|
||||
util3d::isFinite(lastFrame_->getWords3()[iter->second]))
|
||||
if(util3d::isFinite(iter->second))
|
||||
{
|
||||
++ptsWithDepth;
|
||||
}
|
||||
@@ -1192,29 +1153,26 @@ Transform OdometryF2M::computeTransform(
|
||||
{
|
||||
frameValid = true;
|
||||
// update local map
|
||||
UASSERT_MSG(lastFrame_->getWordsDescriptors().rows == (int)lastFrame_->getWords3().size(), uFormat("%d vs %d", lastFrame_->getWordsDescriptors().rows, (int)lastFrame_->getWords3().size()).c_str());
|
||||
UASSERT_MSG(lastFrame_->getWordsDescriptors().size() == lastFrame_->getWords3().size(), uFormat("%d vs %d", lastFrame_->getWordsDescriptors().size(), lastFrame_->getWords3().size()).c_str());
|
||||
UASSERT(lastFrame_->getWords3().size() == lastFrame_->getWords().size());
|
||||
|
||||
std::multimap<int, int> words;
|
||||
std::vector<cv::KeyPoint> wordsKpts;
|
||||
std::vector<cv::Point3f> transformedPoints;
|
||||
std::multimap<int, cv::KeyPoint> words;
|
||||
std::multimap<int, cv::Point3f> transformedPoints;
|
||||
std::multimap<int, int> mapPointWeights;
|
||||
cv::Mat descriptors;
|
||||
if(!lastFrame_->getWords3().empty())
|
||||
std::multimap<int, cv::Mat> descriptors;
|
||||
UASSERT(lastFrame_->getWords3().size() == lastFrame_->getWordsDescriptors().size());
|
||||
std::multimap<int, cv::KeyPoint>::const_iterator wordsIter = lastFrame_->getWords().begin();
|
||||
std::multimap<int, cv::Mat>::const_iterator descIter = lastFrame_->getWordsDescriptors().begin();
|
||||
for (std::multimap<int, cv::Point3f>::const_iterator iter = lastFrame_->getWords3().begin();
|
||||
iter != lastFrame_->getWords3().end();
|
||||
++iter, ++descIter, ++wordsIter)
|
||||
{
|
||||
for (std::multimap<int, int>::const_iterator iter = lastFrame_->getWords().begin();
|
||||
iter != lastFrame_->getWords().end();
|
||||
++iter)
|
||||
if (util3d::isFinite(iter->second))
|
||||
{
|
||||
const cv::Point3f & pt = lastFrame_->getWords3()[iter->second];
|
||||
if (util3d::isFinite(pt))
|
||||
{
|
||||
words.insert(words.end(), std::make_pair(iter->first, words.size()));
|
||||
wordsKpts.push_back(lastFrame_->getWordsKpts()[iter->second]);
|
||||
transformedPoints.push_back(util3d::transformPoint(pt, newFramePose));
|
||||
mapPointWeights.insert(std::make_pair(iter->first, 0));
|
||||
descriptors.push_back(lastFrame_->getWordsDescriptors().row(iter->second));
|
||||
}
|
||||
words.insert(*wordsIter);
|
||||
transformedPoints.insert(std::make_pair(iter->first, util3d::transformPoint(iter->second, newFramePose)));
|
||||
mapPointWeights.insert(std::make_pair(iter->first, 0));
|
||||
descriptors.insert(*descIter);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1235,29 +1193,25 @@ Transform OdometryF2M::computeTransform(
|
||||
}
|
||||
|
||||
// update bundleWordReferences_: used for bundle adjustment
|
||||
if(!wordsKpts.empty())
|
||||
for(std::multimap<int, cv::KeyPoint>::const_iterator iter=words.begin(); iter!=words.end(); ++iter)
|
||||
{
|
||||
for(std::multimap<int, int>::const_iterator iter=words.begin(); iter!=words.end(); ++iter)
|
||||
if(words.count(iter->first) == 1)
|
||||
{
|
||||
if(words.count(iter->first) == 1)
|
||||
UASSERT(bundleWordReferences_.find(iter->first) == bundleWordReferences_.end());
|
||||
std::map<int, FeatureBA> framePt;
|
||||
|
||||
//get depth
|
||||
float d = 0.0f;
|
||||
if(lastFrame_->getWords3().count(iter->first) == 1 &&
|
||||
util3d::isFinite(lastFrame_->getWords3().find(iter->first)->second))
|
||||
{
|
||||
UASSERT(bundleWordReferences_.find(iter->first) == bundleWordReferences_.end());
|
||||
std::map<int, FeatureBA> framePt;
|
||||
|
||||
//get depth
|
||||
float d = 0.0f;
|
||||
if(lastFrame_->getWords().count(iter->first) == 1 &&
|
||||
!lastFrame_->getWords3().empty() &&
|
||||
util3d::isFinite(lastFrame_->getWords3()[lastFrame_->getWords().find(iter->first)->second]))
|
||||
{
|
||||
//move back point in camera frame (to get depth along z)
|
||||
d = util3d::transformPoint(lastFrame_->getWords3()[lastFrame_->getWords().find(iter->first)->second], invLocalTransform).z;
|
||||
}
|
||||
|
||||
|
||||
framePt.insert(std::make_pair(lastFrame_->id(), FeatureBA(wordsKpts[iter->second], d)));
|
||||
bundleWordReferences_.insert(std::make_pair(iter->first, framePt));
|
||||
//move back point in camera frame (to get depth along z)
|
||||
d = util3d::transformPoint(lastFrame_->getWords3().find(iter->first)->second, invLocalTransform).z;
|
||||
}
|
||||
|
||||
|
||||
framePt.insert(std::make_pair(lastFrame_->id(), FeatureBA(iter->second, d)));
|
||||
bundleWordReferences_.insert(std::make_pair(iter->first, framePt));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1292,7 +1246,9 @@ Transform OdometryF2M::computeTransform(
|
||||
}
|
||||
}
|
||||
|
||||
map_->setWords(words, wordsKpts, transformedPoints, descriptors);
|
||||
map_->setWords(words);
|
||||
map_->setWords3(transformedPoints);
|
||||
map_->setWordsDescriptors(descriptors);
|
||||
addKeyFrame = true;
|
||||
}
|
||||
else
|
||||
@@ -1304,7 +1260,7 @@ Transform OdometryF2M::computeTransform(
|
||||
{
|
||||
if (lastFrame_->sensorData().laserScanRaw().size())
|
||||
{
|
||||
pcl::PointCloud<pcl::PointXYZINormal>::Ptr mapCloudNormals = util3d::laserScanToPointCloudINormal(lastFrame_->sensorData().laserScanRaw(), newFramePose * lastFrame_->sensorData().laserScanRaw().localTransform());
|
||||
pcl::PointCloud<pcl::PointNormal>::Ptr mapCloudNormals = util3d::laserScanToPointCloudNormal(lastFrame_->sensorData().laserScanRaw(), newFramePose * lastFrame_->sensorData().laserScanRaw().localTransform());
|
||||
|
||||
double complexity = 0.0;;
|
||||
if(!frameValid)
|
||||
@@ -1315,17 +1271,9 @@ Transform OdometryF2M::computeTransform(
|
||||
Parameters::parse(parameters_, Parameters::kIcpPointToPlaneMinComplexity(), minComplexity);
|
||||
if(p2n && minComplexity>0.0f)
|
||||
{
|
||||
if(lastFrame_->sensorData().laserScanRaw().hasNormals())
|
||||
complexity = util3d::computeNormalsComplexity(*mapCloudNormals, Transform::getIdentity(), lastFrame_->sensorData().laserScanRaw().is2d());
|
||||
if(complexity > minComplexity)
|
||||
{
|
||||
complexity = util3d::computeNormalsComplexity(*mapCloudNormals, Transform::getIdentity(), lastFrame_->sensorData().laserScanRaw().is2d());
|
||||
if(complexity > minComplexity)
|
||||
{
|
||||
frameValid = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Input raw scan doesn't have normals, complexity check on first frame is not done.");
|
||||
frameValid = true;
|
||||
}
|
||||
}
|
||||
@@ -1350,7 +1298,7 @@ Transform OdometryF2M::computeTransform(
|
||||
util3d::laserScan2dFromPointCloud(*mapCloudNormals, mapViewpoint),
|
||||
0,
|
||||
0.0f,
|
||||
LaserScan::kXYINormal,
|
||||
LaserScan::kXYNormal,
|
||||
Transform(newFramePose.x(), newFramePose.y(), lastFrame_->sensorData().laserScanRaw().localTransform().z(),0,0,0)));
|
||||
}
|
||||
else
|
||||
@@ -1361,7 +1309,7 @@ Transform OdometryF2M::computeTransform(
|
||||
util3d::laserScanFromPointCloud(*mapCloudNormals, mapViewpoint),
|
||||
0,
|
||||
0.0f,
|
||||
LaserScan::kXYZINormal,
|
||||
LaserScan::kXYZNormal,
|
||||
newFramePose.translation()));
|
||||
}
|
||||
|
||||
@@ -1391,14 +1339,7 @@ Transform OdometryF2M::computeTransform(
|
||||
|
||||
if(this->isInfoDataFilled())
|
||||
{
|
||||
info->localMap.clear();
|
||||
if(!map_->getWords3().empty())
|
||||
{
|
||||
for(std::multimap<int, int>::const_iterator iter=map_->getWords().begin(); iter!=map_->getWords().end(); ++iter)
|
||||
{
|
||||
info->localMap.insert(std::make_pair(iter->first, map_->getWords3()[iter->second]));
|
||||
}
|
||||
}
|
||||
info->localMap = uMultimapToMap(map_->getWords3());
|
||||
info->localScanMap = map_->sensorData().laserScanRaw();
|
||||
}
|
||||
}
|
||||
@@ -1411,14 +1352,7 @@ Transform OdometryF2M::computeTransform(
|
||||
{
|
||||
if(regPipeline_->isImageRequired())
|
||||
{
|
||||
info->words.clear();
|
||||
if(!lastFrame_->getWordsKpts().empty())
|
||||
{
|
||||
for(std::multimap<int, int>::const_iterator iter=lastFrame_->getWords().begin(); iter!=lastFrame_->getWords().end(); ++iter)
|
||||
{
|
||||
info->words.insert(std::make_pair(iter->first, lastFrame_->getWordsKpts()[iter->second]));
|
||||
}
|
||||
}
|
||||
info->words = lastFrame_->getWords();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -283,15 +283,15 @@ Transform OdometryMono::computeTransform(SensorData & data, const Transform & gu
|
||||
newCorners[oi] = imagePoints[i];
|
||||
if(localMap_.count(ids[i]) == 1)
|
||||
{
|
||||
if(prevS->getWords().count(ids[i]) == 1 && !prevS->getWordsKpts().empty())
|
||||
if(prevS->getWords().count(ids[i]) == 1)
|
||||
{
|
||||
// set guess if unique
|
||||
refCorners[oi] = prevS->getWordsKpts()[prevS->getWords().find(ids[i])->second].pt;
|
||||
refCorners[oi] = prevS->getWords().find(ids[i])->second.pt;
|
||||
}
|
||||
if(newS->getWords().count(ids[i]) == 1 && !newS->getWordsKpts().empty())
|
||||
if(newS->getWords().count(ids[i]) == 1)
|
||||
{
|
||||
// set guess if unique
|
||||
newCorners[oi] = newS->getWordsKpts()[newS->getWords().find(ids[i])->second].pt;
|
||||
newCorners[oi] = newS->getWords().find(ids[i])->second.pt;
|
||||
}
|
||||
}
|
||||
objectPointsTmp[oi] = objectPoints[i];
|
||||
@@ -338,9 +338,9 @@ Transform OdometryMono::computeTransform(SensorData & data, const Transform & gu
|
||||
if(this->isInfoDataFilled() && info)
|
||||
{
|
||||
cv::KeyPoint kpt;
|
||||
if(newS->getWords().count(matches[i]) == 1 && !newS->getWordsKpts().empty())
|
||||
if(newS->getWords().count(matches[i]) == 1)
|
||||
{
|
||||
kpt = newS->getWordsKpts()[newS->getWords().find(matches[i])->second];
|
||||
kpt = newS->getWords().find(matches[i])->second;
|
||||
}
|
||||
kpt.pt = newCorners[i];
|
||||
info->words.insert(std::make_pair(matches[i], kpt));
|
||||
@@ -437,9 +437,9 @@ Transform OdometryMono::computeTransform(SensorData & data, const Transform & gu
|
||||
for(std::set<int>::iterator iter = memory_->getStMem().begin(); iter!=memory_->getStMem().end(); ++iter)
|
||||
{
|
||||
const Signature * s = memory_->getSignature(*iter);
|
||||
for(std::multimap<int, int>::const_iterator jter=s->getWords().begin(); jter!=s->getWords().end(); ++jter)
|
||||
for(std::multimap<int, cv::KeyPoint>::const_iterator jter=s->getWords().begin(); jter!=s->getWords().end(); ++jter)
|
||||
{
|
||||
if(s->getWords().count(jter->first) == 1 && localMap_.find(jter->first)!=localMap_.end() && !s->getWordsKpts().empty())
|
||||
if(s->getWords().count(jter->first) == 1 && localMap_.find(jter->first)!=localMap_.end())
|
||||
{
|
||||
if(wordReferences.find(jter->first)==wordReferences.end())
|
||||
{
|
||||
@@ -451,8 +451,7 @@ Transform OdometryMono::computeTransform(SensorData & data, const Transform & gu
|
||||
{
|
||||
depth = keyFrameWords3D_.at(s->id()).at(jter->first).x;
|
||||
}
|
||||
const cv::KeyPoint & kpts = s->getWordsKpts()[jter->second];
|
||||
wordReferences.at(jter->first).insert(std::make_pair(s->id(), FeatureBA(kpts, depth, cv::Mat())));
|
||||
wordReferences.at(jter->first).insert(std::make_pair(s->id(), FeatureBA(jter->second, depth, cv::Mat())));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -503,21 +502,9 @@ Transform OdometryMono::computeTransform(SensorData & data, const Transform & gu
|
||||
}
|
||||
else if(float(inliers)/float(imagePoints.size()) < keyFrameThr_)
|
||||
{
|
||||
std::map<int, int> uniqueWordsPrevious = uMultimapToMapUnique(previousS->getWords());
|
||||
std::map<int, int> uniqueWordsNew = uMultimapToMapUnique(newS->getWords());
|
||||
std::map<int, cv::KeyPoint> wordsPrevious;
|
||||
std::map<int, cv::KeyPoint> wordsNew;
|
||||
for(std::map<int, int>::iterator iter=uniqueWordsPrevious.begin(); iter!=uniqueWordsPrevious.end(); ++iter)
|
||||
{
|
||||
wordsPrevious.insert(std::make_pair(iter->first, previousS->getWordsKpts()[iter->second]));
|
||||
}
|
||||
for(std::map<int, int>::iterator iter=uniqueWordsNew.begin(); iter!=uniqueWordsNew.end(); ++iter)
|
||||
{
|
||||
wordsNew.insert(std::make_pair(iter->first, newS->getWordsKpts()[iter->second]));
|
||||
}
|
||||
std::map<int, cv::Point3f> inliers3D = util3d::generateWords3DMono(
|
||||
wordsPrevious,
|
||||
wordsNew,
|
||||
uMultimapToMapUnique(previousS->getWords()),
|
||||
uMultimapToMapUnique(newS->getWords()),
|
||||
cameraModel,
|
||||
cameraTransform,
|
||||
fundMatrixReprojError_,
|
||||
@@ -639,9 +626,9 @@ Transform OdometryMono::computeTransform(SensorData & data, const Transform & gu
|
||||
int ii=0;
|
||||
for(std::map<int, cv::Point2f>::iterator iter=firstFrameGuessCorners_.begin(); iter!=firstFrameGuessCorners_.end(); ++iter)
|
||||
{
|
||||
std::multimap<int, int>::const_iterator jter=refS->getWords().find(iter->first);
|
||||
UASSERT(jter != refS->getWords().end() && !refS->getWordsKpts().empty());
|
||||
refCorners[ii] = refS->getWordsKpts()[jter->second].pt;
|
||||
std::multimap<int, cv::KeyPoint>::const_iterator jter=refS->getWords().find(iter->first);
|
||||
UASSERT(jter != refS->getWords().end());
|
||||
refCorners[ii] = jter->second.pt;
|
||||
refCornersGuess[ii] = iter->second;
|
||||
cornerIds[ii] = iter->first;
|
||||
++ii;
|
||||
@@ -813,15 +800,14 @@ Transform OdometryMono::computeTransform(SensorData & data, const Transform & gu
|
||||
// generate kpts
|
||||
if(memory_->update(SensorData(data)))
|
||||
{
|
||||
const Signature * s = memory_->getLastWorkingSignature();
|
||||
const std::multimap<int, int> & words = s->getWords();
|
||||
if((int)words.size() > minInliers_ && !s->getWordsKpts().empty())
|
||||
const std::multimap<int, cv::KeyPoint> & words = memory_->getLastWorkingSignature()->getWords();
|
||||
if((int)words.size() > minInliers_)
|
||||
{
|
||||
for(std::multimap<int, int>::const_iterator iter=words.begin(); iter!=words.end(); ++iter)
|
||||
for(std::multimap<int, cv::KeyPoint>::const_iterator iter=words.begin(); iter!=words.end(); ++iter)
|
||||
{
|
||||
if(words.count(iter->first) == 1)
|
||||
{
|
||||
firstFrameGuessCorners_.insert(std::make_pair(iter->first, s->getWordsKpts()[iter->second].pt));
|
||||
firstFrameGuessCorners_.insert(std::make_pair(iter->first, iter->second.pt));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -185,7 +185,7 @@ public:
|
||||
mBuf.unlock();
|
||||
TicToc processTime;
|
||||
processMeasurements();
|
||||
UDEBUG("VINS process time: %f", processTime.toc());
|
||||
printf("process time: %f\n", processTime.toc());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -80,19 +80,24 @@ using namespace std;
|
||||
namespace rtabmap
|
||||
{
|
||||
|
||||
static float IC_Angle(const Mat& image, Point2f pt, const vector<int> & u_max, int halfPatchSize)
|
||||
const int PATCH_SIZE = 31;
|
||||
const int HALF_PATCH_SIZE = 15;
|
||||
const int EDGE_THRESHOLD = 19;
|
||||
|
||||
|
||||
static float IC_Angle(const Mat& image, Point2f pt, const vector<int> & u_max)
|
||||
{
|
||||
int m_01 = 0, m_10 = 0;
|
||||
|
||||
const uchar* center = &image.at<uchar> (cvRound(pt.y), cvRound(pt.x));
|
||||
|
||||
// Treat the center line differently, v=0
|
||||
for (int u = -halfPatchSize; u <= halfPatchSize; ++u)
|
||||
for (int u = -HALF_PATCH_SIZE; u <= HALF_PATCH_SIZE; ++u)
|
||||
m_10 += u * center[u];
|
||||
|
||||
// Go line by line in the circuI853lar patch
|
||||
int step = (int)image.step1();
|
||||
for (int v = 1; v <= halfPatchSize; ++v)
|
||||
for (int v = 1; v <= HALF_PATCH_SIZE; ++v)
|
||||
{
|
||||
// Proceed over the two lines
|
||||
int v_sum = 0;
|
||||
@@ -414,11 +419,10 @@ static int bit_pattern_31_[256*4] =
|
||||
};
|
||||
|
||||
ORBextractor::ORBextractor(int _nfeatures, float _scaleFactor, int _nlevels,
|
||||
int _iniThFAST, int _minThFAST, int _patchSize, int _edgeThreshold):
|
||||
int _iniThFAST, int _minThFAST):
|
||||
nfeatures(_nfeatures), scaleFactor(_scaleFactor), nlevels(_nlevels),
|
||||
iniThFAST(_iniThFAST), minThFAST(_minThFAST), patchSize(_patchSize), edgeThreshold(_edgeThreshold)
|
||||
iniThFAST(_iniThFAST), minThFAST(_minThFAST)
|
||||
{
|
||||
halfPatchSize = patchSize/2;
|
||||
mvScaleFactor.resize(nlevels);
|
||||
mvLevelSigma2.resize(nlevels);
|
||||
mvScaleFactor[0]=1.0f;
|
||||
@@ -458,16 +462,16 @@ ORBextractor::ORBextractor(int _nfeatures, float _scaleFactor, int _nlevels,
|
||||
|
||||
//This is for orientation
|
||||
// pre-compute the end of a row in a circular patch
|
||||
umax.resize(halfPatchSize + 1);
|
||||
umax.resize(HALF_PATCH_SIZE + 1);
|
||||
|
||||
int v, v0, vmax = cvFloor(float(halfPatchSize) * sqrt(2.f) / 2 + 1);
|
||||
int vmin = cvCeil(float(halfPatchSize) * sqrt(2.f) / 2);
|
||||
const double hp2 = halfPatchSize*halfPatchSize;
|
||||
int v, v0, vmax = cvFloor(HALF_PATCH_SIZE * sqrt(2.f) / 2 + 1);
|
||||
int vmin = cvCeil(HALF_PATCH_SIZE * sqrt(2.f) / 2);
|
||||
const double hp2 = HALF_PATCH_SIZE*HALF_PATCH_SIZE;
|
||||
for (v = 0; v <= vmax; ++v)
|
||||
umax[v] = cvRound(sqrt(hp2 - v * v));
|
||||
|
||||
// Make sure we are symmetric
|
||||
for (v = halfPatchSize, v0 = 0; v >= vmin; --v)
|
||||
for (v = HALF_PATCH_SIZE, v0 = 0; v >= vmin; --v)
|
||||
{
|
||||
while (umax[v0] == umax[v0 + 1])
|
||||
++v0;
|
||||
@@ -476,12 +480,12 @@ ORBextractor::ORBextractor(int _nfeatures, float _scaleFactor, int _nlevels,
|
||||
}
|
||||
}
|
||||
|
||||
static void computeOrientation(const Mat& image, vector<KeyPoint>& keypoints, const vector<int>& umax, int halfPatchSize)
|
||||
static void computeOrientation(const Mat& image, vector<KeyPoint>& keypoints, const vector<int>& umax)
|
||||
{
|
||||
for (vector<KeyPoint>::iterator keypoint = keypoints.begin(),
|
||||
keypointEnd = keypoints.end(); keypoint != keypointEnd; ++keypoint)
|
||||
{
|
||||
keypoint->angle = IC_Angle(image, keypoint->pt, umax, halfPatchSize);
|
||||
keypoint->angle = IC_Angle(image, keypoint->pt, umax);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -777,10 +781,10 @@ void ORBextractor::ComputeKeyPointsOctTree(vector<vector<KeyPoint> >& allKeypoin
|
||||
|
||||
for (int level = 0; level < nlevels; ++level)
|
||||
{
|
||||
const int minBorderX = edgeThreshold-3;
|
||||
const int minBorderX = EDGE_THRESHOLD-3;
|
||||
const int minBorderY = minBorderX;
|
||||
const int maxBorderX = mvImagePyramid[level].cols-edgeThreshold+3;
|
||||
const int maxBorderY = mvImagePyramid[level].rows-edgeThreshold+3;
|
||||
const int maxBorderX = mvImagePyramid[level].cols-EDGE_THRESHOLD+3;
|
||||
const int maxBorderY = mvImagePyramid[level].rows-EDGE_THRESHOLD+3;
|
||||
|
||||
vector<cv::KeyPoint> vToDistributeKeys;
|
||||
vToDistributeKeys.reserve(nfeatures*10);
|
||||
@@ -841,7 +845,7 @@ void ORBextractor::ComputeKeyPointsOctTree(vector<vector<KeyPoint> >& allKeypoin
|
||||
keypoints = DistributeOctTree(vToDistributeKeys, minBorderX, maxBorderX,
|
||||
minBorderY, maxBorderY,mnFeaturesPerLevel[level], level);
|
||||
|
||||
const int scaledPatchSize = patchSize*mvScaleFactor[level];
|
||||
const int scaledPatchSize = PATCH_SIZE*mvScaleFactor[level];
|
||||
|
||||
// Add border to coordinates and scale information
|
||||
const int nkps = keypoints.size();
|
||||
@@ -856,7 +860,7 @@ void ORBextractor::ComputeKeyPointsOctTree(vector<vector<KeyPoint> >& allKeypoin
|
||||
|
||||
// compute orientations
|
||||
for (int level = 0; level < nlevels; ++level)
|
||||
computeOrientation(mvImagePyramid[level], allKeypoints[level], umax, halfPatchSize);
|
||||
computeOrientation(mvImagePyramid[level], allKeypoints[level], umax);
|
||||
}
|
||||
|
||||
void ORBextractor::ComputeKeyPointsOld(std::vector<std::vector<KeyPoint> > &allKeypoints)
|
||||
@@ -872,10 +876,10 @@ void ORBextractor::ComputeKeyPointsOld(std::vector<std::vector<KeyPoint> > &allK
|
||||
const int levelCols = sqrt((float)nDesiredFeatures/(5*imageRatio));
|
||||
const int levelRows = imageRatio*levelCols;
|
||||
|
||||
const int minBorderX = edgeThreshold;
|
||||
const int minBorderX = EDGE_THRESHOLD;
|
||||
const int minBorderY = minBorderX;
|
||||
const int maxBorderX = mvImagePyramid[level].cols-edgeThreshold;
|
||||
const int maxBorderY = mvImagePyramid[level].rows-edgeThreshold;
|
||||
const int maxBorderX = mvImagePyramid[level].cols-EDGE_THRESHOLD;
|
||||
const int maxBorderY = mvImagePyramid[level].rows-EDGE_THRESHOLD;
|
||||
|
||||
const int W = maxBorderX - minBorderX;
|
||||
const int H = maxBorderY - minBorderY;
|
||||
@@ -1002,7 +1006,7 @@ void ORBextractor::ComputeKeyPointsOld(std::vector<std::vector<KeyPoint> > &allK
|
||||
vector<KeyPoint> & keypoints = allKeypoints[level];
|
||||
keypoints.reserve(nDesiredFeatures*2);
|
||||
|
||||
const int scaledPatchSize = patchSize*mvScaleFactor[level];
|
||||
const int scaledPatchSize = PATCH_SIZE*mvScaleFactor[level];
|
||||
|
||||
// Retain by score and transform coordinates
|
||||
for(int i=0; i<levelRows; i++)
|
||||
@@ -1035,7 +1039,7 @@ void ORBextractor::ComputeKeyPointsOld(std::vector<std::vector<KeyPoint> > &allK
|
||||
|
||||
// and compute orientations
|
||||
for (int level = 0; level < nlevels; ++level)
|
||||
computeOrientation(mvImagePyramid[level], allKeypoints[level], umax, halfPatchSize);
|
||||
computeOrientation(mvImagePyramid[level], allKeypoints[level], umax);
|
||||
}
|
||||
|
||||
static void computeDescriptors(const Mat& image, vector<KeyPoint>& keypoints, Mat& descriptors,
|
||||
@@ -1117,21 +1121,21 @@ void ORBextractor::ComputePyramid(cv::Mat image)
|
||||
{
|
||||
float scale = mvInvScaleFactor[level];
|
||||
Size sz(cvRound((float)image.cols*scale), cvRound((float)image.rows*scale));
|
||||
Size wholeSize(sz.width + edgeThreshold*2, sz.height + edgeThreshold*2);
|
||||
Size wholeSize(sz.width + EDGE_THRESHOLD*2, sz.height + EDGE_THRESHOLD*2);
|
||||
Mat temp(wholeSize, image.type()), masktemp;
|
||||
mvImagePyramid[level] = temp(Rect(edgeThreshold, edgeThreshold, sz.width, sz.height));
|
||||
mvImagePyramid[level] = temp(Rect(EDGE_THRESHOLD, EDGE_THRESHOLD, sz.width, sz.height));
|
||||
|
||||
// Compute the resized image
|
||||
if( level != 0 )
|
||||
{
|
||||
resize(mvImagePyramid[level-1], mvImagePyramid[level], sz, 0, 0, INTER_LINEAR);
|
||||
|
||||
copyMakeBorder(mvImagePyramid[level], temp, edgeThreshold, edgeThreshold, edgeThreshold, edgeThreshold,
|
||||
copyMakeBorder(mvImagePyramid[level], temp, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD,
|
||||
BORDER_REFLECT_101+BORDER_ISOLATED);
|
||||
}
|
||||
else
|
||||
{
|
||||
copyMakeBorder(image, temp, edgeThreshold, edgeThreshold, edgeThreshold, edgeThreshold,
|
||||
copyMakeBorder(image, temp, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD, EDGE_THRESHOLD,
|
||||
BORDER_REFLECT_101);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
enum {HARRIS_SCORE=0, FAST_SCORE=1 };
|
||||
|
||||
ORBextractor(int nfeatures, float scaleFactor, int nlevels,
|
||||
int iniThFAST, int minThFAST, int patchSize, int edgeThreshold);
|
||||
int iniThFAST, int minThFAST);
|
||||
|
||||
~ORBextractor(){}
|
||||
|
||||
@@ -107,10 +107,6 @@ protected:
|
||||
int nlevels;
|
||||
int iniThFAST;
|
||||
int minThFAST;
|
||||
int patchSize;
|
||||
int edgeThreshold;
|
||||
int halfPatchSize;
|
||||
|
||||
|
||||
std::vector<int> mnFeaturesPerLevel;
|
||||
|
||||
|
||||
@@ -1496,11 +1496,6 @@ std::map<int, Transform> OptimizerG2O::optimizeBA(
|
||||
if(points3DMap.find(id) != points3DMap.end())
|
||||
{
|
||||
cv::Point3f pt3d = points3DMap.at(id);
|
||||
if(!util3d::isFinite(pt3d))
|
||||
{
|
||||
UWARN("Ignoring 3D point %d because it has nan value(s)!", id);
|
||||
continue;
|
||||
}
|
||||
g2o::VertexSBAPointXYZ* vpt3d = new g2o::VertexSBAPointXYZ();
|
||||
|
||||
vpt3d->setEstimate(Eigen::Vector3d(pt3d.x, pt3d.y, pt3d.z));
|
||||
@@ -1527,7 +1522,7 @@ std::map<int, Transform> OptimizerG2O::optimizeBA(
|
||||
const FeatureBA & pt = jter->second;
|
||||
double depth = pt.depth;
|
||||
|
||||
//UDEBUG("Added observation pt=%d to cam=%d (%d,%d) depth=%f", vpt3d->id()-stepVertexId, camId, (int)pt.kpt.pt.x, (int)pt.kpt.pt.y, depth);
|
||||
//UDEBUG("Added observation pt=%d to cam=%d (%f,%f) depth=%f", vpt3d->id()-stepVertexId, camId, pt.x, pt.y, depth);
|
||||
|
||||
g2o::OptimizableGraph::Edge * e;
|
||||
double baseline = 0.0;
|
||||
@@ -1573,9 +1568,9 @@ std::map<int, Transform> OptimizerG2O::optimizeBA(
|
||||
if(baseline > 0.0)
|
||||
{
|
||||
UDEBUG("Stereo camera model detected but current "
|
||||
"observation (pt=%d to cam=%d, kpt=[%d,%d]) has null depth (%f m), adding "
|
||||
"observation (pt=%d to cam=%d) has null depth (%f m), adding "
|
||||
"mono observation instead.",
|
||||
vpt3d->id()-stepVertexId, camId, (int)pt.kpt.pt.x, (int)pt.kpt.pt.y, depth);
|
||||
vpt3d->id()-stepVertexId, camId, depth);
|
||||
}
|
||||
// mono edge
|
||||
#ifdef RTABMAP_ORB_SLAM2
|
||||
|
||||
@@ -107,14 +107,12 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
|
||||
|
||||
// detect if there is a global pose prior set, if so remove rootId
|
||||
bool gpsPriorOnly = false;
|
||||
bool hasPriorPoses = false;
|
||||
if(!priorsIgnored())
|
||||
{
|
||||
for(std::multimap<int, Link>::const_iterator iter=edgeConstraints.begin(); iter!=edgeConstraints.end(); ++iter)
|
||||
{
|
||||
if(iter->second.from() == iter->second.to() && iter->second.type() == Link::kPosePrior)
|
||||
{
|
||||
hasPriorPoses = true;
|
||||
if ((isSlam2d() && 1 / static_cast<double>(iter->second.infMatrix().at<double>(5,5)) < 9999) ||
|
||||
(1 / static_cast<double>(iter->second.infMatrix().at<double>(3,3)) < 9999.0 &&
|
||||
1 / static_cast<double>(iter->second.infMatrix().at<double>(4,4)) < 9999.0 &&
|
||||
@@ -138,18 +136,17 @@ std::map<int, Transform> OptimizerGTSAM::optimize(
|
||||
{
|
||||
UASSERT(uContains(poses, rootId));
|
||||
const Transform & initialPose = poses.at(rootId);
|
||||
UDEBUG("hasPriorPoses=%s, gpsPriorOnly=%s", hasPriorPoses?"true":"false", gpsPriorOnly?"true":"false");
|
||||
if(isSlam2d())
|
||||
{
|
||||
gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances(gtsam::Vector3(0.01, 0.01, hasPriorPoses?1e-2:std::numeric_limits<double>::min()));
|
||||
gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances(gtsam::Vector3(0.01, 0.01, 0.01));
|
||||
graph.add(gtsam::PriorFactor<gtsam::Pose2>(rootId, gtsam::Pose2(initialPose.x(), initialPose.y(), initialPose.theta()), priorNoise));
|
||||
}
|
||||
else
|
||||
{
|
||||
gtsam::noiseModel::Diagonal::shared_ptr priorNoise = gtsam::noiseModel::Diagonal::Variances(
|
||||
(gtsam::Vector(6) <<
|
||||
1e-2, 1e-2, hasPriorPoses?1e-2:std::numeric_limits<double>::min(), // roll, pitch, fixed yaw if there are no priors
|
||||
(gpsPriorOnly?2:1e-2), gpsPriorOnly?2:1e-2, gpsPriorOnly?2:1e-2 // xyz
|
||||
(gpsPriorOnly?2:1e-2), gpsPriorOnly?2:1e-2, gpsPriorOnly?2:1e-2,
|
||||
1e-2, 1e-2, 1e-2
|
||||
).finished());
|
||||
graph.add(gtsam::PriorFactor<gtsam::Pose3>(rootId, gtsam::Pose3(initialPose.toEigen4d()), priorNoise));
|
||||
}
|
||||
|
||||
@@ -146,14 +146,7 @@ std::map<int, Transform> OptimizerTORO::optimize(
|
||||
UERROR("Map: Edge already exits between nodes %d and %d, skipping", id1, id2);
|
||||
}
|
||||
}
|
||||
else if(id1 == id2)
|
||||
{
|
||||
UWARN("TORO optimizer doesn't support prior or gravity links, use GTSAM or g2o optimizers (see parameter %s). Link %d ignored...", Parameters::kOptimizerStrategy().c_str(), id1);
|
||||
}
|
||||
else if(id1 < 0 || id2 < 0)
|
||||
{
|
||||
UWARN("TORO optimizer doesn't support landmark links, use GTSAM or g2o optimizers (see parameter %s). Link %d->%d ignored...", Parameters::kOptimizerStrategy().c_str(), id1, id2);
|
||||
}
|
||||
//else // not supporting pose prior and landmarks
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -185,14 +178,7 @@ std::map<int, Transform> OptimizerTORO::optimize(
|
||||
UERROR("Map: Edge already exits between nodes %d and %d, skipping", id1, id2);
|
||||
}
|
||||
}
|
||||
else if(id1 == id2)
|
||||
{
|
||||
UWARN("TORO optimizer doesn't support prior or gravity links, use GTSAM or g2o optimizers (see parameter %s). Link %d ignored...", Parameters::kOptimizerStrategy().c_str(), id1);
|
||||
}
|
||||
else if(id1 < 0 || id2 < 0)
|
||||
{
|
||||
UWARN("TORO optimizer doesn't support landmark links, use GTSAM or g2o optimizers (see parameter %s). Link %d->%d ignored...", Parameters::kOptimizerStrategy().c_str(), id1, id2);
|
||||
}
|
||||
//else // not supporting pose prior and landmarks
|
||||
}
|
||||
}
|
||||
UDEBUG("buildMST... root=%d", rootId);
|
||||
|
||||
@@ -10,16 +10,6 @@
|
||||
|
||||
#include <gtsam/linear/NoiseModel.h>
|
||||
#include <Eigen/Eigen>
|
||||
#include <gtsam/config.h>
|
||||
|
||||
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR==4 && GTSAM_VERSION_MINOR>=1)
|
||||
namespace gtsam {
|
||||
gtsam::Matrix inverse(const gtsam::Matrix & matrix)
|
||||
{
|
||||
return matrix.inverse();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace vertigo {
|
||||
|
||||
@@ -49,11 +39,7 @@ namespace vertigo {
|
||||
double nu1 = 1.0/sqrt(gtsam::inverse(info1).determinant());
|
||||
double l1 = nu1 * exp(-0.5*m1);
|
||||
|
||||
#if GTSAM_VERSION_MAJOR > 4 || (GTSAM_VERSION_MAJOR==4 && GTSAM_VERSION_MINOR>=1)
|
||||
double m2 = nullHypothesisModel->squaredMahalanobisDistance(error);
|
||||
#else
|
||||
double m2 = nullHypothesisModel->distance(error);
|
||||
#endif
|
||||
gtsam::noiseModel::Gaussian::shared_ptr g2 = nullHypothesisModel;
|
||||
gtsam::Matrix info2(g2->R().transpose()*g2->R());
|
||||
double nu2 = 1.0/sqrt(gtsam::inverse(info2).determinant());
|
||||
|
||||
@@ -78,8 +78,8 @@ namespace vertigo {
|
||||
inline SwitchVariableLinear between(const SwitchVariableLinear& l2,
|
||||
boost::optional<gtsam::Matrix&> H1=boost::none,
|
||||
boost::optional<gtsam::Matrix&> H2=boost::none) const {
|
||||
if(H1) *H1 = -gtsam::Matrix::Identity(1, 1);
|
||||
if(H2) *H2 = gtsam::Matrix::Identity(1, 1);
|
||||
if(H1) *H1 = -gtsam::eye(1);
|
||||
if(H2) *H2 = gtsam::eye(1);
|
||||
return SwitchVariableLinear(l2.value() - value());
|
||||
}
|
||||
|
||||
|
||||
@@ -78,8 +78,8 @@ namespace vertigo {
|
||||
inline SwitchVariableSigmoid between(const SwitchVariableSigmoid& l2,
|
||||
boost::optional<gtsam::Matrix&> H1=boost::none,
|
||||
boost::optional<gtsam::Matrix&> H2=boost::none) const {
|
||||
if(H1) *H1 = -gtsam::Matrix::Identity(1, 1);
|
||||
if(H2) *H2 = gtsam::Matrix::Identity(1, 1);
|
||||
if(H1) *H1 = -gtsam::eye(1);
|
||||
if(H2) *H2 = gtsam::eye(1);
|
||||
return SwitchVariableSigmoid(l2.value() - value());
|
||||
}
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@
|
||||
#include <pcl/common/distances.h>
|
||||
#include <pcl18/surface/texture_mapping.h>
|
||||
#include <pcl/search/octree.h>
|
||||
#include <pcl/common/common.h> // for getAngle3D
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
template<typename PointInT> std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> >
|
||||
@@ -1055,8 +1054,7 @@ pcl::TextureMapping<PointInT>::textureMeshwithMultipleCameras2 (
|
||||
pcl::TextureMesh &mesh,
|
||||
const pcl::texture_mapping::CameraVector &cameras,
|
||||
const rtabmap::ProgressState * state,
|
||||
std::vector<std::map<int, pcl::PointXY> > * vertexToPixels,
|
||||
bool distanceToCamPolicy)
|
||||
std::vector<std::map<int, pcl::PointXY> > * vertexToPixels)
|
||||
{
|
||||
|
||||
if (mesh.tex_polygons.size () != 1)
|
||||
@@ -1078,14 +1076,7 @@ pcl::TextureMapping<PointInT>::textureMeshwithMultipleCameras2 (
|
||||
std::vector<std::map<int, FaceInfo > > visibleFaces(cameras.size());
|
||||
std::vector<Eigen::Affine3f> invCamTransform(cameras.size());
|
||||
std::vector<std::list<int> > faceCameras(faces.size());
|
||||
std::string msg = uFormat("Computing visible faces per cam (%d faces, %d cams)", (int)faces.size(), (int)cameras.size());
|
||||
UINFO(msg.c_str());
|
||||
if(state && !state->callback(msg))
|
||||
{
|
||||
//cancelled!
|
||||
UWARN("Texturing cancelled!");
|
||||
return false;
|
||||
}
|
||||
UINFO("Precompute visible faces per cam (%d faces, %d cams)", (int)faces.size(), (int)cameras.size());
|
||||
for (unsigned int current_cam = 0; current_cam < cameras.size(); ++current_cam)
|
||||
{
|
||||
UDEBUG("Texture camera %d...", current_cam);
|
||||
@@ -1281,7 +1272,7 @@ pcl::TextureMapping<PointInT>::textureMeshwithMultipleCameras2 (
|
||||
}
|
||||
}
|
||||
|
||||
msg = uFormat("Processed camera %d/%d: %d occluded and %d spurious polygons out of %d", (int)current_cam+1, (int)cameras.size(), (int)occludedFaces.size(), clusterFaces, (int)visibilityIndices.size());
|
||||
std::string msg = uFormat("Processed camera %d/%d: %d occluded and %d spurious polygons out of %d", (int)current_cam+1, (int)cameras.size(), (int)occludedFaces.size(), clusterFaces, (int)visibilityIndices.size());
|
||||
UINFO(msg.c_str());
|
||||
if(state && !state->callback(msg))
|
||||
{
|
||||
@@ -1291,7 +1282,7 @@ pcl::TextureMapping<PointInT>::textureMeshwithMultipleCameras2 (
|
||||
}
|
||||
}
|
||||
|
||||
msg = uFormat("Texturing %d polygons...", (int)faces.size());
|
||||
std::string msg = uFormat("Texturing %d polygons...", (int)faces.size());
|
||||
UINFO(msg.c_str());
|
||||
if(state && !state->callback(msg))
|
||||
{
|
||||
@@ -1394,15 +1385,10 @@ pcl::TextureMapping<PointInT>::textureMeshwithMultipleCameras2 (
|
||||
|
||||
//UDEBUG("Process polygon %d cam =%d distanceToCam=%f", idx_face, current_cam, distanceToCam);
|
||||
|
||||
float distance = distanceToCenter;
|
||||
if(distanceToCamPolicy)
|
||||
{
|
||||
distance = distanceToCam;
|
||||
}
|
||||
if(distance <= smallestWeight || (!depthSet && currentDepthSet))
|
||||
if(distanceToCenter <= smallestWeight || (!depthSet && currentDepthSet))
|
||||
{
|
||||
cameraIndex = current_cam;
|
||||
smallestWeight = distance;
|
||||
smallestWeight = distanceToCenter;
|
||||
uv_coords[0] = iter->second.uv_coord1;
|
||||
uv_coords[1] = iter->second.uv_coord2;
|
||||
uv_coords[2] = iter->second.uv_coord3;
|
||||
|
||||
@@ -43,7 +43,6 @@
|
||||
#include <pcl/surface/reconstruction.h>
|
||||
#include <pcl/common/transforms.h>
|
||||
#include <pcl/TextureMesh.h>
|
||||
#include <pcl/octree/octree.h>
|
||||
#include <rtabmap/core/ProgressState.h>
|
||||
#include <rtabmap/utilite/ULogger.h>
|
||||
#include <rtabmap/utilite/UStl.h>
|
||||
@@ -367,8 +366,7 @@ namespace pcl
|
||||
textureMeshwithMultipleCameras2 (pcl::TextureMesh &mesh,
|
||||
const pcl::texture_mapping::CameraVector &cameras,
|
||||
const rtabmap::ProgressState * callback = 0,
|
||||
std::vector<std::map<int, pcl::PointXY> > * vertexToPixels = 0,
|
||||
bool distanceToCamPolicy = false);
|
||||
std::vector<std::map<int, pcl::PointXY> > * vertexToPixels = 0);
|
||||
|
||||
protected:
|
||||
/** \brief mesh scale control. */
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
-- *******************************************************************
|
||||
-- DatabaseSchema: Script for creating the database
|
||||
-- Usage:
|
||||
-- $ sqlite3 LTM.db < DatabaseSchema.sql
|
||||
--
|
||||
-- *******************************************************************
|
||||
|
||||
-- *******************************************************************
|
||||
-- CLEAN
|
||||
-- *******************************************************************
|
||||
/*DROP TABLE Node;*/
|
||||
|
||||
-- *******************************************************************
|
||||
-- CREATE
|
||||
-- *******************************************************************
|
||||
CREATE TABLE Node (
|
||||
id INTEGER NOT NULL,
|
||||
map_id INTEGER NOT NULL,
|
||||
weight INTEGER,
|
||||
stamp FLOAT,
|
||||
pose BLOB, -- 3x4 float
|
||||
ground_truth_pose BLOB, -- 3x4 float
|
||||
velocity BLOB, -- 6 float (vx,vy,vz,vroll,vpitch,vyaw) m/s and rad/s
|
||||
label TEXT,
|
||||
gps BLOB, -- 1x6 double: stamp, longitude (DD), latitude (DD), altitude (m), accuracy (m), bearing (North 0->360 deg clockwise)
|
||||
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Data (
|
||||
id INTEGER NOT NULL,
|
||||
image BLOB, -- compressed image (Grayscale or RGB)
|
||||
depth BLOB, -- compressed image (Depth or Right image)
|
||||
calibration BLOB, -- fx, fy, cx, cy, [baseline,] width, height, local_transform
|
||||
|
||||
scan BLOB, -- compressed data (Laser scan)
|
||||
scan_info BLOB, -- scan_max_pts, scan_max_range, local_transform
|
||||
|
||||
ground_cells BLOB, -- compressed data (occupancy grid)
|
||||
obstacle_cells BLOB, -- compressed data (occupancy grid)
|
||||
empty_cells BLOB, -- compressed data (occupancy grid)
|
||||
cell_size FLOAT,
|
||||
view_point_x FLOAT,
|
||||
view_point_y FLOAT,
|
||||
view_point_z FLOAT,
|
||||
|
||||
user_data BLOB, -- compressed data (User data)
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Link (
|
||||
from_id INTEGER NOT NULL,
|
||||
to_id INTEGER NOT NULL,
|
||||
type INTEGER NOT NULL, -- neighbor=0, loop=1, child=2
|
||||
information_matrix BLOB NOT NULL, -- 6x6 double (inverse covariance)
|
||||
transform BLOB, -- 3x4 float
|
||||
user_data BLOB, -- compressed data (User data)
|
||||
FOREIGN KEY (from_id) REFERENCES Node(id),
|
||||
FOREIGN KEY (to_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
--
|
||||
CREATE TABLE Word (
|
||||
id INTEGER NOT NULL,
|
||||
descriptor_size INTEGER NOT NULL,
|
||||
descriptor BLOB NOT NULL,
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Feature (
|
||||
node_id INTEGER NOT NULL,
|
||||
word_id INTEGER NOT NULL,
|
||||
pos_x FLOAT NOT NULL,
|
||||
pos_y FLOAT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
dir FLOAT NOT NULL,
|
||||
response FLOAT NOT NULL,
|
||||
octave INTEGER NOT NULL,
|
||||
depth_x FLOAT,
|
||||
depth_y FLOAT,
|
||||
depth_z FLOAT,
|
||||
descriptor_size INTEGER,
|
||||
descriptor BLOB,
|
||||
FOREIGN KEY (node_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Info (
|
||||
STM_size INTEGER,
|
||||
last_sign_added INTEGER,
|
||||
process_mem_used INTEGER,
|
||||
database_mem_used INTEGER,
|
||||
dictionary_size INTEGER,
|
||||
parameters TEXT,
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
CREATE TABLE Statistics (
|
||||
id INTEGER NOT NULL,
|
||||
stamp FLOAT,
|
||||
data BLOB,
|
||||
FOREIGN KEY (id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Admin (
|
||||
version TEXT,
|
||||
preview_image BLOB, -- compressed image
|
||||
|
||||
opt_cloud BLOB, -- compressed data
|
||||
opt_ids BLOB, -- Node ids used to generate the optimized cloud/mesh
|
||||
opt_poses BLOB, -- compressed N*3x4 float
|
||||
opt_polygons_size INTEGER, -- e.g., 3
|
||||
opt_polygons BLOB, -- compressed data [length_v0, i0,i1,i3, length_v1, i0,i1,i3]
|
||||
opt_tex_coords BLOB, -- compressed data [length_v0, u0,v0,u1,v1,u2,v2, length_v1, u0,v0,u1,v1,u2,v2]
|
||||
opt_tex_materials BLOB, -- compressed image
|
||||
opt_map BLOB, -- compressed CV_8SC1 occupancy grid
|
||||
opt_map_x_min FLOAT,
|
||||
opt_map_y_min FLOAT,
|
||||
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
-- *******************************************************************
|
||||
-- TRIGGERS
|
||||
-- *******************************************************************
|
||||
CREATE TRIGGER insert_Feature BEFORE INSERT ON Feature
|
||||
WHEN NOT EXISTS (SELECT Node.id FROM Node WHERE Node.id = NEW.node_id)
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key constraint failed in Feature table');
|
||||
END;
|
||||
|
||||
-- Creating a trigger for time_enter
|
||||
CREATE TRIGGER insert_Node_timeEnter AFTER INSERT ON Node
|
||||
BEGIN
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Data_timeEnter AFTER INSERT ON Data
|
||||
BEGIN
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Word_timeEnter AFTER INSERT ON Word
|
||||
BEGIN
|
||||
UPDATE Word SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Info_timeEnter AFTER INSERT ON Info
|
||||
BEGIN
|
||||
UPDATE Info SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
-- *******************************************************************
|
||||
-- INDEXES
|
||||
-- *******************************************************************
|
||||
CREATE UNIQUE INDEX IDX_Node_id on Node (id);
|
||||
CREATE INDEX IDX_Feature_node_id on Feature (node_id);
|
||||
CREATE INDEX IDX_Link_from_id on Link (from_id);
|
||||
CREATE UNIQUE INDEX IDX_node_label on Node (label);
|
||||
CREATE UNIQUE INDEX IDX_Statistics_id on Statistics (id);
|
||||
|
||||
-- *******************************************************************
|
||||
-- VERSION
|
||||
-- *******************************************************************
|
||||
INSERT INTO Admin(version) VALUES('0.16.0');
|
||||
|
||||
|
||||
@@ -1,169 +0,0 @@
|
||||
-- *******************************************************************
|
||||
-- DatabaseSchema: Script for creating the database
|
||||
-- Usage:
|
||||
-- $ sqlite3 LTM.db < DatabaseSchema.sql
|
||||
--
|
||||
-- *******************************************************************
|
||||
|
||||
-- *******************************************************************
|
||||
-- CLEAN
|
||||
-- *******************************************************************
|
||||
/*DROP TABLE Node;*/
|
||||
|
||||
-- *******************************************************************
|
||||
-- CREATE
|
||||
-- *******************************************************************
|
||||
CREATE TABLE Node (
|
||||
id INTEGER NOT NULL,
|
||||
map_id INTEGER NOT NULL,
|
||||
weight INTEGER,
|
||||
stamp FLOAT,
|
||||
pose BLOB, -- 3x4 float
|
||||
ground_truth_pose BLOB, -- 3x4 float
|
||||
velocity BLOB, -- 6 float (vx,vy,vz,vroll,vpitch,vyaw) m/s and rad/s
|
||||
label TEXT,
|
||||
gps BLOB, -- 1x6 double: stamp, longitude (DD), latitude (DD), altitude (m), accuracy (m), bearing (North 0->360 deg clockwise)
|
||||
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Data (
|
||||
id INTEGER NOT NULL,
|
||||
image BLOB, -- compressed image (Grayscale or RGB)
|
||||
depth BLOB, -- compressed image (Depth or Right image)
|
||||
calibration BLOB, -- fx, fy, cx, cy, [baseline,] width, height, local_transform
|
||||
|
||||
scan BLOB, -- compressed data (Laser scan)
|
||||
scan_info BLOB, -- scan_max_pts, scan_max_range, scan_format, local_transform
|
||||
|
||||
ground_cells BLOB, -- compressed data (occupancy grid)
|
||||
obstacle_cells BLOB, -- compressed data (occupancy grid)
|
||||
empty_cells BLOB, -- compressed data (occupancy grid)
|
||||
cell_size FLOAT,
|
||||
view_point_x FLOAT,
|
||||
view_point_y FLOAT,
|
||||
view_point_z FLOAT,
|
||||
|
||||
user_data BLOB, -- compressed data (User data)
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Link (
|
||||
from_id INTEGER NOT NULL,
|
||||
to_id INTEGER NOT NULL,
|
||||
type INTEGER NOT NULL, -- neighbor=0, loop=1, child=2
|
||||
information_matrix BLOB NOT NULL, -- 6x6 double (inverse covariance)
|
||||
transform BLOB, -- 3x4 float
|
||||
user_data BLOB, -- compressed data (User data)
|
||||
FOREIGN KEY (from_id) REFERENCES Node(id),
|
||||
FOREIGN KEY (to_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
--
|
||||
CREATE TABLE Word (
|
||||
id INTEGER NOT NULL,
|
||||
descriptor_size INTEGER NOT NULL,
|
||||
descriptor BLOB NOT NULL,
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Feature (
|
||||
node_id INTEGER NOT NULL,
|
||||
word_id INTEGER NOT NULL,
|
||||
pos_x FLOAT NOT NULL,
|
||||
pos_y FLOAT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
dir FLOAT NOT NULL,
|
||||
response FLOAT NOT NULL,
|
||||
octave INTEGER NOT NULL,
|
||||
depth_x FLOAT,
|
||||
depth_y FLOAT,
|
||||
depth_z FLOAT,
|
||||
descriptor_size INTEGER,
|
||||
descriptor BLOB,
|
||||
FOREIGN KEY (node_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Info (
|
||||
STM_size INTEGER,
|
||||
last_sign_added INTEGER,
|
||||
process_mem_used INTEGER,
|
||||
database_mem_used INTEGER,
|
||||
dictionary_size INTEGER,
|
||||
parameters TEXT,
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
CREATE TABLE Statistics (
|
||||
id INTEGER NOT NULL,
|
||||
stamp FLOAT,
|
||||
data BLOB,
|
||||
FOREIGN KEY (id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Admin (
|
||||
version TEXT,
|
||||
preview_image BLOB, -- compressed image
|
||||
|
||||
opt_cloud BLOB, -- compressed data
|
||||
opt_ids BLOB, -- Node ids used to generate the optimized cloud/mesh
|
||||
opt_poses BLOB, -- compressed N*3x4 float
|
||||
opt_polygons_size INTEGER, -- e.g., 3
|
||||
opt_polygons BLOB, -- compressed data [length_v0, i0,i1,i3, length_v1, i0,i1,i3]
|
||||
opt_tex_coords BLOB, -- compressed data [length_v0, u0,v0,u1,v1,u2,v2, length_v1, u0,v0,u1,v1,u2,v2]
|
||||
opt_tex_materials BLOB, -- compressed image
|
||||
opt_map BLOB, -- compressed CV_8SC1 occupancy grid
|
||||
opt_map_x_min FLOAT,
|
||||
opt_map_y_min FLOAT,
|
||||
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
-- *******************************************************************
|
||||
-- TRIGGERS
|
||||
-- *******************************************************************
|
||||
CREATE TRIGGER insert_Feature BEFORE INSERT ON Feature
|
||||
WHEN NOT EXISTS (SELECT Node.id FROM Node WHERE Node.id = NEW.node_id)
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key constraint failed in Feature table');
|
||||
END;
|
||||
|
||||
-- Creating a trigger for time_enter
|
||||
CREATE TRIGGER insert_Node_timeEnter AFTER INSERT ON Node
|
||||
BEGIN
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Data_timeEnter AFTER INSERT ON Data
|
||||
BEGIN
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Word_timeEnter AFTER INSERT ON Word
|
||||
BEGIN
|
||||
UPDATE Word SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Info_timeEnter AFTER INSERT ON Info
|
||||
BEGIN
|
||||
UPDATE Info SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
-- *******************************************************************
|
||||
-- INDEXES
|
||||
-- *******************************************************************
|
||||
CREATE UNIQUE INDEX IDX_Node_id on Node (id);
|
||||
CREATE INDEX IDX_Feature_node_id on Feature (node_id);
|
||||
CREATE INDEX IDX_Link_from_id on Link (from_id);
|
||||
CREATE UNIQUE INDEX IDX_node_label on Node (label);
|
||||
CREATE UNIQUE INDEX IDX_Statistics_id on Statistics (id);
|
||||
|
||||
-- *******************************************************************
|
||||
-- VERSION
|
||||
-- *******************************************************************
|
||||
INSERT INTO Admin(version) VALUES('0.16.1');
|
||||
|
||||
|
||||
@@ -1,170 +0,0 @@
|
||||
-- *******************************************************************
|
||||
-- DatabaseSchema: Script for creating the database
|
||||
-- Usage:
|
||||
-- $ sqlite3 LTM.db < DatabaseSchema.sql
|
||||
--
|
||||
-- *******************************************************************
|
||||
|
||||
-- *******************************************************************
|
||||
-- CLEAN
|
||||
-- *******************************************************************
|
||||
/*DROP TABLE Node;*/
|
||||
|
||||
-- *******************************************************************
|
||||
-- CREATE
|
||||
-- *******************************************************************
|
||||
CREATE TABLE Node (
|
||||
id INTEGER NOT NULL,
|
||||
map_id INTEGER NOT NULL,
|
||||
weight INTEGER,
|
||||
stamp FLOAT,
|
||||
pose BLOB, -- 3x4 float
|
||||
ground_truth_pose BLOB, -- 3x4 float
|
||||
velocity BLOB, -- 6 float (vx,vy,vz,vroll,vpitch,vyaw) m/s and rad/s
|
||||
label TEXT,
|
||||
gps BLOB, -- 1x6 double: stamp, longitude (DD), latitude (DD), altitude (m), accuracy (m), bearing (North 0->360 deg clockwise)
|
||||
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Data (
|
||||
id INTEGER NOT NULL,
|
||||
image BLOB, -- compressed image (Grayscale or RGB)
|
||||
depth BLOB, -- compressed image (Depth or Right image)
|
||||
calibration BLOB, -- fx, fy, cx, cy, [baseline,] width, height, local_transform
|
||||
|
||||
scan BLOB, -- compressed data (Laser scan)
|
||||
scan_info BLOB, -- scan_max_pts, scan_max_range, scan_format, local_transform
|
||||
|
||||
ground_cells BLOB, -- compressed data (occupancy grid)
|
||||
obstacle_cells BLOB, -- compressed data (occupancy grid)
|
||||
empty_cells BLOB, -- compressed data (occupancy grid)
|
||||
cell_size FLOAT,
|
||||
view_point_x FLOAT,
|
||||
view_point_y FLOAT,
|
||||
view_point_z FLOAT,
|
||||
|
||||
user_data BLOB, -- compressed data (User data)
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Link (
|
||||
from_id INTEGER NOT NULL,
|
||||
to_id INTEGER NOT NULL,
|
||||
type INTEGER NOT NULL, -- neighbor=0, loop=1, child=2
|
||||
information_matrix BLOB NOT NULL, -- 6x6 double (inverse covariance)
|
||||
transform BLOB, -- 3x4 float
|
||||
user_data BLOB, -- compressed data (User data)
|
||||
FOREIGN KEY (from_id) REFERENCES Node(id),
|
||||
FOREIGN KEY (to_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
--
|
||||
CREATE TABLE Word (
|
||||
id INTEGER NOT NULL,
|
||||
descriptor_size INTEGER NOT NULL,
|
||||
descriptor BLOB NOT NULL,
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Feature (
|
||||
node_id INTEGER NOT NULL,
|
||||
word_id INTEGER NOT NULL,
|
||||
pos_x FLOAT NOT NULL,
|
||||
pos_y FLOAT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
dir FLOAT NOT NULL,
|
||||
response FLOAT NOT NULL,
|
||||
octave INTEGER NOT NULL,
|
||||
depth_x FLOAT,
|
||||
depth_y FLOAT,
|
||||
depth_z FLOAT,
|
||||
descriptor_size INTEGER,
|
||||
descriptor BLOB,
|
||||
FOREIGN KEY (node_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Info (
|
||||
STM_size INTEGER,
|
||||
last_sign_added INTEGER,
|
||||
process_mem_used INTEGER,
|
||||
database_mem_used INTEGER,
|
||||
dictionary_size INTEGER,
|
||||
parameters TEXT,
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
CREATE TABLE Statistics (
|
||||
id INTEGER NOT NULL,
|
||||
stamp FLOAT,
|
||||
data BLOB, -- compressed string
|
||||
wm_state BLOB, -- compressed data
|
||||
FOREIGN KEY (id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Admin (
|
||||
version TEXT,
|
||||
preview_image BLOB, -- compressed image
|
||||
|
||||
opt_cloud BLOB, -- compressed data
|
||||
opt_ids BLOB, -- Node ids used to generate the optimized cloud/mesh
|
||||
opt_poses BLOB, -- compressed N*3x4 float
|
||||
opt_polygons_size INTEGER, -- e.g., 3
|
||||
opt_polygons BLOB, -- compressed data [length_v0, i0,i1,i3, length_v1, i0,i1,i3]
|
||||
opt_tex_coords BLOB, -- compressed data [length_v0, u0,v0,u1,v1,u2,v2, length_v1, u0,v0,u1,v1,u2,v2]
|
||||
opt_tex_materials BLOB, -- compressed image
|
||||
opt_map BLOB, -- compressed CV_8SC1 occupancy grid
|
||||
opt_map_x_min FLOAT,
|
||||
opt_map_y_min FLOAT,
|
||||
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
-- *******************************************************************
|
||||
-- TRIGGERS
|
||||
-- *******************************************************************
|
||||
CREATE TRIGGER insert_Feature BEFORE INSERT ON Feature
|
||||
WHEN NOT EXISTS (SELECT Node.id FROM Node WHERE Node.id = NEW.node_id)
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key constraint failed in Feature table');
|
||||
END;
|
||||
|
||||
-- Creating a trigger for time_enter
|
||||
CREATE TRIGGER insert_Node_timeEnter AFTER INSERT ON Node
|
||||
BEGIN
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Data_timeEnter AFTER INSERT ON Data
|
||||
BEGIN
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Word_timeEnter AFTER INSERT ON Word
|
||||
BEGIN
|
||||
UPDATE Word SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Info_timeEnter AFTER INSERT ON Info
|
||||
BEGIN
|
||||
UPDATE Info SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
-- *******************************************************************
|
||||
-- INDEXES
|
||||
-- *******************************************************************
|
||||
CREATE UNIQUE INDEX IDX_Node_id on Node (id);
|
||||
CREATE INDEX IDX_Feature_node_id on Feature (node_id);
|
||||
CREATE INDEX IDX_Link_from_id on Link (from_id);
|
||||
CREATE UNIQUE INDEX IDX_node_label on Node (label);
|
||||
CREATE UNIQUE INDEX IDX_Statistics_id on Statistics (id);
|
||||
|
||||
-- *******************************************************************
|
||||
-- VERSION
|
||||
-- *******************************************************************
|
||||
INSERT INTO Admin(version) VALUES('0.16.2');
|
||||
|
||||
|
||||
@@ -1,172 +0,0 @@
|
||||
-- *******************************************************************
|
||||
-- DatabaseSchema: Script for creating the database
|
||||
-- Usage:
|
||||
-- $ sqlite3 LTM.db < DatabaseSchema.sql
|
||||
--
|
||||
-- *******************************************************************
|
||||
|
||||
-- *******************************************************************
|
||||
-- CLEAN
|
||||
-- *******************************************************************
|
||||
/*DROP TABLE Node;*/
|
||||
|
||||
-- *******************************************************************
|
||||
-- CREATE
|
||||
-- *******************************************************************
|
||||
CREATE TABLE Node (
|
||||
id INTEGER NOT NULL,
|
||||
map_id INTEGER NOT NULL,
|
||||
weight INTEGER,
|
||||
stamp FLOAT,
|
||||
pose BLOB, -- 3x4 float
|
||||
ground_truth_pose BLOB, -- 3x4 float
|
||||
velocity BLOB, -- 6 float (vx,vy,vz,vroll,vpitch,vyaw) m/s and rad/s
|
||||
label TEXT,
|
||||
gps BLOB, -- 1x6 double: stamp, longitude (DD), latitude (DD), altitude (m), accuracy (m), bearing (North 0->360 deg clockwise)
|
||||
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Data (
|
||||
id INTEGER NOT NULL,
|
||||
image BLOB, -- compressed image (Grayscale or RGB)
|
||||
depth BLOB, -- compressed image (Depth or Right image)
|
||||
calibration BLOB, -- fx, fy, cx, cy, [baseline,] width, height, local_transform
|
||||
|
||||
scan BLOB, -- compressed data (Laser scan)
|
||||
scan_info BLOB, -- scan_max_pts, scan_max_range, scan_format, local_transform
|
||||
|
||||
ground_cells BLOB, -- compressed data (occupancy grid)
|
||||
obstacle_cells BLOB, -- compressed data (occupancy grid)
|
||||
empty_cells BLOB, -- compressed data (occupancy grid)
|
||||
cell_size FLOAT,
|
||||
view_point_x FLOAT,
|
||||
view_point_y FLOAT,
|
||||
view_point_z FLOAT,
|
||||
|
||||
user_data BLOB, -- compressed data (User data)
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Link (
|
||||
from_id INTEGER NOT NULL,
|
||||
to_id INTEGER NOT NULL,
|
||||
type INTEGER NOT NULL, -- neighbor=0, loop=1, child=2
|
||||
information_matrix BLOB NOT NULL, -- 6x6 double (inverse covariance)
|
||||
transform BLOB, -- 3x4 float
|
||||
user_data BLOB, -- compressed data (User data)
|
||||
FOREIGN KEY (from_id) REFERENCES Node(id),
|
||||
FOREIGN KEY (to_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
--
|
||||
CREATE TABLE Word (
|
||||
id INTEGER NOT NULL,
|
||||
descriptor_size INTEGER NOT NULL,
|
||||
descriptor BLOB NOT NULL,
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Feature (
|
||||
node_id INTEGER NOT NULL,
|
||||
word_id INTEGER NOT NULL,
|
||||
pos_x FLOAT NOT NULL,
|
||||
pos_y FLOAT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
dir FLOAT NOT NULL,
|
||||
response FLOAT NOT NULL,
|
||||
octave INTEGER NOT NULL,
|
||||
depth_x FLOAT,
|
||||
depth_y FLOAT,
|
||||
depth_z FLOAT,
|
||||
descriptor_size INTEGER,
|
||||
descriptor BLOB,
|
||||
FOREIGN KEY (node_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Info (
|
||||
STM_size INTEGER,
|
||||
last_sign_added INTEGER,
|
||||
process_mem_used INTEGER,
|
||||
database_mem_used INTEGER,
|
||||
dictionary_size INTEGER,
|
||||
parameters TEXT,
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
CREATE TABLE Statistics (
|
||||
id INTEGER NOT NULL,
|
||||
stamp FLOAT,
|
||||
data BLOB, -- compressed string
|
||||
wm_state BLOB, -- compressed data
|
||||
FOREIGN KEY (id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Admin (
|
||||
version TEXT,
|
||||
preview_image BLOB, -- compressed image
|
||||
|
||||
opt_cloud BLOB, -- compressed data
|
||||
opt_ids BLOB, -- Node ids used to generate the optimized cloud/mesh
|
||||
opt_poses BLOB, -- compressed N*3x4 float
|
||||
opt_last_localization BLOB, -- 3x4 float
|
||||
opt_polygons_size INTEGER, -- e.g., 3
|
||||
opt_polygons BLOB, -- compressed data [length_v0, i0,i1,i3, length_v1, i0,i1,i3]
|
||||
opt_tex_coords BLOB, -- compressed data [length_v0, u0,v0,u1,v1,u2,v2, length_v1, u0,v0,u1,v1,u2,v2]
|
||||
opt_tex_materials BLOB, -- compressed image
|
||||
opt_map BLOB, -- compressed CV_8SC1 occupancy grid
|
||||
opt_map_x_min FLOAT,
|
||||
opt_map_y_min FLOAT,
|
||||
opt_map_resolution FLOAT,
|
||||
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
-- *******************************************************************
|
||||
-- TRIGGERS
|
||||
-- *******************************************************************
|
||||
CREATE TRIGGER insert_Feature BEFORE INSERT ON Feature
|
||||
WHEN NOT EXISTS (SELECT Node.id FROM Node WHERE Node.id = NEW.node_id)
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key constraint failed in Feature table');
|
||||
END;
|
||||
|
||||
-- Creating a trigger for time_enter
|
||||
CREATE TRIGGER insert_Node_timeEnter AFTER INSERT ON Node
|
||||
BEGIN
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Data_timeEnter AFTER INSERT ON Data
|
||||
BEGIN
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Word_timeEnter AFTER INSERT ON Word
|
||||
BEGIN
|
||||
UPDATE Word SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Info_timeEnter AFTER INSERT ON Info
|
||||
BEGIN
|
||||
UPDATE Info SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
-- *******************************************************************
|
||||
-- INDEXES
|
||||
-- *******************************************************************
|
||||
CREATE UNIQUE INDEX IDX_Node_id on Node (id);
|
||||
CREATE INDEX IDX_Feature_node_id on Feature (node_id);
|
||||
CREATE INDEX IDX_Link_from_id on Link (from_id);
|
||||
CREATE UNIQUE INDEX IDX_node_label on Node (label);
|
||||
CREATE UNIQUE INDEX IDX_Statistics_id on Statistics (id);
|
||||
|
||||
-- *******************************************************************
|
||||
-- VERSION
|
||||
-- *******************************************************************
|
||||
INSERT INTO Admin(version) VALUES('0.17.0');
|
||||
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
-- *******************************************************************
|
||||
-- DatabaseSchema: Script for creating the database
|
||||
-- Usage:
|
||||
-- $ sqlite3 LTM.db < DatabaseSchema.sql
|
||||
--
|
||||
-- *******************************************************************
|
||||
|
||||
-- *******************************************************************
|
||||
-- CLEAN
|
||||
-- *******************************************************************
|
||||
/*DROP TABLE Node;*/
|
||||
|
||||
-- *******************************************************************
|
||||
-- CREATE
|
||||
-- *******************************************************************
|
||||
CREATE TABLE Node (
|
||||
id INTEGER NOT NULL,
|
||||
map_id INTEGER NOT NULL,
|
||||
weight INTEGER,
|
||||
stamp FLOAT,
|
||||
pose BLOB, -- 3x4 float
|
||||
ground_truth_pose BLOB, -- 3x4 float
|
||||
velocity BLOB, -- 6 float (vx,vy,vz,vroll,vpitch,vyaw) m/s and rad/s
|
||||
label TEXT,
|
||||
gps BLOB, -- 1x6 double: stamp, longitude (DD), latitude (DD), altitude (m), accuracy (m), bearing (North 0->360 deg clockwise)
|
||||
env_sensors BLOB, -- Variable 3xdouble: (sensorId1, value, stamp, sensorId2, value, stamp, ...)
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Data (
|
||||
id INTEGER NOT NULL,
|
||||
image BLOB, -- compressed image (Grayscale or RGB)
|
||||
depth BLOB, -- compressed image (Depth or Right image)
|
||||
calibration BLOB, -- fx, fy, cx, cy, [baseline,] width, height, local_transform
|
||||
|
||||
scan BLOB, -- compressed data (Laser scan)
|
||||
scan_info BLOB, -- scan_max_pts, scan_max_range, scan_format, local_transform
|
||||
|
||||
ground_cells BLOB, -- compressed data (occupancy grid)
|
||||
obstacle_cells BLOB, -- compressed data (occupancy grid)
|
||||
empty_cells BLOB, -- compressed data (occupancy grid)
|
||||
cell_size FLOAT,
|
||||
view_point_x FLOAT,
|
||||
view_point_y FLOAT,
|
||||
view_point_z FLOAT,
|
||||
|
||||
user_data BLOB, -- compressed data (User data)
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Link (
|
||||
from_id INTEGER NOT NULL,
|
||||
to_id INTEGER NOT NULL,
|
||||
type INTEGER NOT NULL, -- neighbor=0, loop=1, child=2
|
||||
information_matrix BLOB NOT NULL, -- 6x6 double (inverse covariance)
|
||||
transform BLOB, -- 3x4 float
|
||||
user_data BLOB, -- compressed data (User data)
|
||||
FOREIGN KEY (from_id) REFERENCES Node(id),
|
||||
FOREIGN KEY (to_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
--
|
||||
CREATE TABLE Word (
|
||||
id INTEGER NOT NULL,
|
||||
descriptor_size INTEGER NOT NULL,
|
||||
descriptor BLOB NOT NULL,
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Feature (
|
||||
node_id INTEGER NOT NULL,
|
||||
word_id INTEGER NOT NULL,
|
||||
pos_x FLOAT NOT NULL,
|
||||
pos_y FLOAT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
dir FLOAT NOT NULL,
|
||||
response FLOAT NOT NULL,
|
||||
octave INTEGER NOT NULL,
|
||||
depth_x FLOAT,
|
||||
depth_y FLOAT,
|
||||
depth_z FLOAT,
|
||||
descriptor_size INTEGER,
|
||||
descriptor BLOB,
|
||||
FOREIGN KEY (node_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
--
|
||||
CREATE TABLE Tag (
|
||||
node_id INTEGER NOT NULL,
|
||||
tag_id INTEGER NOT NULL,
|
||||
stamp FLOAT NOT NULL,
|
||||
transform BLOB NOT NULL, -- 3x4 float, /base_link -> /tag_frame
|
||||
FOREIGN KEY (node_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Info (
|
||||
STM_size INTEGER,
|
||||
last_sign_added INTEGER,
|
||||
process_mem_used INTEGER,
|
||||
database_mem_used INTEGER,
|
||||
dictionary_size INTEGER,
|
||||
parameters TEXT,
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
CREATE TABLE Statistics (
|
||||
id INTEGER NOT NULL,
|
||||
stamp FLOAT,
|
||||
data BLOB, -- compressed string
|
||||
wm_state BLOB, -- compressed data
|
||||
FOREIGN KEY (id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Admin (
|
||||
version TEXT,
|
||||
preview_image BLOB, -- compressed image
|
||||
|
||||
opt_cloud BLOB, -- compressed data
|
||||
opt_ids BLOB, -- Node ids used to generate the optimized cloud/mesh
|
||||
opt_poses BLOB, -- compressed N*3x4 float
|
||||
opt_last_localization BLOB, -- 3x4 float
|
||||
opt_polygons_size INTEGER, -- e.g., 3
|
||||
opt_polygons BLOB, -- compressed data [length_v0, i0,i1,i3, length_v1, i0,i1,i3]
|
||||
opt_tex_coords BLOB, -- compressed data [length_v0, u0,v0,u1,v1,u2,v2, length_v1, u0,v0,u1,v1,u2,v2]
|
||||
opt_tex_materials BLOB, -- compressed image
|
||||
opt_map BLOB, -- compressed CV_8SC1 occupancy grid
|
||||
opt_map_x_min FLOAT,
|
||||
opt_map_y_min FLOAT,
|
||||
opt_map_resolution FLOAT,
|
||||
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
-- *******************************************************************
|
||||
-- TRIGGERS
|
||||
-- *******************************************************************
|
||||
CREATE TRIGGER insert_Feature BEFORE INSERT ON Feature
|
||||
WHEN NOT EXISTS (SELECT Node.id FROM Node WHERE Node.id = NEW.node_id)
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key constraint failed in Feature table');
|
||||
END;
|
||||
|
||||
-- Creating a trigger for time_enter
|
||||
CREATE TRIGGER insert_Node_timeEnter AFTER INSERT ON Node
|
||||
BEGIN
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Data_timeEnter AFTER INSERT ON Data
|
||||
BEGIN
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Word_timeEnter AFTER INSERT ON Word
|
||||
BEGIN
|
||||
UPDATE Word SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Info_timeEnter AFTER INSERT ON Info
|
||||
BEGIN
|
||||
UPDATE Info SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
-- *******************************************************************
|
||||
-- INDEXES
|
||||
-- *******************************************************************
|
||||
CREATE UNIQUE INDEX IDX_Node_id on Node (id);
|
||||
CREATE INDEX IDX_Feature_node_id on Feature (node_id);
|
||||
CREATE INDEX IDX_Link_from_id on Link (from_id);
|
||||
CREATE UNIQUE INDEX IDX_node_label on Node (label);
|
||||
CREATE UNIQUE INDEX IDX_Statistics_id on Statistics (id);
|
||||
|
||||
-- *******************************************************************
|
||||
-- VERSION
|
||||
-- *******************************************************************
|
||||
INSERT INTO Admin(version) VALUES('0.18.0');
|
||||
|
||||
|
||||
@@ -1,181 +0,0 @@
|
||||
-- *******************************************************************
|
||||
-- DatabaseSchema: Script for creating the database
|
||||
-- Usage:
|
||||
-- $ sqlite3 LTM.db < DatabaseSchema.sql
|
||||
--
|
||||
-- *******************************************************************
|
||||
|
||||
-- *******************************************************************
|
||||
-- CLEAN
|
||||
-- *******************************************************************
|
||||
/*DROP TABLE Node;*/
|
||||
|
||||
-- *******************************************************************
|
||||
-- CREATE
|
||||
-- *******************************************************************
|
||||
CREATE TABLE Node (
|
||||
id INTEGER NOT NULL,
|
||||
map_id INTEGER NOT NULL,
|
||||
weight INTEGER,
|
||||
stamp FLOAT,
|
||||
pose BLOB, -- 3x4 float
|
||||
ground_truth_pose BLOB, -- 3x4 float
|
||||
velocity BLOB, -- 6 float (vx,vy,vz,vroll,vpitch,vyaw) m/s and rad/s
|
||||
label TEXT,
|
||||
gps BLOB, -- 1x6 double: stamp, longitude (DD), latitude (DD), altitude (m), accuracy (m), bearing (North 0->360 deg clockwise)
|
||||
env_sensors BLOB, -- Variable 3xdouble: (sensorId1, value, stamp, sensorId2, value, stamp, ...)
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Data (
|
||||
id INTEGER NOT NULL,
|
||||
image BLOB, -- compressed image (Grayscale or RGB)
|
||||
depth BLOB, -- compressed image (Depth or Right image)
|
||||
calibration BLOB, -- fx, fy, cx, cy, [baseline,] width, height, local_transform
|
||||
|
||||
scan BLOB, -- compressed data (Laser scan)
|
||||
scan_info BLOB, -- scan_max_pts, scan_max_range, scan_format, local_transform
|
||||
|
||||
ground_cells BLOB, -- compressed data (occupancy grid)
|
||||
obstacle_cells BLOB, -- compressed data (occupancy grid)
|
||||
empty_cells BLOB, -- compressed data (occupancy grid)
|
||||
cell_size FLOAT,
|
||||
view_point_x FLOAT,
|
||||
view_point_y FLOAT,
|
||||
view_point_z FLOAT,
|
||||
|
||||
user_data BLOB, -- compressed data (User data)
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Link (
|
||||
from_id INTEGER NOT NULL,
|
||||
to_id INTEGER NOT NULL,
|
||||
type INTEGER NOT NULL, -- neighbor=0, loop=1, child=2
|
||||
information_matrix BLOB NOT NULL, -- 6x6 double (inverse covariance)
|
||||
transform BLOB, -- 3x4 float
|
||||
user_data BLOB, -- compressed data (User data)
|
||||
FOREIGN KEY (from_id) REFERENCES Node(id),
|
||||
FOREIGN KEY (to_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
--
|
||||
CREATE TABLE Word (
|
||||
id INTEGER NOT NULL,
|
||||
descriptor_size INTEGER NOT NULL,
|
||||
descriptor BLOB NOT NULL,
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Feature (
|
||||
node_id INTEGER NOT NULL,
|
||||
word_id INTEGER NOT NULL,
|
||||
pos_x FLOAT NOT NULL,
|
||||
pos_y FLOAT NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
dir FLOAT NOT NULL,
|
||||
response FLOAT NOT NULL,
|
||||
octave INTEGER NOT NULL,
|
||||
depth_x FLOAT,
|
||||
depth_y FLOAT,
|
||||
depth_z FLOAT,
|
||||
descriptor_size INTEGER,
|
||||
descriptor BLOB,
|
||||
FOREIGN KEY (node_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
--
|
||||
CREATE TABLE Tag (
|
||||
node_id INTEGER NOT NULL,
|
||||
tag_id INTEGER NOT NULL,
|
||||
stamp FLOAT NOT NULL,
|
||||
transform BLOB NOT NULL, -- 3x4 float, /base_link -> /tag_frame
|
||||
FOREIGN KEY (node_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Info (
|
||||
STM_size INTEGER,
|
||||
last_sign_added INTEGER,
|
||||
process_mem_used INTEGER,
|
||||
database_mem_used INTEGER,
|
||||
dictionary_size INTEGER,
|
||||
parameters TEXT,
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
CREATE TABLE Statistics (
|
||||
id INTEGER NOT NULL,
|
||||
stamp FLOAT,
|
||||
data BLOB, -- compressed string
|
||||
wm_state BLOB, -- compressed data
|
||||
FOREIGN KEY (id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Admin (
|
||||
version TEXT,
|
||||
preview_image BLOB, -- compressed image
|
||||
|
||||
opt_cloud BLOB, -- compressed data
|
||||
opt_ids BLOB, -- Node ids used to generate the optimized cloud/mesh
|
||||
opt_poses BLOB, -- compressed N*3x4 float
|
||||
opt_last_localization BLOB, -- 3x4 float
|
||||
opt_polygons_size INTEGER, -- e.g., 3
|
||||
opt_polygons BLOB, -- compressed data [length_v0, i0,i1,i3, length_v1, i0,i1,i3]
|
||||
opt_tex_coords BLOB, -- compressed data [length_v0, u0,v0,u1,v1,u2,v2, length_v1, u0,v0,u1,v1,u2,v2]
|
||||
opt_tex_materials BLOB, -- compressed image
|
||||
opt_map BLOB, -- compressed CV_8SC1 occupancy grid
|
||||
opt_map_x_min FLOAT,
|
||||
opt_map_y_min FLOAT,
|
||||
opt_map_resolution FLOAT,
|
||||
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
-- *******************************************************************
|
||||
-- TRIGGERS
|
||||
-- *******************************************************************
|
||||
CREATE TRIGGER insert_Feature BEFORE INSERT ON Feature
|
||||
WHEN NOT EXISTS (SELECT Node.id FROM Node WHERE Node.id = NEW.node_id)
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key constraint failed in Feature table');
|
||||
END;
|
||||
|
||||
-- Creating a trigger for time_enter
|
||||
CREATE TRIGGER insert_Node_timeEnter AFTER INSERT ON Node
|
||||
BEGIN
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Data_timeEnter AFTER INSERT ON Data
|
||||
BEGIN
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Word_timeEnter AFTER INSERT ON Word
|
||||
BEGIN
|
||||
UPDATE Word SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_Info_timeEnter AFTER INSERT ON Info
|
||||
BEGIN
|
||||
UPDATE Info SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
-- *******************************************************************
|
||||
-- INDEXES
|
||||
-- *******************************************************************
|
||||
CREATE UNIQUE INDEX IDX_Node_id on Node (id);
|
||||
CREATE INDEX IDX_Feature_node_id on Feature (node_id);
|
||||
CREATE INDEX IDX_Link_from_id on Link (from_id);
|
||||
CREATE UNIQUE INDEX IDX_node_label on Node (label);
|
||||
CREATE UNIQUE INDEX IDX_Statistics_id on Statistics (id);
|
||||
|
||||
-- *******************************************************************
|
||||
-- VERSION
|
||||
-- *******************************************************************
|
||||
INSERT INTO Admin(version) VALUES('0.18.3');
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ SuperPoint::SuperPoint()
|
||||
|
||||
convDa(torch::nn::Conv2dOptions(c4, c5, 3).stride(1).padding(1)),
|
||||
convDb(torch::nn::Conv2dOptions(c5, d1, 1).stride(1).padding(0))
|
||||
|
||||
|
||||
{
|
||||
register_module("conv1a", conv1a);
|
||||
register_module("conv1b", conv1b);
|
||||
@@ -168,16 +168,12 @@ std::vector<cv::KeyPoint> SPDetector::detect(const cv::Mat &img, const cv::Mat &
|
||||
auto kpts = (prob_ > threshold_);
|
||||
kpts = torch::nonzero(kpts); // [n_keypoints, 2] (y, x)
|
||||
|
||||
//convert back to cpu if in gpu
|
||||
auto kpts_cpu = kpts.to(torch::kCPU);
|
||||
auto prob_cpu = prob_.to(torch::kCPU);
|
||||
|
||||
std::vector<cv::KeyPoint> keypoints_no_nms;
|
||||
for (int i = 0; i < kpts_cpu.size(0); i++) {
|
||||
if(mask.empty() || mask.at<unsigned char>(kpts_cpu[i][0].item<int>(), kpts_cpu[i][1].item<int>()) != 0)
|
||||
for (int i = 0; i < kpts.size(0); i++) {
|
||||
if(mask.empty() || mask.at<unsigned char>(kpts[i][0].item<int>(), kpts[i][1].item<int>()) != 0)
|
||||
{
|
||||
float response = prob_cpu[kpts_cpu[i][0]][kpts_cpu[i][1]].item<float>();
|
||||
keypoints_no_nms.push_back(cv::KeyPoint(kpts_cpu[i][1].item<float>(), kpts_cpu[i][0].item<float>(), 8, -1, response));
|
||||
float response = prob_[kpts[i][0]][kpts[i][1]].item<float>();
|
||||
keypoints_no_nms.push_back(cv::KeyPoint(kpts[i][1].item<float>(), kpts[i][0].item<float>(), 8, -1, response));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -187,7 +183,7 @@ std::vector<cv::KeyPoint> SPDetector::detect(const cv::Mat &img, const cv::Mat &
|
||||
for (size_t i = 0; i < keypoints_no_nms.size(); i++) {
|
||||
int x = keypoints_no_nms[i].pt.x;
|
||||
int y = keypoints_no_nms[i].pt.y;
|
||||
conf.at<float>(i, 0) = prob_cpu[y][x].item<float>();
|
||||
conf.at<float>(i, 0) = prob_[y][x].item<float>();
|
||||
}
|
||||
|
||||
int border = 0;
|
||||
@@ -293,7 +289,7 @@ void NMS(const std::vector<cv::KeyPoint> & ptsIn,
|
||||
confidence.setTo(0);
|
||||
|
||||
for (size_t i = 0; i < pts_raw.size(); i++)
|
||||
{
|
||||
{
|
||||
int uu = (int) pts_raw[i].x;
|
||||
int vv = (int) pts_raw[i].y;
|
||||
|
||||
@@ -312,7 +308,7 @@ void NMS(const std::vector<cv::KeyPoint> & ptsIn,
|
||||
cv::copyMakeBorder(grid, grid, dist_thresh, dist_thresh, dist_thresh, dist_thresh, cv::BORDER_CONSTANT, 0);
|
||||
|
||||
for (size_t i = 0; i < pts_raw.size(); i++)
|
||||
{
|
||||
{
|
||||
// account for top left padding
|
||||
int uu = (int) pts_raw[i].x + dist_thresh;
|
||||
int vv = (int) pts_raw[i].y + dist_thresh;
|
||||
@@ -360,7 +356,7 @@ void NMS(const std::vector<cv::KeyPoint> & ptsIn,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if(!descriptorsIn.empty())
|
||||
{
|
||||
UASSERT(descriptorsIn.rows == (int)ptsIn.size());
|
||||
|
||||
@@ -2044,55 +2044,6 @@ cv::Mat exposureFusion(const std::vector<cv::Mat> & images)
|
||||
return fusion;
|
||||
}
|
||||
|
||||
void HSVtoRGB( float *r, float *g, float *b, float h, float s, float v )
|
||||
{
|
||||
int i;
|
||||
float f, p, q, t;
|
||||
if( s == 0 ) {
|
||||
// achromatic (grey)
|
||||
*r = *g = *b = v;
|
||||
return;
|
||||
}
|
||||
h /= 60; // sector 0 to 5
|
||||
i = floor( h );
|
||||
f = h - i; // factorial part of h
|
||||
p = v * ( 1 - s );
|
||||
q = v * ( 1 - s * f );
|
||||
t = v * ( 1 - s * ( 1 - f ) );
|
||||
switch( i ) {
|
||||
case 0:
|
||||
*r = v;
|
||||
*g = t;
|
||||
*b = p;
|
||||
break;
|
||||
case 1:
|
||||
*r = q;
|
||||
*g = v;
|
||||
*b = p;
|
||||
break;
|
||||
case 2:
|
||||
*r = p;
|
||||
*g = v;
|
||||
*b = t;
|
||||
break;
|
||||
case 3:
|
||||
*r = p;
|
||||
*g = q;
|
||||
*b = v;
|
||||
break;
|
||||
case 4:
|
||||
*r = t;
|
||||
*g = p;
|
||||
*b = v;
|
||||
break;
|
||||
default: // case 5:
|
||||
*r = v;
|
||||
*g = p;
|
||||
*b = q;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user