mirror of
https://github.com/introlab/rtabmap.git
synced 2026-09-12 06:20:19 +08:00
Merged Audio branch to trunk
git-svn-id: http://rtabmap.googlecode.com/svn/trunk/rtabmap@560 f169173b-cf89-36c8-b27e-44dbe73f0c83
This commit is contained in:
@@ -1,82 +1,82 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>rtabmap</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||
<triggers>clean,full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>?name?</key>
|
||||
<value></value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.append_environment</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
|
||||
<value>all</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.buildArguments</key>
|
||||
<value>-C ${ProjDirPath}/build VERBOSE=true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.buildCommand</key>
|
||||
<value>make</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.buildLocation</key>
|
||||
<value>${workspace_loc:/RTAB-Map}</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
|
||||
<value>clean</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.contents</key>
|
||||
<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
|
||||
<value>false</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableFullBuild</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
|
||||
<value>all</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.stopOnError</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
|
||||
<value>false</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<projectDescription>
|
||||
<name>rtabmap</name>
|
||||
<comment></comment>
|
||||
<projects>
|
||||
</projects>
|
||||
<buildSpec>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.genmakebuilder</name>
|
||||
<triggers>clean,full,incremental,</triggers>
|
||||
<arguments>
|
||||
<dictionary>
|
||||
<key>?name?</key>
|
||||
<value></value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.append_environment</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.autoBuildTarget</key>
|
||||
<value>all</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.buildArguments</key>
|
||||
<value>-C ${ProjDirPath}/build VERBOSE=true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.buildCommand</key>
|
||||
<value>mingw32-make</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.buildLocation</key>
|
||||
<value>${workspace_loc:/RTAB-Map}</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.cleanBuildTarget</key>
|
||||
<value>clean</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.contents</key>
|
||||
<value>org.eclipse.cdt.make.core.activeConfigSettings</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableAutoBuild</key>
|
||||
<value>false</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableCleanBuild</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.enableFullBuild</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.fullBuildTarget</key>
|
||||
<value>all</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.stopOnError</key>
|
||||
<value>true</value>
|
||||
</dictionary>
|
||||
<dictionary>
|
||||
<key>org.eclipse.cdt.make.core.useDefaultBuildCmd</key>
|
||||
<value>false</value>
|
||||
</dictionary>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
<buildCommand>
|
||||
<name>org.eclipse.cdt.managedbuilder.core.ScannerConfigBuilder</name>
|
||||
<arguments>
|
||||
</arguments>
|
||||
</buildCommand>
|
||||
</buildSpec>
|
||||
<natures>
|
||||
<nature>org.eclipse.cdt.core.cnature</nature>
|
||||
<nature>org.eclipse.cdt.core.ccnature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.managedBuildNature</nature>
|
||||
<nature>org.eclipse.cdt.managedbuilder.core.ScannerConfigNature</nature>
|
||||
</natures>
|
||||
</projectDescription>
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+47
-13
@@ -14,7 +14,7 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
|
||||
#######################
|
||||
# VERSION
|
||||
#######################
|
||||
SET(PROJECT_VERSION "0.3.2")
|
||||
SET(PROJECT_VERSION "0.4.0")
|
||||
|
||||
STRING(REGEX MATCHALL "[0-9]" PROJECT_VERSION_PARTS "${PROJECT_VERSION}")
|
||||
|
||||
@@ -45,9 +45,9 @@ ENDIF()
|
||||
|
||||
IF(MINGW)
|
||||
# Hide the --enable-auto-import warning
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "-enable-auto-import")
|
||||
SET(CMAKE_MODULE_LINKER_FLAGS "-enable-auto-import")
|
||||
SET(CMAKE_SHARED_LINKER_FLAGS "-enable-auto-import")
|
||||
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--enable-auto-import")
|
||||
SET(CMAKE_MODULE_LINKER_FLAGS "-Wl,--enable-auto-import")
|
||||
SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--enable-auto-import")
|
||||
ENDIF(MINGW)
|
||||
|
||||
# GCC 4 required
|
||||
@@ -82,7 +82,10 @@ ELSEIF(APPLE)
|
||||
ENDIF()
|
||||
|
||||
####### Build libraries as shared or static #######
|
||||
OPTION(BUILD_SHARED_LIBS "Set to OFF to build static libraries" ON)
|
||||
# It is a bit messed up on Windows between STATIC and SHARED, if we don't want
|
||||
# to add UtiLite_DEFINITIONS in FindUtiLite.cmake... to know from 3rd party application if it needs to
|
||||
# link dynamically [UTILITE_EXP __declspec( dllimport )] or statically (UTILITE_EXP "nothing").
|
||||
OPTION( BUILD_SHARED_LIBS "Set to OFF to build static libraries" ON )
|
||||
|
||||
####### SET RPATH #########
|
||||
# When RPATH is activated (supported on most UNIX systems),
|
||||
@@ -107,6 +110,12 @@ SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
|
||||
SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/bin)
|
||||
SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${PROJECT_SOURCE_DIR}/lib)
|
||||
|
||||
####### BUILD OPTIONS #######
|
||||
OPTION(BUILD_TESTS "Set to ON to build tests" OFF)
|
||||
OPTION(BUILD_LIBS_ONLY "Set to ON to build only the libraries" OFF)
|
||||
IF(APPLE AND BUILD_AS_BUNDLE)
|
||||
OPTION(BUILD_AS_BUNDLE "Set to ON to build as bundle (DragNDrop)" OFF)
|
||||
ENDIF(APPLE AND BUILD_AS_BUNDLE)
|
||||
|
||||
####### DEPENDENCIES #######
|
||||
FIND_PACKAGE(UtiLite REQUIRED)
|
||||
@@ -114,18 +123,30 @@ FIND_PACKAGE(OpenCV REQUIRED)
|
||||
FIND_PACKAGE(Sqlite3 REQUIRED)
|
||||
FIND_PACKAGE(FFTW3F REQUIRED)
|
||||
FIND_PACKAGE(ZLIB REQUIRED)
|
||||
|
||||
# If Qt is here, the GUI will be built
|
||||
FIND_PACKAGE(Qt4 COMPONENTS QtCore QtGui QtSvg)
|
||||
# If CppUnit is here, the test will be built
|
||||
FIND_PACKAGE(CppUnit)
|
||||
|
||||
IF(BUILD_TESTS)
|
||||
# If CppUnit is here, the tests will be built
|
||||
FIND_PACKAGE(CppUnit REQUIRED)
|
||||
ENDIF(BUILD_TESTS)
|
||||
|
||||
####### OSX BUNDLE CMAKE_INSTALL_PREFIX #######
|
||||
OPTION(BUILD_AS_BUNDLE "Set to ON to build as bundle (DragNDrop)" OFF)
|
||||
IF(APPLE AND BUILD_AS_BUNDLE)
|
||||
IF(QT4_FOUND AND QT_QTCORE_FOUND AND QT_QTGUI_FOUND)
|
||||
|
||||
#Force to Off, easiest to package into the bundle
|
||||
SET( BUILD_SHARED_LIBS OFF )
|
||||
IF(BUILD_SHARED_LIBS)
|
||||
MESSAGE(STATUS "As BUILD_AS_BUNDLE=ON, set BUILD_SHARED_LIBS=OFF")
|
||||
SET( BUILD_SHARED_LIBS OFF )
|
||||
ENDIF(BUILD_SHARED_LIBS)
|
||||
|
||||
#Must create app, so force to off BUILD_LIBS_ONLY
|
||||
IF(BUILD_LIBS_ONLY)
|
||||
MESSAGE(STATUS "As BUILD_AS_BUNDLE=ON, set BUILD_LIBS_ONLY=OFF")
|
||||
SET( BUILD_LIBS_ONLY OFF )
|
||||
ENDIF(BUILD_LIBS_ONLY)
|
||||
|
||||
# Required when packaging, and set CMAKE_INSTALL_PREFIX to "/".
|
||||
SET(CPACK_SET_DESTDIR TRUE)
|
||||
@@ -153,16 +174,24 @@ ENDIF(APPLE AND BUILD_AS_BUNDLE)
|
||||
|
||||
####### SOURCES (Projects) #######
|
||||
ADD_SUBDIRECTORY( corelib )
|
||||
INCLUDE_DIRECTORIES(corelib/include/)
|
||||
|
||||
IF(QT4_FOUND AND QT_QTCORE_FOUND AND QT_QTGUI_FOUND)
|
||||
ADD_SUBDIRECTORY( guilib )
|
||||
INCLUDE_DIRECTORIES(guilib/include/)
|
||||
ADD_SUBDIRECTORY( app )
|
||||
IF(NOT BUILD_LIBS_ONLY)
|
||||
ADD_SUBDIRECTORY( app )
|
||||
ENDIF(NOT BUILD_LIBS_ONLY)
|
||||
ELSE()
|
||||
MESSAGE(STATUS "[WARNING] Qt4 not found, the GUI lib and the stand-alone application will not be compiled...")
|
||||
ENDIF()
|
||||
|
||||
IF(NOT BUILD_LIBS_ONLY)
|
||||
ADD_SUBDIRECTORY( tools )
|
||||
ENDIF(NOT BUILD_LIBS_ONLY)
|
||||
|
||||
IF(BUILD_TESTS)
|
||||
ADD_SUBDIRECTORY( tests )
|
||||
ENDIF(BUILD_TESTS)
|
||||
|
||||
#######################
|
||||
# Uninstall target, for "make uninstall"
|
||||
#######################
|
||||
@@ -271,7 +300,12 @@ MESSAGE(STATUS "--------------------------------------------")
|
||||
MESSAGE(STATUS "Info :")
|
||||
MESSAGE(STATUS " CMAKE_INSTALL_PREFIX = ${CMAKE_INSTALL_PREFIX}")
|
||||
MESSAGE(STATUS " CMAKE_BUILD_TYPE = ${CMAKE_BUILD_TYPE}")
|
||||
MESSAGE(STATUS " BUILD_SHARED_LIBS = ${BUILD_SHARED_LIBS}")
|
||||
IF(NOT WIN32)
|
||||
# see comment above for the BUILD_SHARED_LIBS option on Windows
|
||||
MESSAGE(STATUS " BUILD_SHARED_LIBS = ${BUILD_SHARED_LIBS}")
|
||||
ENDIF(NOT WIN32)
|
||||
MESSAGE(STATUS " BUILD_LIBS_ONLY = ${BUILD_LIBS_ONLY}")
|
||||
MESSAGE(STATUS " BUILD_TESTS = ${BUILD_TESTS}")
|
||||
IF(APPLE)
|
||||
MESSAGE(STATUS " BUILD_AS_BUNDLE = ${BUILD_AS_BUNDLE}")
|
||||
ENDIF(APPLE)
|
||||
|
||||
@@ -13,6 +13,8 @@ SET(SRC_FILES
|
||||
)
|
||||
|
||||
SET(INCLUDE_DIRS
|
||||
${PROJECT_SOURCE_DIR}/corelib/include
|
||||
${PROJECT_SOURCE_DIR}/guilib/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${UTILITE_INCLUDE_DIRS}
|
||||
${OpenCV_INCLUDE_DIRS}
|
||||
@@ -58,7 +60,7 @@ IF(APPLE AND BUILD_AS_BUNDLE)
|
||||
ELSE()
|
||||
ADD_EXECUTABLE(main_app WIN32 ${SRC_FILES})
|
||||
ENDIF()
|
||||
TARGET_LINK_LIBRARIES(main_app corelib guilib ${LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(main_app rtabmap_corelib rtabmap_guilib ${LIBRARIES})
|
||||
|
||||
IF(APPLE AND BUILD_AS_BUNDLE)
|
||||
SET_TARGET_PROPERTIES(main_app PROPERTIES
|
||||
|
||||
+1
-2
@@ -44,8 +44,7 @@ int main(int argc, char* argv[])
|
||||
|
||||
/* Add handlers to the EventsManager */
|
||||
UEventsManager::addHandler(mainWindow);
|
||||
UEventsManager::removeHandler(rtabmap); // Force removing for rtabmap to be the last.. FIXME: Rtabmap object should not register to EventsManager in its constructor...
|
||||
UEventsManager::addHandler(rtabmap); //thread
|
||||
UEventsManager::addHandler(rtabmap);
|
||||
|
||||
/* Start thread's task */
|
||||
mainWindow->showNormal();
|
||||
|
||||
Binary file not shown.
@@ -1,79 +1,111 @@
|
||||
# - Find UTILITE
|
||||
# This module finds an installed UTILITE package.
|
||||
# - Find UtiLite
|
||||
# This module finds an installed UtiLite package.
|
||||
#
|
||||
# It sets the following variables:
|
||||
# UTILITE_FOUND - Set to false, or undefined, if UTILITE isn't found.
|
||||
# UTILITE_INCLUDE_DIRS - The UTILITE include directory.
|
||||
# UTILITE_LIBRARIES - The UTILITE library to link against.
|
||||
# UtiLite_FOUND - Set to false, or undefined, if UtiLite isn't found.
|
||||
# UtiLite_INCLUDE_DIRS - The UtiLite include directory.
|
||||
# UtiLite_LIBRARIES - The UtiLite library to link against.
|
||||
# URESOURCEGENERATOR_EXEC - The resource generator tool executable
|
||||
#
|
||||
# Backward compatibility:
|
||||
# UTILITE_FOUND - Set to false, or undefined, if UtiLite isn't found.
|
||||
# UTILITE_INCLUDE_DIRS - The UtiLite include directory.
|
||||
# UTILITE_LIBRARIES - The UtiLite library to link against.
|
||||
# UTILITE_INCLUDE_DIR - The UtiLite include directory.
|
||||
# UTILITE_LIBRARY - The UtiLite library to link against.
|
||||
#
|
||||
#
|
||||
|
||||
SET(UTILITE_VERSION_REQUIRED 0.2.13)
|
||||
SET(UtiLite_VERSION_REQUIRED 0.2.14)
|
||||
|
||||
SET(UTILITE_ROOT)
|
||||
SET(UtiLite_ROOT)
|
||||
|
||||
# Add ROS UtiLite directory if ROS is installed
|
||||
FIND_PROGRAM(ROSPACK_EXEC NAME rospack PATHS)
|
||||
IF(ROSPACK_EXEC)
|
||||
EXECUTE_PROCESS(COMMAND ${ROSPACK_EXEC} find utilite
|
||||
OUTPUT_VARIABLE UTILITE_ROS_PATH
|
||||
OUTPUT_VARIABLE UtiLite_ROS_PATH
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
WORKING_DIRECTORY "./"
|
||||
)
|
||||
IF(UTILITE_ROS_PATH)
|
||||
MESSAGE(STATUS "Found UtiLite ROS pkg : ${UTILITE_ROS_PATH}")
|
||||
SET(UTILITE_ROOT
|
||||
${UTILITE_ROS_PATH}/utilite
|
||||
${UTILITE_ROOT}
|
||||
IF(UtiLite_ROS_PATH)
|
||||
MESSAGE(STATUS "Found UtiLite ROS pkg : ${UtiLite_ROS_PATH}")
|
||||
SET(UtiLite_ROOT
|
||||
${UtiLite_ROS_PATH}/utilite
|
||||
${UtiLite_ROOT}
|
||||
)
|
||||
ENDIF(UTILITE_ROS_PATH)
|
||||
ENDIF(UtiLite_ROS_PATH)
|
||||
ENDIF(ROSPACK_EXEC)
|
||||
|
||||
FIND_PROGRAM(URESOURCEGENERATOR_EXEC NAME uresourcegenerator PATHS ${UTILITE_ROOT}/bin)
|
||||
FIND_PROGRAM(URESOURCEGENERATOR_EXEC NAME uresourcegenerator PATHS ${UtiLite_ROOT}/bin)
|
||||
IF(URESOURCEGENERATOR_EXEC)
|
||||
EXECUTE_PROCESS(COMMAND ${URESOURCEGENERATOR_EXEC} -v
|
||||
OUTPUT_VARIABLE UTILITE_VERSION
|
||||
OUTPUT_VARIABLE UtiLite_VERSION
|
||||
OUTPUT_STRIP_TRAILING_WHITESPACE
|
||||
WORKING_DIRECTORY "./"
|
||||
)
|
||||
|
||||
IF(UTILITE_VERSION VERSION_LESS UTILITE_VERSION_REQUIRED)
|
||||
IF(UtiLite_VERSION VERSION_LESS UtiLite_VERSION_REQUIRED)
|
||||
IF(UtiLite_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Your version of UtiLite is too old (${UTILITE_VERSION}), UtiLite ${UTILITE_VERSION_REQUIRED} is required.")
|
||||
MESSAGE(FATAL_ERROR "Your version of UtiLite is too old (${UtiLite_VERSION}), UtiLite ${UtiLite_VERSION_REQUIRED} is required.")
|
||||
ENDIF(UtiLite_FIND_REQUIRED)
|
||||
ENDIF(UTILITE_VERSION VERSION_LESS UTILITE_VERSION_REQUIRED)
|
||||
ENDIF(UtiLite_VERSION VERSION_LESS UtiLite_VERSION_REQUIRED)
|
||||
|
||||
IF(WIN32)
|
||||
FIND_PATH(UTILITE_INCLUDE_DIRS
|
||||
FIND_PATH(UtiLite_INCLUDE_DIRS
|
||||
utilite/UEventsManager.h
|
||||
PATH_SUFFIXES "../include")
|
||||
|
||||
FIND_LIBRARY(UTILITE_LIBRARIES NAMES utilite
|
||||
FIND_LIBRARY(UtiLite_LIBRARIES
|
||||
NAMES utilite
|
||||
PATH_SUFFIXES "../lib")
|
||||
FIND_LIBRARY(UtiLite_Qt
|
||||
NAMES utilite_qt
|
||||
PATH_SUFFIXES "../lib")
|
||||
FIND_LIBRARY(UtiLite_Audio
|
||||
NAMES utilite_audio
|
||||
PATH_SUFFIXES "../lib")
|
||||
|
||||
ELSE()
|
||||
FIND_PATH(UTILITE_INCLUDE_DIRS
|
||||
FIND_PATH(UtiLite_INCLUDE_DIRS
|
||||
utilite/UEventsManager.h
|
||||
PATHS ${UTILITE_ROOT}/include)
|
||||
PATHS ${UtiLite_ROOT}/include)
|
||||
|
||||
FIND_LIBRARY(UTILITE_LIBRARIES
|
||||
FIND_LIBRARY(UtiLite_LIBRARIES
|
||||
NAMES utilite
|
||||
PATHS ${UTILITE_ROOT}/lib)
|
||||
PATHS ${UtiLite_ROOT}/lib)
|
||||
FIND_LIBRARY(UtiLite_Qt
|
||||
NAMES utilite_qt
|
||||
PATHS ${UtiLite_ROOT}/lib)
|
||||
FIND_LIBRARY(UtiLite_Audio
|
||||
NAMES utilite_audio
|
||||
PATHS ${UtiLite_ROOT}/lib)
|
||||
ENDIF()
|
||||
IF(UtiLite_LIBRARIES AND UtiLite_Qt)
|
||||
SET(UtiLite_LIBRARIES ${UtiLite_LIBRARIES} ${UtiLite_Qt})
|
||||
ENDIF(UtiLite_LIBRARIES AND UtiLite_Qt)
|
||||
IF(UtiLite_LIBRARIES AND UtiLite_Audio)
|
||||
SET(UtiLite_LIBRARIES ${UtiLite_LIBRARIES} ${UtiLite_Audio})
|
||||
ENDIF(UtiLite_LIBRARIES AND UtiLite_Audio)
|
||||
|
||||
IF (UTILITE_INCLUDE_DIRS AND UTILITE_LIBRARIES)
|
||||
SET(UTILITE_FOUND TRUE)
|
||||
ENDIF (UTILITE_INCLUDE_DIRS AND UTILITE_LIBRARIES)
|
||||
IF (UtiLite_INCLUDE_DIRS AND UtiLite_LIBRARIES)
|
||||
SET(UtiLite_FOUND TRUE)
|
||||
ENDIF (UtiLite_INCLUDE_DIRS AND UtiLite_LIBRARIES)
|
||||
ENDIF(URESOURCEGENERATOR_EXEC)
|
||||
|
||||
IF (UTILITE_FOUND)
|
||||
# show which UTILITE was found only if not quiet
|
||||
IF (UtiLite_FOUND)
|
||||
# show which UtiLite was found only if not quiet
|
||||
IF (NOT UtiLite_FIND_QUIETLY)
|
||||
MESSAGE(STATUS "Found UtiLite ${UTILITE_VERSION}")
|
||||
MESSAGE(STATUS "Found UtiLite ${UtiLite_VERSION}")
|
||||
ENDIF (NOT UtiLite_FIND_QUIETLY)
|
||||
# backward compatibility...
|
||||
SET(UTILITE_FOUND ${UtiLite_FOUND})
|
||||
SET(UTILITE_INCLUDE_DIRS ${UtiLite_INCLUDE_DIRS})
|
||||
SET(UTILITE_LIBRARIES ${UtiLite_LIBRARIES})
|
||||
SET(UTILITE_INCLUDE_DIR ${UtiLite_INCLUDE_DIRS})
|
||||
SET(UTILITE_LIBRARY ${UtiLite_LIBRARIES})
|
||||
ELSE ()
|
||||
# fatal error if UTILITE is required but not found
|
||||
# fatal error if UtiLite is required but not found
|
||||
IF (UtiLite_FIND_REQUIRED)
|
||||
MESSAGE(FATAL_ERROR "Could not find UtiLite. Verify your PATH if it is already installed or download it at http://utilite.googlecode.com")
|
||||
ENDIF (UtiLite_FIND_REQUIRED)
|
||||
|
||||
+1
-20
@@ -1,20 +1 @@
|
||||
ADD_SUBDIRECTORY( src )
|
||||
ADD_SUBDIRECTORY( ConsoleApp )
|
||||
ADD_SUBDIRECTORY( ImagesJoiner )
|
||||
ADD_SUBDIRECTORY( WebcamCapture )
|
||||
ADD_SUBDIRECTORY( LogPolar )
|
||||
ADD_SUBDIRECTORY( ImagesDbExtractor )
|
||||
ADD_SUBDIRECTORY( ColorIndexesGenerator )
|
||||
|
||||
IF(QT4_FOUND AND QT_QTCORE_FOUND AND QT_QTGUI_FOUND)
|
||||
ADD_SUBDIRECTORY( DatabaseViewer )
|
||||
ELSE()
|
||||
MESSAGE(STATUS "[WARNING] Qt4 not found, the databaseViewer program will not be built...")
|
||||
ENDIF()
|
||||
|
||||
IF(CPPUNIT_FOUND)
|
||||
ADD_SUBDIRECTORY( tests )
|
||||
#MESSAGE(STATUS "Tests are desactivated...")
|
||||
ELSE(CPPUNIT_FOUND)
|
||||
MESSAGE(STATUS "CppUnit is not found, tests for the ${PROJECT_NAME} project won't be compiled...")
|
||||
ENDIF(CPPUNIT_FOUND)
|
||||
ADD_SUBDIRECTORY( src )
|
||||
+53
-52
@@ -1,52 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2011, Mathieu Labbe and IntRoLab - Universite de Sherbrooke
|
||||
*
|
||||
* This file is part of RTAB-Map.
|
||||
*
|
||||
* RTAB-Map is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* RTAB-Map is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CAMERAEVENT_H_
|
||||
#define CAMERAEVENT_H_
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include "utilite/UEvent.h"
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
|
||||
class RTABMAP_EXP CameraEvent :
|
||||
public UEvent
|
||||
{
|
||||
public:
|
||||
enum Code {
|
||||
kCodeNoMoreImages
|
||||
};
|
||||
|
||||
public:
|
||||
CameraEvent() :
|
||||
UEvent(kCodeNoMoreImages)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CameraEvent() {}
|
||||
|
||||
virtual std::string getClassName() const {return std::string("CameraEvent");}
|
||||
};
|
||||
|
||||
} // namespace rtabmap
|
||||
|
||||
#endif /* CAMERAEVENT_H_ */
|
||||
/*
|
||||
* Copyright (C) 2010-2011, Mathieu Labbe and IntRoLab - Universite de Sherbrooke
|
||||
*
|
||||
* This file is part of RTAB-Map.
|
||||
*
|
||||
* RTAB-Map is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* RTAB-Map is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef ACTUATOR_H_
|
||||
#define ACTUATOR_H_
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <utilite/UEvent.h>
|
||||
#include <list>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
class Actuator
|
||||
{
|
||||
public:
|
||||
enum Type{kTypeTwist=0, kTypeNotSpecified};
|
||||
public:
|
||||
Actuator(const cv::Mat & data, Type type, int num = 0) :
|
||||
_data(data),
|
||||
_type(type),
|
||||
_num(num)
|
||||
{}
|
||||
const cv::Mat & data() const {return _data;}
|
||||
int type() const {return _type;}
|
||||
int num() const {return _num;}
|
||||
virtual ~Actuator() {};
|
||||
private:
|
||||
cv::Mat _data;
|
||||
int _type;
|
||||
int _num;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* ACTUATOR_H_ */
|
||||
@@ -53,11 +53,11 @@ public:
|
||||
std::string getPredictionLCStr() const; // for convenience {Vp, Lc, l1, l2, l3, l4...}
|
||||
bool isPredictionOnNonNullActionsOnly() const {return _predictionOnNonNullActionsOnly;}
|
||||
|
||||
bool generatePrediction(CvMat * prediction, const Memory * memory, const std::vector<int> & ids) const;
|
||||
bool generatePrediction(cv::Mat & prediction, const Memory * memory, const std::vector<int> & ids) const;
|
||||
|
||||
private:
|
||||
void updatePosterior(const Memory * memory, const std::vector<int> & likelihoodIds);
|
||||
float addNeighborProb(CvMat * prediction, unsigned int col, const std::map<int, int> & neighbors, const std::map<int, int> & idToIndexMap) const;
|
||||
float addNeighborProb(cv::Mat & prediction, unsigned int col, const std::map<int, int> & neighbors, const std::map<int, int> & idToIndexMap) const;
|
||||
|
||||
private:
|
||||
std::map<int, float> _posterior;
|
||||
@@ -22,60 +22,69 @@
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
#include "utilite/UThreadNode.h"
|
||||
#include "utilite/UEventsHandler.h"
|
||||
#include <opencv2/features2d/features2d.hpp>
|
||||
#include <utilite/UThreadNode.h>
|
||||
#include <utilite/UEventsHandler.h>
|
||||
#include <utilite/UEvent.h>
|
||||
#include <utilite/UDirectory.h>
|
||||
#include <utilite/UTimer.h>
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "rtabmap/core/KeypointDetector.h"
|
||||
#include "rtabmap/core/KeypointDescriptor.h"
|
||||
#include <set>
|
||||
#include <stack>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
class UDirectory;
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
|
||||
class KeypointDetector;
|
||||
class KeypointDescriptor;
|
||||
class SMState;
|
||||
|
||||
/**
|
||||
* No treatment
|
||||
*/
|
||||
class RTABMAP_EXP CamPostTreatment
|
||||
class CameraEvent :
|
||||
public UEvent
|
||||
{
|
||||
public:
|
||||
CamPostTreatment(const ParametersMap & parameters = ParametersMap()) {
|
||||
this->parseParameters(parameters);
|
||||
}
|
||||
virtual ~CamPostTreatment() {}
|
||||
virtual void process(SMState * smState) const;
|
||||
virtual void parseParameters(const ParametersMap & parameters) {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Extract keypoints from the image
|
||||
*/
|
||||
class RTABMAP_EXP CamKeypointTreatment : public CamPostTreatment
|
||||
{
|
||||
public:
|
||||
enum DetectorStrategy {kDetectorSurf, kDetectorStar, kDetectorSift, kDetectorFast, kDetectorUndef};
|
||||
enum DescriptorStrategy {kDescriptorSurf, kDescriptorSift, kDescriptorBrief, kDescriptorColor, kDescriptorHue, kDescriptorUndef};
|
||||
enum Code {
|
||||
kCodeFeatures,
|
||||
kCodeImage,
|
||||
kCodeNoMoreImages
|
||||
};
|
||||
|
||||
public:
|
||||
CamKeypointTreatment(const ParametersMap & parameters = ParametersMap()) :
|
||||
_keypointDetector(0),
|
||||
_keypointDescriptor(0)
|
||||
CameraEvent(const cv::Mat & image, int cameraId = 0) :
|
||||
UEvent(kCodeImage),
|
||||
_cameraId(cameraId),
|
||||
_image(image)
|
||||
{
|
||||
this->parseParameters(parameters);
|
||||
}
|
||||
virtual ~CamKeypointTreatment();
|
||||
virtual void process(SMState * smState) const;
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
DetectorStrategy detectorStrategy() const;
|
||||
CameraEvent(const cv::Mat & descriptors, const std::vector<cv::KeyPoint> & keypoints, const cv::Mat & image = cv::Mat(), int cameraId = 0) :
|
||||
UEvent(kCodeFeatures),
|
||||
_cameraId(cameraId),
|
||||
_image(image),
|
||||
_descriptors(descriptors),
|
||||
_keypoints(keypoints)
|
||||
{
|
||||
}
|
||||
CameraEvent(int cameraId = 0) :
|
||||
UEvent(kCodeNoMoreImages),
|
||||
_cameraId(cameraId)
|
||||
{
|
||||
}
|
||||
|
||||
int cameraId() const {return _cameraId;}
|
||||
|
||||
// Image or descriptors
|
||||
const cv::Mat & image() const {return _image;}
|
||||
const cv::Mat & descriptors() const {return _descriptors;}
|
||||
const std::vector<cv::KeyPoint> & keypoints() const {return _keypoints;}
|
||||
|
||||
virtual ~CameraEvent() {}
|
||||
virtual std::string getClassName() const {return std::string("CameraEvent");}
|
||||
|
||||
private:
|
||||
KeypointDetector * _keypointDetector;
|
||||
KeypointDescriptor * _keypointDescriptor;
|
||||
int _cameraId;
|
||||
cv::Mat _image;
|
||||
cv::Mat _descriptors;
|
||||
std::vector<cv::KeyPoint> _keypoints;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -91,17 +100,20 @@ public:
|
||||
|
||||
public:
|
||||
virtual ~Camera();
|
||||
|
||||
virtual IplImage * takeImage(std::list<std::vector<float> > * actions = 0) = 0;
|
||||
SMState * takeSMState();
|
||||
cv::Mat takeImage();
|
||||
cv::Mat takeImage(cv::Mat & descriptors, std::vector<cv::KeyPoint> & keypoints);
|
||||
virtual bool init() = 0;
|
||||
bool isPaused() const {return !this->isRunning();}
|
||||
bool isCapturing() const {return this->isRunning();}
|
||||
unsigned int getImageWidth() const {return _imageWidth;}
|
||||
unsigned int getImageHeight() const {return _imageHeight;}
|
||||
void setPostThreatement(CamPostTreatment * strategy); // ownership is transferred
|
||||
float getImageRate() const {return _imageRate;}
|
||||
bool isFeaturesExtracted() const {return _featuresExtracted;}
|
||||
void setFeaturesExtracted(bool featuresExtracted, KeypointDetector::DetectorType detector = KeypointDetector::kDetectorUndef, KeypointDescriptor::DescriptorType descriptor = KeypointDescriptor::kDescriptorUndef);
|
||||
void setImageRate(float imageRate) {_imageRate = imageRate;}
|
||||
void setAutoRestart(bool autoRestart) {_autoRestart = autoRestart;}
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
int id() const {return _id;}
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -109,15 +121,16 @@ protected:
|
||||
*
|
||||
* @param imageRate : image/second , 0 for fast as the camera can
|
||||
*/
|
||||
Camera(float imageRate = 0, bool autoRestart = false, unsigned int imageWidth = 0, unsigned int imageHeight = 0);
|
||||
Camera(float imageRate = 0, bool autoRestart = false, unsigned int imageWidth = 0, unsigned int imageHeight = 0, unsigned int framesDropped = 0, int id = 0);
|
||||
|
||||
virtual void handleEvent(UEvent* anEvent);
|
||||
virtual cv::Mat captureImage() = 0;
|
||||
|
||||
private:
|
||||
virtual void mainLoopBegin();
|
||||
virtual void mainLoop();
|
||||
void process();
|
||||
void pushNewState(State newState, const ParametersMap & parameters = ParametersMap());
|
||||
virtual void parseParameters(const ParametersMap & parameters) {_postThreatement->parseParameters(parameters);}
|
||||
|
||||
private:
|
||||
float _imageRate;
|
||||
@@ -125,11 +138,16 @@ private:
|
||||
bool _autoRestart;
|
||||
unsigned int _imageWidth;
|
||||
unsigned int _imageHeight;
|
||||
CamPostTreatment * _postThreatement;
|
||||
unsigned int _framesDropped;
|
||||
UTimer _frameRateTimer;
|
||||
|
||||
UMutex _stateMutex;
|
||||
std::stack<State> _state;
|
||||
std::stack<ParametersMap> _stateParam;
|
||||
|
||||
bool _featuresExtracted;
|
||||
KeypointDetector * _keypointDetector;
|
||||
KeypointDescriptor * _keypointDescriptor;
|
||||
};
|
||||
|
||||
|
||||
@@ -147,19 +165,23 @@ public:
|
||||
float imageRate = 0,
|
||||
bool autoRestart = false,
|
||||
unsigned int imageWidth = 0,
|
||||
unsigned int imageHeight = 0);
|
||||
unsigned int imageHeight = 0,
|
||||
unsigned int framesDropped = 0,
|
||||
int id = 0);
|
||||
virtual ~CameraImages();
|
||||
|
||||
virtual IplImage * takeImage(std::list<std::vector<float> > * actions = 0);
|
||||
virtual bool init();
|
||||
|
||||
protected:
|
||||
virtual cv::Mat captureImage();
|
||||
|
||||
private:
|
||||
std::string _path;
|
||||
int _startAt;
|
||||
// If the list of files in the directory is refreshed
|
||||
// on each call of takeImage()
|
||||
bool _refreshDir;
|
||||
UDirectory * _dir;
|
||||
UDirectory _dir;
|
||||
int _count;
|
||||
std::string _lastFileName;
|
||||
|
||||
@@ -184,22 +206,29 @@ public:
|
||||
float imageRate = 0,
|
||||
bool autoRestart = false,
|
||||
unsigned int imageWidth = 0,
|
||||
unsigned int imageHeight = 0);
|
||||
unsigned int imageHeight = 0,
|
||||
unsigned int framesDropped = 0,
|
||||
int id = 0);
|
||||
CameraVideo(const std::string & fileName,
|
||||
float imageRate = 0,
|
||||
bool autoRestart = false,
|
||||
unsigned int imageWidth = 0,
|
||||
unsigned int imageHeight = 0);
|
||||
unsigned int imageHeight = 0,
|
||||
unsigned int framesDropped = 0,
|
||||
int id = 0);
|
||||
virtual ~CameraVideo();
|
||||
|
||||
virtual IplImage * takeImage(std::list<std::vector<float> > * actions = 0);
|
||||
virtual bool init();
|
||||
int getUsbDevice() {return _usbDevice;}
|
||||
|
||||
protected:
|
||||
virtual cv::Mat captureImage();
|
||||
|
||||
private:
|
||||
// File type
|
||||
std::string _fileName;
|
||||
|
||||
CvCapture* _capture;
|
||||
cv::VideoCapture _capture;
|
||||
Source _src;
|
||||
|
||||
// Usb camera
|
||||
@@ -207,36 +236,4 @@ private:
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////
|
||||
// CameraDatabase
|
||||
/////////////////////////
|
||||
class DBDriver;
|
||||
class RTABMAP_EXP CameraDatabase :
|
||||
public Camera
|
||||
{
|
||||
public:
|
||||
CameraDatabase(const std::string & path,
|
||||
bool loadActions,
|
||||
float imageRate = 0,
|
||||
bool autoRestart = false,
|
||||
unsigned int imageWidth = 0,
|
||||
unsigned int imageHeight = 0);
|
||||
virtual ~CameraDatabase();
|
||||
|
||||
virtual IplImage * takeImage(std::list<std::vector<float> > * actions = 0);
|
||||
virtual bool init();
|
||||
|
||||
private:
|
||||
std::string _path;
|
||||
bool _loadActions;
|
||||
std::set<int>::iterator _indexIter;
|
||||
DBDriver * _dbDriver;
|
||||
std::set<int> _ids;
|
||||
};
|
||||
|
||||
|
||||
} // namespace rtabmap
|
||||
|
||||
@@ -10,6 +10,16 @@ namespace rtabmap
|
||||
{
|
||||
class RTABMAP_EXP ColorTable
|
||||
{
|
||||
public:
|
||||
enum Size{kSize8 = 8,
|
||||
kSize16 = 16,
|
||||
kSize32 = 32,
|
||||
kSize64 = 64,
|
||||
kSize128 = 128,
|
||||
kSize256 = 256,
|
||||
kSize512 = 512,
|
||||
kSize1024 = 1024,
|
||||
kSize65536 = 65536};
|
||||
public:
|
||||
ColorTable(int size);
|
||||
virtual ~ColorTable() {}
|
||||
@@ -92,22 +92,23 @@ public:
|
||||
|
||||
// Load objects
|
||||
bool load(VWDictionary * dictionary) const;
|
||||
bool loadLastSignatures(std::list<Signature *> & signatures) const;
|
||||
bool loadLastNodes(std::list<Signature *> & signatures) const;
|
||||
bool loadKeypointSignatures(const std::list<int> & ids, std::list<Signature *> & signatures);
|
||||
bool loadSMSignatures(const std::list<int> & ids, std::list<Signature *> & signatures);
|
||||
bool loadWords(const std::list<int> & wordIds, std::list<VisualWord *> & vws);
|
||||
|
||||
// Specific queries...
|
||||
bool getImage(int id, IplImage ** img) const;
|
||||
bool getNeighborIds(int signatureId, std::list<int> & neighbors, bool onlyWithActions = false) const;
|
||||
bool getRawData(int id, std::list<Sensor> & data) const;
|
||||
bool getActuatorData(int id, std::list<Actuator> & data) const;
|
||||
bool getNeighborIds(int signatureId, std::set<int> & neighbors, bool onlyWithActions = false) const;
|
||||
bool loadNeighbors(int signatureId, NeighborsMultiMap & neighbors) const;
|
||||
bool getWeight(int signatureId, int & weight) const;
|
||||
bool getLoopClosureIds(int signatureId, std::set<int> & loopIds, std::set<int> & childIds) const;
|
||||
bool getAllSignatureIds(std::set<int> & ids) const;
|
||||
bool getLastSignatureId(int & id) const;
|
||||
bool getLastVisualWordId(int & id) const;
|
||||
bool getSurfNi(int signatureId, int & ni) const;
|
||||
bool getHighestWeightedSignatures(unsigned int count, std::multimap<int, int> & ids) const;
|
||||
bool getAllNodeIds(std::set<int> & ids) const;
|
||||
bool getLastNodeId(int & id) const;
|
||||
bool getLastWordId(int & id) const;
|
||||
bool getInvertedIndexNi(int signatureId, int & ni) const;
|
||||
bool getHighestWeightedNodeIds(unsigned int count, std::multimap<int, int> & ids) const;
|
||||
|
||||
protected:
|
||||
DBDriver(const ParametersMap & parameters = ParametersMap());
|
||||
@@ -122,7 +123,7 @@ private:
|
||||
|
||||
virtual bool changeWordsRefQuery(const std::map<int, int> & refsToChange) const = 0; // <oldWordId, activeWordId>
|
||||
virtual bool deleteWordsQuery(const std::vector<int> & ids) const = 0;
|
||||
virtual bool getNeighborIdsQuery(int signatureId, std::list<int> & neighbors, bool onlyWithActions = false) const = 0;
|
||||
virtual bool getNeighborIdsQuery(int signatureId, std::set<int> & neighbors, bool onlyWithActions = false) const = 0;
|
||||
virtual bool getWeightQuery(int signatureId, int & weight) const = 0;
|
||||
virtual bool getLoopClosureIdsQuery(int signatureId, std::set<int> & loopIds, std::set<int> & childIds) const = 0;
|
||||
|
||||
@@ -132,7 +133,7 @@ private:
|
||||
|
||||
// Load objects
|
||||
virtual bool loadQuery(VWDictionary * dictionary) const = 0;
|
||||
virtual bool loadLastSignaturesQuery(std::list<Signature *> & signatures) const = 0;
|
||||
virtual bool loadLastNodesQuery(std::list<Signature *> & signatures) const = 0;
|
||||
virtual bool loadQuery(int signatureId, Signature ** s) const = 0;
|
||||
virtual bool loadQuery(int wordId, VisualWord ** vw) const = 0;
|
||||
virtual bool loadQuery(int signatureId, KeypointSignature * ss) const = 0;
|
||||
@@ -142,12 +143,13 @@ private:
|
||||
virtual bool loadWordsQuery(const std::list<int> & wordIds, std::list<VisualWord *> & vws) const = 0;
|
||||
virtual bool loadNeighborsQuery(int signatureId, NeighborsMultiMap & neighbors) const = 0;
|
||||
|
||||
virtual bool getImageQuery(int id, IplImage ** image) const = 0;
|
||||
virtual bool getAllSignatureIdsQuery(std::set<int> & ids) const = 0;
|
||||
virtual bool getLastSignatureIdQuery(int & id) const = 0;
|
||||
virtual bool getLastVisualWordIdQuery(int & id) const = 0;
|
||||
virtual bool getSurfNiQuery(int signatureId, int & ni) const = 0;
|
||||
virtual bool getHighestWeightedSignaturesQuery(unsigned int count, std::multimap<int,int> & signatures) const = 0;
|
||||
virtual bool getRawDataQuery(int id, std::list<Sensor> & rawData) const = 0;
|
||||
virtual bool getActuatorDataQuery(int id, std::list<Actuator> & rawData) const = 0;
|
||||
virtual bool getAllNodeIdsQuery(std::set<int> & ids) const = 0;
|
||||
virtual bool getLastNodeIdQuery(int & id) const = 0;
|
||||
virtual bool getLastWordIdQuery(int & id) const = 0;
|
||||
virtual bool getInvertedIndexNiQuery(int signatureId, int & ni) const = 0;
|
||||
virtual bool getHighestWeightedNodeIdsQuery(unsigned int count, std::multimap<int,int> & signatures) const = 0;
|
||||
|
||||
private:
|
||||
//non-abstract methods
|
||||
@@ -167,7 +169,6 @@ private:
|
||||
unsigned int _minSignaturesToSave;
|
||||
unsigned int _minWordsToSave;
|
||||
bool _imagesCompressed;
|
||||
bool _asyncWaiting;
|
||||
double _emptyTrashesTime;
|
||||
std::string _url;
|
||||
};
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* DBReader.h
|
||||
*
|
||||
* Created on: 2012-06-13
|
||||
* Author: mathieu
|
||||
*/
|
||||
|
||||
#ifndef DBREADER_H_
|
||||
#define DBREADER_H_
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include "rtabmap/core/Sensor.h"
|
||||
#include "rtabmap/core/Actuator.h"
|
||||
|
||||
#include <utilite/UThreadNode.h>
|
||||
#include <utilite/UTimer.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
class DBDriver;
|
||||
|
||||
class RTABMAP_EXP DBReader : public UThreadNode {
|
||||
public:
|
||||
DBReader(const std::string & databasePath,
|
||||
float frameRate = 0.0f,
|
||||
const std::set<Sensor::Type> & sensorTypes = std::set<Sensor::Type>(),
|
||||
const std::set<Actuator::Type> & actuatorTypes = std::set<Actuator::Type>());
|
||||
virtual ~DBReader();
|
||||
|
||||
bool init();
|
||||
void setFrameRate(float frameRate);
|
||||
void getNextSensorimotorState(std::list<Sensor> & sensors, std::list<Actuator> & actuators);
|
||||
|
||||
protected:
|
||||
virtual void mainLoopBegin();
|
||||
virtual void mainLoop();
|
||||
|
||||
private:
|
||||
std::string _path;
|
||||
float _frameRate;
|
||||
std::set<Sensor::Type> _sensorTypes;
|
||||
std::set<Actuator::Type> _actuatorTypes;
|
||||
|
||||
DBDriver * _dbDriver;
|
||||
UTimer _timer;
|
||||
std::set<int> _ids;
|
||||
std::set<int>::iterator _currentId;
|
||||
};
|
||||
|
||||
} /* namespace rtabmap */
|
||||
#endif /* DBREADER_H_ */
|
||||
@@ -22,12 +22,63 @@
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/features2d/features2d.hpp>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
|
||||
//epipolar geometry
|
||||
void RTABMAP_EXP findEpipolesFromF(const cv::Mat & fundamentalMatrix, cv::Vec3d & e1, cv::Vec3d & e2);
|
||||
void RTABMAP_EXP findPFromF(const cv::Mat & fundamentalMatrix, cv::Mat & p2, cv::Vec3d e2 = cv::Vec3d());
|
||||
void RTABMAP_EXP findEpipolesFromF(
|
||||
const cv::Mat & fundamentalMatrix,
|
||||
cv::Vec3d & e1,
|
||||
cv::Vec3d & e2);
|
||||
|
||||
cv::Mat RTABMAP_EXP findPFromF(
|
||||
const cv::Mat & fundamentalMatrix,
|
||||
const cv::Mat & x1,
|
||||
const cv::Mat & x2);
|
||||
|
||||
// return fundamental matrix
|
||||
// status -> inliers = 1, outliers = 0
|
||||
cv::Mat RTABMAP_EXP findFFromWords(
|
||||
const std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs, // id, kpt1, kpt2
|
||||
std::vector<uchar> & status,
|
||||
double ransacParam1 = 3.0,
|
||||
double ransacParam2 = 0.99);
|
||||
|
||||
// assume a canonical camera (without K)
|
||||
void RTABMAP_EXP findRTFromP(
|
||||
const cv::Mat & p,
|
||||
cv::Mat & r,
|
||||
cv::Mat & t);
|
||||
|
||||
/**
|
||||
* 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 RTABMAP_EXP 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);
|
||||
|
||||
/**
|
||||
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(2,2) (4,4)]
|
||||
* realPairsCount = 5
|
||||
*/
|
||||
int RTABMAP_EXP 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);
|
||||
|
||||
/**
|
||||
* 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 RTABMAP_EXP 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);
|
||||
|
||||
} // namespace rtabmap
|
||||
|
||||
@@ -31,10 +31,13 @@
|
||||
namespace rtabmap {
|
||||
|
||||
class RTABMAP_EXP KeypointDescriptor {
|
||||
public:
|
||||
enum DescriptorType {kDescriptorSurf, kDescriptorSift, kDescriptorBrief, kDescriptorColor, kDescriptorHue, kDescriptorUndef};
|
||||
|
||||
public:
|
||||
virtual ~KeypointDescriptor();
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual cv::Mat generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const = 0;
|
||||
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const = 0;
|
||||
|
||||
protected:
|
||||
KeypointDescriptor(const ParametersMap & parameters = ParametersMap());
|
||||
@@ -47,10 +50,15 @@ public:
|
||||
SURFDescriptor(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~SURFDescriptor();
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual cv::Mat generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
|
||||
private:
|
||||
CvSURFParams _params;
|
||||
double _hessianThreshold;
|
||||
int _nOctaves;
|
||||
int _nOctaveLayers;
|
||||
bool _extended;
|
||||
bool _upright;
|
||||
|
||||
bool _gpuVersion;
|
||||
};
|
||||
|
||||
@@ -61,11 +69,14 @@ public:
|
||||
SIFTDescriptor(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~SIFTDescriptor();
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual cv::Mat generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
|
||||
private:
|
||||
cv::SIFT::CommonParams _commonParams;
|
||||
cv::SIFT::DescriptorParams _descriptorParams;
|
||||
int _nfeatures;
|
||||
int _nOctaveLayers;
|
||||
double _contrastThreshold;
|
||||
double _edgeThreshold;
|
||||
double _sigma;
|
||||
};
|
||||
|
||||
//BRIEFDescriptor
|
||||
@@ -75,7 +86,7 @@ public:
|
||||
BRIEFDescriptor(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~BRIEFDescriptor();
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual cv::Mat generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
|
||||
private:
|
||||
int _size;
|
||||
@@ -88,7 +99,7 @@ public:
|
||||
ColorDescriptor(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~ColorDescriptor();
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual cv::Mat generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
protected:
|
||||
void getCircularROI(int R, std::vector<int> & RxV) const;
|
||||
};
|
||||
@@ -100,7 +111,7 @@ public:
|
||||
HueDescriptor(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~HueDescriptor();
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual cv::Mat generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
virtual cv::Mat generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
|
||||
private:
|
||||
// assuming that rgb values are normalized [0,1]
|
||||
float rgb2hue(float r, float g, float b) const;
|
||||
|
||||
@@ -35,25 +35,22 @@ class VWDictionary;
|
||||
|
||||
class RTABMAP_EXP KeypointDetector
|
||||
{
|
||||
public:
|
||||
enum DetectorType {kDetectorSurf, kDetectorStar, kDetectorSift, kDetectorFast, kDetectorUndef};
|
||||
|
||||
public:
|
||||
virtual ~KeypointDetector() {}
|
||||
std::vector<cv::KeyPoint> generateKeypoints(const IplImage * image);
|
||||
std::vector<cv::KeyPoint> generateKeypoints(const cv::Mat & image);
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
unsigned int getWordsPerImageTarget() const {return _wordsPerImageTarget;}
|
||||
double getAdaptiveResponseThr() const {return _adaptiveResponseThr;}
|
||||
virtual double getMinimumResponseThr() const = 0;
|
||||
bool isUsingAdaptiveResponseThr() const {return _usingAdaptiveResponseThr;}
|
||||
void setRoi(const std::string & roi);
|
||||
cv::Rect computeRoi(const IplImage * image) const;
|
||||
cv::Rect computeRoi(const cv::Mat & image) const;
|
||||
protected:
|
||||
KeypointDetector(const ParametersMap & parameters = ParametersMap());
|
||||
void setAdaptiveResponseThr(float adaptiveResponseThr) {_adaptiveResponseThr = adaptiveResponseThr;}
|
||||
private:
|
||||
virtual std::vector<cv::KeyPoint> _generateKeypoints(const IplImage * image, const cv::Rect & roi) const = 0;
|
||||
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const = 0;
|
||||
private:
|
||||
unsigned int _wordsPerImageTarget;
|
||||
bool _usingAdaptiveResponseThr;
|
||||
double _adaptiveResponseThr;
|
||||
std::vector<float> _roiRatios; // size 4
|
||||
};
|
||||
|
||||
@@ -64,11 +61,15 @@ public:
|
||||
SURFDetector(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~SURFDetector();
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual double getMinimumResponseThr() const {return _params.hessianThreshold;};
|
||||
private:
|
||||
virtual std::vector<cv::KeyPoint> _generateKeypoints(const IplImage * image, const cv::Rect & roi) const;
|
||||
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const;
|
||||
private:
|
||||
CvSURFParams _params;
|
||||
double _hessianThreshold;
|
||||
int _nOctaves;
|
||||
int _nOctaveLayers;
|
||||
bool _extended;
|
||||
bool _upright;
|
||||
|
||||
bool _gpuVersion;
|
||||
};
|
||||
|
||||
@@ -79,12 +80,14 @@ public:
|
||||
SIFTDetector(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~SIFTDetector();
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual double getMinimumResponseThr() const {return _detectorParams.threshold;};
|
||||
private:
|
||||
virtual std::vector<cv::KeyPoint> _generateKeypoints(const IplImage * image, const cv::Rect & roi) const;
|
||||
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const;
|
||||
private:
|
||||
cv::SIFT::CommonParams _commonParams;
|
||||
cv::SIFT::DetectorParams _detectorParams;
|
||||
int _nfeatures;
|
||||
int _nOctaveLayers;
|
||||
double _contrastThreshold;
|
||||
double _edgeThreshold;
|
||||
double _sigma;
|
||||
};
|
||||
|
||||
//StarDetector
|
||||
@@ -94,11 +97,14 @@ public:
|
||||
StarDetector(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~StarDetector();
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual double getMinimumResponseThr() const {return (double)_params.responseThreshold;};
|
||||
private:
|
||||
virtual std::vector<cv::KeyPoint> _generateKeypoints(const IplImage * image, const cv::Rect & roi) const;
|
||||
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const;
|
||||
private:
|
||||
CvStarDetectorParams _params;
|
||||
int _maxSize;
|
||||
int _responseThreshold;
|
||||
int _lineThresholdProjected;
|
||||
int _lineThresholdBinarized;
|
||||
int _suppressNonmaxSize;
|
||||
};
|
||||
|
||||
//FASTDetector
|
||||
@@ -108,9 +114,8 @@ public:
|
||||
FASTDetector(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~FASTDetector();
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual double getMinimumResponseThr() const {return (double)_threshold;};
|
||||
private:
|
||||
virtual std::vector<cv::KeyPoint> _generateKeypoints(const IplImage * image, const cv::Rect & roi) const;
|
||||
virtual std::vector<cv::KeyPoint> _generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const;
|
||||
private:
|
||||
int _threshold;
|
||||
bool _nonmaxSuppression;
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include "Memory.h"
|
||||
#include "rtabmap/core/Memory.h"
|
||||
#include <opencv2/features2d/features2d.hpp>
|
||||
|
||||
namespace rtabmap {
|
||||
@@ -34,10 +34,6 @@ class KeypointDescriptor;
|
||||
|
||||
class RTABMAP_EXP KeypointMemory : public Memory
|
||||
{
|
||||
public:
|
||||
enum DetectorStrategy {kDetectorSurf, kDetectorStar, kDetectorSift, kDetectorFast, kDetectorUndef};
|
||||
enum DescriptorStrategy {kDescriptorSurf, kDescriptorSift, kDescriptorBrief, kDescriptorColor, kDescriptorHue, kDescriptorUndef};
|
||||
|
||||
public:
|
||||
KeypointMemory(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~KeypointMemory();
|
||||
@@ -56,18 +52,17 @@ public:
|
||||
const KeypointDescriptor * getKeypointDescriptor() const {return _keypointDescriptor;}
|
||||
const VWDictionary * getVWD() const {return _vwd;}
|
||||
std::multimap<int, cv::KeyPoint> getWords(int signatureId) const;
|
||||
DetectorStrategy detectorStrategy() const;
|
||||
|
||||
protected:
|
||||
virtual Signature * getSignatureLtMem(int id);
|
||||
virtual void addSignatureToStm(Signature * signature, const std::list<std::vector<float> > & actions = std::list<std::vector<float> >());
|
||||
virtual void addSignatureToStm(Signature * signature, const std::list<Actuator> & actions = std::list<Actuator>());
|
||||
virtual void clear();
|
||||
virtual void moveToTrash(Signature * s);
|
||||
virtual void preUpdate();
|
||||
|
||||
private:
|
||||
virtual void copyData(const Signature * from, Signature * to);
|
||||
virtual Signature * createSignature(int id, const SMState * rawData, bool keepRawData=false);
|
||||
virtual Signature * createSignature(int id, const std::list<Sensor> & sensors, bool keepRawData=false);
|
||||
|
||||
void disableWordsRef(int signatureId);
|
||||
void enableWordsRef(const std::list<int> & signatureIds);
|
||||
@@ -75,7 +70,6 @@ private:
|
||||
int getNi(int signatureId) const;
|
||||
|
||||
private:
|
||||
std::list<int> _commonWords;
|
||||
VWDictionary * _vwd;
|
||||
KeypointDetector * _keypointDetector;
|
||||
KeypointDescriptor * _keypointDescriptor;
|
||||
@@ -31,6 +31,8 @@
|
||||
#include <set>
|
||||
#include "utilite/UStl.h"
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include "rtabmap/core/Sensor.h"
|
||||
#include "rtabmap/core/Actuator.h"
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
@@ -38,7 +40,6 @@ class Signature;
|
||||
class NeighborLink;
|
||||
class DBDriver;
|
||||
class Node;
|
||||
class SMState;
|
||||
|
||||
class RTABMAP_EXP Memory
|
||||
{
|
||||
@@ -52,17 +53,33 @@ public:
|
||||
virtual ~Memory();
|
||||
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
bool update(const SMState * rawData, std::map<std::string, float> & stats);
|
||||
virtual bool init(const std::string & dbDriverName, const std::string & dbUrl, bool dbOverwritten = false, const ParametersMap & parameters = ParametersMap());
|
||||
virtual std::map<int, float> computeLikelihood(const Signature * signature, const std::list<int> & ids, float & maximumScore);
|
||||
bool update(const std::list<Sensor> & sensors,
|
||||
const std::list<Actuator> & actuators,
|
||||
std::map<std::string, float> & stats);
|
||||
virtual bool init(const std::string & dbDriverName,
|
||||
const std::string & dbUrl,
|
||||
bool dbOverwritten = false,
|
||||
const ParametersMap & parameters = ParametersMap());
|
||||
virtual std::map<int, float> computeLikelihood(const Signature * signature,
|
||||
const std::list<int> & ids,
|
||||
float & maximumScore);
|
||||
virtual int forget(const std::set<int> & ignoredIds = std::set<int>());
|
||||
virtual std::set<int> reactivateSignatures(const std::list<int> & ids, unsigned int maxLoaded, double & timeDbAccess);
|
||||
virtual std::set<int> reactivateSignatures(const std::list<int> & ids,
|
||||
unsigned int maxLoaded,
|
||||
double & timeDbAccess);
|
||||
|
||||
int cleanup(const std::list<int> & ignoredIds = std::list<int>());
|
||||
void emptyTrash();
|
||||
void joinTrashThread();
|
||||
bool addLoopClosureLink(int oldId, int newId);
|
||||
std::map<int, int> getNeighborsId(double & dbAccessTime, int signatureId, unsigned int margin, int maxCheckedInDatabase = -1, bool onlyWithActions = false, bool incrementMarginOnLoop = false, bool ignoreSTM = true, bool ignoreLoopIds = false) const;
|
||||
std::map<int, int> getNeighborsId(double & dbAccessTime,
|
||||
int signatureId,
|
||||
unsigned int margin,
|
||||
int maxCheckedInDatabase = -1,
|
||||
bool onlyWithActions = false,
|
||||
bool incrementMarginOnLoop = false,
|
||||
bool ignoreSTM = true,
|
||||
bool ignoreLoopIds = false) const;
|
||||
float compareOneToOne(const std::vector<int> & idsA, const std::vector<int> & idsB);
|
||||
|
||||
//getters
|
||||
@@ -70,18 +87,25 @@ public:
|
||||
unsigned int getStMemSize() const {return _stMem.size();};
|
||||
const std::set<int> & getWorkingMem() const {return _workingMem;}
|
||||
const std::set<int> & getStMem() const {return _stMem;}
|
||||
std::list<NeighborLink> getNeighborLinks(int signatureId, bool ignoreNeighborByLoopClosure = false, bool lookInDatabase = false) const;
|
||||
void getLoopClosureIds(int signatureId, std::set<int> & loopClosureIds, std::set<int> & childLoopClosureIds, bool lookInDatabase = false) const;
|
||||
std::list<NeighborLink> getNeighborLinks(int signatureId,
|
||||
bool ignoreNeighborByLoopClosure = false,
|
||||
bool lookInDatabase = false,
|
||||
bool onlyWithActions = false) const;
|
||||
void getLoopClosureIds(int signatureId,
|
||||
std::set<int> & loopClosureIds,
|
||||
std::set<int> & childLoopClosureIds,
|
||||
bool lookInDatabase = false) const;
|
||||
bool isRawDataKept() const {return _rawDataKept;}
|
||||
float getSimilarityThr() const {return _similarityThreshold;}
|
||||
std::map<int, int> getWeights() const;
|
||||
int getWeight(int id) const;
|
||||
const std::vector<int> & getLastBaseIds() const {return _lastBaseIds;}
|
||||
float getSimilarityOnlyLast() const {return _similarityOnlyLast;}
|
||||
const std::map<int, std::map<int, float> > & getSimilaritiesMap() const {return _similaritiesMap;}
|
||||
const Signature * getLastSignature() const;
|
||||
int getDatabaseMemoryUsed() const; // in bytes
|
||||
double getDbSavingTime() const;
|
||||
IplImage * getImage(int id) const;
|
||||
std::list<Sensor> getRawData(int id) const;
|
||||
bool isCommonSignatureUsed() const {return _commonSignatureUsed;}
|
||||
std::set<int> getAllSignatureIds() const;
|
||||
bool memoryChanged() const {return _memoryChanged;}
|
||||
@@ -105,20 +129,24 @@ public:
|
||||
void generateGraph(const std::string & fileName, std::set<int> ids = std::set<int>());
|
||||
void cleanLocalGraph(int id, unsigned int margin);
|
||||
void cleanLTM(int maxDepth = 10);
|
||||
void createGraph(Node * parent, unsigned int maxDepth, const std::set<int> & endIds = std::set<int>());
|
||||
void createGraph(Node * parent,
|
||||
unsigned int maxDepth,
|
||||
const std::set<int> & endIds = std::set<int>());
|
||||
|
||||
protected:
|
||||
virtual void preUpdate();
|
||||
virtual void postUpdate() {}
|
||||
|
||||
virtual void addSignatureToStm(Signature * signature, const std::list<std::vector<float> > & actions = std::list<std::vector<float> >());
|
||||
virtual void addSignatureToStm(Signature * signature,
|
||||
const std::list<Actuator> & actuators = std::list<Actuator>());
|
||||
virtual void clear();
|
||||
virtual void moveToTrash(Signature * s);
|
||||
virtual Signature * getSignatureLtMem(int id);
|
||||
|
||||
void addSignatureToWm(Signature * signature);
|
||||
Signature * _getSignature(int id) const;
|
||||
std::list<Signature *> getRemovableSignatures(int count, const std::set<int> & ignoredIds = std::set<int>());
|
||||
std::list<Signature *> getRemovableSignatures(int count,
|
||||
const std::set<int> & ignoredIds = std::set<int>());
|
||||
int getNextId();
|
||||
void initCountId();
|
||||
void rehearsal(Signature * signature, std::map<std::string, float> & stats);
|
||||
@@ -127,7 +155,9 @@ protected:
|
||||
|
||||
private:
|
||||
virtual void copyData(const Signature * from, Signature * to) = 0;
|
||||
virtual Signature * createSignature(int id, const SMState * rawData, bool keepRawData=false) = 0;
|
||||
virtual Signature * createSignature(int id,
|
||||
const std::list<Sensor> & sensors,
|
||||
bool keepRawData=false) = 0;
|
||||
|
||||
void createVirtualSignature(Signature ** signature);
|
||||
void cleanGraph(const Node * root);
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Micro.h
|
||||
*
|
||||
* Created on: Mar 5, 2012
|
||||
* Author: MatLab
|
||||
*/
|
||||
|
||||
#ifndef MICRO_H_
|
||||
#define MICRO_H_
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include <utilite/UThreadNode.h>
|
||||
#include <utilite/UTimer.h>
|
||||
#include <utilite/UEvent.h>
|
||||
#include <utilite/ULogger.h>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
class UAudioRecorder;
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
class MicroEvent :
|
||||
public UEvent
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
kTypeFrame,
|
||||
kTypeFrameFreq,
|
||||
kTypeFrameFreqSqrdMagn,
|
||||
kTypeNoMoreFrames
|
||||
};
|
||||
|
||||
public:
|
||||
// kTypeNoMoreFrames constructor
|
||||
MicroEvent(int microId = 0) :
|
||||
UEvent(kTypeNoMoreFrames),
|
||||
_sampleSize(0),
|
||||
_microId(microId)
|
||||
{
|
||||
}
|
||||
// kTypeFrame constructor
|
||||
MicroEvent(const cv::Mat & frame,
|
||||
int sampleSize,
|
||||
int fs,
|
||||
int channels,
|
||||
int microId = 0) :
|
||||
UEvent(kTypeFrame),
|
||||
_frame(frame),
|
||||
_sampleSize(sampleSize),
|
||||
_microId(microId)
|
||||
{
|
||||
}
|
||||
// kTypeFrameFreq and kTypeFrameFreqSqrdMagn constructors
|
||||
MicroEvent(Type frameType,
|
||||
const cv::Mat & frameFreq,
|
||||
int fs,
|
||||
int channels,
|
||||
int microId = 0) :
|
||||
UEvent(frameType),
|
||||
_frame(frameFreq),
|
||||
_sampleSize(sizeof(float)),
|
||||
_microId(microId)
|
||||
{
|
||||
UASSERT(frameType == kTypeFrameFreqSqrdMagn || frameType == kTypeFrameFreq);
|
||||
}
|
||||
|
||||
int type() const {return this->getCode();}
|
||||
const cv::Mat & frame() const {return _frame;}
|
||||
int sampleSize() const {return _sampleSize;}
|
||||
int microId() const {return _microId;}
|
||||
virtual ~MicroEvent() {}
|
||||
virtual std::string getClassName() const {return std::string("MicroEvent");}
|
||||
|
||||
private:
|
||||
cv::Mat _frame;
|
||||
int _sampleSize; // bytes
|
||||
int _fs; //sampling rate
|
||||
int _microId;
|
||||
};
|
||||
|
||||
class RTABMAP_EXP Micro : public UThreadNode
|
||||
{
|
||||
typedef float fftwf_complex[2];
|
||||
public:
|
||||
Micro(MicroEvent::Type eventType,
|
||||
int deviceId,
|
||||
int fs,
|
||||
int frameLength,
|
||||
int channels,
|
||||
int bytesPerSample,
|
||||
int id = 0);
|
||||
Micro(MicroEvent::Type eventType,
|
||||
const std::string & path,
|
||||
bool simulateFrameRate,
|
||||
int frameLength,
|
||||
int id = 0,
|
||||
bool playWhileRecording = false);
|
||||
virtual ~Micro();
|
||||
|
||||
bool init();
|
||||
void stop(); // same as kill() but handle the case where underlying recorder is running and not the micro.
|
||||
void startRecorder(); // must only be used if Micro::start() is not used
|
||||
|
||||
cv::Mat getFrame();
|
||||
cv::Mat getFrame(cv::Mat & frameFreq, bool sqrdMagn = false);
|
||||
|
||||
int fs();
|
||||
int bytesPerSample();
|
||||
int channels();
|
||||
int nfft();
|
||||
|
||||
protected:
|
||||
virtual void mainLoopBegin();
|
||||
virtual void mainLoop();
|
||||
virtual void mainLoopKill();
|
||||
|
||||
private:
|
||||
MicroEvent::Type _eventType;
|
||||
UAudioRecorder* _recorder;
|
||||
bool _simulateFreq;
|
||||
UTimer _timer;
|
||||
std::vector<float> _window;
|
||||
std::vector<float> _in;
|
||||
fftwf_complex * _out; // fftwf_complex
|
||||
void * _p; // fftwf_plan
|
||||
int _id;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* MICRO_H_ */
|
||||
@@ -70,6 +70,7 @@ protected:
|
||||
|
||||
/////////////////////////
|
||||
// KdTreeNN
|
||||
// FIXME KdTreeNN seems broken, it does not give same results as naive and FLANN
|
||||
/////////////////////////
|
||||
class RTABMAP_EXP KdTreeNN : public NearestNeighbor
|
||||
{
|
||||
@@ -92,12 +93,11 @@ public:
|
||||
int knn = 1,
|
||||
int emax = 64) const;
|
||||
|
||||
virtual bool isDist64F() const {return true;}
|
||||
virtual bool isDist64F() const {return false;}
|
||||
virtual bool isDistSquared() const {return false;}
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
private:
|
||||
CvFeatureTree * _tree;
|
||||
CvMat _dataMat;
|
||||
cv::KDTree _tree;
|
||||
};
|
||||
|
||||
|
||||
@@ -122,13 +122,13 @@ class RTABMAP_EXP Parameters
|
||||
// Rtabmap parameters
|
||||
RTABMAP_PARAM(Rtabmap, VhStrategy, int, 0); // None 0, Similarity 1, Epipolar 2
|
||||
RTABMAP_PARAM(Rtabmap, PublishStats, bool, true); // Publishing statistics
|
||||
RTABMAP_PARAM(Rtabmap, PublishImages, bool, true); // Publishing images
|
||||
RTABMAP_PARAM(Rtabmap, PublishRawData, bool, true); // Publishing raw data
|
||||
RTABMAP_PARAM(Rtabmap, PublishPdf, bool, true); // Publishing pdf
|
||||
RTABMAP_PARAM(Rtabmap, PublishLikelihood, bool, true); // Publishing likelihood
|
||||
RTABMAP_PARAM(Rtabmap, RetrievalThr, float, 0.0); // Reactivation threshold
|
||||
RTABMAP_PARAM(Rtabmap, TimeThr, float, 700.0); // Maximum time allowed for the detector (ms) (0 means infinity)
|
||||
RTABMAP_PARAM(Rtabmap, MemoryThr, int, 0); // Maximum signatures in the Working Memory (ms) (0 means infinity)
|
||||
RTABMAP_PARAM(Rtabmap, SMStateBufferSize, int, 1); // Data buffer size (0 min inf)
|
||||
RTABMAP_PARAM(Rtabmap, SMStateBufferSize, int, 0); // Data buffer size (0 min inf)
|
||||
RTABMAP_PARAM_STR(Rtabmap, WorkingDirectory, Parameters::getDefaultWorkingDirectory()); // Working directory
|
||||
RTABMAP_PARAM(Rtabmap, MaxRetrieved, unsigned int, 2); // Maximum locations retrieved at the same time from LTM
|
||||
RTABMAP_PARAM(Rtabmap, SelectionNeighborhoodSummationUsed, bool, false); // Neighborhood summation for hypothesis selection
|
||||
@@ -136,15 +136,16 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(Rtabmap, ActionsSentRejectHyp, bool, true); // Actions sent also on rejected hypotheses (on decreasing hypotheses)
|
||||
RTABMAP_PARAM(Rtabmap, ConfidenceThr, float, 0.0); // Actions are not sent when the loop closure hypothesis is under the confidence threshold
|
||||
RTABMAP_PARAM(Rtabmap, LikelihoodStdDevRemoved, bool, true); // Remove std dev on likelihood normalization.
|
||||
RTABMAP_PARAM(Rtabmap, LikelihoodNullValuesIgnored, bool, true); // Ignore null values on likelihood normalization
|
||||
|
||||
// Hypotheses selection
|
||||
RTABMAP_PARAM(Rtabmap, LoopThr, float, 0.15); // Loop closing threshold
|
||||
RTABMAP_PARAM(Rtabmap, LoopRatio, float, 0.0); // The loop closure hypothesis must be over LoopRatio x lastHypothesisValue
|
||||
RTABMAP_PARAM(Rtabmap, LoopRatio, float, 0.9); // The loop closure hypothesis must be over LoopRatio x lastHypothesisValue
|
||||
|
||||
// Memory
|
||||
RTABMAP_PARAM(Mem, SimilarityThr, float, 0.20); // Similarity between the last signature and neighbor
|
||||
RTABMAP_PARAM(Mem, SimilarityOnlyLast, bool, false); // Only compare to the last signature in STM, otherwise it compares to all signatures in STM
|
||||
RTABMAP_PARAM(Mem, RawDataKept, bool, false); // Keep raw data
|
||||
RTABMAP_PARAM(Mem, RawDataKept, bool, true); // Keep raw data
|
||||
RTABMAP_PARAM(Mem, MaxStMemSize, unsigned int, 30); // Short-time memory size
|
||||
RTABMAP_PARAM(Mem, CommonSignatureUsed, bool, true); // A common signature/virtual place is automatically updated with id -1
|
||||
RTABMAP_PARAM(Mem, IncrementalMemory, bool, true);
|
||||
@@ -165,7 +166,6 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(Kp, MaxLeafs, int, 64); // Maximum number of leafs checked (when using kd-trees)
|
||||
RTABMAP_PARAM(Kp, DetectorStrategy, int, 0); // Surf detector 0, Star detector 1, SIFT detector 2, FAST detector 3
|
||||
RTABMAP_PARAM(Kp, DescriptorStrategy, int, 0); // kDescriptorSurf=0, kDescriptorSift, kDescriptorBrief, kDescriptorColor, kDescriptorHue, kDescriptorUndef
|
||||
RTABMAP_PARAM(Kp, UsingAdaptiveResponseThr, bool, false);
|
||||
RTABMAP_PARAM(Kp, ReactivatedWordsComparedToNewWords, bool, true); //Reactivated words are compared to the last words added in the dictionary (which are not indexed)
|
||||
RTABMAP_PARAM(Kp, TfIdfLikelihoodUsed, bool, false); // 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
|
||||
@@ -174,11 +174,13 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM_STR(Kp, DictionaryPath, ""); // Path of the pre-computed dictionary
|
||||
|
||||
// SM memory
|
||||
RTABMAP_PARAM(SM, PublishMasks, bool, true); // Publishing motion masks
|
||||
RTABMAP_PARAM(SM, PublishMasks, bool, false); // Publishing motion masks
|
||||
RTABMAP_PARAM(SM, MotionMaskUsed, bool, false); // Use motion mask
|
||||
RTABMAP_PARAM(SM, LogPolarUsed, bool, false); // Use log-polar images
|
||||
RTABMAP_PARAM(SM, VotingSchemeUsed, bool, false); // Use likelihood voting scheme
|
||||
RTABMAP_PARAM(SM, ColorTable, int, 8); // Color table size 0=8, 1=16, 2=32, 3=64, 4=128, 5=256, 6=512, 7=1024, 8=65536
|
||||
RTABMAP_PARAM(SM, AudioDBThreshold, float, 0.0f); // Audio dB threshold
|
||||
RTABMAP_PARAM(SM, AudioDBIndexing, bool, true); // dB (decibel) indexing (otherwise it's squared magnitude indexing)
|
||||
RTABMAP_PARAM(SM, MagnitudeInvariant, bool, false); // Make audio signature magnitude-invariant
|
||||
|
||||
//Database
|
||||
RTABMAP_PARAM(Db, MinSignaturesToSave, int, 20); // Minimum signatures needed in the trash to save them (empty trash thread)
|
||||
@@ -195,11 +197,14 @@ class RTABMAP_EXP Parameters
|
||||
RTABMAP_PARAM(SURF, HessianThreshold, float, 150.0);
|
||||
RTABMAP_PARAM(SURF, Octaves, int, 4);
|
||||
RTABMAP_PARAM(SURF, OctaveLayers, int, 2);
|
||||
RTABMAP_PARAM(SURF, GpuVersion, bool, false);
|
||||
RTABMAP_PARAM(SURF, Upright, bool, false); // U-SURF
|
||||
RTABMAP_PARAM(SURF, GpuVersion, bool, false);
|
||||
|
||||
RTABMAP_PARAM(SIFT, Threshold, double, 0.006667); // true=128, false=64
|
||||
RTABMAP_PARAM(SIFT, NFeatures, int, 0);
|
||||
RTABMAP_PARAM(SIFT, NOctaveLayers, int, 3);
|
||||
RTABMAP_PARAM(SIFT, ContrastThreshold, double, 0.04);
|
||||
RTABMAP_PARAM(SIFT, EdgeThreshold, double, 10.0);
|
||||
RTABMAP_PARAM(SIFT, Sigma, double, 1.6);
|
||||
|
||||
RTABMAP_PARAM(FAST, Threshold, int, 10);
|
||||
RTABMAP_PARAM(FAST, NonmaxSuppression, bool, true);
|
||||
|
||||
@@ -17,8 +17,8 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef CTABMAP_H_
|
||||
#define CTABMAP_H_
|
||||
#ifndef RTABMAP_H_
|
||||
#define RTABMAP_H_
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
@@ -29,6 +29,8 @@
|
||||
#include "utilite/UVariant.h"
|
||||
#include "rtabmap/core/RtabmapEvent.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "rtabmap/core/Sensor.h"
|
||||
#include "rtabmap/core/Actuator.h"
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <list>
|
||||
#include <stack>
|
||||
@@ -42,7 +44,6 @@ class Signature;
|
||||
class HypVerificator;
|
||||
class Memory;
|
||||
class BayesFilter;
|
||||
class SMState;
|
||||
|
||||
class RTABMAP_EXP Rtabmap :
|
||||
public UThreadNode,
|
||||
@@ -57,7 +58,8 @@ public:
|
||||
kStateDumpingMemory,
|
||||
kStateDumpingPrediction,
|
||||
kStateGeneratingGraph,
|
||||
kStateDeletingMemory
|
||||
kStateDeletingMemory,
|
||||
kStateCleanSensorsBuffer
|
||||
};
|
||||
|
||||
enum VhStrategy {kVhNone, kVhSim, kVhEpipolar, kVhUndef};
|
||||
@@ -76,18 +78,19 @@ public:
|
||||
Rtabmap();
|
||||
virtual ~Rtabmap();
|
||||
|
||||
// ownership is transferred
|
||||
void process(SMState * data);
|
||||
void process(const std::list<Sensor> & data);
|
||||
void process(const Sensor & data); // for convenience when only one sensor is used
|
||||
void dumpData();
|
||||
|
||||
void init(const ParametersMap & param);
|
||||
void init(const char * configFile = 0);
|
||||
void clearBufferedSensors();
|
||||
|
||||
const std::string & getWorkingDir() const {return _wDir;}
|
||||
int getLoopClosureId() const;
|
||||
int getReactivatedId() const;
|
||||
int getLastSignatureId() const;
|
||||
const std::list<std::vector<float> > & getActions() const {return _actions;}
|
||||
const std::list<Actuator> & getActuator() const {return _actuators;}
|
||||
std::list<int> getWorkingMem() const;
|
||||
std::set<int> getStMem() const;
|
||||
std::map<int, int> getWeights() const;
|
||||
@@ -110,12 +113,12 @@ protected:
|
||||
|
||||
private:
|
||||
virtual void mainLoop();
|
||||
virtual void killCleanup();
|
||||
virtual void startInit();
|
||||
virtual void mainLoopKill();
|
||||
virtual void mainLoopBegin();
|
||||
void process();
|
||||
void resetMemory(bool dbOverwritten = false);
|
||||
void addSMState(SMState * data); // ownership is transferred
|
||||
SMState * getSMState();
|
||||
void addSensorimotor(const std::list<Sensor> & sensors, const std::list<Actuator> & actuators);
|
||||
void getSensorimotor(std::list<Sensor> & sensors, std::list<Actuator> & actuators);
|
||||
void setupLogFiles(bool overwrite = false);
|
||||
void releaseAllStrategies();
|
||||
void pushNewState(State newState, const ParametersMap & parameters = ParametersMap());
|
||||
@@ -125,14 +128,14 @@ private:
|
||||
private:
|
||||
// Modifiable parameters
|
||||
bool _publishStats;
|
||||
bool _publishImages;
|
||||
bool _publishRawData;
|
||||
bool _publishPdf;
|
||||
bool _publishLikelihood;
|
||||
bool _publishKeypoints;
|
||||
bool _publishMasks;
|
||||
float _maxTimeAllowed; // in ms
|
||||
unsigned int _maxMemoryAllowed; // signatures count in WM
|
||||
int _smStateBufferMaxSize;
|
||||
int _sensorsBufferMaxSize;
|
||||
float _loopThr;
|
||||
float _loopRatio;
|
||||
float _retrievalThr;
|
||||
@@ -142,20 +145,21 @@ private:
|
||||
bool _actionsSentRejectHyp;
|
||||
float _confidenceThr;
|
||||
bool _likelihoodStdDevRemoved;
|
||||
bool _likelihoodNullValuesIgnored;
|
||||
|
||||
int _lcHypothesisId;
|
||||
int _reactivateId;
|
||||
float _lastLcHypothesisValue;
|
||||
int _lastLoopClosureId;
|
||||
std::list<std::vector<float> > _actions;
|
||||
std::list<Actuator> _actuators;
|
||||
|
||||
UMutex _stateMutex;
|
||||
std::stack<State> _state;
|
||||
std::stack<ParametersMap> _stateParam;
|
||||
|
||||
std::list<SMState *> _smStateBuffer;
|
||||
UMutex _smStateBufferMutex;
|
||||
USemaphore _newSMStateSem;
|
||||
std::list<std::pair<std::list<Sensor>, std::list<Actuator> > > _sensorimotorBuffer;
|
||||
UMutex _sensorimotorMutex;
|
||||
USemaphore _sensorimotorAdded;
|
||||
|
||||
// Abstract classes containing all loop closure
|
||||
// strategies for a type of signature or configuration.
|
||||
@@ -171,6 +175,6 @@ private:
|
||||
std::string _graphFileName;
|
||||
};
|
||||
|
||||
#endif /* CTABMAP_H_ */
|
||||
#endif /* RTABMAP_H_ */
|
||||
|
||||
} // namespace rtabmap
|
||||
|
||||
@@ -22,11 +22,13 @@
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include "utilite/UEvent.h"
|
||||
#include "rtabmap/core/Sensor.h"
|
||||
#include "rtabmap/core/Actuator.h"
|
||||
#include <utilite/UEvent.h>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/features2d/features2d.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include "utilite/ULogger.h"
|
||||
#include <utilite/ULogger.h>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
|
||||
@@ -63,6 +65,7 @@ class RTABMAP_EXP Statistics
|
||||
RTABMAP_STATS(Memory, Signatures_removed,);
|
||||
RTABMAP_STATS(Memory, Signatures_retrieved,);
|
||||
RTABMAP_STATS(Memory, Images_buffered,);
|
||||
RTABMAP_STATS(Memory, Similarities_map,);
|
||||
|
||||
RTABMAP_STATS(Timing, Memory_update, ms);
|
||||
RTABMAP_STATS(Timing, Cleaning_neighbors, ms);
|
||||
@@ -90,7 +93,6 @@ public:
|
||||
|
||||
public:
|
||||
Statistics();
|
||||
Statistics(const Statistics & s);
|
||||
virtual ~Statistics();
|
||||
|
||||
// name format = "Grp/Name/unit"
|
||||
@@ -100,11 +102,9 @@ public:
|
||||
void setExtended(bool extended) {_extended = extended;}
|
||||
void setRefImageId(int refImageId) {_refImageId = refImageId;}
|
||||
void setLoopClosureId(int loopClosureId) {_loopClosureId = loopClosureId;}
|
||||
void setActions(const std::list<std::vector<float> > & actions) {_actions = actions;}
|
||||
void setRefImage(IplImage ** refImage);
|
||||
void setRefImage(const IplImage * refImage);
|
||||
void setLoopClosureImage(IplImage ** loopClosureImage);
|
||||
void setLoopClosureImage(const IplImage * loopClosureImage);
|
||||
void setActuators(const std::list<Actuator> & actuators) {_actuators = actuators;}
|
||||
void setRefRawData(const std::list<Sensor> & refRawData);
|
||||
void setLoopClosureRawData(const std::list<Sensor> & loopClosureRawData);
|
||||
void setWeights(const std::map<int, int> & weights) {_weights = weights;}
|
||||
void setPosterior(const std::map<int, float> & posterior) {_posterior = posterior;}
|
||||
void setLikelihood(const std::map<int, float> & likelihood) {_likelihood = likelihood;}
|
||||
@@ -117,9 +117,9 @@ public:
|
||||
bool extended() const {return _extended;}
|
||||
int refImageId() const {return _refImageId;}
|
||||
int loopClosureId() const {return _loopClosureId;}
|
||||
const std::list<std::vector<float> > & getActions() const {return _actions;}
|
||||
const IplImage * refImage() const {return _refImage;}
|
||||
const IplImage * loopClosureImage() const {return _loopClosureImage;}
|
||||
const std::list<Actuator> & getActuators() const {return _actuators;}
|
||||
const std::list<Sensor> & refRawData() const {return _refRawData;}
|
||||
const std::list<Sensor> & loopClosureRawData() const {return _loopClosureRawData;}
|
||||
const std::map<int, int> & weights() const {return _weights;}
|
||||
const std::map<int, float> & posterior() const {return _posterior;}
|
||||
const std::map<int, float> & likelihood() const {return _likelihood;}
|
||||
@@ -130,20 +130,17 @@ public:
|
||||
|
||||
const std::map<std::string, float> & data() const {return _data;}
|
||||
|
||||
|
||||
Statistics & operator=(const Statistics & s);
|
||||
|
||||
private:
|
||||
int _extended; // 0 -> only loop closure and last signature ID fields are filled
|
||||
|
||||
int _refImageId;
|
||||
int _loopClosureId;
|
||||
|
||||
std::list<std::vector<float> > _actions;
|
||||
std::list<Actuator> _actuators;
|
||||
|
||||
// extended data start here...
|
||||
IplImage * _refImage; // Released by the event destructor
|
||||
IplImage * _loopClosureImage; // Released by the event destructor
|
||||
std::list<Sensor> _refRawData;
|
||||
std::list<Sensor> _loopClosureRawData;
|
||||
|
||||
std::map<int, int> _weights;
|
||||
std::map<int, float> _posterior;
|
||||
@@ -191,7 +188,8 @@ public:
|
||||
kCmdDumpMemory,
|
||||
kCmdDumpPrediction,
|
||||
kCmdGenerateGraph,
|
||||
kCmdDeleteMemory};
|
||||
kCmdDeleteMemory,
|
||||
kCmdCleanSensorsBuffer};
|
||||
public:
|
||||
RtabmapEventCmd(Cmd cmd) :
|
||||
UEvent(0),
|
||||
|
||||
@@ -20,16 +20,12 @@
|
||||
#ifndef RTABMAPEXP_H
|
||||
#define RTABMAPEXP_H
|
||||
|
||||
#ifdef WIN32
|
||||
#ifdef RTABMAP_EXPORTS
|
||||
#if defined(_WIN32)
|
||||
#if defined(rtabmap_corelib_EXPORTS) || defined(rtabmap_guilib_EXPORTS)
|
||||
#define RTABMAP_EXP __declspec( dllexport )
|
||||
#else
|
||||
#ifdef RTABMAP_EXPORTS_STATIC
|
||||
#define RTABMAP_EXP
|
||||
#else
|
||||
#define RTABMAP_EXP __declspec( dllimport )
|
||||
#endif
|
||||
#endif
|
||||
#define RTABMAP_EXP __declspec( dllimport )
|
||||
#endif
|
||||
#else
|
||||
#define RTABMAP_EXP
|
||||
#endif
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include "Memory.h"
|
||||
#include "rtabmap/core/Memory.h"
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
@@ -35,28 +35,21 @@ public:
|
||||
SMMemory(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~SMMemory();
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
virtual bool init(const std::string & dbDriverName, const std::string & dbUrl, bool dbOverwritten = false, const ParametersMap & parameters = ParametersMap());
|
||||
virtual std::map<int, float> computeLikelihood(const Signature * signature, const std::list<int> & ids, float & maximumScore);
|
||||
virtual std::set<int> reactivateSignatures(const std::list<int> & ids, unsigned int maxLoaded, double & timeDbAccess);
|
||||
void setRoi(const std::string & roi);
|
||||
void setVotingScheme(bool useVotingScheme);
|
||||
void setColorTable(int size);
|
||||
|
||||
protected:
|
||||
virtual void moveToTrash(Signature * s);
|
||||
virtual Signature * getSignatureLtMem(int id);
|
||||
|
||||
private:
|
||||
virtual void copyData(const Signature * from, Signature * to);
|
||||
virtual Signature * createSignature(int id, const SMState * rawData, bool keepRawData=false);
|
||||
void updateDictionary(const Signature * s);
|
||||
virtual Signature * createSignature(int id, const std::list<Sensor> & sensors, bool keepRawData=false);
|
||||
|
||||
private:
|
||||
bool _useLogPolar;
|
||||
bool _useVotingScheme;
|
||||
ColorTable * _colorTable;
|
||||
bool _useMotionMask;
|
||||
std::vector<std::map<int, std::set<int> > > _dictionary;
|
||||
float _dBThreshold;
|
||||
bool _dBIndexing;
|
||||
bool _magnitudeInvariant;
|
||||
};
|
||||
|
||||
}
|
||||
@@ -1,157 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2011, Mathieu Labbe and IntRoLab - Universite de Sherbrooke
|
||||
*
|
||||
* This file is part of RTAB-Map.
|
||||
*
|
||||
* RTAB-Map is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* RTAB-Map is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SMPAIRVARIANT_H_
|
||||
#define SMPAIRVARIANT_H_
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/highgui/highgui_c.h>
|
||||
#include <opencv2/features2d/features2d.hpp>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
#include <utilite/ULogger.h>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
// SensoriMotor state
|
||||
class SMState
|
||||
{
|
||||
public:
|
||||
// Constructor 0 : ownership is transferred
|
||||
SMState(IplImage * image = 0) :
|
||||
_image(image)
|
||||
{}
|
||||
// Constructor 1
|
||||
SMState(const cv::Mat & sensors, const std::list<std::vector<float> > & actuators) :
|
||||
_sensors(sensors),
|
||||
_actuators(actuators),
|
||||
_image(0)
|
||||
{}
|
||||
// Constructor 2 : for convenience with ROS conversion...
|
||||
// Sensors and actuators vectors will be split into a list with smaller vectors of length sensorStep and actuatorStep respectively.
|
||||
SMState(const std::vector<float> & sensors, int sensorStep, const std::vector<float> & actuators, int actuatorStep) :
|
||||
_image(0)
|
||||
{
|
||||
if(sensorStep && sensors.size() % sensorStep != 0)
|
||||
{
|
||||
UERROR("Sensors must all have the same length.");
|
||||
}
|
||||
if(actuatorStep && actuators.size() % actuatorStep != 0)
|
||||
{
|
||||
UERROR("Actuators must all have the same length.");
|
||||
}
|
||||
for(unsigned int i=0; i<sensors.size() && i<i+sensorStep; i+=sensorStep)
|
||||
{
|
||||
_sensors.push_back(std::vector<float>(sensors.data()+i, sensors.data()+i+sensorStep));
|
||||
}
|
||||
for(unsigned int i=0; i<actuators.size() && i<i+actuatorStep; i+=actuatorStep)
|
||||
{
|
||||
_actuators.push_back(std::vector<float>(actuators.data()+i, actuators.data()+i+actuatorStep));
|
||||
}
|
||||
}
|
||||
|
||||
virtual ~SMState()
|
||||
{
|
||||
if(_image)
|
||||
{
|
||||
cvReleaseImage(&_image);
|
||||
}
|
||||
}
|
||||
|
||||
const IplImage * getImage() const {return _image;}
|
||||
const std::vector<cv::KeyPoint> & getKeypoints() const {return _keypoints;}
|
||||
const cv::Mat & getSensors() const {return _sensors;}
|
||||
const std::list<std::vector<float> > & getActuators() const {return _actuators;}
|
||||
void setSensors(const cv::Mat & sensors) {_sensors=sensors;}
|
||||
void setActuators(const std::list<std::vector<float> > & actuators) {_actuators=actuators;}
|
||||
void setKeypoints(const std::vector<cv::KeyPoint> & keypoints) {_keypoints = keypoints;}
|
||||
|
||||
//ownership is transferred
|
||||
void setImage(IplImage * image)
|
||||
{
|
||||
if(_image)
|
||||
{
|
||||
cvReleaseImage(&_image);
|
||||
}
|
||||
_image = image;
|
||||
}
|
||||
|
||||
void getSensorsMerged(std::vector<float> & sensors, int & step) const
|
||||
{
|
||||
sensors.clear();
|
||||
step = 0;
|
||||
if(!_sensors.empty())
|
||||
{
|
||||
// here we assume that all sensors have the same length
|
||||
step = _sensors.cols;
|
||||
sensors = std::vector<float>(_sensors.total());
|
||||
for(int i=0; i<_sensors.rows; ++i)
|
||||
{
|
||||
const float * rowFl = _sensors.ptr<float>(i);
|
||||
memcpy(&sensors[i*_sensors.cols], rowFl, _sensors.cols*sizeof(float));
|
||||
}
|
||||
}
|
||||
}
|
||||
void getActuatorsMerged(std::vector<float> & actuators, int & step) const
|
||||
{
|
||||
actuators.clear();
|
||||
step = 0;
|
||||
if(_actuators.size())
|
||||
{
|
||||
// here we assume that all sensors have the same length
|
||||
step = _actuators.front().size();
|
||||
for(std::list<std::vector<float> >::const_iterator iter = _actuators.begin();
|
||||
iter != _actuators.end();
|
||||
++iter)
|
||||
{
|
||||
actuators.insert(actuators.end(), iter->begin(), iter->end());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
cv::Mat _sensors; // descriptors
|
||||
std::list<std::vector<float> > _actuators;
|
||||
IplImage * _image;
|
||||
std::vector<cv::KeyPoint> _keypoints;
|
||||
};
|
||||
|
||||
// Sensorimotor state event
|
||||
// Take ownership of the state
|
||||
class SMStateEvent : public UEvent
|
||||
{
|
||||
public:
|
||||
SMStateEvent(SMState * state) :
|
||||
UEvent(0),
|
||||
_state(state) {}
|
||||
|
||||
virtual ~SMStateEvent() {if(_state) delete _state;}
|
||||
const SMState * getSMState() const {return _state;}
|
||||
SMState * getSMStateOwnership() {SMState * state = _state; _state=0; return state;}
|
||||
virtual std::string getClassName() const {return "SMStateEvent";} // TODO : macro?
|
||||
|
||||
private:
|
||||
SMState * _state;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SMPAIRVARIANT_H_ */
|
||||
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2011, Mathieu Labbe and IntRoLab - Universite de Sherbrooke
|
||||
*
|
||||
* This file is part of RTAB-Map.
|
||||
*
|
||||
* RTAB-Map is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* RTAB-Map is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef SENSOR_H_
|
||||
#define SENSOR_H_
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/features2d/features2d.hpp>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <utilite/UEvent.h>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
class Sensor
|
||||
{
|
||||
public:
|
||||
enum Type{kTypeImage=0, kTypeImageFeatures2d, kTypeAudio, kTypeAudioFreq, kTypeAudioFreqSqrdMagn, kTypeJointState, kTypeTwist, kTypeNotSpecified};
|
||||
public:
|
||||
Sensor(const cv::Mat & data, Type type, int num = 0) :
|
||||
_data(data),
|
||||
_type(type),
|
||||
_num(num)
|
||||
{}
|
||||
Sensor(const cv::Mat & descriptors, const std::vector<cv::KeyPoint> & keypoints, int num = 0) :
|
||||
_data(descriptors),
|
||||
_type(kTypeImageFeatures2d),
|
||||
_num(num),
|
||||
_keypoints(keypoints)
|
||||
{}
|
||||
const cv::Mat & data() const {return _data;}
|
||||
int type() const {return _type;}
|
||||
int num() const {return _num;}
|
||||
virtual ~Sensor() {};
|
||||
void setKeypoints(const std::vector<cv::KeyPoint> & keypoints) {_keypoints = keypoints;}
|
||||
const std::vector<cv::KeyPoint> & getKeypoints() const {return _keypoints;}
|
||||
private:
|
||||
cv::Mat _data;
|
||||
int _type;
|
||||
int _num; // sensor number
|
||||
std::vector<cv::KeyPoint> _keypoints; // for convenience with kTypeImageFeatures
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* SENSOR_H_ */
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* SensorimotorEvent.h
|
||||
*
|
||||
* Created on: 2012-05-27
|
||||
* Author: mathieu
|
||||
*/
|
||||
|
||||
#ifndef SENSORIMOTOREVENT_H_
|
||||
#define SENSORIMOTOREVENT_H_
|
||||
|
||||
#include "rtabmap/core/Sensor.h"
|
||||
#include "rtabmap/core/Actuator.h"
|
||||
#include <utilite/UEvent.h>
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
|
||||
class SensorimotorEvent : public UEvent
|
||||
{
|
||||
public:
|
||||
enum Type {
|
||||
kTypeData,
|
||||
kTypeNoMoreData
|
||||
};
|
||||
|
||||
public:
|
||||
SensorimotorEvent() :
|
||||
UEvent(kTypeNoMoreData) {}
|
||||
SensorimotorEvent(const std::list<Sensor> & sensors,
|
||||
const std::list<Actuator> & actuators) :
|
||||
UEvent(kTypeData),
|
||||
sensors_(sensors),
|
||||
actuators_(actuators) {}
|
||||
virtual ~SensorimotorEvent() {}
|
||||
int type() const {return this->getCode();}
|
||||
virtual std::string getClassName() const {return "SensorimotorEvent";}
|
||||
const std::list<Sensor> & sensors() const {return sensors_;}
|
||||
const std::list<Actuator> & actuators() const {return actuators_;}
|
||||
private:
|
||||
std::list<Sensor> sensors_;
|
||||
std::list<Actuator> actuators_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
|
||||
#endif /* SENSORIMOTOREVENT_H_ */
|
||||
@@ -24,6 +24,8 @@
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/features2d/features2d.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
#include "rtabmap/core/Sensor.h"
|
||||
#include "rtabmap/core/Actuator.h"
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <vector>
|
||||
@@ -37,21 +39,24 @@ namespace rtabmap
|
||||
class RTABMAP_EXP NeighborLink
|
||||
{
|
||||
public:
|
||||
NeighborLink(int id, const std::list<std::vector<float> > & actions = std::list<std::vector<float> >(), const std::vector<int> & baseIds = std::vector<int>()) :
|
||||
_id(id),
|
||||
_actions(actions),
|
||||
NeighborLink(int toId, const std::vector<int> & baseIds = std::vector<int>(), const std::list<Actuator> & actuators = std::list<Actuator>(), int actuatorId = 0) :
|
||||
_toId(toId),
|
||||
_actuatorId(actuatorId),
|
||||
_actuators(actuators),
|
||||
_baseIds(baseIds)
|
||||
{}
|
||||
virtual ~NeighborLink() {}
|
||||
|
||||
int id() const {return _id;}
|
||||
const std::list<std::vector<float> > & actions() const {return _actions;}
|
||||
int toId() const {return _toId;}
|
||||
int actuatorId() const {return _actuatorId;}
|
||||
const std::list<Actuator> & actuators() const {return _actuators;}
|
||||
const std::vector<int> & baseIds() const {return _baseIds;}
|
||||
bool updateIds(int idFrom, int idTo);
|
||||
|
||||
private:
|
||||
int _id;
|
||||
std::list<std::vector<float> > _actions;
|
||||
int _toId;
|
||||
int _actuatorId;
|
||||
std::list<Actuator> _actuators;
|
||||
std::vector<int> _baseIds; // first is the nearest
|
||||
};
|
||||
|
||||
@@ -60,10 +65,6 @@ typedef std::multimap<int, NeighborLink> NeighborsMultiMap;
|
||||
|
||||
class RTABMAP_EXP Signature
|
||||
{
|
||||
public:
|
||||
static CvMat * compressImage(const IplImage * image);
|
||||
static IplImage * decompressImage(const CvMat * imageCompressed);
|
||||
|
||||
public:
|
||||
virtual ~Signature();
|
||||
|
||||
@@ -72,29 +73,35 @@ public:
|
||||
*/
|
||||
virtual float compareTo(const Signature * signature) const = 0;
|
||||
virtual bool isBadSignature() const = 0;
|
||||
virtual std::string signatureType() const = 0;
|
||||
virtual std::string nodeType() const = 0;
|
||||
|
||||
const IplImage * getImage() const;
|
||||
void setImage(const IplImage * image);
|
||||
void setRawData(const std::list<Sensor> & rawData) {_rawData = rawData;}
|
||||
const std::list<Sensor> & getRawData() const {return _rawData;}
|
||||
|
||||
int id() const {return _id;}
|
||||
|
||||
void addNeighbors(const NeighborsMultiMap & neighbors);
|
||||
void addNeighbor(const NeighborLink & neighbor);
|
||||
void removeNeighbor(int neighborId) {if(_neighbors.erase(neighborId)) _neighborsModified = true;}
|
||||
void removeNeighbor(int neighborId) {
|
||||
if(_neighbors.erase(neighborId))
|
||||
_neighborsModified = true;
|
||||
_neighborsWithActuators.erase(neighborId);
|
||||
_neighborsAll.erase(neighborId);}
|
||||
bool hasNeighbor(int neighborId) const {return _neighbors.find(neighborId) != _neighbors.end();}
|
||||
void setWeight(int weight) {if(_weight!=weight)_modified=true;_weight = weight;}
|
||||
void setLoopClosureIds(const std::set<int> & loopClosureIds) {_loopClosureIds = loopClosureIds;_modified=true;}
|
||||
void addLoopClosureId(int loopClosureId) {if(loopClosureId && _loopClosureIds.insert(loopClosureId).second)_modified=true;}
|
||||
void removeLoopClosureId(int loopClosureId) {if(loopClosureId && _loopClosureIds.erase(loopClosureId))_modified=true;}
|
||||
void setLoopClosureIds(const std::set<int> & loopClosureIds) {_loopClosureIds = loopClosureIds;_neighborsModified=true;}
|
||||
void addLoopClosureId(int loopClosureId) {if(loopClosureId && _loopClosureIds.insert(loopClosureId).second)_neighborsModified=true;}
|
||||
void removeLoopClosureId(int loopClosureId) {if(loopClosureId && _loopClosureIds.erase(loopClosureId))_neighborsModified=true;}
|
||||
bool hasLoopClosureId(int loopClosureId) const {return _loopClosureIds.find(loopClosureId) != _loopClosureIds.end();}
|
||||
void setChildLoopClosureIds(std::set<int> & childLoopClosureIds) {_childLoopClosureIds = childLoopClosureIds;_modified=true;}
|
||||
void addChildLoopClosureId(int childLoopClosureId) {if(childLoopClosureId && _childLoopClosureIds.insert(childLoopClosureId).second)_modified=true;}
|
||||
void setChildLoopClosureIds(std::set<int> & childLoopClosureIds) {_childLoopClosureIds = childLoopClosureIds;_neighborsModified=true;}
|
||||
void addChildLoopClosureId(int childLoopClosureId) {if(childLoopClosureId && _childLoopClosureIds.insert(childLoopClosureId).second)_neighborsModified=true;}
|
||||
void setSaved(bool saved) {_saved = saved;}
|
||||
void setModified(bool modified) {_modified = modified; _neighborsModified = modified;}
|
||||
void changeNeighborIds(int idFrom, int idTo);
|
||||
|
||||
const NeighborsMultiMap & getNeighbors() const {return _neighbors;}
|
||||
const std::set<int> & getNeighborsWithActuators() const {return _neighborsWithActuators;}
|
||||
const std::set<int> & getNeighborsAll() const {return _neighborsAll;}
|
||||
int getWeight() const {return _weight;}
|
||||
const std::set<int> & getLoopClosureIds() const {return _loopClosureIds;}
|
||||
const std::set<int> & getChildLoopClosureIds() const {return _childLoopClosureIds;}
|
||||
@@ -103,15 +110,18 @@ public:
|
||||
bool isNeighborsModified() const {return _neighborsModified;}
|
||||
|
||||
protected:
|
||||
Signature(int id, const IplImage * image = 0, bool keepImage = false);
|
||||
Signature(int id);
|
||||
Signature(int id, const std::list<Sensor> & rawData);
|
||||
|
||||
private:
|
||||
int _id;
|
||||
NeighborsMultiMap _neighbors; // id, neighborLink
|
||||
std::set<int> _neighborsWithActuators; // Hack, to increase efficiency of Memory::getNeighborIds()
|
||||
std::set<int> _neighborsAll; // Hack, to increase efficiency of Memory::getNeighborIds()
|
||||
int _weight;
|
||||
std::set<int> _loopClosureIds;
|
||||
std::set<int> _childLoopClosureIds;
|
||||
IplImage * _image;
|
||||
std::list<Sensor> _rawData;
|
||||
bool _saved; // If it's saved to bd
|
||||
bool _modified;
|
||||
bool _neighborsModified; // Optimization when updating signatures in database
|
||||
@@ -125,18 +135,20 @@ class RTABMAP_EXP KeypointSignature :
|
||||
public Signature
|
||||
{
|
||||
public:
|
||||
KeypointSignature(int id);
|
||||
KeypointSignature(
|
||||
const std::multimap<int, cv::KeyPoint> & words,
|
||||
int id);
|
||||
KeypointSignature(
|
||||
const std::multimap<int, cv::KeyPoint> & words,
|
||||
int id,
|
||||
const IplImage * image = 0,
|
||||
bool keepRawData = false);
|
||||
KeypointSignature(int id);
|
||||
const std::list<Sensor> & sensors);
|
||||
|
||||
virtual ~KeypointSignature();
|
||||
|
||||
virtual float compareTo(const Signature * signature) const;
|
||||
virtual bool isBadSignature() const;
|
||||
virtual std::string signatureType() const {return "KeypointSignature";};
|
||||
virtual std::string nodeType() const {return "KeypointSignature";};
|
||||
|
||||
void removeAllWords();
|
||||
void removeWord(int wordId);
|
||||
@@ -164,27 +176,24 @@ class RTABMAP_EXP SMSignature :
|
||||
{
|
||||
public:
|
||||
SMSignature(
|
||||
const std::vector<int> & sensors,
|
||||
const std::vector<unsigned char> & motionMask,
|
||||
const std::list<std::vector<int> > & data,
|
||||
int id);
|
||||
SMSignature(
|
||||
const std::list<std::vector<int> > & data,
|
||||
int id,
|
||||
const IplImage * image = 0,
|
||||
bool keepRawData = false);
|
||||
const std::list<Sensor> & rawData);
|
||||
SMSignature(int id);
|
||||
|
||||
virtual ~SMSignature();
|
||||
|
||||
virtual float compareTo(const Signature * signature) const;
|
||||
virtual bool isBadSignature() const;
|
||||
virtual std::string signatureType() const {return "SMSignature";};
|
||||
virtual std::string nodeType() const {return "SMSignature";};
|
||||
|
||||
void setSensors(const std::vector<int> & sensors) {_sensors= sensors;}
|
||||
const std::vector<int> & getSensors() const {return _sensors;}
|
||||
|
||||
void setMotionMask(const std::vector<unsigned char> & motionMask) {_motionMask= motionMask;}
|
||||
const std::vector<unsigned char> & getMotionMask() const {return _motionMask;}
|
||||
void setSensors(const std::list<std::vector<int> > & data) {_data = data;}
|
||||
const std::list<std::vector<int> > & getData() const {return _data;}
|
||||
private:
|
||||
std::vector<int> _sensors;
|
||||
std::vector<unsigned char> _motionMask;
|
||||
std::list<std::vector<int> > _data;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include "VisualWord.h"
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/features2d/features2d.hpp>
|
||||
@@ -33,6 +32,7 @@ namespace rtabmap
|
||||
|
||||
class NearestNeighbor;
|
||||
class DBDriver;
|
||||
class VisualWord;
|
||||
|
||||
class RTABMAP_EXP VWDictionary
|
||||
{
|
||||
@@ -68,19 +68,12 @@ class KeypointSignature;
|
||||
|
||||
class RTABMAP_EXP HypVerificatorEpipolarGeo : public HypVerificator
|
||||
{
|
||||
public:
|
||||
static int findPairsOne(const std::multimap<int, cv::KeyPoint> & wordsA, const std::multimap<int, cv::KeyPoint> & wordsB, std::list<std::pair<cv::KeyPoint, cv::KeyPoint> > & pairs, std::list<int> & pairsId);
|
||||
static int findPairsDirect(const std::multimap<int, cv::KeyPoint> & wordsA, const std::multimap<int, cv::KeyPoint> & wordsB, std::list<std::pair<cv::KeyPoint, cv::KeyPoint> > & pairs, std::list<int> & pairsId);
|
||||
static int findPairsAll(const std::multimap<int, cv::KeyPoint> & wordsA, const std::multimap<int, cv::KeyPoint> & wordsB, std::list<std::pair<cv::KeyPoint, cv::KeyPoint> > & pairs, std::list<int> & pairsId);
|
||||
static std::list<int> findSameIds(const std::multimap<int, cv::KeyPoint> & wordsA, const std::multimap<int, cv::KeyPoint> & wordsB);
|
||||
public:
|
||||
HypVerificatorEpipolarGeo(const ParametersMap & parameters = ParametersMap());
|
||||
virtual ~HypVerificatorEpipolarGeo();
|
||||
virtual bool verify(const Signature * ref, const Signature * hyp);
|
||||
virtual void parseParameters(const ParametersMap & parameters);
|
||||
|
||||
int getTotalSimilarities(const std::multimap<int, cv::KeyPoint> & wordsA, const std::multimap<int, cv::KeyPoint> & wordsB);
|
||||
|
||||
int getMatchCountMinAccepted() const {return _matchCountMinAccepted;}
|
||||
double getRansacParam1() const {return _ransacParam1;}
|
||||
double getRansacParam2() const {return _ransacParam2;}
|
||||
+38
-43
@@ -17,8 +17,8 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "BayesFilter.h"
|
||||
#include "Memory.h"
|
||||
#include "rtabmap/core/BayesFilter.h"
|
||||
#include "rtabmap/core/Memory.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include <iostream>
|
||||
@@ -160,9 +160,9 @@ const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
|
||||
CvMat * prediction = 0;
|
||||
CvMat * prior = 0;
|
||||
CvMat * posterior = 0;
|
||||
cv::Mat prediction;
|
||||
cv::Mat prior;
|
||||
cv::Mat posterior;
|
||||
|
||||
float sum = 0;
|
||||
int j=0;
|
||||
@@ -171,27 +171,26 @@ const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory
|
||||
prediction = cvCreateMat(likelihood.size(), likelihood.size(), CV_32FC1);
|
||||
if(this->generatePrediction(prediction, memory, uKeys(likelihood)))
|
||||
{
|
||||
ULOGGER_DEBUG("STEP1-generate prior=%fs, rows=%d, cols=%d", timer.ticks(), prediction->rows, prediction->cols);
|
||||
//std::cout << "Prediction=" << cv::Mat(prediction) << std::endl;
|
||||
ULOGGER_DEBUG("STEP1-generate prior=%fs, rows=%d, cols=%d", timer.ticks(), prediction.rows, prediction.cols);
|
||||
//std::cout << "Prediction=" << prediction << std::endl;
|
||||
|
||||
// Adjust the last posterior if some images were
|
||||
// reactivated or removed from the working memory
|
||||
posterior = cvCreateMat(likelihood.size(), 1, CV_32FC1);
|
||||
posterior = cv::Mat(likelihood.size(), 1, CV_32FC1);
|
||||
this->updatePosterior(memory, uKeys(likelihood));
|
||||
j=0;
|
||||
for(std::map<int, float>::const_iterator i=_posterior.begin(); i!= _posterior.end(); ++i)
|
||||
{
|
||||
posterior->data.fl[j++] = (*i).second;
|
||||
((float*)posterior.data)[j++] = (*i).second;
|
||||
}
|
||||
ULOGGER_DEBUG("STEP1-update posterior=%fs, posterior=%d, _posterior size=%d", posterior->rows, _posterior.size());
|
||||
//std::cout << "LastPosterior=" << cv::Mat(posterior) << std::endl;
|
||||
ULOGGER_DEBUG("STEP1-update posterior=%fs, posterior=%d, _posterior size=%d", posterior.rows, _posterior.size());
|
||||
//std::cout << "LastPosterior=" << posterior << std::endl;
|
||||
|
||||
// Multiply prediction matrix with the last posterior
|
||||
// (m,m) X (m,1) = (m,1)
|
||||
prior = cvCreateMat(likelihood.size(), 1, CV_32FC1);
|
||||
cvMatMul(prediction, posterior, prior);
|
||||
prior = prediction * posterior;
|
||||
ULOGGER_DEBUG("STEP1-matrix mult time=%fs", timer.ticks());
|
||||
//std::cout << "ResultingPrior=" << cv::Mat(prior) << std::endl;
|
||||
//std::cout << "ResultingPrior=" << prior << std::endl;
|
||||
|
||||
ULOGGER_DEBUG("STEP1-matrix mult time=%fs", timer.ticks());
|
||||
std::vector<float> likelihoodValues = uValues(likelihood);
|
||||
@@ -204,7 +203,7 @@ const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory
|
||||
std::map<int, float>::iterator p =_posterior.find((*i).first);
|
||||
if(p!= _posterior.end())
|
||||
{
|
||||
(*p).second = (*i).second * prior->data.fl[j++];
|
||||
(*p).second = (*i).second * ((float*)prior.data)[j++];
|
||||
sum+=(*p).second;
|
||||
}
|
||||
else
|
||||
@@ -226,14 +225,10 @@ const std::map<int, float> & BayesFilter::computePosterior(const Memory * memory
|
||||
ULOGGER_DEBUG("normalize time=%fs", timer.ticks());
|
||||
}
|
||||
|
||||
cvReleaseMat(&prediction);
|
||||
cvReleaseMat(&prior);
|
||||
cvReleaseMat(&posterior);
|
||||
|
||||
return _posterior;
|
||||
}
|
||||
|
||||
bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory, const std::vector<int> & ids) const
|
||||
bool BayesFilter::generatePrediction(cv::Mat & prediction, const Memory * memory, const std::vector<int> & ids) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
UTimer timer;
|
||||
@@ -242,9 +237,9 @@ bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory,
|
||||
timerGlobal.start();
|
||||
|
||||
if(!memory ||
|
||||
prediction == 0 ||
|
||||
prediction->rows != prediction->cols ||
|
||||
(unsigned int)prediction->rows != ids.size() ||
|
||||
prediction.empty() ||
|
||||
prediction.rows != prediction.cols ||
|
||||
(unsigned int)prediction.rows != ids.size() ||
|
||||
_predictionLC.size() < 2 ||
|
||||
!ids.size())
|
||||
{
|
||||
@@ -262,9 +257,9 @@ bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory,
|
||||
idToIndexMap.insert(idToIndexMap.end(), std::make_pair(ids[i], i));
|
||||
}
|
||||
|
||||
//int rows = prediction->rows;
|
||||
cvSetZero(prediction);
|
||||
int cols = prediction->cols;
|
||||
//int rows = prediction.rows;
|
||||
prediction = cv::Mat::zeros(prediction.rows, prediction.cols, prediction.type());
|
||||
int cols = prediction.cols;
|
||||
|
||||
// Each prior is a column vector
|
||||
ULOGGER_DEBUG("_predictionLC.size()=%d",_predictionLC.size());
|
||||
@@ -291,7 +286,7 @@ bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory,
|
||||
if(sum < totalModelValues-_predictionLC[0])
|
||||
{
|
||||
float delta = totalModelValues-_predictionLC[0]-sum;
|
||||
prediction->data.fl[i + i*cols] += delta;
|
||||
((float*)prediction.data)[i + i*cols] += delta;
|
||||
sum+=delta;
|
||||
}
|
||||
|
||||
@@ -307,10 +302,10 @@ bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory,
|
||||
float value = allOtherPlacesValue / float(cols - 1);
|
||||
for(int j=ids[0] < 0?1:0; j<cols; ++j)
|
||||
{
|
||||
if(prediction->data.fl[i + j*cols] == 0)
|
||||
if(((float*)prediction.data)[i + j*cols] == 0)
|
||||
{
|
||||
prediction->data.fl[i + j*cols] = value;
|
||||
sum += prediction->data.fl[i + j*cols];
|
||||
((float*)prediction.data)[i + j*cols] = value;
|
||||
sum += ((float*)prediction.data)[i + j*cols];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -321,7 +316,7 @@ bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory,
|
||||
{
|
||||
for(int j=ids[0] < 0?1:0; j<cols; ++j)
|
||||
{
|
||||
prediction->data.fl[i + j*cols] *= maxNorm / sum;
|
||||
((float*)prediction.data)[i + j*cols] *= maxNorm / sum;
|
||||
}
|
||||
sum = maxNorm;
|
||||
}
|
||||
@@ -329,14 +324,14 @@ bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory,
|
||||
// ADD virtual place prob
|
||||
if(ids[0] < 0)
|
||||
{
|
||||
prediction->data.fl[i] = _predictionLC[0];
|
||||
sum += prediction->data.fl[i];
|
||||
((float*)prediction.data)[i] = _predictionLC[0];
|
||||
sum += ((float*)prediction.data)[i];
|
||||
}
|
||||
|
||||
//debug
|
||||
//for(int j=0; j<cols; ++j)
|
||||
//{
|
||||
// ULOGGER_DEBUG("test col=%d = %f", i, prediction->data.fl[i + j*cols]);
|
||||
// ULOGGER_DEBUG("test col=%d = %f", i, prediction.data.fl[i + j*cols]);
|
||||
//}
|
||||
|
||||
if(sum<0.99 || sum > 1.01)
|
||||
@@ -351,16 +346,16 @@ bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory,
|
||||
{
|
||||
if(cols>1) // The first must be the virtual place
|
||||
{
|
||||
prediction->data.fl[i] = _virtualPlacePrior;
|
||||
((float*)prediction.data)[i] = _virtualPlacePrior;
|
||||
float val = (1.0-_virtualPlacePrior)/(cols-1);
|
||||
for(int j=1; j<cols; j++)
|
||||
{
|
||||
prediction->data.fl[i + j*cols] = val;
|
||||
((float*)prediction.data)[i + j*cols] = val;
|
||||
}
|
||||
}
|
||||
else if(cols>0)
|
||||
{
|
||||
prediction->data.fl[i] = 1;
|
||||
((float*)prediction.data)[i] = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -372,12 +367,12 @@ bool BayesFilter::generatePrediction(CvMat * prediction, const Memory * memory,
|
||||
float val = 1.0/cols;
|
||||
for(int j=0; j<cols; j++)
|
||||
{
|
||||
prediction->data.fl[i + j*cols] = val;
|
||||
((float*)prediction.data)[i + j*cols] = val;
|
||||
}
|
||||
}
|
||||
else if(cols>0)
|
||||
{
|
||||
prediction->data.fl[i] = 1;
|
||||
((float*)prediction.data)[i] = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -414,10 +409,10 @@ void BayesFilter::updatePosterior(const Memory * memory, const std::vector<int>
|
||||
_posterior = newPosterior;
|
||||
}
|
||||
|
||||
float BayesFilter::addNeighborProb(CvMat * prediction, unsigned int col, const std::map<int, int> & neighbors, const std::map<int, int> & idToIndexMap) const
|
||||
float BayesFilter::addNeighborProb(cv::Mat & prediction, unsigned int col, const std::map<int, int> & neighbors, const std::map<int, int> & idToIndexMap) const
|
||||
{
|
||||
if((unsigned int)prediction->cols != idToIndexMap.size() ||
|
||||
(unsigned int)prediction->rows != idToIndexMap.size())
|
||||
if((unsigned int)prediction.cols != idToIndexMap.size() ||
|
||||
(unsigned int)prediction.rows != idToIndexMap.size())
|
||||
{
|
||||
UFATAL("Requirements no met");
|
||||
}
|
||||
@@ -428,7 +423,7 @@ float BayesFilter::addNeighborProb(CvMat * prediction, unsigned int col, const s
|
||||
int index = uValue(idToIndexMap, iter->first, -1);
|
||||
if(index >= 0)
|
||||
{
|
||||
sum += prediction->data.fl[col + index*prediction->cols] = _predictionLC[iter->second+1];
|
||||
sum += ((float*)prediction.data)[col + index*prediction.cols] = _predictionLC[iter->second+1];
|
||||
}
|
||||
}
|
||||
return sum;
|
||||
|
||||
@@ -10,8 +10,10 @@ SET(SRC_FILES
|
||||
DBDriverFactory.cpp
|
||||
DBDriver.cpp
|
||||
DBDriverSqlite3.cpp
|
||||
DBReader.cpp
|
||||
|
||||
Camera.cpp
|
||||
Micro.cpp
|
||||
EpipolarGeometry.cpp
|
||||
VisualWord.cpp
|
||||
VWDictionary.cpp
|
||||
@@ -34,6 +36,7 @@ SET(INCLUDE_DIRS
|
||||
${OpenCV_INCLUDE_DIRS}
|
||||
${SQLITE3_INCLUDE_DIR}
|
||||
${ZLIB_INCLUDE_DIRS}
|
||||
${FFTW3F_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
SET(LIBRARIES
|
||||
@@ -41,6 +44,7 @@ SET(LIBRARIES
|
||||
${OpenCV_LIBS}
|
||||
${SQLITE3_LIBRARY}
|
||||
${ZLIB_LIBRARIES}
|
||||
${FFTW3F_LIBRARIES}
|
||||
)
|
||||
|
||||
####################################
|
||||
@@ -128,27 +132,19 @@ SET(RESOURCES
|
||||
# Make sure the compiler can find include files from our library.
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
|
||||
|
||||
IF(WIN32)
|
||||
IF(BUILD_SHARED_LIBS)
|
||||
ADD_DEFINITIONS(-DRTABMAP_EXPORTS)
|
||||
ELSE()
|
||||
ADD_DEFINITIONS(-DRTABMAP_EXPORTS_STATIC)
|
||||
ENDIF()
|
||||
ENDIF(WIN32)
|
||||
|
||||
# Add binary that is built from the source file "main.cpp".
|
||||
# The extension is automatically found.
|
||||
ADD_LIBRARY(corelib ${SRC_FILES} ${RESOURCES})
|
||||
TARGET_LINK_LIBRARIES(corelib ${LIBRARIES})
|
||||
ADD_LIBRARY(rtabmap_corelib ${SRC_FILES} ${RESOURCES})
|
||||
TARGET_LINK_LIBRARIES(rtabmap_corelib ${LIBRARIES})
|
||||
|
||||
SET_TARGET_PROPERTIES(
|
||||
corelib
|
||||
rtabmap_corelib
|
||||
PROPERTIES
|
||||
OUTPUT_NAME ${PROJECT_PREFIX}_core
|
||||
INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
INSTALL(TARGETS corelib
|
||||
INSTALL(TARGETS rtabmap_corelib
|
||||
RUNTIME DESTINATION bin COMPONENT runtime
|
||||
LIBRARY DESTINATION lib COMPONENT devel
|
||||
ARCHIVE DESTINATION lib COMPONENT devel)
|
||||
|
||||
+222
-335
@@ -18,31 +18,44 @@
|
||||
*/
|
||||
|
||||
#include "rtabmap/core/Camera.h"
|
||||
#include "rtabmap/core/CameraEvent.h"
|
||||
#include "utilite/UEventsManager.h"
|
||||
#include "utilite/UConversion.h"
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
#include "rtabmap/core/DBDriverFactory.h"
|
||||
#include "rtabmap/core/KeypointDescriptor.h"
|
||||
#include "rtabmap/core/KeypointDetector.h"
|
||||
#include "rtabmap/core/SMState.h"
|
||||
#include "utilite/UStl.h"
|
||||
#include "utilite/UConversion.h"
|
||||
#include "utilite/UFile.h"
|
||||
#include "utilite/UDirectory.h"
|
||||
#include "utilite/UTimer.h"
|
||||
#include <opencv2/imgproc/imgproc_c.h>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
|
||||
void CamPostTreatment::process(SMState * smState) const
|
||||
Camera::Camera(float imageRate,
|
||||
bool autoRestart,
|
||||
unsigned int imageWidth,
|
||||
unsigned int imageHeight,
|
||||
unsigned int framesDropped,
|
||||
int id) :
|
||||
_imageRate(imageRate),
|
||||
_id(id),
|
||||
_autoRestart(autoRestart),
|
||||
_imageWidth(imageWidth),
|
||||
_imageHeight(imageHeight),
|
||||
_framesDropped(framesDropped),
|
||||
_featuresExtracted(false),
|
||||
_keypointDetector(0),
|
||||
_keypointDescriptor(0)
|
||||
{
|
||||
//no threatment...
|
||||
}
|
||||
|
||||
CamKeypointTreatment::~CamKeypointTreatment()
|
||||
Camera::~Camera()
|
||||
{
|
||||
UEventsManager::removeHandler(this);
|
||||
join(true);
|
||||
if(_keypointDetector)
|
||||
{
|
||||
delete _keypointDetector;
|
||||
@@ -52,48 +65,56 @@ CamKeypointTreatment::~CamKeypointTreatment()
|
||||
delete _keypointDescriptor;
|
||||
}
|
||||
}
|
||||
void CamKeypointTreatment::process(SMState * smState) const
|
||||
|
||||
void Camera::setFeaturesExtracted(bool featuresExtracted, KeypointDetector::DetectorType detector, KeypointDescriptor::DescriptorType descriptor)
|
||||
{
|
||||
if(_keypointDetector && _keypointDescriptor && smState && smState->getImage() && smState->getKeypoints().size() == 0 && smState->getSensors().empty())
|
||||
_featuresExtracted = featuresExtracted;
|
||||
if(detector != KeypointDetector::kDetectorUndef || descriptor != KeypointDescriptor::kDescriptorUndef)
|
||||
{
|
||||
std::vector<cv::KeyPoint> keypoints = _keypointDetector->generateKeypoints(smState->getImage());
|
||||
cv::Mat descriptors = _keypointDescriptor->generateDescriptors(smState->getImage(), keypoints);
|
||||
smState->setSensors(descriptors);
|
||||
smState->setKeypoints(keypoints);
|
||||
ParametersMap pm;
|
||||
pm.insert(ParametersPair(Parameters::kKpDetectorStrategy(), uNumber2Str((int)detector)));
|
||||
pm.insert(ParametersPair(Parameters::kKpDescriptorStrategy(), uNumber2Str((int)detector)));
|
||||
this->parseParameters(pm);
|
||||
}
|
||||
}
|
||||
|
||||
void CamKeypointTreatment::parseParameters(const ParametersMap & parameters)
|
||||
void Camera::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
UDEBUG("");
|
||||
ParametersMap::const_iterator iter;
|
||||
//Keypoint detector
|
||||
DetectorStrategy detectorStrategy = kDetectorUndef;
|
||||
KeypointDetector::DetectorType detector = KeypointDetector::kDetectorUndef;
|
||||
if((iter=parameters.find(Parameters::kKpDetectorStrategy())) != parameters.end())
|
||||
{
|
||||
detectorStrategy = (DetectorStrategy)std::atoi((*iter).second.c_str());
|
||||
detector = (KeypointDetector::DetectorType)std::atoi((*iter).second.c_str());
|
||||
}
|
||||
DetectorStrategy currentDetectorStrategy = this->detectorStrategy();
|
||||
if(!_keypointDetector || ( detectorStrategy!=kDetectorUndef && (detectorStrategy != currentDetectorStrategy) ) )
|
||||
//Keypoint descriptor
|
||||
KeypointDescriptor::DescriptorType descriptor = KeypointDescriptor::kDescriptorUndef;
|
||||
if((iter=parameters.find(Parameters::kKpDescriptorStrategy())) != parameters.end())
|
||||
{
|
||||
ULOGGER_DEBUG("new detector strategy %d", int(detectorStrategy));
|
||||
descriptor = (KeypointDescriptor::DescriptorType)std::atoi((*iter).second.c_str());
|
||||
}
|
||||
|
||||
if(detector!=KeypointDetector::kDetectorUndef)
|
||||
{
|
||||
ULOGGER_DEBUG("new detector strategy %d", int(detector));
|
||||
if(_keypointDetector)
|
||||
{
|
||||
delete _keypointDetector;
|
||||
_keypointDetector = 0;
|
||||
}
|
||||
switch(detectorStrategy)
|
||||
switch(detector)
|
||||
{
|
||||
case kDetectorStar:
|
||||
case KeypointDetector::kDetectorStar:
|
||||
_keypointDetector = new StarDetector(parameters);
|
||||
break;
|
||||
case kDetectorSift:
|
||||
case KeypointDetector::kDetectorSift:
|
||||
_keypointDetector = new SIFTDetector(parameters);
|
||||
break;
|
||||
case kDetectorFast:
|
||||
case KeypointDetector::kDetectorFast:
|
||||
_keypointDetector = new FASTDetector(parameters);
|
||||
break;
|
||||
case kDetectorSurf:
|
||||
case KeypointDetector::kDetectorSurf:
|
||||
default:
|
||||
_keypointDetector = new SURFDetector(parameters);
|
||||
break;
|
||||
@@ -104,35 +125,29 @@ void CamKeypointTreatment::parseParameters(const ParametersMap & parameters)
|
||||
_keypointDetector->parseParameters(parameters);
|
||||
}
|
||||
|
||||
//Keypoint descriptor
|
||||
DescriptorStrategy descriptorStrategy = kDescriptorUndef;
|
||||
if((iter=parameters.find(Parameters::kKpDescriptorStrategy())) != parameters.end())
|
||||
if(descriptor!=KeypointDescriptor::kDescriptorUndef)
|
||||
{
|
||||
descriptorStrategy = (DescriptorStrategy)std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if(!_keypointDescriptor || descriptorStrategy!=kDescriptorUndef)
|
||||
{
|
||||
ULOGGER_DEBUG("new descriptor strategy %d", int(descriptorStrategy));
|
||||
ULOGGER_DEBUG("new descriptor strategy %d", int(descriptor));
|
||||
if(_keypointDescriptor)
|
||||
{
|
||||
delete _keypointDescriptor;
|
||||
_keypointDescriptor = 0;
|
||||
}
|
||||
switch(descriptorStrategy)
|
||||
switch(descriptor)
|
||||
{
|
||||
case kDescriptorSift:
|
||||
case KeypointDescriptor::kDescriptorSift:
|
||||
_keypointDescriptor = new SIFTDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorBrief:
|
||||
case KeypointDescriptor::kDescriptorBrief:
|
||||
_keypointDescriptor = new BRIEFDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorColor:
|
||||
case KeypointDescriptor::kDescriptorColor:
|
||||
_keypointDescriptor = new ColorDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorHue:
|
||||
case KeypointDescriptor::kDescriptorHue:
|
||||
_keypointDescriptor = new HueDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorSurf:
|
||||
case KeypointDescriptor::kDescriptorSurf:
|
||||
default:
|
||||
_keypointDescriptor = new SURFDescriptor(parameters);
|
||||
break;
|
||||
@@ -142,55 +157,11 @@ void CamKeypointTreatment::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
_keypointDescriptor->parseParameters(parameters);
|
||||
}
|
||||
CamPostTreatment::parseParameters(parameters);
|
||||
}
|
||||
|
||||
CamKeypointTreatment::DetectorStrategy CamKeypointTreatment::detectorStrategy() const
|
||||
void Camera::mainLoopBegin()
|
||||
{
|
||||
DetectorStrategy strategy = kDetectorUndef;
|
||||
StarDetector * star = dynamic_cast<StarDetector*>(_keypointDetector);
|
||||
SURFDetector * surf = dynamic_cast<SURFDetector*>(_keypointDetector);
|
||||
if(star)
|
||||
{
|
||||
strategy = kDetectorStar;
|
||||
}
|
||||
else if(surf)
|
||||
{
|
||||
strategy = kDetectorSurf;
|
||||
}
|
||||
return strategy;
|
||||
}
|
||||
|
||||
Camera::Camera(float imageRate,
|
||||
bool autoRestart,
|
||||
unsigned int imageWidth,
|
||||
unsigned int imageHeight) :
|
||||
_imageRate(imageRate),
|
||||
_autoRestart(autoRestart),
|
||||
_imageWidth(imageWidth),
|
||||
_imageHeight(imageHeight)
|
||||
{
|
||||
_postThreatement = new CamPostTreatment();
|
||||
UEventsManager::addHandler(this);
|
||||
}
|
||||
|
||||
Camera::~Camera()
|
||||
{
|
||||
join(true);
|
||||
delete _postThreatement;
|
||||
}
|
||||
|
||||
SMState * Camera::takeSMState()
|
||||
{
|
||||
std::list<std::vector<float> > actions;
|
||||
IplImage * img = this->takeImage(&actions);
|
||||
if(img)
|
||||
{
|
||||
SMState * smState = new SMState(cv::Mat(), actions);
|
||||
smState->setImage(img);
|
||||
return smState;
|
||||
}
|
||||
return 0;
|
||||
_frameRateTimer.start();
|
||||
}
|
||||
|
||||
void Camera::mainLoop()
|
||||
@@ -220,16 +191,6 @@ void Camera::mainLoop()
|
||||
}
|
||||
}
|
||||
|
||||
// ownership is transferred
|
||||
void Camera::setPostThreatement(CamPostTreatment * strategy)
|
||||
{
|
||||
if(strategy)
|
||||
{
|
||||
delete _postThreatement;
|
||||
_postThreatement = strategy;
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::pushNewState(State newState, const ParametersMap & parameters)
|
||||
{
|
||||
ULOGGER_DEBUG("to %d", newState);
|
||||
@@ -260,29 +221,105 @@ void Camera::handleEvent(UEvent* anEvent)
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat Camera::takeImage()
|
||||
{
|
||||
cv::Mat descriptors;
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
bool tmp = _featuresExtracted;
|
||||
_featuresExtracted = false; // no need to extract descriptors/keypoints in this function
|
||||
cv::Mat img = takeImage(descriptors, keypoints);
|
||||
_featuresExtracted = tmp;
|
||||
return img;
|
||||
}
|
||||
|
||||
cv::Mat Camera::takeImage(cv::Mat & descriptors, std::vector<cv::KeyPoint> & keypoints)
|
||||
{
|
||||
descriptors = cv::Mat();
|
||||
keypoints.clear();
|
||||
if(_imageRate>0)
|
||||
{
|
||||
int sleepTime = (1000.0f/_imageRate - 1000.0f*_frameRateTimer.getElapsedTime());
|
||||
if(sleepTime > 2)
|
||||
{
|
||||
uSleep(sleepTime-2);
|
||||
}
|
||||
|
||||
// Add precision at the cost of a small overhead
|
||||
while(_frameRateTimer.getElapsedTime() < 1.0/double(_imageRate)-0.000001)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
double slept = _frameRateTimer.getElapsedTime();
|
||||
_frameRateTimer.start();
|
||||
UDEBUG("slept=%fs vs target=%fs", slept, 1.0/double(_imageRate));
|
||||
}
|
||||
|
||||
cv::Mat img;
|
||||
if(!this->isKilled())
|
||||
{
|
||||
UTimer timer;
|
||||
img = this->captureImage();
|
||||
UDEBUG("Time capturing image = %fs", timer.ticks());
|
||||
if(img.depth() != CV_8U)
|
||||
{
|
||||
UWARN("Images should have already 8U depth !?");
|
||||
cv::Mat tmp = img;
|
||||
img = cv::Mat();
|
||||
tmp.convertTo(img, CV_8U);
|
||||
UDEBUG("Time converting image to 8U = %fs", timer.ticks());
|
||||
}
|
||||
|
||||
if(!img.empty())
|
||||
{
|
||||
if(_featuresExtracted && _keypointDetector && _keypointDescriptor)
|
||||
{
|
||||
keypoints = _keypointDetector->generateKeypoints(img);
|
||||
descriptors = _keypointDescriptor->generateDescriptors(img, keypoints);
|
||||
UDEBUG("Post treatment time = %fs", timer.ticks());
|
||||
}
|
||||
|
||||
if(_framesDropped)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
while(count++ < _framesDropped)
|
||||
{
|
||||
cv::Mat tmp = this->captureImage();
|
||||
if(!tmp.empty())
|
||||
{
|
||||
UDEBUG("frame dropped (%d/%d)", (int)count, (int)_framesDropped);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
UDEBUG("Frames dropped time = %fs", timer.ticks());
|
||||
}
|
||||
}
|
||||
}
|
||||
return img;
|
||||
}
|
||||
|
||||
void Camera::process()
|
||||
{
|
||||
UTimer timer;
|
||||
ULOGGER_DEBUG("Camera::process()");
|
||||
SMState * smState = this->takeSMState();
|
||||
if(smState)
|
||||
cv::Mat descriptors;
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
cv::Mat img = this->takeImage(descriptors, keypoints);
|
||||
if(!img.empty())
|
||||
{
|
||||
_postThreatement->process(smState);
|
||||
this->post(new SMStateEvent(smState));
|
||||
|
||||
double elapsed = timer.ticks();
|
||||
UDEBUG("Post treatment time = %fs", elapsed);
|
||||
if(_imageRate>0)
|
||||
if(_featuresExtracted)
|
||||
{
|
||||
float sleepTime = 1000.0f/_imageRate - 1000.0f*elapsed;
|
||||
if(sleepTime > 0)
|
||||
{
|
||||
UDEBUG("Now sleeping for = %fms", sleepTime);
|
||||
uSleep(sleepTime);
|
||||
}
|
||||
this->post(new CameraEvent(descriptors, keypoints, img, _id));
|
||||
}
|
||||
else
|
||||
{
|
||||
this->post(new CameraEvent(img, _id));
|
||||
}
|
||||
}
|
||||
else
|
||||
else if(!this->isKilled())
|
||||
{
|
||||
if(_autoRestart)
|
||||
{
|
||||
@@ -292,7 +329,7 @@ void Camera::process()
|
||||
{
|
||||
ULOGGER_DEBUG("Camera::process() : no more images...");
|
||||
this->kill();
|
||||
this->post(new CameraEvent());
|
||||
this->post(new CameraEvent(_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -307,12 +344,13 @@ CameraImages::CameraImages(const std::string & path,
|
||||
float imageRate,
|
||||
bool autoRestart,
|
||||
unsigned int imageWidth,
|
||||
unsigned int imageHeight) :
|
||||
Camera(imageRate, autoRestart, imageWidth, imageHeight),
|
||||
unsigned int imageHeight,
|
||||
unsigned int framesDropped,
|
||||
int id) :
|
||||
Camera(imageRate, autoRestart, imageWidth, imageHeight, framesDropped, id),
|
||||
_path(path),
|
||||
_startAt(startAt),
|
||||
_refreshDir(refreshDir),
|
||||
_dir(0),
|
||||
_count(0)
|
||||
{
|
||||
}
|
||||
@@ -320,60 +358,48 @@ CameraImages::CameraImages(const std::string & path,
|
||||
CameraImages::~CameraImages(void)
|
||||
{
|
||||
join(true);
|
||||
if(_dir)
|
||||
{
|
||||
delete _dir;
|
||||
_dir = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool CameraImages::init()
|
||||
{
|
||||
if(_dir)
|
||||
{
|
||||
delete _dir;
|
||||
_dir = 0;
|
||||
}
|
||||
_dir = new UDirectory(_path, "jpg ppm png bmp pnm");
|
||||
UDEBUG("");
|
||||
_dir = UDirectory(_path, "jpg ppm png bmp pnm");
|
||||
_count = 0;
|
||||
if(_path[_path.size()-1] != '\\' && _path[_path.size()-1] != '/')
|
||||
{
|
||||
_path.append("/");
|
||||
}
|
||||
if(!_dir)
|
||||
if(!_dir.isValid())
|
||||
{
|
||||
ULOGGER_ERROR("Directory path not valid \"%s\"", _path.c_str());
|
||||
ULOGGER_ERROR("Directory path is not valid \"%s\"", _path.c_str());
|
||||
}
|
||||
else if(_dir->getFileNames().size() == 0)
|
||||
else if(_dir.getFileNames().size() == 0)
|
||||
{
|
||||
UWARN("Directory is empty \"%s\"", _path.c_str());
|
||||
}
|
||||
return _dir != 0;
|
||||
return _dir.isValid();
|
||||
}
|
||||
|
||||
IplImage * CameraImages::takeImage(std::list<std::vector<float> > * actions)
|
||||
cv::Mat CameraImages::captureImage()
|
||||
{
|
||||
if(actions)
|
||||
{
|
||||
actions->clear();
|
||||
}
|
||||
IplImage * img = 0;
|
||||
if(_dir)
|
||||
UDEBUG("");
|
||||
cv::Mat img;
|
||||
if(_dir.isValid())
|
||||
{
|
||||
if(_refreshDir)
|
||||
{
|
||||
_dir->update();
|
||||
_dir.update();
|
||||
}
|
||||
if(_startAt == 0)
|
||||
{
|
||||
const std::list<std::string> & fileNames = _dir->getFileNames();
|
||||
const std::list<std::string> & fileNames = _dir.getFileNames();
|
||||
if(fileNames.size())
|
||||
{
|
||||
if(_lastFileName.empty() || uStrNumCmp(_lastFileName,*fileNames.rbegin()) < 0)
|
||||
{
|
||||
_lastFileName = *fileNames.rbegin();
|
||||
std::string fullPath = _path + _lastFileName;
|
||||
img = cvLoadImage(fullPath.c_str(), CV_LOAD_IMAGE_COLOR);
|
||||
img = cv::imread(fullPath.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -381,18 +407,31 @@ IplImage * CameraImages::takeImage(std::list<std::vector<float> > * actions)
|
||||
{
|
||||
std::string fileName;
|
||||
std::string fullPath;
|
||||
fileName = _dir->getNextFileName();
|
||||
fileName = _dir.getNextFileName();
|
||||
if(fileName.size())
|
||||
{
|
||||
fullPath = _path + fileName;
|
||||
while(++_count < _startAt && (fileName = _dir->getNextFileName()).size())
|
||||
while(++_count < _startAt && (fileName = _dir.getNextFileName()).size())
|
||||
{
|
||||
fullPath = _path + fileName;
|
||||
}
|
||||
if(fileName.size())
|
||||
{
|
||||
ULOGGER_DEBUG("Loading image : %s\n", fullPath.c_str());
|
||||
img = cvLoadImage(fullPath.c_str(), CV_LOAD_IMAGE_COLOR);
|
||||
ULOGGER_DEBUG("Loading image : %s", fullPath.c_str());
|
||||
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
|
||||
img = cv::imread(fullPath.c_str(), cv::IMREAD_UNCHANGED);
|
||||
#else
|
||||
img = cv::imread(fullPath.c_str(), -1);
|
||||
#endif
|
||||
// FIXME : it seems that some png are incorrectly loaded with opencv c++ interface, where c interface works...
|
||||
if(img.depth() != CV_8U)
|
||||
{
|
||||
// The depth should be 8U
|
||||
UWARN("Cannot read the image correctly, falling back to old OpenCV C interface...");
|
||||
IplImage * i = cvLoadImage(fullPath.c_str());
|
||||
img = cv::Mat(i, true);
|
||||
cvReleaseImage(&i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -401,22 +440,18 @@ IplImage * CameraImages::takeImage(std::list<std::vector<float> > * actions)
|
||||
{
|
||||
UWARN("Directory is not set, camera must be initialized.");
|
||||
}
|
||||
if(img &&
|
||||
|
||||
if(!img.empty() &&
|
||||
getImageWidth() &&
|
||||
getImageHeight() &&
|
||||
getImageWidth() != (unsigned int)img->width &&
|
||||
getImageHeight() != (unsigned int)img->height)
|
||||
getImageWidth() != (unsigned int)img.cols &&
|
||||
getImageHeight() != (unsigned int)img.rows)
|
||||
{
|
||||
// declare a destination IplImage object with correct size, depth and channels
|
||||
IplImage * resampledImg = cvCreateImage( cvSize((int)(getImageWidth()) ,
|
||||
(int)(getImageHeight()) ),
|
||||
img->depth, img->nChannels );
|
||||
|
||||
//use cvResize to resize source to a destination image (linear interpolation)
|
||||
cvResize(img, resampledImg);
|
||||
cvReleaseImage(&img);
|
||||
img = resampledImg;
|
||||
cv::Mat resampled;
|
||||
cv::resize(img, resampled, cv::Size(getImageWidth(), getImageHeight()));
|
||||
img = resampled;
|
||||
}
|
||||
UDEBUG("");
|
||||
return img;
|
||||
}
|
||||
|
||||
@@ -429,9 +464,10 @@ CameraVideo::CameraVideo(int usbDevice,
|
||||
float imageRate,
|
||||
bool autoRestart,
|
||||
unsigned int imageWidth,
|
||||
unsigned int imageHeight) :
|
||||
Camera(imageRate, autoRestart, imageWidth, imageHeight),
|
||||
_capture(0),
|
||||
unsigned int imageHeight,
|
||||
unsigned int framesDropped,
|
||||
int id) :
|
||||
Camera(imageRate, autoRestart, imageWidth, imageHeight, framesDropped, id),
|
||||
_src(kUsbDevice),
|
||||
_usbDevice(usbDevice)
|
||||
{
|
||||
@@ -442,10 +478,11 @@ CameraVideo::CameraVideo(const std::string & fileName,
|
||||
float imageRate,
|
||||
bool autoRestart,
|
||||
unsigned int imageWidth,
|
||||
unsigned int imageHeight) :
|
||||
Camera(imageRate, autoRestart, imageWidth, imageHeight),
|
||||
unsigned int imageHeight,
|
||||
unsigned int framesDropped,
|
||||
int id) :
|
||||
Camera(imageRate, autoRestart, imageWidth, imageHeight, framesDropped, id),
|
||||
_fileName(fileName),
|
||||
_capture(0),
|
||||
_src(kVideoFile)
|
||||
{
|
||||
}
|
||||
@@ -453,221 +490,71 @@ CameraVideo::CameraVideo(const std::string & fileName,
|
||||
CameraVideo::~CameraVideo()
|
||||
{
|
||||
join(true);
|
||||
if(_capture)
|
||||
{
|
||||
cvReleaseCapture(&_capture);
|
||||
}
|
||||
_capture.release();
|
||||
}
|
||||
|
||||
bool CameraVideo::init()
|
||||
{
|
||||
if(_capture)
|
||||
if(_capture.isOpened())
|
||||
{
|
||||
cvReleaseCapture(&_capture);
|
||||
_capture = 0;
|
||||
_capture.release();
|
||||
}
|
||||
|
||||
if(_src == kUsbDevice)
|
||||
{
|
||||
ULOGGER_DEBUG("CameraVideo::init() Usb device initialization on device %d with imgSize=[%d,%d]", _usbDevice, getImageWidth(), getImageHeight());
|
||||
_capture = cvCaptureFromCAM(_usbDevice);
|
||||
if(_capture && getImageWidth() && getImageHeight())
|
||||
_capture.open(_usbDevice);
|
||||
if(getImageWidth() && getImageHeight())
|
||||
{
|
||||
cvSetCaptureProperty(_capture, CV_CAP_PROP_FRAME_WIDTH, double(getImageWidth()));
|
||||
cvSetCaptureProperty(_capture, CV_CAP_PROP_FRAME_HEIGHT, double(getImageHeight()));
|
||||
_capture.set(CV_CAP_PROP_FRAME_WIDTH, double(getImageWidth()));
|
||||
_capture.set(CV_CAP_PROP_FRAME_HEIGHT, double(getImageHeight()));
|
||||
}
|
||||
}
|
||||
else if(_src == kVideoFile)
|
||||
{
|
||||
ULOGGER_DEBUG("CameraVideo::init() filename=\"%s\"", _fileName.c_str());
|
||||
_capture = cvCaptureFromAVI(_fileName.c_str());
|
||||
ULOGGER_DEBUG("Camera: filename=\"%s\"", _fileName.c_str());
|
||||
_capture.open(_fileName.c_str());
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_ERROR("CameraVideo::init() Unknown source...");
|
||||
ULOGGER_ERROR("Camera: Unknown source...");
|
||||
}
|
||||
if(!_capture)
|
||||
if(!_capture.isOpened())
|
||||
{
|
||||
ULOGGER_ERROR("CameraVideo::init() Failed to create a capture object!");
|
||||
ULOGGER_ERROR("Camera: Failed to create a capture object!");
|
||||
_capture.release();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IplImage * CameraVideo::takeImage(std::list<std::vector<float> > * actions)
|
||||
cv::Mat CameraVideo::captureImage()
|
||||
{
|
||||
if(actions)
|
||||
cv::Mat img; // Null image
|
||||
if(_capture.isOpened())
|
||||
{
|
||||
actions->clear();
|
||||
}
|
||||
IplImage * img = 0; // Null image
|
||||
if(_capture)
|
||||
{
|
||||
if(!cvGrabFrame(_capture)){ // capture a frame
|
||||
ULOGGER_WARN("CameraVideo: Could not grab a frame, the end of the feed may be reached...");
|
||||
}
|
||||
else
|
||||
{
|
||||
img=cvRetrieveFrame(_capture); // retrieve the captured frame
|
||||
}
|
||||
_capture.read(img);
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_WARN("CameraVideo::takeImage() The camera must be initialized before requesting an image.");
|
||||
ULOGGER_WARN("The camera must be initialized before requesting an image.");
|
||||
}
|
||||
|
||||
if(img &&
|
||||
if(!img.empty() &&
|
||||
getImageWidth() &&
|
||||
getImageHeight() &&
|
||||
getImageWidth() != (unsigned int)img->width &&
|
||||
getImageHeight() != (unsigned int)img->height)
|
||||
getImageWidth() != (unsigned int)img.cols &&
|
||||
getImageHeight() != (unsigned int)img.rows)
|
||||
{
|
||||
// declare a destination IplImage object with correct size, depth and channels
|
||||
IplImage * resampledImg = cvCreateImage( cvSize((int)(getImageWidth()),(int)(getImageHeight())),
|
||||
img->depth,
|
||||
img->nChannels );
|
||||
|
||||
//use cvResize to resize source to a destination image (linear interpolation)
|
||||
cvResize(img, resampledImg);
|
||||
img = resampledImg;
|
||||
}
|
||||
else if(img)
|
||||
{
|
||||
img = cvCloneImage(img);
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/////////////////////////
|
||||
// CameraDatabase
|
||||
/////////////////////////
|
||||
CameraDatabase::CameraDatabase(const std::string & path,
|
||||
bool loadActions,
|
||||
float imageRate,
|
||||
bool autoRestart,
|
||||
unsigned int imageWidth,
|
||||
unsigned int imageHeight) :
|
||||
Camera(imageRate, autoRestart, imageWidth, imageHeight),
|
||||
_path(path),
|
||||
_loadActions(loadActions),
|
||||
_indexIter(_ids.begin()),
|
||||
_dbDriver(0)
|
||||
{
|
||||
}
|
||||
|
||||
CameraDatabase::~CameraDatabase(void)
|
||||
{
|
||||
join(true);
|
||||
if(_dbDriver)
|
||||
{
|
||||
_dbDriver->closeConnection();
|
||||
delete _dbDriver;
|
||||
}
|
||||
}
|
||||
|
||||
bool CameraDatabase::init()
|
||||
{
|
||||
if(_dbDriver)
|
||||
{
|
||||
_dbDriver->closeConnection();
|
||||
delete _dbDriver;
|
||||
_dbDriver = 0;
|
||||
}
|
||||
_ids.clear();
|
||||
_indexIter = _ids.begin();
|
||||
|
||||
std::string driverType = "sqlite3";
|
||||
ParametersMap parameters;
|
||||
parameters.insert(ParametersPair(Parameters::kDbSqlite3InMemory(), "false"));
|
||||
_dbDriver = rtabmap::DBDriverFactory::createDBDriver(driverType, parameters);
|
||||
if(!_dbDriver)
|
||||
{
|
||||
ULOGGER_ERROR("CameraDatabase::init() can't create \"%s\" driver",driverType.c_str());
|
||||
return false;
|
||||
}
|
||||
else if(!_dbDriver->openConnection(_path.c_str()))
|
||||
{
|
||||
ULOGGER_ERROR("CameraDatabase::init() Can't read database \"%s\"",_path.c_str());
|
||||
return false;
|
||||
cv::Mat resampled;
|
||||
cv::resize(img, resampled, cv::Size(getImageWidth(), getImageHeight()));
|
||||
return resampled;
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbDriver->getAllSignatureIds(_ids);
|
||||
_indexIter = _ids.begin();
|
||||
// clone required
|
||||
return img.clone();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
IplImage * CameraDatabase::takeImage(std::list<std::vector<float> > * actions)
|
||||
{
|
||||
if(actions)
|
||||
{
|
||||
actions->clear();
|
||||
}
|
||||
IplImage * img = 0;
|
||||
if(_dbDriver && _indexIter != _ids.end())
|
||||
{
|
||||
// Get image
|
||||
_dbDriver->getImage(*_indexIter, &img);
|
||||
|
||||
// Get actions from its previous neighbor
|
||||
if(actions && _loadActions)
|
||||
{
|
||||
if(*_indexIter-1 > 0)
|
||||
{
|
||||
NeighborsMultiMap neighbors;
|
||||
_dbDriver->loadNeighbors(*_indexIter-1, neighbors);
|
||||
for(NeighborsMultiMap::iterator iter = neighbors.begin(); iter!=neighbors.end(); ++iter)
|
||||
{
|
||||
if(iter->first>*_indexIter-1 && iter->second.actions().size())
|
||||
{
|
||||
*actions = iter->second.actions();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(actions->size() == 0)
|
||||
{
|
||||
UWARN("actions from previous %d to current %d are null", *_indexIter-1, *_indexIter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
++_indexIter;
|
||||
}
|
||||
else if(!_dbDriver)
|
||||
{
|
||||
ULOGGER_WARN("The camera must be initialized first...");
|
||||
}
|
||||
else if(_ids.size() == 0)
|
||||
{
|
||||
ULOGGER_WARN("The database \"%s\" is empty...", _path.c_str());
|
||||
}
|
||||
|
||||
if(img &&
|
||||
getImageWidth() &&
|
||||
getImageHeight() &&
|
||||
getImageWidth() != (unsigned int)img->width &&
|
||||
getImageHeight() != (unsigned int)img->height)
|
||||
{
|
||||
// declare a destination IplImage object with correct size, depth and channels
|
||||
IplImage * resampledImg = cvCreateImage( cvSize((int)(getImageWidth()) ,
|
||||
(int)(getImageHeight()) ),
|
||||
img->depth, img->nChannels );
|
||||
|
||||
//use cvResize to resize source to a destination image (linear interpolation)
|
||||
cvResize(img, resampledImg);
|
||||
cvReleaseImage(&img);
|
||||
img = resampledImg;
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
} // namespace rtabmap
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
*, Author: MatLab
|
||||
*/
|
||||
|
||||
#include "ColorTable.h"
|
||||
#include "rtabmap/core/ColorTable.h"
|
||||
#include "ColorIndexes65536_bin_zip.h"
|
||||
#include "ColorIndexes1024_bin_zip.h"
|
||||
#include "ColorIndexes512_bin_zip.h"
|
||||
@@ -75,21 +75,19 @@ ColorTable::ColorTable(int size) :
|
||||
uLongf totalUncompressed = uncompressed.size();
|
||||
UDEBUG("zip bytes=%d, uncompressed prediction=%d", (int)bytes.size(), (int)totalUncompressed);
|
||||
int err_code = uncompress((Bytef*)uncompressed.data(), &totalUncompressed, (const Bytef*)bytes.data(), bytes.size());
|
||||
if(err_code == Z_OK)
|
||||
UDEBUG("totalUncompressed=%ld", totalUncompressed);
|
||||
|
||||
if(err_code == Z_MEM_ERROR)
|
||||
{
|
||||
UDEBUG("Ok! totalUncompressed=%ld", totalUncompressed);
|
||||
}
|
||||
else if(err_code == Z_MEM_ERROR)
|
||||
{
|
||||
UFATAL("Z_MEM_ERROR");
|
||||
UFATAL("Z_MEM_ERROR : Insufficient memory.");
|
||||
}
|
||||
else if(err_code == Z_BUF_ERROR)
|
||||
{
|
||||
UFATAL("Z_BUF_ERROR");
|
||||
UFATAL("Z_BUF_ERROR : The buffer dest was not large enough to hold the uncompressed data.");
|
||||
}
|
||||
else if(err_code == Z_DATA_ERROR)
|
||||
{
|
||||
UFATAL("Z_DATA_ERROR");
|
||||
UFATAL("Z_DATA_ERROR : The compressed data (referenced by source) was corrupted.");
|
||||
}
|
||||
|
||||
_rgb2indexed = std::vector<unsigned short>(uncompressed.size()/sizeof(unsigned short));
|
||||
|
||||
+47
-41
@@ -20,7 +20,8 @@
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "VWDictionary.h"
|
||||
#include "rtabmap/core/VWDictionary.h"
|
||||
#include "rtabmap/core/VisualWord.h"
|
||||
#include "utilite/UConversion.h"
|
||||
#include "utilite/UMath.h"
|
||||
#include "utilite/ULogger.h"
|
||||
@@ -33,7 +34,6 @@ DBDriver::DBDriver(const ParametersMap & parameters) :
|
||||
_minSignaturesToSave(Parameters::defaultDbMinSignaturesToSave()),
|
||||
_minWordsToSave(Parameters::defaultDbMinWordsToSave()),
|
||||
_imagesCompressed(Parameters::defaultDbImagesCompressed()),
|
||||
_asyncWaiting(true),
|
||||
_emptyTrashesTime(0)
|
||||
{
|
||||
this->parseParameters(parameters);
|
||||
@@ -109,16 +109,12 @@ long DBDriver::getMemoryUsed() const
|
||||
|
||||
void DBDriver::mainLoop()
|
||||
{
|
||||
UDEBUG("");
|
||||
this->emptyTrashes();
|
||||
UDEBUG("");
|
||||
this->kill(); // Do it only once
|
||||
UDEBUG("");
|
||||
}
|
||||
|
||||
void DBDriver::killCleanup()
|
||||
{
|
||||
UDEBUG("");
|
||||
}
|
||||
|
||||
void DBDriver::beginTransaction() const
|
||||
@@ -166,8 +162,6 @@ void DBDriver::emptyTrashes(bool async)
|
||||
_trashSignatures.clear();
|
||||
_trashVisualWords.clear();
|
||||
|
||||
_asyncWaiting = true;
|
||||
|
||||
_dbSafeAccessMutex.lock();
|
||||
}
|
||||
_trashesMutex.unlock();
|
||||
@@ -219,32 +213,35 @@ void DBDriver::emptyTrashes(bool async)
|
||||
|
||||
void DBDriver::asyncSave(Signature * s)
|
||||
{
|
||||
_trashesMutex.lock();
|
||||
if(s)
|
||||
{
|
||||
_trashSignatures.insert(std::pair<int, Signature*>(s->id(), s));
|
||||
if(_trashSignatures.size() > _minSignaturesToSave && this->isRunning() && _asyncWaiting)
|
||||
UDEBUG("s=%d", s->id());
|
||||
_trashesMutex.lock();
|
||||
{
|
||||
ULOGGER_DEBUG("(Sign) Releasing addSem...");
|
||||
_asyncWaiting = false;
|
||||
this->start();
|
||||
_trashSignatures.insert(std::pair<int, Signature*>(s->id(), s));
|
||||
if(_trashSignatures.size() > _minSignaturesToSave && this->isIdle())
|
||||
{
|
||||
this->start();
|
||||
}
|
||||
}
|
||||
_trashesMutex.unlock();
|
||||
}
|
||||
_trashesMutex.unlock();
|
||||
}
|
||||
|
||||
void DBDriver::asyncSave(VisualWord * vw)
|
||||
{
|
||||
_trashesMutex.lock();
|
||||
if(vw)
|
||||
{
|
||||
_trashVisualWords.insert(std::pair<int, VisualWord*>(vw->id(), vw));
|
||||
if(_trashVisualWords.size() > _minWordsToSave && this->isRunning() && _asyncWaiting)
|
||||
_trashesMutex.lock();
|
||||
{
|
||||
ULOGGER_DEBUG("(Word) Releasing addSem...");
|
||||
_asyncWaiting = false;
|
||||
this->start();
|
||||
_trashVisualWords.insert(std::pair<int, VisualWord*>(vw->id(), vw));
|
||||
if(_trashVisualWords.size() > _minWordsToSave && this->isIdle())
|
||||
{
|
||||
this->start();
|
||||
}
|
||||
}
|
||||
_trashesMutex.unlock();
|
||||
}
|
||||
_trashesMutex.unlock();
|
||||
}
|
||||
|
||||
bool DBDriver::getSignature(int signatureId, Signature ** s)
|
||||
@@ -350,11 +347,11 @@ bool DBDriver::load(VWDictionary * dictionary) const
|
||||
return r;
|
||||
}
|
||||
|
||||
bool DBDriver::loadLastSignatures(std::list<Signature *> & signatures) const
|
||||
bool DBDriver::loadLastNodes(std::list<Signature *> & signatures) const
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->loadLastSignaturesQuery(signatures);
|
||||
r = this->loadLastNodesQuery(signatures);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return r;
|
||||
}
|
||||
@@ -605,7 +602,7 @@ bool DBDriver::deleteAllObsoleteSSVWLinks() const
|
||||
if(this->isConnected())
|
||||
{
|
||||
std::string query;
|
||||
query += "DELETE FROM Map_SS_VW WHERE NOT EXISTS (SELECT id FROM VisualWord WHERE id = Map_SS_VW.visualWordId);";
|
||||
query += "DELETE FROM Map_Node_Word WHERE NOT EXISTS (SELECT id FROM Word WHERE id = Map_Node_Word.word_id);";
|
||||
|
||||
_dbSafeAccessMutex.lock();
|
||||
bool r = this->executeNoResultQuery(query);
|
||||
@@ -620,7 +617,7 @@ bool DBDriver::deleteUnreferencedWords() const
|
||||
ULOGGER_DEBUG("");
|
||||
if(this->isConnected())
|
||||
{
|
||||
std::string query = "DELETE FROM visualword WHERE id NOT IN (SELECT visualWordid FROM map_ss_vw);";
|
||||
std::string query = "DELETE FROM Word WHERE id NOT IN (SELECT word_id FROM Map_Node_Word);";
|
||||
_dbSafeAccessMutex.lock();
|
||||
bool r = this->executeNoResultQuery(query);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
@@ -630,16 +627,25 @@ bool DBDriver::deleteUnreferencedWords() const
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::getImage(int id, IplImage ** img) const
|
||||
bool DBDriver::getRawData(int id, std::list<Sensor> & rawData) const
|
||||
{
|
||||
_dbSafeAccessMutex.lock();
|
||||
bool result = this->getImageQuery(id, img);
|
||||
bool result = this->getRawDataQuery(id, rawData);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::getNeighborIds(int signatureId, std::list<int> & neighbors, bool onlyWithActions) const
|
||||
bool DBDriver::getActuatorData(int id, std::list<Actuator> & data) const
|
||||
{
|
||||
_dbSafeAccessMutex.lock();
|
||||
bool result = this->getActuatorDataQuery(id, data);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return result;
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::getNeighborIds(int signatureId, std::set<int> & neighbors, bool onlyWithActions) const
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
@@ -679,50 +685,50 @@ bool DBDriver::getLoopClosureIds(int signatureId, std::set<int> & loopIds, std::
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::getAllSignatureIds(std::set<int> & ids) const
|
||||
bool DBDriver::getAllNodeIds(std::set<int> & ids) const
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->getAllSignatureIdsQuery(ids);
|
||||
r = this->getAllNodeIdsQuery(ids);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::getLastSignatureId(int & id) const
|
||||
bool DBDriver::getLastNodeId(int & id) const
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->getLastSignatureIdQuery(id);
|
||||
r = this->getLastNodeIdQuery(id);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::getLastVisualWordId(int & id) const
|
||||
bool DBDriver::getLastWordId(int & id) const
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->getLastVisualWordIdQuery(id);
|
||||
r = this->getLastWordIdQuery(id);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
//TODO Check also in the trash ?
|
||||
bool DBDriver::getSurfNi(int signatureId, int & ni) const
|
||||
bool DBDriver::getInvertedIndexNi(int signatureId, int & ni) const
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->getSurfNiQuery(signatureId, ni);
|
||||
r = this->getInvertedIndexNiQuery(signatureId, ni);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return r;
|
||||
}
|
||||
|
||||
bool DBDriver::getHighestWeightedSignatures(unsigned int count, std::multimap<int, int> & ids) const
|
||||
bool DBDriver::getHighestWeightedNodeIds(unsigned int count, std::multimap<int, int> & ids) const
|
||||
{
|
||||
bool r;
|
||||
_dbSafeAccessMutex.lock();
|
||||
r = this->getHighestWeightedSignaturesQuery(count, ids);
|
||||
r = this->getHighestWeightedNodeIdsQuery(count, ids);
|
||||
_dbSafeAccessMutex.unlock();
|
||||
return r;
|
||||
}
|
||||
@@ -733,7 +739,7 @@ bool DBDriver::addStatisticsAfterRun(int stMemSize, int lastSignAdded, int proce
|
||||
if(this->isConnected())
|
||||
{
|
||||
std::stringstream query;
|
||||
query << "INSERT INTO StatisticsAfterRun(stMemSize,lastSignAdded,processMemUsed,databaseMemUsed) values("
|
||||
query << "INSERT INTO Statistics(STM_size,last_sign_added,process_mem_used,database_mem_used) values("
|
||||
<< stMemSize << ","
|
||||
<< lastSignAdded << ","
|
||||
<< processMemUsed << ","
|
||||
@@ -751,7 +757,7 @@ bool DBDriver::addStatisticsAfterRunSurf(int dictionarySize) const
|
||||
if(this->isConnected())
|
||||
{
|
||||
std::stringstream query;
|
||||
query << "INSERT INTO StatisticsAfterRunSurf(dictionarySize) values(" << dictionarySize << ");";
|
||||
query << "INSERT INTO StatisticsDictionary(dictionary_size) values(" << dictionarySize << ");";
|
||||
|
||||
bool r = this->executeNoResultQuery(query.str());
|
||||
return r;
|
||||
|
||||
+799
-895
File diff suppressed because it is too large
Load Diff
@@ -50,7 +50,7 @@ private:
|
||||
|
||||
virtual bool changeWordsRefQuery(const std::map<int, int> & refsToChange) const; // <oldWordId, activeWordId>
|
||||
virtual bool deleteWordsQuery(const std::vector<int> & ids) const;
|
||||
virtual bool getNeighborIdsQuery(int signatureId, std::list<int> & neighbors, bool onlyWithActions = false) const;
|
||||
virtual bool getNeighborIdsQuery(int signatureId, std::set<int> & neighbors, bool onlyWithActions = false) const;
|
||||
virtual bool getWeightQuery(int signatureId, int & weight) const;
|
||||
virtual bool getLoopClosureIdsQuery(int signatureId, std::set<int> & loopIds, std::set<int> & childIds) const;
|
||||
|
||||
@@ -60,7 +60,7 @@ private:
|
||||
|
||||
// Load objects
|
||||
virtual bool loadQuery(VWDictionary * dictionary) const;
|
||||
virtual bool loadLastSignaturesQuery(std::list<Signature *> & signatures) const;
|
||||
virtual bool loadLastNodesQuery(std::list<Signature *> & signatures) const;
|
||||
virtual bool loadQuery(int signatureId, Signature ** s) const;
|
||||
virtual bool loadQuery(int wordId, VisualWord ** vw) const;
|
||||
virtual bool loadQuery(int signatureId, KeypointSignature * ss) const;
|
||||
@@ -69,28 +69,30 @@ private:
|
||||
virtual bool loadSMSignaturesQuery(const std::list<int> & ids, std::list<Signature *> & signatures) const;
|
||||
virtual bool loadWordsQuery(const std::list<int> & wordIds, std::list<VisualWord *> & vws) const;
|
||||
virtual bool loadNeighborsQuery(int signatureId, NeighborsMultiMap & neighbors) const;
|
||||
bool loadNeighborsQuery(std::list<Signature *> & signatures) const;
|
||||
bool loadLinksQuery(std::list<Signature *> & signatures) const;
|
||||
|
||||
virtual bool getImageQuery(int id, IplImage ** image) const;
|
||||
virtual bool getAllSignatureIdsQuery(std::set<int> & ids) const;
|
||||
virtual bool getLastSignatureIdQuery(int & id) const;
|
||||
virtual bool getLastVisualWordIdQuery(int & id) const;
|
||||
virtual bool getSurfNiQuery(int signatureId, int & ni) const;
|
||||
virtual bool getHighestWeightedSignaturesQuery(unsigned int count, std::multimap<int, int> & ids) const;
|
||||
virtual bool getRawDataQuery(int id, std::list<Sensor> & rawData) const;
|
||||
virtual bool getActuatorDataQuery(int id, std::list<Actuator> & data) const;
|
||||
virtual bool getAllNodeIdsQuery(std::set<int> & ids) const;
|
||||
virtual bool getLastNodeIdQuery(int & id) const;
|
||||
virtual bool getLastWordIdQuery(int & id) const;
|
||||
virtual bool getInvertedIndexNiQuery(int signatureId, int & ni) const;
|
||||
virtual bool getHighestWeightedNodeIdsQuery(unsigned int count, std::multimap<int, int> & ids) const;
|
||||
|
||||
private:
|
||||
std::string queryStepSignature() const;
|
||||
std::string queryStepImage() const;
|
||||
std::string queryStepNeighborLink() const;
|
||||
std::string queryStepNode() const;
|
||||
std::string queryStepSensor() const;
|
||||
std::string queryStepLink() const;
|
||||
std::string queryStepActuator() const;
|
||||
std::string queryStepWordsChanged() const;
|
||||
std::string queryStepKeypoint() const;
|
||||
std::string queryStepSensors() const;
|
||||
int stepSignature(sqlite3_stmt * ppStmt, const Signature * s) const;
|
||||
int stepImage(sqlite3_stmt * ppStmt, int id, const IplImage * img) const;
|
||||
int stepNeighborLink(sqlite3_stmt * ppStmt, int signatureId, const NeighborLink & n) const;
|
||||
int stepNode(sqlite3_stmt * ppStmt, const Signature * s) const;
|
||||
int stepSensor(sqlite3_stmt * ppStmt, int id, int num, const std::vector<int> & data, const Sensor & sensor) const;
|
||||
int stepLink(sqlite3_stmt * ppStmt, int fromId, int toId, int type, int actuator_id, const std::vector<int> & baseIds) const;
|
||||
int stepActuator(sqlite3_stmt * ppStmt, int id, int num, const Actuator & actuator) const;
|
||||
int stepWordsChanged(sqlite3_stmt * ppStmt, int signatureId, int oldWordId, int newWordId) const;
|
||||
int stepKeypoint(sqlite3_stmt * ppStmt, int signatureId, int wordId, const cv::KeyPoint & kp) const;
|
||||
int stepSensors(sqlite3_stmt * ppStmt, const SMSignature * s) const;
|
||||
|
||||
private:
|
||||
int loadOrSaveDb(sqlite3 *pInMemory, const std::string & fileName, int isSave) const;
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
/*
|
||||
* DBReader.cpp
|
||||
*
|
||||
* Created on: 2012-06-13
|
||||
* Author: mathieu
|
||||
*/
|
||||
|
||||
#include "rtabmap/core/DBReader.h"
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
|
||||
#include "rtabmap/core/SensorimotorEvent.h"
|
||||
#include "rtabmap/core/DBDriverFactory.h"
|
||||
|
||||
#include <utilite/ULogger.h>
|
||||
#include <utilite/UEventsManager.h>
|
||||
#include <utilite/UFile.h>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
DBReader::DBReader(const std::string & databasePath,
|
||||
float frameRate,
|
||||
const std::set<Sensor::Type> & sensorTypes,
|
||||
const std::set<Actuator::Type> & actuatorTypes) :
|
||||
_path(databasePath),
|
||||
_frameRate(frameRate),
|
||||
_sensorTypes(sensorTypes),
|
||||
_actuatorTypes(actuatorTypes),
|
||||
_dbDriver(0),
|
||||
_currentId(_ids.end())
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
DBReader::~DBReader()
|
||||
{
|
||||
if(_dbDriver)
|
||||
{
|
||||
_dbDriver->closeConnection();
|
||||
delete _dbDriver;
|
||||
}
|
||||
}
|
||||
|
||||
bool DBReader::init()
|
||||
{
|
||||
if(_dbDriver)
|
||||
{
|
||||
_dbDriver->closeConnection();
|
||||
delete _dbDriver;
|
||||
_dbDriver = 0;
|
||||
}
|
||||
_ids.clear();
|
||||
_currentId=_ids.end();
|
||||
|
||||
if(!UFile::exists(_path))
|
||||
{
|
||||
UERROR("Database path does not exist (%s)", _path.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
rtabmap::ParametersMap parameters;
|
||||
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kDbSqlite3InMemory(), "false"));
|
||||
_dbDriver = DBDriverFactory::createDBDriver("sqlite3", parameters);
|
||||
if(!_dbDriver)
|
||||
{
|
||||
UERROR("Driver doesn't exist.");
|
||||
return false;
|
||||
}
|
||||
if(!_dbDriver->openConnection(_path))
|
||||
{
|
||||
UERROR("Can't open database %s", _path.c_str());
|
||||
delete _dbDriver;
|
||||
_dbDriver = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
_dbDriver->getAllNodeIds(_ids);
|
||||
_currentId = _ids.begin();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void DBReader::setFrameRate(float frameRate)
|
||||
{
|
||||
if(frameRate >= 0.0f)
|
||||
{
|
||||
_frameRate = frameRate;
|
||||
}
|
||||
}
|
||||
|
||||
void DBReader::mainLoopBegin()
|
||||
{
|
||||
_timer.start();
|
||||
}
|
||||
|
||||
void DBReader::mainLoop()
|
||||
{
|
||||
std::list<Sensor> sensors;
|
||||
std::list<Actuator> actuators;
|
||||
this->getNextSensorimotorState(sensors, actuators);
|
||||
if(!sensors.empty() || !actuators.empty())
|
||||
{
|
||||
UEventsManager::post(new SensorimotorEvent(sensors, actuators));
|
||||
}
|
||||
else if(!this->isKilled())
|
||||
{
|
||||
UDEBUG("no more sensorimotor states...");
|
||||
this->kill();
|
||||
UEventsManager::post(new SensorimotorEvent());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void DBReader::getNextSensorimotorState(std::list<Sensor> & sensors, std::list<Actuator> & actuators)
|
||||
{
|
||||
sensors.clear();
|
||||
actuators.clear();
|
||||
|
||||
if(_dbDriver)
|
||||
{
|
||||
float frameRate = _frameRate;
|
||||
if(frameRate>0.0f)
|
||||
{
|
||||
int sleepTime = (1000.0f/frameRate - 1000.0f*_timer.getElapsedTime());
|
||||
if(sleepTime > 2)
|
||||
{
|
||||
uSleep(sleepTime-2);
|
||||
}
|
||||
|
||||
// Add precision at the cost of a small overhead
|
||||
while(_timer.getElapsedTime() < 1.0/double(frameRate)-0.000001)
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
double slept = _timer.getElapsedTime();
|
||||
_timer.start();
|
||||
UDEBUG("slept=%fs vs target=%fs", slept, 1.0/double(frameRate));
|
||||
}
|
||||
|
||||
if(!this->isKilled() && _currentId != _ids.end())
|
||||
{
|
||||
//sensors
|
||||
_dbDriver->getRawData(*_currentId, sensors);
|
||||
|
||||
//actuators
|
||||
NeighborsMultiMap neighbors;
|
||||
++_currentId;
|
||||
if(_currentId != _ids.end())
|
||||
{
|
||||
_dbDriver->getActuatorData(*_currentId, actuators);
|
||||
}
|
||||
|
||||
UDEBUG("sensors.size=%d actuators.size=%d", sensors.size(), actuators.size());
|
||||
|
||||
//filtering for types wanted
|
||||
if(_sensorTypes.size())
|
||||
{
|
||||
for(std::list<Sensor>::iterator jter=sensors.begin(); jter!=sensors.end();)
|
||||
{
|
||||
if(_sensorTypes.find((Sensor::Type)jter->type()) == _sensorTypes.end())
|
||||
{
|
||||
jter = sensors.erase(jter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++jter;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(_actuatorTypes.size())
|
||||
{
|
||||
for(std::list<Actuator>::iterator jter=actuators.begin(); jter!=actuators.end();)
|
||||
{
|
||||
if(_actuatorTypes.find((Actuator::Type)jter->type()) == _actuatorTypes.end())
|
||||
{
|
||||
jter = actuators.erase(jter);
|
||||
}
|
||||
else
|
||||
{
|
||||
++jter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
UDEBUG("after filtering sensors.size=%d actuators.size=%d", sensors.size(), actuators.size());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Not initialized...");
|
||||
}
|
||||
}
|
||||
|
||||
} /* namespace rtabmap */
|
||||
@@ -19,9 +19,13 @@
|
||||
|
||||
#include "rtabmap/core/EpipolarGeometry.h"
|
||||
#include "utilite/ULogger.h"
|
||||
#include "utilite/UTimer.h"
|
||||
#include "utilite/UStl.h"
|
||||
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <opencv2/core/core_c.h>
|
||||
#include <opencv2/calib3d/calib3d.hpp>
|
||||
#include <iostream>
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
@@ -41,71 +45,375 @@ void findEpipolesFromF(const cv::Mat & fundamentalMatrix, cv::Vec3d & e1, cv::Ve
|
||||
return;
|
||||
}
|
||||
|
||||
CvMat * w = cvCreateMat(3, 3, CV_64FC1);
|
||||
CvMat * u = cvCreateMat(3, 3, CV_64FC1);
|
||||
CvMat * v = cvCreateMat(3, 3, CV_64FC1);
|
||||
|
||||
CvMat f = fundamentalMatrix;
|
||||
cvSVD(&f, w, u, v);
|
||||
cv::SVD svd(fundamentalMatrix);
|
||||
cv::Mat u = svd.u;
|
||||
cv::Mat v = svd.vt;
|
||||
cv::Mat w = svd.w;
|
||||
|
||||
// v is for image 1
|
||||
// u is for image 2
|
||||
|
||||
e1[0] = v->data.db[0*3+2];// /v->data.db[2*3+2];
|
||||
e1[1] = v->data.db[1*3+2];// /v->data.db[2*3+2];
|
||||
e1[2] = v->data.db[2*3+2];// /v->data.db[2*3+2];
|
||||
e1[0] = v.at<double>(0,2);// /v->data.db[2*3+2];
|
||||
e1[1] = v.at<double>(1,2);// /v->data.db[2*3+2];
|
||||
e1[2] = v.at<double>(2,2);// /v->data.db[2*3+2];
|
||||
|
||||
e2[0] = u->data.db[0*3+2];// /u->data.db[2*3+2];
|
||||
e2[1] = u->data.db[1*3+2];// /u->data.db[2*3+2];
|
||||
e2[2] = u->data.db[2*3+2];// /u->data.db[2*3+2];
|
||||
|
||||
cvReleaseMat(&w);
|
||||
cvReleaseMat(&u);
|
||||
cvReleaseMat(&v);
|
||||
e2[0] = u.at<double>(0,2);// /u->data.db[2*3+2];
|
||||
e2[1] = u.at<double>(1,2);// /u->data.db[2*3+2];
|
||||
e2[2] = u.at<double>(2,2);// /u->data.db[2*3+2];
|
||||
}
|
||||
|
||||
// P2 = [M | t] = [[e']_x * F | e']
|
||||
void findPFromF(const cv::Mat & fundamentalMatrix, cv::Mat & p2, cv::Vec3d e2)
|
||||
//Assuming P0 = [eye(3) zeros(3,1)]
|
||||
// x1 and x2 are 2D points
|
||||
// return camera matrix P (3x4) matrix
|
||||
cv::Mat findPFromF(const cv::Mat & fundamentalMatrix, const cv::Mat & x1, const cv::Mat & x2)
|
||||
{
|
||||
if(p2.rows != 3 || p2.cols != 4 || fundamentalMatrix.rows != 3 || fundamentalMatrix.cols != 3)
|
||||
|
||||
if(fundamentalMatrix.rows != 3 || fundamentalMatrix.cols != 3)
|
||||
{
|
||||
ULOGGER_ERROR("Matrices are not the good size... ");
|
||||
return;
|
||||
return cv::Mat();
|
||||
}
|
||||
|
||||
if(p2.type()!= CV_64FC1 || fundamentalMatrix.type() != CV_64FC1)
|
||||
if(fundamentalMatrix.type() != CV_64FC1)
|
||||
{
|
||||
ULOGGER_ERROR("Matrices are not the good type...");
|
||||
return;
|
||||
return cv::Mat();
|
||||
}
|
||||
|
||||
if(e2[0] == 0 && e2[1] == 0 && e2[2] == 0)
|
||||
// P matrix 3x4
|
||||
cv::Mat p = cv::Mat::zeros(3, 4, CV_64FC1);
|
||||
|
||||
// P0 matrix 3X4
|
||||
cv::Mat p0 = cv::Mat::zeros(3, 4, CV_64FC1);
|
||||
p0.at<double>(0,0) = 1;
|
||||
p0.at<double>(1,1) = 1;
|
||||
p0.at<double>(2,2) = 1;
|
||||
|
||||
// cv::SVD doesn't five same results as cvSVD ?!? cvSVD return same values as in MatLab
|
||||
/*cv::SVD svd(fundamentalMatrix);
|
||||
cv::Mat u = svd.u;
|
||||
cv::Mat v = svd.vt;
|
||||
cv::Mat s = svd.w;
|
||||
cv::Mat e = u.col(2);*/
|
||||
|
||||
CvMat F = fundamentalMatrix;
|
||||
cv::Mat u(3,3,CV_64F);
|
||||
cv::Mat v(3,3,CV_64F);
|
||||
cv::Mat s(3,3,CV_64F);
|
||||
CvMat U = u;
|
||||
CvMat S = s;
|
||||
CvMat V = v;
|
||||
cvSVD(&F, &S, &U, &V, CV_SVD_U_T|CV_SVD_V_T); // F = U D V^T
|
||||
u = u.t();
|
||||
//
|
||||
// INFO: may be required to multiply by -1 the last column of U
|
||||
// TODO: Is any way to detect when it is required to do that ? When
|
||||
// it is wrong, triangulated points have their Z value below 1 (between 0 and 1)...
|
||||
//
|
||||
/*u.at<double>(0,2) = -u.at<double>(0,2);
|
||||
u.at<double>(1,2) = -u.at<double>(1,2);
|
||||
u.at<double>(2,2) = -u.at<double>(2,2);*/
|
||||
v = v.t();
|
||||
cv::Mat e = u.col(2);
|
||||
|
||||
//std::cout << "u=" << u << std::endl;
|
||||
//std::cout << "v=" << v << std::endl;
|
||||
//std::cout << "s=" << s << std::endl;
|
||||
|
||||
// skew matrix 3X3
|
||||
cv::Mat skew = cv::Mat::zeros( 3, 3, CV_64FC1);
|
||||
skew.at<double>(0,1) = -1;
|
||||
skew.at<double>(1,0) = 1;
|
||||
skew.at<double>(2,2) = 1;
|
||||
|
||||
cv::Mat r;
|
||||
cv::Mat x4d;
|
||||
|
||||
cv::Mat x = x1.col(0); // just take one point
|
||||
cv::Mat xp = x2.col(0); // just take one point
|
||||
|
||||
// INFO: There 4 cases of P, only one have the points in
|
||||
// front of the two cameras (positive z).
|
||||
|
||||
// Case 1 : P = [U*W*V' e];
|
||||
r = u*skew*v.t();
|
||||
p.at<double>(0,0) = r.at<double>(0,0);
|
||||
p.at<double>(0,1) = r.at<double>(0,1);
|
||||
p.at<double>(0,2) = r.at<double>(0,2);
|
||||
p.at<double>(1,0) = r.at<double>(1,0);
|
||||
p.at<double>(1,1) = r.at<double>(1,1);
|
||||
p.at<double>(1,2) = r.at<double>(1,2);
|
||||
p.at<double>(2,0) = r.at<double>(2,0);
|
||||
p.at<double>(2,1) = r.at<double>(2,1);
|
||||
p.at<double>(2,2) = r.at<double>(2,2);
|
||||
p.at<double>(0,3) = e.at<double>(0,0);
|
||||
p.at<double>(1,3) = e.at<double>(1,0);
|
||||
p.at<double>(2,3) = e.at<double>(2,0);
|
||||
|
||||
cv::triangulatePoints(p0, p, x, xp, x4d);
|
||||
x4d.at<double>(0) = x4d.at<double>(0)/x4d.at<double>(3);
|
||||
x4d.at<double>(1) = x4d.at<double>(1)/x4d.at<double>(3);
|
||||
x4d.at<double>(2) = x4d.at<double>(2)/x4d.at<double>(3);
|
||||
x4d.at<double>(3) = x4d.at<double>(3)/x4d.at<double>(3);
|
||||
|
||||
cv::Mat xt1 = p0*x4d;
|
||||
cv::Mat xt2 = p*x4d;
|
||||
|
||||
if(xt1.at<double>(2,0) < 0 || xt2.at<double>(2,0) < 0)
|
||||
{
|
||||
cv::Vec3d e1;
|
||||
findEpipolesFromF(fundamentalMatrix, e1, e2);
|
||||
// Case 2 : P = [U*W*V' -e];
|
||||
p.at<double>(0,3) = -e.at<double>(0,0);
|
||||
p.at<double>(1,3) = -e.at<double>(1,0);
|
||||
p.at<double>(2,3) = -e.at<double>(2,0);
|
||||
cv::triangulatePoints(p0, p, x, xp, x4d);
|
||||
x4d.at<double>(0) = x4d.at<double>(0)/x4d.at<double>(3);
|
||||
x4d.at<double>(1) = x4d.at<double>(1)/x4d.at<double>(3);
|
||||
x4d.at<double>(2) = x4d.at<double>(2)/x4d.at<double>(3);
|
||||
x4d.at<double>(3) = x4d.at<double>(3)/x4d.at<double>(3);
|
||||
xt1 = p0*x4d;
|
||||
xt2 = p*x4d;
|
||||
if(xt1.at<double>(2,0) < 0 || xt2.at<double>(2,0) < 0)
|
||||
{
|
||||
// Case 3 : P = [U*W'*V' e];
|
||||
r = u*skew.t()*v.t();
|
||||
p.at<double>(0,0) = r.at<double>(0,0);
|
||||
p.at<double>(0,1) = r.at<double>(0,1);
|
||||
p.at<double>(0,2) = r.at<double>(0,2);
|
||||
p.at<double>(1,0) = r.at<double>(1,0);
|
||||
p.at<double>(1,1) = r.at<double>(1,1);
|
||||
p.at<double>(1,2) = r.at<double>(1,2);
|
||||
p.at<double>(2,0) = r.at<double>(2,0);
|
||||
p.at<double>(2,1) = r.at<double>(2,1);
|
||||
p.at<double>(2,2) = r.at<double>(2,2);
|
||||
p.at<double>(0,3) = e.at<double>(0,0);
|
||||
p.at<double>(1,3) = e.at<double>(1,0);
|
||||
p.at<double>(2,3) = e.at<double>(2,0);
|
||||
p.col(3) = e;
|
||||
cv::triangulatePoints(p0, p, x, xp, x4d);
|
||||
x4d.at<double>(0) = x4d.at<double>(0)/x4d.at<double>(3);
|
||||
x4d.at<double>(1) = x4d.at<double>(1)/x4d.at<double>(3);
|
||||
x4d.at<double>(2) = x4d.at<double>(2)/x4d.at<double>(3);
|
||||
x4d.at<double>(3) = x4d.at<double>(3)/x4d.at<double>(3);
|
||||
xt1 = p0*x4d;
|
||||
xt2 = p*x4d;
|
||||
if(xt1.at<double>(2,0) < 0 || xt2.at<double>(2,0) < 0)
|
||||
{
|
||||
// Case 4 : P = [U*W'*V' -e];
|
||||
p.at<double>(0,3) = -e.at<double>(0,0);
|
||||
p.at<double>(1,3) = -e.at<double>(1,0);
|
||||
p.at<double>(2,3) = -e.at<double>(2,0);
|
||||
cv::triangulatePoints(p0, p, x, xp, x4d);
|
||||
x4d.at<double>(0) = x4d.at<double>(0)/x4d.at<double>(3);
|
||||
x4d.at<double>(1) = x4d.at<double>(1)/x4d.at<double>(3);
|
||||
x4d.at<double>(2) = x4d.at<double>(2)/x4d.at<double>(3);
|
||||
x4d.at<double>(3) = x4d.at<double>(3)/x4d.at<double>(3);
|
||||
xt1 = p0*x4d;
|
||||
xt2 = p*x4d;
|
||||
UDEBUG("Case 4");
|
||||
}
|
||||
else
|
||||
{
|
||||
UDEBUG("Case 3");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UDEBUG("Case 2");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UDEBUG("Case 1");
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
cv::Mat findFFromWords(
|
||||
const std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs, // id, kpt1, kpt2
|
||||
std::vector<uchar> & status,
|
||||
double ransacParam1,
|
||||
double ransacParam2)
|
||||
{
|
||||
|
||||
status = std::vector<uchar>(pairs.size(), 0);
|
||||
//Convert Keypoints to a structure that OpenCV understands
|
||||
//3 dimensions (Homogeneous vectors)
|
||||
cv::Mat points1(1, pairs.size(), CV_32FC2);
|
||||
cv::Mat points2(1, pairs.size(), CV_32FC2);
|
||||
|
||||
float * points1data = points1.ptr<float>(0);
|
||||
float * points2data = points2.ptr<float>(0);
|
||||
|
||||
// Fill the points here ...
|
||||
int i=0;
|
||||
for(std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > >::const_iterator iter = pairs.begin();
|
||||
iter != pairs.end();
|
||||
++iter )
|
||||
{
|
||||
points1data[i*2] = (*iter).second.first.pt.x;
|
||||
points1data[i*2+1] = (*iter).second.first.pt.y;
|
||||
|
||||
points2data[i*2] = (*iter).second.second.pt.x;
|
||||
points2data[i*2+1] = (*iter).second.second.pt.y;
|
||||
|
||||
++i;
|
||||
}
|
||||
|
||||
double e2_sd[3*3] = { 0., -e2[2], e2[1],
|
||||
e2[2], 0., -e2[0],
|
||||
-e2[1], e2[0], 0. };
|
||||
CvMat e2_smt = cvMat( 3, 3, CV_64FC1, e2_sd );
|
||||
cv::Mat e2_sm(&e2_smt); //;
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
|
||||
cv::Mat m = e2_sm*fundamentalMatrix;
|
||||
// Find the fundamental matrix
|
||||
cv::Mat fundamentalMatrix = cv::findFundamentalMat(
|
||||
points1,
|
||||
points2,
|
||||
status,
|
||||
cv::FM_RANSAC,
|
||||
ransacParam1,
|
||||
ransacParam2);
|
||||
|
||||
p2.at<double>(0,0) = m.at<double>(0,0);
|
||||
p2.at<double>(0,1) = m.at<double>(0,1);
|
||||
p2.at<double>(0,2) = m.at<double>(0,2);
|
||||
p2.at<double>(1,0) = m.at<double>(1,0);
|
||||
p2.at<double>(1,1) = m.at<double>(1,1);
|
||||
p2.at<double>(1,2) = m.at<double>(1,2);
|
||||
p2.at<double>(2,0) = m.at<double>(2,0);
|
||||
p2.at<double>(2,1) = m.at<double>(2,1);
|
||||
p2.at<double>(2,2) = m.at<double>(2,2);
|
||||
ULOGGER_DEBUG("Find fundamental matrix (OpenCV) time = %fs", timer.ticks());
|
||||
|
||||
p2.at<double>(0,3) = e2[0];
|
||||
p2.at<double>(1,3) = e2[1];
|
||||
p2.at<double>(2,3) = e2[2];
|
||||
// Fundamental matrix is valid ?
|
||||
bool fundMatFound = false;
|
||||
UASSERT(fundamentalMatrix.type() == CV_64FC1);
|
||||
if(fundamentalMatrix.cols==3 && fundamentalMatrix.rows==3 &&
|
||||
(fundamentalMatrix.at<double>(0,0) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(0,1) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(0,2) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(1,0) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(1,1) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(1,2) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(2,0) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(2,1) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(2,2) != 0.0) )
|
||||
|
||||
{
|
||||
fundMatFound = true;
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("fm_count=%d...", fundMatFound);
|
||||
|
||||
if(fundMatFound)
|
||||
{
|
||||
// Show the fundamental matrix
|
||||
UDEBUG(
|
||||
"F = [%f %f %f;%f %f %f;%f %f %f]",
|
||||
fundamentalMatrix.ptr<double>(0)[0],
|
||||
fundamentalMatrix.ptr<double>(0)[1],
|
||||
fundamentalMatrix.ptr<double>(0)[2],
|
||||
fundamentalMatrix.ptr<double>(0)[3],
|
||||
fundamentalMatrix.ptr<double>(0)[4],
|
||||
fundamentalMatrix.ptr<double>(0)[5],
|
||||
fundamentalMatrix.ptr<double>(0)[6],
|
||||
fundamentalMatrix.ptr<double>(0)[7],
|
||||
fundamentalMatrix.ptr<double>(0)[8]);
|
||||
}
|
||||
return fundamentalMatrix;
|
||||
}
|
||||
|
||||
void findRTFromP(
|
||||
const cv::Mat & p,
|
||||
cv::Mat & r,
|
||||
cv::Mat & t)
|
||||
{
|
||||
UASSERT(p.cols == 4 && p.rows == 3);
|
||||
UDEBUG("");
|
||||
r = cv::Mat(p, cv::Range(0,3), cv::Range(0,3));
|
||||
UDEBUG("");
|
||||
r = -r.inv();
|
||||
UDEBUG("r=%d %d, t=%d", r.cols, r.rows, p.col(3).rows);
|
||||
t = r*p.col(3);
|
||||
UDEBUG("");
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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 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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
} // namespace rtabmap
|
||||
|
||||
@@ -26,6 +26,9 @@
|
||||
#include <opencv2/imgproc/imgproc_c.h>
|
||||
#include <opencv2/gpu/gpu.hpp>
|
||||
#include <opencv2/core/version.hpp>
|
||||
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
|
||||
#include <opencv2/nonfree/features2d.hpp>
|
||||
#endif
|
||||
|
||||
#define OPENCV_SURF_GPU CV_MAJOR_VERSION >= 2 and CV_MINOR_VERSION >=2 and CV_SUBMINOR_VERSION>=1
|
||||
|
||||
@@ -48,14 +51,14 @@ void KeypointDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
//SURFDescriptor
|
||||
//////////////////////////
|
||||
SURFDescriptor::SURFDescriptor(const ParametersMap & parameters) :
|
||||
KeypointDescriptor(parameters)
|
||||
KeypointDescriptor(parameters),
|
||||
_hessianThreshold(Parameters::defaultSURFHessianThreshold()),
|
||||
_nOctaves(Parameters::defaultSURFOctaves()),
|
||||
_nOctaveLayers(Parameters::defaultSURFOctaveLayers()),
|
||||
_extended(Parameters::defaultSURFExtended()),
|
||||
_upright(Parameters::defaultSURFUpright()),
|
||||
_gpuVersion(Parameters::defaultSURFGpuVersion())
|
||||
{
|
||||
_params.hessianThreshold = Parameters::defaultSURFHessianThreshold();
|
||||
_params.extended = Parameters::defaultSURFExtended();
|
||||
_params.nOctaveLayers = Parameters::defaultSURFOctaveLayers();
|
||||
_params.nOctaves = Parameters::defaultSURFOctaves();
|
||||
_params.upright = Parameters::defaultSURFUpright();
|
||||
_gpuVersion = Parameters::defaultSURFGpuVersion();
|
||||
this->parseParameters(parameters);
|
||||
}
|
||||
|
||||
@@ -68,23 +71,27 @@ void SURFDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
ParametersMap::const_iterator iter;
|
||||
if((iter=parameters.find(Parameters::kSURFExtended())) != parameters.end())
|
||||
{
|
||||
_params.extended = uStr2Bool((*iter).second.c_str());
|
||||
_extended = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFHessianThreshold())) != parameters.end())
|
||||
{
|
||||
_params.hessianThreshold = std::atof((*iter).second.c_str()); // is it needed for the descriptor?
|
||||
_hessianThreshold = std::atof((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFOctaveLayers())) != parameters.end())
|
||||
{
|
||||
_params.nOctaveLayers = std::atoi((*iter).second.c_str()); // is it needed for the descriptor?
|
||||
_nOctaveLayers = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
|
||||
{
|
||||
_params.nOctaves = std::atoi((*iter).second.c_str()); // is it needed for the descriptor?
|
||||
_nOctaves = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
|
||||
{
|
||||
_nOctaves = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFUpright())) != parameters.end())
|
||||
{
|
||||
_params.upright = uStr2Bool((*iter).second.c_str());
|
||||
_upright = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFGpuVersion())) != parameters.end())
|
||||
{
|
||||
@@ -93,32 +100,31 @@ void SURFDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
KeypointDescriptor::parseParameters(parameters);
|
||||
}
|
||||
|
||||
cv::Mat SURFDescriptor::generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
cv::Mat SURFDescriptor::generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
cv::Mat descriptors;
|
||||
if(!image)
|
||||
if(image.empty())
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
return descriptors;
|
||||
}
|
||||
// SURF support only grayscale images
|
||||
IplImage * imageGrayScale = 0;
|
||||
if(image->nChannels != 1 || image->depth != IPL_DEPTH_8U)
|
||||
cv::Mat imageGrayScale;
|
||||
if(image.channels() != 1 || image.depth() != CV_8U)
|
||||
{
|
||||
imageGrayScale = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1);
|
||||
cvCvtColor(image, imageGrayScale, CV_BGR2GRAY);
|
||||
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
|
||||
}
|
||||
cv::Mat img;
|
||||
if(imageGrayScale)
|
||||
if(!imageGrayScale.empty())
|
||||
{
|
||||
img = cv::Mat(imageGrayScale);
|
||||
img = imageGrayScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
img = cv::Mat(image);
|
||||
img = image;
|
||||
}
|
||||
#if OPENCV_SURF_GPU
|
||||
/*#if OPENCV_SURF_GPU
|
||||
if(_gpuVersion)
|
||||
{
|
||||
std::vector<float> d;
|
||||
@@ -142,15 +148,15 @@ cv::Mat SURFDescriptor::generateDescriptors(const IplImage * image, std::vector<
|
||||
cv::SurfDescriptorExtractor extractor(_params.nOctaves, _params.nOctaveLayers, _params.extended, _params.upright);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
}
|
||||
#else*/
|
||||
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
|
||||
cv::SURF extractor(_hessianThreshold, _nOctaves, _nOctaveLayers, _extended, _upright);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
#else
|
||||
cv::SurfDescriptorExtractor extractor(_params.nOctaves, _params.nOctaveLayers, _params.extended, _params.upright);
|
||||
cv::SurfDescriptorExtractor extractor(_nOctaves, _nOctaveLayers, _extended, _upright);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
#endif
|
||||
|
||||
if(imageGrayScale)
|
||||
{
|
||||
cvReleaseImage(&imageGrayScale);
|
||||
}
|
||||
//#endif
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
@@ -158,7 +164,12 @@ cv::Mat SURFDescriptor::generateDescriptors(const IplImage * image, std::vector<
|
||||
//SIFTDescriptor
|
||||
//////////////////////////
|
||||
SIFTDescriptor::SIFTDescriptor(const ParametersMap & parameters) :
|
||||
KeypointDescriptor(parameters)
|
||||
KeypointDescriptor(parameters),
|
||||
_nfeatures(Parameters::defaultSIFTNFeatures()),
|
||||
_nOctaveLayers(Parameters::defaultSIFTNOctaveLayers()),
|
||||
_contrastThreshold(Parameters::defaultSIFTContrastThreshold()),
|
||||
_edgeThreshold(Parameters::defaultSIFTEdgeThreshold()),
|
||||
_sigma(Parameters::defaultSIFTSigma())
|
||||
{
|
||||
this->parseParameters(parameters);
|
||||
}
|
||||
@@ -170,40 +181,64 @@ SIFTDescriptor::~SIFTDescriptor()
|
||||
void SIFTDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
ParametersMap::const_iterator iter;
|
||||
if((iter=parameters.find(Parameters::kSIFTContrastThreshold())) != parameters.end())
|
||||
{
|
||||
_contrastThreshold = std::atof((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSIFTEdgeThreshold())) != parameters.end())
|
||||
{
|
||||
_edgeThreshold = std::atof((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSIFTNFeatures())) != parameters.end())
|
||||
{
|
||||
_nfeatures = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSIFTNOctaveLayers())) != parameters.end())
|
||||
{
|
||||
_nOctaveLayers = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSIFTSigma())) != parameters.end())
|
||||
{
|
||||
_sigma = std::atof((*iter).second.c_str());
|
||||
}
|
||||
KeypointDescriptor::parseParameters(parameters);
|
||||
}
|
||||
|
||||
cv::Mat SIFTDescriptor::generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
cv::Mat SIFTDescriptor::generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
cv::Mat descriptors;
|
||||
if(!image)
|
||||
if(image.empty())
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
return descriptors;
|
||||
}
|
||||
// SURF support only grayscale images
|
||||
IplImage * imageGrayScale = 0;
|
||||
if(image->nChannels != 1 || image->depth != IPL_DEPTH_8U)
|
||||
cv::Mat imageGrayScale;
|
||||
if(image.channels() != 1 || image.depth() != CV_8U)
|
||||
{
|
||||
imageGrayScale = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1);
|
||||
cvCvtColor(image, imageGrayScale, CV_BGR2GRAY);
|
||||
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
|
||||
}
|
||||
cv::Mat img;
|
||||
if(imageGrayScale)
|
||||
if(!imageGrayScale.empty())
|
||||
{
|
||||
img = cv::Mat(imageGrayScale);
|
||||
img = imageGrayScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
img = cv::Mat(image);
|
||||
img = image;
|
||||
}
|
||||
cv::SiftDescriptorExtractor extractor(_descriptorParams, _commonParams);
|
||||
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
|
||||
cv::SIFT extractor(_nfeatures, _nOctaveLayers, _contrastThreshold, _edgeThreshold, _sigma);
|
||||
extractor.compute(img, keypoints, descriptors);
|
||||
if(imageGrayScale)
|
||||
{
|
||||
cvReleaseImage(&imageGrayScale);
|
||||
}
|
||||
#else
|
||||
cv::SIFT extractor(cv::SIFT::DescriptorParams::GET_DEFAULT_MAGNIFICATION(),
|
||||
cv::SIFT::DescriptorParams::DEFAULT_IS_NORMALIZE,
|
||||
true,
|
||||
cv::SIFT::CommonParams::DEFAULT_NOCTAVES,
|
||||
_nOctaveLayers);
|
||||
extractor(img, cv::Mat(), keypoints, descriptors, true);
|
||||
#endif
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
@@ -231,38 +266,32 @@ void BRIEFDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
KeypointDescriptor::parseParameters(parameters);
|
||||
}
|
||||
|
||||
cv::Mat BRIEFDescriptor::generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
cv::Mat BRIEFDescriptor::generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
cv::Mat descriptors;
|
||||
if(!image)
|
||||
if(image.empty())
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
return descriptors;
|
||||
}
|
||||
// BRIEF support only grayscale images ?
|
||||
IplImage * imageGrayScale = 0;
|
||||
if(image->nChannels != 1 || image->depth != IPL_DEPTH_8U)
|
||||
cv::Mat imageGrayScale;
|
||||
if(image.channels() != 1 || image.depth() != CV_8U)
|
||||
{
|
||||
imageGrayScale = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1);
|
||||
cvCvtColor(image, imageGrayScale, CV_BGR2GRAY);
|
||||
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
|
||||
}
|
||||
cv::Mat img;
|
||||
if(imageGrayScale)
|
||||
if(!imageGrayScale.empty())
|
||||
{
|
||||
img = cv::Mat(imageGrayScale);
|
||||
img = imageGrayScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
img = cv::Mat(image);
|
||||
img = image;
|
||||
}
|
||||
cv::BriefDescriptorExtractor brief(_size);
|
||||
brief.compute(img, keypoints, descriptors);
|
||||
|
||||
if(imageGrayScale)
|
||||
{
|
||||
cvReleaseImage(&imageGrayScale);
|
||||
}
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
@@ -285,30 +314,29 @@ void ColorDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
KeypointDescriptor::parseParameters(parameters);
|
||||
}
|
||||
|
||||
cv::Mat ColorDescriptor::generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
cv::Mat ColorDescriptor::generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
cv::Mat descriptors;
|
||||
if(!image)
|
||||
if(image.empty())
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
IplImage * imageConverted = 0;
|
||||
if(image->nChannels != 3 || image->depth != IPL_DEPTH_8U)
|
||||
cv::Mat imageConverted;
|
||||
if(image.channels() != 3 || image.depth() != CV_8U)
|
||||
{
|
||||
imageConverted = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 3);
|
||||
cvCvtColor(image, imageConverted, CV_GRAY2BGR);
|
||||
cv::cvtColor(image, imageConverted, CV_GRAY2BGR);
|
||||
}
|
||||
cv::Mat imgMat;
|
||||
if(imageConverted)
|
||||
if(!imageConverted.empty())
|
||||
{
|
||||
imgMat = cv::Mat(imageConverted);
|
||||
imgMat = imageConverted;
|
||||
}
|
||||
else
|
||||
{
|
||||
imgMat = cv::Mat(image);
|
||||
imgMat = image;
|
||||
}
|
||||
|
||||
//create descriptors...
|
||||
@@ -365,12 +393,6 @@ cv::Mat ColorDescriptor::generateDescriptors(const IplImage * image, std::vector
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
if(imageConverted)
|
||||
{
|
||||
cvReleaseImage(&imageConverted);
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
@@ -404,30 +426,29 @@ void HueDescriptor::parseParameters(const ParametersMap & parameters)
|
||||
KeypointDescriptor::parseParameters(parameters);
|
||||
}
|
||||
|
||||
cv::Mat HueDescriptor::generateDescriptors(const IplImage * image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
cv::Mat HueDescriptor::generateDescriptors(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
cv::Mat descriptors;
|
||||
if(!image)
|
||||
if(image.empty())
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
IplImage * imageConverted = 0;
|
||||
if(image->nChannels != 3 || image->depth != IPL_DEPTH_8U)
|
||||
cv::Mat imageConverted;
|
||||
if(image.channels() != 3 || image.depth() != CV_8U)
|
||||
{
|
||||
imageConverted = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 3);
|
||||
cvCvtColor(image, imageConverted, CV_GRAY2BGR);
|
||||
cv::cvtColor(image, imageConverted, CV_GRAY2BGR);
|
||||
}
|
||||
cv::Mat imgMat;
|
||||
if(imageConverted)
|
||||
if(!imageConverted.empty())
|
||||
{
|
||||
imgMat = cv::Mat(imageConverted);
|
||||
imgMat = imageConverted;
|
||||
}
|
||||
else
|
||||
{
|
||||
imgMat = cv::Mat(image);
|
||||
imgMat = image;
|
||||
}
|
||||
|
||||
//create descriptors...
|
||||
@@ -497,12 +518,6 @@ cv::Mat HueDescriptor::generateDescriptors(const IplImage * image, std::vector<c
|
||||
memcpy(rowFl, &d[i*2], 2*sizeof(float));
|
||||
++i;
|
||||
}
|
||||
|
||||
if(imageConverted)
|
||||
{
|
||||
cvReleaseImage(&imageConverted);
|
||||
}
|
||||
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
|
||||
+103
-141
@@ -18,15 +18,18 @@
|
||||
*/
|
||||
|
||||
#include "rtabmap/core/KeypointDetector.h"
|
||||
#include "VWDictionary.h"
|
||||
#include "rtabmap/core/VWDictionary.h"
|
||||
#include "utilite/ULogger.h"
|
||||
#include "utilite/UTimer.h"
|
||||
#include "utilite/UStl.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "utilite/UConversion.h"
|
||||
#include <opencv2/imgproc/imgproc_c.h>
|
||||
#include <opencv2/gpu/gpu.hpp>
|
||||
#include <opencv2/imgproc/imgproc.hpp>
|
||||
//#include <opencv2/gpu/gpu.hpp>
|
||||
#include <opencv2/core/version.hpp>
|
||||
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
|
||||
#include <opencv2/nonfree/features2d.hpp>
|
||||
#endif
|
||||
|
||||
#define OPENCV_SURF_GPU CV_MAJOR_VERSION >= 2 and CV_MINOR_VERSION >=2 and CV_SUBMINOR_VERSION>=1
|
||||
|
||||
@@ -35,8 +38,6 @@ namespace rtabmap
|
||||
|
||||
KeypointDetector::KeypointDetector(const ParametersMap & parameters) :
|
||||
_wordsPerImageTarget(Parameters::defaultKpWordsPerImage()),
|
||||
_usingAdaptiveResponseThr(Parameters::defaultKpUsingAdaptiveResponseThr()),
|
||||
_adaptiveResponseThr(1),
|
||||
_roiRatios(std::vector<float>(4, 0.0f))
|
||||
{
|
||||
this->setRoi(Parameters::defaultKpRoiRatios());
|
||||
@@ -50,21 +51,17 @@ void KeypointDetector::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
_wordsPerImageTarget = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kKpUsingAdaptiveResponseThr())) != parameters.end())
|
||||
{
|
||||
_usingAdaptiveResponseThr = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kKpRoiRatios())) != parameters.end())
|
||||
{
|
||||
this->setRoi((*iter).second);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<cv::KeyPoint> KeypointDetector::generateKeypoints(const IplImage * image)
|
||||
std::vector<cv::KeyPoint> KeypointDetector::generateKeypoints(const cv::Mat & image)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
if(image)
|
||||
if(!image.empty())
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
@@ -79,17 +76,8 @@ std::vector<cv::KeyPoint> KeypointDetector::generateKeypoints(const IplImage * i
|
||||
// Variable hessian threshold
|
||||
if(_wordsPerImageTarget > 0)
|
||||
{
|
||||
ULOGGER_DEBUG("_adaptiveResponseThr=%f", _adaptiveResponseThr);
|
||||
if(keypoints.size() > 0)
|
||||
{
|
||||
if(keypoints.size() > _wordsPerImageTarget)
|
||||
{
|
||||
_adaptiveResponseThr *= 1+((float(keypoints.size())/float(_wordsPerImageTarget)-1)/1000);
|
||||
}
|
||||
else if(keypoints.size() < _wordsPerImageTarget)
|
||||
{
|
||||
_adaptiveResponseThr *= 1-((1-float(keypoints.size())/float(_wordsPerImageTarget))/1);
|
||||
}
|
||||
// 10% margin...
|
||||
if(keypoints.size() > 1.1 * _wordsPerImageTarget)
|
||||
{
|
||||
@@ -115,12 +103,8 @@ std::vector<cv::KeyPoint> KeypointDetector::generateKeypoints(const IplImage * i
|
||||
kptsTmp[k].pt.x += roi.x;
|
||||
kptsTmp[k].pt.y += roi.y;
|
||||
}
|
||||
if(iter->first!=0)
|
||||
{
|
||||
_adaptiveResponseThr = iter->first;
|
||||
}
|
||||
keypoints = kptsTmp;
|
||||
ULOGGER_DEBUG("%d keypoints removed, (kept %d)", removed, keypoints.size());
|
||||
ULOGGER_DEBUG("%d keypoints removed, (kept %d), minimum response=%f", removed, keypoints.size(), kptsTmp.size()?kptsTmp.back().response:0.0f);
|
||||
}
|
||||
else if(roi.x || roi.y)
|
||||
{
|
||||
@@ -132,18 +116,8 @@ std::vector<cv::KeyPoint> KeypointDetector::generateKeypoints(const IplImage * i
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_adaptiveResponseThr /= 2;
|
||||
}
|
||||
|
||||
if(_adaptiveResponseThr < this->getMinimumResponseThr())
|
||||
{
|
||||
_adaptiveResponseThr = this->getMinimumResponseThr();
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("new _adaptiveResponseThr=%f", _adaptiveResponseThr);
|
||||
ULOGGER_DEBUG("adjusting hessian threshold time = %f s", timer.ticks());
|
||||
ULOGGER_DEBUG("removing words time = %f s", timer.ticks());
|
||||
}
|
||||
else if(roi.x || roi.y)
|
||||
{
|
||||
@@ -193,16 +167,16 @@ void KeypointDetector::setRoi(const std::string & roi)
|
||||
}
|
||||
}
|
||||
|
||||
cv::Rect KeypointDetector::computeRoi(const IplImage * image) const
|
||||
cv::Rect KeypointDetector::computeRoi(const cv::Mat & image) const
|
||||
{
|
||||
if(image && _roiRatios.size() == 4)
|
||||
if(!image.empty() && _roiRatios.size() == 4)
|
||||
{
|
||||
cv::Rect roi(0, 0, image->width, image->height);
|
||||
float width = image.cols;
|
||||
float height = image.rows;
|
||||
cv::Rect roi(0, 0, width, height);
|
||||
UDEBUG("roi ratios = %f, %f, %f, %f", _roiRatios[0],_roiRatios[1],_roiRatios[2],_roiRatios[3]);
|
||||
UDEBUG("roi = %d, %d, %d, %d", roi.x, roi.y, roi.width, roi.height);
|
||||
|
||||
float width = image->width;
|
||||
float height = image->height;
|
||||
//left roi
|
||||
if(_roiRatios[0] > 0 && _roiRatios[0] < 1 - _roiRatios[1])
|
||||
{
|
||||
@@ -244,16 +218,15 @@ cv::Rect KeypointDetector::computeRoi(const IplImage * image) const
|
||||
//SURFDetector
|
||||
//////////////////////////
|
||||
SURFDetector::SURFDetector(const ParametersMap & parameters) :
|
||||
KeypointDetector(parameters)
|
||||
KeypointDetector(parameters),
|
||||
_hessianThreshold(Parameters::defaultSURFHessianThreshold()),
|
||||
_nOctaves(Parameters::defaultSURFOctaves()),
|
||||
_nOctaveLayers(Parameters::defaultSURFOctaveLayers()),
|
||||
_extended(Parameters::defaultSURFExtended()),
|
||||
_upright(Parameters::defaultSURFUpright()),
|
||||
_gpuVersion(Parameters::defaultSURFGpuVersion())
|
||||
{
|
||||
_params.hessianThreshold = Parameters::defaultSURFHessianThreshold();
|
||||
_params.extended = Parameters::defaultSURFExtended();
|
||||
_params.nOctaveLayers = Parameters::defaultSURFOctaveLayers();
|
||||
_params.nOctaves = Parameters::defaultSURFOctaves();
|
||||
_gpuVersion = Parameters::defaultSURFGpuVersion();
|
||||
_params.upright = Parameters::defaultSURFUpright();
|
||||
this->parseParameters(parameters);
|
||||
this->setAdaptiveResponseThr(_params.hessianThreshold);
|
||||
}
|
||||
|
||||
SURFDetector::~SURFDetector()
|
||||
@@ -265,70 +238,62 @@ void SURFDetector::parseParameters(const ParametersMap & parameters)
|
||||
ParametersMap::const_iterator iter;
|
||||
if((iter=parameters.find(Parameters::kSURFExtended())) != parameters.end())
|
||||
{
|
||||
_params.extended = uStr2Bool((*iter).second.c_str());
|
||||
_extended = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFHessianThreshold())) != parameters.end())
|
||||
{
|
||||
_params.hessianThreshold = std::atof((*iter).second.c_str());
|
||||
this->setAdaptiveResponseThr(_params.hessianThreshold);
|
||||
_hessianThreshold = std::atof((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFOctaveLayers())) != parameters.end())
|
||||
{
|
||||
_params.nOctaveLayers = std::atoi((*iter).second.c_str());
|
||||
_nOctaveLayers = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
|
||||
{
|
||||
_params.nOctaves = std::atoi((*iter).second.c_str());
|
||||
_nOctaves = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFOctaves())) != parameters.end())
|
||||
{
|
||||
_params.nOctaves = std::atoi((*iter).second.c_str());
|
||||
_nOctaves = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFUpright())) != parameters.end())
|
||||
{
|
||||
_upright = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFGpuVersion())) != parameters.end())
|
||||
{
|
||||
_gpuVersion = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSURFUpright())) != parameters.end())
|
||||
{
|
||||
_params.upright = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
KeypointDetector::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::vector<cv::KeyPoint> SURFDetector::_generateKeypoints(const IplImage * image, const cv::Rect & roi) const
|
||||
std::vector<cv::KeyPoint> SURFDetector::_generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
if(!image)
|
||||
if(image.empty())
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
return keypoints;
|
||||
}
|
||||
// SURF support only grayscale images
|
||||
IplImage * imageGrayScale = 0;
|
||||
if(image->nChannels != 1 || image->depth != IPL_DEPTH_8U)
|
||||
cv::Mat imageGrayScale;
|
||||
if(image.channels() != 1 || image.depth() != CV_8U)
|
||||
{
|
||||
imageGrayScale = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1);
|
||||
cvCvtColor(image, imageGrayScale, CV_BGR2GRAY);
|
||||
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
|
||||
}
|
||||
cv::Mat img;
|
||||
if(imageGrayScale)
|
||||
if(!imageGrayScale.empty())
|
||||
{
|
||||
img = cv::Mat(imageGrayScale);
|
||||
img = imageGrayScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
img = cv::Mat(image);
|
||||
}
|
||||
|
||||
CvSURFParams params = _params;
|
||||
if(this->isUsingAdaptiveResponseThr())
|
||||
{
|
||||
params.hessianThreshold = this->getAdaptiveResponseThr(); // use the adaptive threshold
|
||||
img = image;
|
||||
}
|
||||
|
||||
cv::Mat imgRoi(img, roi);
|
||||
#if OPENCV_SURF_GPU
|
||||
/*#if OPENCV_SURF_GPU
|
||||
if(_gpuVersion )
|
||||
{
|
||||
cv::gpu::GpuMat imgGpu(imgRoi);
|
||||
@@ -342,15 +307,15 @@ std::vector<cv::KeyPoint> SURFDetector::_generateKeypoints(const IplImage * imag
|
||||
cv::SurfFeatureDetector detector(params.hessianThreshold, params.nOctaves, params.nOctaveLayers, params.upright);
|
||||
detector.detect(imgRoi, keypoints);
|
||||
}
|
||||
#else
|
||||
cv::SurfFeatureDetector detector(params.hessianThreshold, params.nOctaves, params.nOctaveLayers, params.upright);
|
||||
#else*/
|
||||
cv::SURF detector(_hessianThreshold, _nOctaves, _nOctaveLayers, _extended, _upright);
|
||||
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
|
||||
detector.detect(imgRoi, keypoints);
|
||||
#else
|
||||
detector(imgRoi, cv::Mat(), keypoints);
|
||||
#endif
|
||||
//#endif
|
||||
|
||||
if(imageGrayScale)
|
||||
{
|
||||
cvReleaseImage(&imageGrayScale);
|
||||
}
|
||||
return keypoints;
|
||||
}
|
||||
|
||||
@@ -358,12 +323,14 @@ std::vector<cv::KeyPoint> SURFDetector::_generateKeypoints(const IplImage * imag
|
||||
//SIFTDetector
|
||||
//////////////////////////
|
||||
SIFTDetector::SIFTDetector(const ParametersMap & parameters) :
|
||||
KeypointDetector(parameters)
|
||||
KeypointDetector(parameters),
|
||||
_nfeatures(Parameters::defaultSIFTNFeatures()),
|
||||
_nOctaveLayers(Parameters::defaultSIFTNOctaveLayers()),
|
||||
_contrastThreshold(Parameters::defaultSIFTContrastThreshold()),
|
||||
_edgeThreshold(Parameters::defaultSIFTEdgeThreshold()),
|
||||
_sigma(Parameters::defaultSIFTSigma())
|
||||
{
|
||||
_detectorParams.threshold = Parameters::defaultSIFTThreshold();
|
||||
_detectorParams.edgeThreshold = Parameters::defaultSIFTEdgeThreshold();
|
||||
this->parseParameters(parameters);
|
||||
this->setAdaptiveResponseThr(_detectorParams.threshold);
|
||||
}
|
||||
|
||||
SIFTDetector::~SIFTDetector()
|
||||
@@ -373,57 +340,62 @@ SIFTDetector::~SIFTDetector()
|
||||
void SIFTDetector::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
ParametersMap::const_iterator iter;
|
||||
if((iter=parameters.find(Parameters::kSIFTThreshold())) != parameters.end())
|
||||
if((iter=parameters.find(Parameters::kSIFTContrastThreshold())) != parameters.end())
|
||||
{
|
||||
_detectorParams.threshold = std::atof((*iter).second.c_str());
|
||||
this->setAdaptiveResponseThr(_detectorParams.threshold);
|
||||
_contrastThreshold = std::atof((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSIFTEdgeThreshold())) != parameters.end())
|
||||
{
|
||||
_detectorParams.edgeThreshold = std::atof((*iter).second.c_str());
|
||||
_edgeThreshold = std::atof((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSIFTNFeatures())) != parameters.end())
|
||||
{
|
||||
_nfeatures = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSIFTNOctaveLayers())) != parameters.end())
|
||||
{
|
||||
_nOctaveLayers = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSIFTSigma())) != parameters.end())
|
||||
{
|
||||
_sigma = std::atof((*iter).second.c_str());
|
||||
}
|
||||
KeypointDetector::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::vector<cv::KeyPoint> SIFTDetector::_generateKeypoints(const IplImage * image, const cv::Rect & roi) const
|
||||
std::vector<cv::KeyPoint> SIFTDetector::_generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
if(!image)
|
||||
if(image.empty())
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
return keypoints;
|
||||
}
|
||||
// SURF support only grayscale images
|
||||
IplImage * imageGrayScale = 0;
|
||||
if(image->nChannels != 1 || image->depth != IPL_DEPTH_8U)
|
||||
cv::Mat imageGrayScale;
|
||||
if(image.channels() != 1 || image.depth() != CV_8U)
|
||||
{
|
||||
imageGrayScale = cvCreateImage(cvSize(image->width,image->height), IPL_DEPTH_8U, 1);
|
||||
cvCvtColor(image, imageGrayScale, CV_BGR2GRAY);
|
||||
cv::cvtColor(image, imageGrayScale, CV_BGR2GRAY);
|
||||
}
|
||||
cv::Mat img;
|
||||
if(imageGrayScale)
|
||||
if(!imageGrayScale.empty())
|
||||
{
|
||||
img = cv::Mat(imageGrayScale);
|
||||
img = imageGrayScale;
|
||||
}
|
||||
else
|
||||
{
|
||||
img = cv::Mat(image);
|
||||
img = image;
|
||||
}
|
||||
|
||||
cv::SIFT::DetectorParams detectorParam = _detectorParams;
|
||||
if(this->isUsingAdaptiveResponseThr())
|
||||
{
|
||||
detectorParam.threshold = this->getAdaptiveResponseThr(); // use the adaptive threshold
|
||||
}
|
||||
|
||||
cv::SiftFeatureDetector detector(detectorParam, _commonParams);
|
||||
cv::Mat imgRoi(img, roi);
|
||||
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
|
||||
cv::SIFT detector(_nfeatures, _nOctaveLayers, _contrastThreshold, _edgeThreshold, _sigma);
|
||||
detector.detect(imgRoi, keypoints); // Opencv surf keypoints
|
||||
if(imageGrayScale)
|
||||
{
|
||||
cvReleaseImage(&imageGrayScale);
|
||||
}
|
||||
#else
|
||||
cv::SIFT detector(_contrastThreshold, _edgeThreshold, cv::SIFT::CommonParams::DEFAULT_NOCTAVES, _nOctaveLayers);
|
||||
detector(imgRoi, cv::Mat(), keypoints); // Opencv surf keypoints
|
||||
#endif
|
||||
return keypoints;
|
||||
}
|
||||
|
||||
@@ -432,15 +404,14 @@ std::vector<cv::KeyPoint> SIFTDetector::_generateKeypoints(const IplImage * imag
|
||||
//StarDetector
|
||||
//////////////////////////
|
||||
StarDetector::StarDetector(const ParametersMap & parameters) :
|
||||
KeypointDetector(parameters)
|
||||
KeypointDetector(parameters),
|
||||
_maxSize(Parameters::defaultStarMaxSize()),
|
||||
_responseThreshold(Parameters::defaultStarResponseThreshold()),
|
||||
_lineThresholdProjected(Parameters::defaultStarLineThresholdProjected()),
|
||||
_lineThresholdBinarized(Parameters::defaultStarLineThresholdBinarized()),
|
||||
_suppressNonmaxSize(Parameters::defaultStarSuppressNonmaxSize())
|
||||
{
|
||||
_params.lineThresholdBinarized = Parameters::defaultStarLineThresholdBinarized();
|
||||
_params.lineThresholdProjected = Parameters::defaultStarLineThresholdProjected();
|
||||
_params.maxSize = Parameters::defaultStarMaxSize();
|
||||
_params.responseThreshold = Parameters::defaultStarResponseThreshold();
|
||||
_params.suppressNonmaxSize = Parameters::defaultStarSuppressNonmaxSize();
|
||||
this->parseParameters(parameters);
|
||||
this->setAdaptiveResponseThr(_params.responseThreshold);
|
||||
}
|
||||
|
||||
StarDetector::~StarDetector()
|
||||
@@ -453,51 +424,47 @@ void StarDetector::parseParameters(const ParametersMap & parameters)
|
||||
ParametersMap::const_iterator iter;
|
||||
if((iter=parameters.find(Parameters::kStarLineThresholdBinarized())) != parameters.end())
|
||||
{
|
||||
_params.lineThresholdBinarized = std::atoi((*iter).second.c_str());
|
||||
_lineThresholdBinarized = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kStarLineThresholdProjected())) != parameters.end())
|
||||
{
|
||||
_params.lineThresholdProjected = std::atoi((*iter).second.c_str());
|
||||
_lineThresholdProjected = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kStarMaxSize())) != parameters.end())
|
||||
{
|
||||
_params.maxSize = std::atoi((*iter).second.c_str());
|
||||
_maxSize = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kStarResponseThreshold())) != parameters.end())
|
||||
{
|
||||
_params.responseThreshold = int(std::atof((*iter).second.c_str()));
|
||||
this->setAdaptiveResponseThr(_params.responseThreshold);
|
||||
_responseThreshold = int(std::atof((*iter).second.c_str()));
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kStarSuppressNonmaxSize())) != parameters.end())
|
||||
{
|
||||
_params.suppressNonmaxSize = std::atoi((*iter).second.c_str());
|
||||
_suppressNonmaxSize = std::atoi((*iter).second.c_str());
|
||||
}
|
||||
KeypointDetector::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::vector<cv::KeyPoint> StarDetector::_generateKeypoints(const IplImage * image, const cv::Rect & roi) const
|
||||
std::vector<cv::KeyPoint> StarDetector::_generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
if(!image)
|
||||
if(image.empty())
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
return keypoints;
|
||||
}
|
||||
|
||||
cv::Mat img(image);
|
||||
// TODO More testing needed with the star detector, NN search distance must be changed to 0.8
|
||||
//find keypoints with the star detector
|
||||
CvStarDetectorParams params = _params;
|
||||
if(this->isUsingAdaptiveResponseThr())
|
||||
{
|
||||
params.responseThreshold = this->getAdaptiveResponseThr(); // use the adaptive threshold
|
||||
}
|
||||
|
||||
// Get keypoints with the star detector
|
||||
cv::Mat imgRoi(img, roi);
|
||||
cv::StarFeatureDetector detector(params);
|
||||
cv::StarDetector detector(_maxSize, _responseThreshold, _lineThresholdProjected, _lineThresholdBinarized, _suppressNonmaxSize);
|
||||
#if CV_MAJOR_VERSION >=2 and CV_MINOR_VERSION >=4
|
||||
detector.detect(imgRoi, keypoints);
|
||||
#else
|
||||
detector(imgRoi, keypoints);
|
||||
#endif
|
||||
return keypoints;
|
||||
}
|
||||
|
||||
@@ -510,7 +477,6 @@ FASTDetector::FASTDetector(const ParametersMap & parameters) :
|
||||
_nonmaxSuppression(Parameters::defaultFASTNonmaxSuppression())
|
||||
{
|
||||
this->parseParameters(parameters);
|
||||
this->setAdaptiveResponseThr(_threshold);
|
||||
}
|
||||
|
||||
FASTDetector::~FASTDetector()
|
||||
@@ -531,11 +497,11 @@ void FASTDetector::parseParameters(const ParametersMap & parameters)
|
||||
KeypointDetector::parseParameters(parameters);
|
||||
}
|
||||
|
||||
std::vector<cv::KeyPoint> FASTDetector::_generateKeypoints(const IplImage * image, const cv::Rect & roi) const
|
||||
std::vector<cv::KeyPoint> FASTDetector::_generateKeypoints(const cv::Mat & image, const cv::Rect & roi) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
if(!image)
|
||||
if(image.empty())
|
||||
{
|
||||
ULOGGER_ERROR("Image is null ?!?");
|
||||
return keypoints;
|
||||
@@ -543,12 +509,8 @@ std::vector<cv::KeyPoint> FASTDetector::_generateKeypoints(const IplImage * imag
|
||||
|
||||
cv::Mat img(image);
|
||||
cv::Mat imgRoi(img, roi);
|
||||
int threshold = _threshold;
|
||||
if(this->isUsingAdaptiveResponseThr())
|
||||
{
|
||||
threshold = (int)this->getAdaptiveResponseThr(); // use the adaptive threshold
|
||||
}
|
||||
cv::FastFeatureDetector fast(threshold, _nonmaxSuppression);
|
||||
|
||||
cv::FastFeatureDetector fast(_threshold, _nonmaxSuppression);
|
||||
|
||||
// Get keypoints with the fast detector
|
||||
fast.detect(imgRoi, keypoints);
|
||||
|
||||
@@ -17,18 +17,18 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "KeypointMemory.h"
|
||||
#include "VWDictionary.h"
|
||||
#include "rtabmap/core/KeypointMemory.h"
|
||||
#include "rtabmap/core/VWDictionary.h"
|
||||
#include "rtabmap/core/VisualWord.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
#include "utilite/UtiLite.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "rtabmap/core/SMState.h"
|
||||
#include "rtabmap/core/KeypointDetector.h"
|
||||
#include "rtabmap/core/KeypointDescriptor.h"
|
||||
#include "rtabmap/core/RtabmapEvent.h"
|
||||
#include "NearestNeighbor.h"
|
||||
#include "VerifyHypotheses.h"
|
||||
#include "rtabmap/core/NearestNeighbor.h"
|
||||
#include "rtabmap/core/VerifyHypotheses.h"
|
||||
#include "utilite/UStl.h"
|
||||
#include <opencv2/core/core.hpp>
|
||||
#include <set>
|
||||
@@ -105,13 +105,12 @@ void KeypointMemory::parseParameters(const ParametersMap & parameters)
|
||||
}
|
||||
|
||||
//Keypoint detector
|
||||
DetectorStrategy detectorStrategy = kDetectorUndef;
|
||||
KeypointDetector::DetectorType detectorStrategy = KeypointDetector::kDetectorUndef;
|
||||
if((iter=parameters.find(Parameters::kKpDetectorStrategy())) != parameters.end())
|
||||
{
|
||||
detectorStrategy = (DetectorStrategy)std::atoi((*iter).second.c_str());
|
||||
detectorStrategy = (KeypointDetector::DetectorType)std::atoi((*iter).second.c_str());
|
||||
}
|
||||
DetectorStrategy currentDetectorStrategy = this->detectorStrategy();
|
||||
if(!_keypointDetector || ( detectorStrategy!=kDetectorUndef && (detectorStrategy != currentDetectorStrategy) ) )
|
||||
if(!_keypointDetector || detectorStrategy!=KeypointDetector::kDetectorUndef)
|
||||
{
|
||||
ULOGGER_DEBUG("new detector strategy %d", int(detectorStrategy));
|
||||
if(_keypointDetector)
|
||||
@@ -121,16 +120,16 @@ void KeypointMemory::parseParameters(const ParametersMap & parameters)
|
||||
}
|
||||
switch(detectorStrategy)
|
||||
{
|
||||
case kDetectorStar:
|
||||
case KeypointDetector::kDetectorStar:
|
||||
_keypointDetector = new StarDetector(parameters);
|
||||
break;
|
||||
case kDetectorSift:
|
||||
case KeypointDetector::kDetectorSift:
|
||||
_keypointDetector = new SIFTDetector(parameters);
|
||||
break;
|
||||
case kDetectorFast:
|
||||
case KeypointDetector::kDetectorFast:
|
||||
_keypointDetector = new FASTDetector(parameters);
|
||||
break;
|
||||
case kDetectorSurf:
|
||||
case KeypointDetector::kDetectorSurf:
|
||||
default:
|
||||
_keypointDetector = new SURFDetector(parameters);
|
||||
break;
|
||||
@@ -142,12 +141,12 @@ void KeypointMemory::parseParameters(const ParametersMap & parameters)
|
||||
}
|
||||
|
||||
//Keypoint descriptor
|
||||
DescriptorStrategy descriptorStrategy = kDescriptorUndef;
|
||||
KeypointDescriptor::DescriptorType descriptorStrategy = KeypointDescriptor::kDescriptorUndef;
|
||||
if((iter=parameters.find(Parameters::kKpDescriptorStrategy())) != parameters.end())
|
||||
{
|
||||
descriptorStrategy = (DescriptorStrategy)std::atoi((*iter).second.c_str());
|
||||
descriptorStrategy = (KeypointDescriptor::DescriptorType)std::atoi((*iter).second.c_str());
|
||||
}
|
||||
if(!_keypointDescriptor || descriptorStrategy!=kDescriptorUndef)
|
||||
if(!_keypointDescriptor || descriptorStrategy!=KeypointDescriptor::kDescriptorUndef)
|
||||
{
|
||||
ULOGGER_DEBUG("new descriptor strategy %d", int(descriptorStrategy));
|
||||
if(_keypointDescriptor)
|
||||
@@ -157,19 +156,19 @@ void KeypointMemory::parseParameters(const ParametersMap & parameters)
|
||||
}
|
||||
switch(descriptorStrategy)
|
||||
{
|
||||
case kDescriptorSift:
|
||||
case KeypointDescriptor::kDescriptorSift:
|
||||
_keypointDescriptor = new SIFTDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorBrief:
|
||||
case KeypointDescriptor::kDescriptorBrief:
|
||||
_keypointDescriptor = new BRIEFDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorColor:
|
||||
case KeypointDescriptor::kDescriptorColor:
|
||||
_keypointDescriptor = new ColorDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorHue:
|
||||
case KeypointDescriptor::kDescriptorHue:
|
||||
_keypointDescriptor = new HueDescriptor(parameters);
|
||||
break;
|
||||
case kDescriptorSurf:
|
||||
case KeypointDescriptor::kDescriptorSurf:
|
||||
default:
|
||||
_keypointDescriptor = new SURFDescriptor(parameters);
|
||||
break;
|
||||
@@ -183,22 +182,6 @@ void KeypointMemory::parseParameters(const ParametersMap & parameters)
|
||||
Memory::parseParameters(parameters);
|
||||
}
|
||||
|
||||
KeypointMemory::DetectorStrategy KeypointMemory::detectorStrategy() const
|
||||
{
|
||||
DetectorStrategy strategy = kDetectorUndef;
|
||||
StarDetector * star = dynamic_cast<StarDetector*>(_keypointDetector);
|
||||
SURFDetector * surf = dynamic_cast<SURFDetector*>(_keypointDetector);
|
||||
if(star)
|
||||
{
|
||||
strategy = kDetectorStar;
|
||||
}
|
||||
else if(surf)
|
||||
{
|
||||
strategy = kDetectorSurf;
|
||||
}
|
||||
return strategy;
|
||||
}
|
||||
|
||||
bool KeypointMemory::init(const std::string & dbDriverName, const std::string & dbUrl, bool dbOverwritten, const ParametersMap & parameters)
|
||||
{
|
||||
UDEBUG("");
|
||||
@@ -241,10 +224,10 @@ bool KeypointMemory::init(const std::string & dbDriverName, const std::string &
|
||||
|
||||
// TODO : Use only the parent method (in Memory)
|
||||
// 1- Put "setEnabled" in the abstract Signature class, so this method is accessible from Memory
|
||||
void KeypointMemory::addSignatureToStm(Signature * signature, const std::list<std::vector<float> > & actions)
|
||||
void KeypointMemory::addSignatureToStm(Signature * signature, const std::list<Actuator> & actuators)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
Memory::addSignatureToStm(signature, actions);
|
||||
Memory::addSignatureToStm(signature, actuators);
|
||||
|
||||
UTimer timer;
|
||||
KeypointSignature * ss = dynamic_cast<KeypointSignature *>(signature);
|
||||
@@ -300,15 +283,15 @@ void KeypointMemory::clear()
|
||||
// _dbDriver->commit();
|
||||
//}
|
||||
ULOGGER_DEBUG("");
|
||||
|
||||
_dbDriver->start();
|
||||
}
|
||||
else
|
||||
{
|
||||
cleanUnusedWords();
|
||||
}
|
||||
|
||||
_commonWords.clear();
|
||||
if(_vwd)
|
||||
{
|
||||
_vwd->clear();
|
||||
}
|
||||
}
|
||||
|
||||
void KeypointMemory::preUpdate()
|
||||
@@ -337,11 +320,6 @@ std::multimap<int, cv::KeyPoint> getMostDescriptiveWords(const std::multimap<int
|
||||
responseWordMap.insert(std::pair<float, std::pair<int, const cv::KeyPoint *> >(itKey->second.response, std::pair<int, const cv::KeyPoint *>(itKey->first, &(itKey->second))));
|
||||
}
|
||||
}
|
||||
int endIndex = 0;
|
||||
if(responseWordMap.size() > (unsigned int)max)
|
||||
{
|
||||
endIndex = responseWordMap.size() - max;
|
||||
}
|
||||
|
||||
//add them
|
||||
int i=0;
|
||||
@@ -532,7 +510,7 @@ int KeypointMemory::getNi(int signatureId) const
|
||||
}
|
||||
else
|
||||
{
|
||||
_dbDriver->getSurfNi(signatureId, ni);
|
||||
_dbDriver->getInvertedIndexNi(signatureId, ni);
|
||||
}
|
||||
return ni;
|
||||
}
|
||||
@@ -576,7 +554,7 @@ private:
|
||||
VWDictionary * _vwp;
|
||||
};
|
||||
|
||||
Signature * KeypointMemory::createSignature(int id, const SMState * smState, bool keepRawData)
|
||||
Signature * KeypointMemory::createSignature(int id, const std::list<Sensor> & sensors, bool keepRawData)
|
||||
{
|
||||
PreUpdateThread preUpdateThread(_vwd);
|
||||
|
||||
@@ -584,46 +562,67 @@ Signature * KeypointMemory::createSignature(int id, const SMState * smState, boo
|
||||
timer.start();
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
cv::Mat descriptors;
|
||||
const IplImage * image = 0;
|
||||
|
||||
if(smState)
|
||||
int treeSize= this->getWorkingMemSize() + this->getStMemSize();
|
||||
int nbCommonWords = 0;
|
||||
if(treeSize > 0)
|
||||
{
|
||||
int treeSize= this->getWorkingMemSize() + this->getStMemSize();
|
||||
int nbCommonWords = 0;
|
||||
if(treeSize > 0)
|
||||
{
|
||||
nbCommonWords = _vwd->getTotalActiveReferences() / treeSize;
|
||||
}
|
||||
nbCommonWords = _vwd->getTotalActiveReferences() / treeSize;
|
||||
}
|
||||
|
||||
if(_parallelized)
|
||||
{
|
||||
preUpdateThread.start();
|
||||
}
|
||||
if(_parallelized)
|
||||
{
|
||||
preUpdateThread.start();
|
||||
}
|
||||
|
||||
if(smState->getSensors().empty())
|
||||
std::list<Sensor>::const_iterator iterImage = sensors.end();
|
||||
std::list<Sensor>::const_iterator iterImageFeatures = sensors.end();
|
||||
for(std::list<Sensor>::const_iterator iter=sensors.begin(); iter!=sensors.end(); ++iter)
|
||||
{
|
||||
if(iter->type() == Sensor::kTypeImage)
|
||||
{
|
||||
image = smState->getImage();
|
||||
if(image && _keypointDetector)
|
||||
iterImage = iter;
|
||||
}
|
||||
else if(iter->type() == Sensor::kTypeImageFeatures2d)
|
||||
{
|
||||
iterImageFeatures = iter;
|
||||
}
|
||||
}
|
||||
if(iterImage == sensors.end() && iterImageFeatures == sensors.end())
|
||||
{
|
||||
UERROR("Keypoint memory only supports image[features] sensor type.");
|
||||
return 0;
|
||||
}
|
||||
if(iterImageFeatures != sensors.end())
|
||||
{
|
||||
// DESCRIPTORS
|
||||
if(iterImageFeatures->data().rows && iterImageFeatures->data().rows >= _badSignRatio * nbCommonWords)
|
||||
{
|
||||
if(iterImageFeatures->data().type() == CV_32F)
|
||||
{
|
||||
keypoints = _keypointDetector->generateKeypoints(image);
|
||||
ULOGGER_DEBUG("time keypoints = %fs", timer.ticks());
|
||||
descriptors = iterImageFeatures->data();
|
||||
keypoints = iterImageFeatures->getKeypoints();
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("ratio=%f, treeSize=%d, nbCommonWords=%d", _badSignRatio, treeSize, nbCommonWords);
|
||||
|
||||
if(keypoints.size() && keypoints.size() >= _badSignRatio * nbCommonWords)
|
||||
else
|
||||
{
|
||||
descriptors = _keypointDescriptor->generateDescriptors(image, keypoints);
|
||||
UERROR("Descriptors must be CV_32F.");
|
||||
}
|
||||
}
|
||||
else
|
||||
}
|
||||
else
|
||||
{
|
||||
// IMAGE RAW
|
||||
if(_keypointDetector)
|
||||
{
|
||||
if(smState->getSensors().rows >= _badSignRatio * nbCommonWords)
|
||||
{
|
||||
descriptors = smState->getSensors();
|
||||
keypoints = smState->getKeypoints();
|
||||
}
|
||||
image = smState->getImage();
|
||||
keypoints = _keypointDetector->generateKeypoints(iterImage->data());
|
||||
ULOGGER_DEBUG("time keypoints = %fs", timer.ticks());
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("ratio=%f, treeSize=%d, nbCommonWords=%d", _badSignRatio, treeSize, nbCommonWords);
|
||||
|
||||
if(keypoints.size() && keypoints.size() >= _badSignRatio * nbCommonWords)
|
||||
{
|
||||
descriptors = _keypointDescriptor->generateDescriptors(iterImage->data(), keypoints);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -665,13 +664,26 @@ Signature * KeypointMemory::createSignature(int id, const SMState * smState, boo
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Words (%d) and keypoints(%d) are not the same size ?!?", (int)wordIds.size(), (int)keypoints.size());
|
||||
if(keypoints.size())
|
||||
{
|
||||
UWARN("Words (%d) and keypoints(%d) are not the same size ?!?", (int)wordIds.size(), (int)keypoints.size());
|
||||
}
|
||||
words.insert(std::pair<int, cv::KeyPoint >(*iter, cv::KeyPoint()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
KeypointSignature * ks = new KeypointSignature(words, id, image, keepRawData);
|
||||
KeypointSignature * ks;
|
||||
std::list<Sensor> tmp;
|
||||
if(keepRawData && iterImage != sensors.end())
|
||||
{
|
||||
UDEBUG("");
|
||||
//Just keep image if there's one
|
||||
tmp.push_back(*iterImage);
|
||||
}
|
||||
|
||||
ks = new KeypointSignature(words, id, tmp);
|
||||
|
||||
ULOGGER_DEBUG("time new signature (id=%d) %fs", id, timer.ticks());
|
||||
if(words.size())
|
||||
{
|
||||
|
||||
+258
-236
@@ -17,14 +17,19 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "Memory.h"
|
||||
#include <utilite/UEventsManager.h>
|
||||
#include <utilite/ULogger.h>
|
||||
#include <utilite/UTimer.h>
|
||||
#include <utilite/UConversion.h>
|
||||
#include <utilite/UProcessInfo.h>
|
||||
|
||||
#include "rtabmap/core/Memory.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "rtabmap/core/DBDriverFactory.h"
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
#include "utilite/UtiLite.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "rtabmap/core/RtabmapEvent.h"
|
||||
#include "rtabmap/core/SMState.h"
|
||||
#include "rtabmap/core/Sensor.h"
|
||||
#include "Node.h"
|
||||
|
||||
namespace rtabmap {
|
||||
@@ -90,7 +95,7 @@ bool Memory::init(const std::string & dbDriverName, const std::string & dbUrl, b
|
||||
// Load the last working memory...
|
||||
UEventsManager::post(new RtabmapEventInit(std::string("Loading last signatures...")));
|
||||
std::list<Signature*> dbSignatures;
|
||||
_dbDriver->loadLastSignatures(dbSignatures);
|
||||
_dbDriver->loadLastNodes(dbSignatures);
|
||||
for(std::list<Signature*>::reverse_iterator iter=dbSignatures.rbegin(); iter!=dbSignatures.rend(); ++iter)
|
||||
{
|
||||
_signatures.insert(std::pair<int, Signature *>((*iter)->id(), *iter));
|
||||
@@ -112,7 +117,7 @@ bool Memory::init(const std::string & dbDriverName, const std::string & dbUrl, b
|
||||
}
|
||||
|
||||
// Last id
|
||||
_dbDriver->getLastSignatureId(_idCount);
|
||||
_dbDriver->getLastNodeId(_idCount);
|
||||
_idCount += 1;
|
||||
}
|
||||
else
|
||||
@@ -125,7 +130,7 @@ bool Memory::init(const std::string & dbDriverName, const std::string & dbUrl, b
|
||||
_idCount = kIdStart;
|
||||
}
|
||||
|
||||
_dbDriver->start();
|
||||
this->setCommonSignatureUsed(_commonSignatureUsed);
|
||||
|
||||
ULOGGER_DEBUG("ids start with %d", _idCount);
|
||||
return success;
|
||||
@@ -206,7 +211,7 @@ void Memory::preUpdate()
|
||||
_signaturesAdded = 0;
|
||||
}
|
||||
|
||||
bool Memory::update(const SMState * smState, std::map<std::string, float> & stats)
|
||||
bool Memory::update(const std::list<Sensor> & sensors, const std::list<Actuator> & actuators, std::map<std::string, float> & stats)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
UTimer timer;
|
||||
@@ -226,24 +231,19 @@ bool Memory::update(const SMState * smState, std::map<std::string, float> & stat
|
||||
//============================================================
|
||||
// Create a signature with the image received.
|
||||
//============================================================
|
||||
Signature * signature = this->createSignature(this->getNextId(), smState, this->isRawDataKept());
|
||||
Signature * signature = this->createSignature(this->getNextId(), sensors, this->isRawDataKept());
|
||||
if (signature == 0)
|
||||
{
|
||||
UFATAL("Failed to create a signature");
|
||||
UERROR("Failed to create a signature");
|
||||
return false;
|
||||
}
|
||||
|
||||
// It will be added to the short-term memory, no need to delete it...
|
||||
if(smState)
|
||||
{
|
||||
this->addSignatureToStm(signature, smState->getActuators());
|
||||
}
|
||||
else
|
||||
{
|
||||
this->addSignatureToStm(signature);
|
||||
}
|
||||
this->addSignatureToStm(signature, actuators);
|
||||
|
||||
_lastSignature = signature;
|
||||
|
||||
if(_lastLoopClosureId == 0)
|
||||
if(_lastLoopClosureId == 0 && !signature->isBadSignature())
|
||||
{
|
||||
// If not set use the new one added
|
||||
_lastLoopClosureId = signature->id();
|
||||
@@ -264,29 +264,6 @@ bool Memory::update(const SMState * smState, std::map<std::string, float> & stat
|
||||
stats.insert(std::pair<std::string, float>(std::string("TimingMem/Rehearsal/ms"), t));
|
||||
ULOGGER_DEBUG("time rehearsal=%f ms", t);
|
||||
|
||||
//============================================================
|
||||
// Update the common signature
|
||||
//============================================================
|
||||
if(_commonSignatureUsed)
|
||||
{
|
||||
Signature * s = _getSignature(kIdVirtual);
|
||||
if(s == 0)
|
||||
{
|
||||
s = this->createSignature(kIdVirtual, 0); // Create a virtual place
|
||||
_signatures.insert(std::pair<int, Signature *>(s->id(), s));
|
||||
_workingMem.insert(s->id());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove virtual signature
|
||||
Signature * s = _getSignature(kIdVirtual);
|
||||
if(s)
|
||||
{
|
||||
this->moveToTrash(s);
|
||||
}
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// Transfer the oldest signature of the short-term memory to the working memory
|
||||
//============================================================
|
||||
@@ -349,24 +326,30 @@ void Memory::setRecentWmRatio(float recentWmRatio)
|
||||
void Memory::setCommonSignatureUsed(bool commonSignatureUsed)
|
||||
{
|
||||
_commonSignatureUsed = commonSignatureUsed;
|
||||
if(!_commonSignatureUsed)
|
||||
|
||||
if(_commonSignatureUsed)
|
||||
{
|
||||
this->moveToTrash(this->_getSignature(kIdVirtual));
|
||||
_workingMem.insert(kIdVirtual);
|
||||
}
|
||||
else
|
||||
{
|
||||
// remove virtual signature
|
||||
_workingMem.erase(kIdVirtual);
|
||||
}
|
||||
}
|
||||
|
||||
void Memory::addSignatureToStm(Signature * signature, const std::list<std::vector<float> > & actions)
|
||||
void Memory::addSignatureToStm(Signature * signature, const std::list<Actuator> & actuators)
|
||||
{
|
||||
UTimer timer;
|
||||
// add signature on top of the short-term memory
|
||||
if(signature)
|
||||
{
|
||||
UDEBUG("adding %d with a=%d", signature->id(), (int)actions.size());
|
||||
UDEBUG("adding %d with a=%d", signature->id(), (int)actuators.size());
|
||||
// Update neighbors
|
||||
if(_stMem.size())
|
||||
{
|
||||
// In terms of sensorimotor learning...
|
||||
_signatures.at(*_stMem.rbegin())->addNeighbor(NeighborLink(signature->id(), actions, _lastBaseIds));
|
||||
// If you want to use Bayes's parameter _predictionOnNonNullActionsOnly with no actions, dummy actions must be sent (null actions are not handled in sqlite3 driver)
|
||||
_signatures.at(*_stMem.rbegin())->addNeighbor(NeighborLink(signature->id(), _lastBaseIds, actuators, signature->id()));
|
||||
// actions are not backward compatible, so set null actions
|
||||
signature->addNeighbor(NeighborLink(*_stMem.rbegin()));
|
||||
}
|
||||
@@ -433,7 +416,7 @@ Signature * Memory::getSignatureLtMem(int id)
|
||||
return s;
|
||||
}
|
||||
|
||||
std::list<NeighborLink> Memory::getNeighborLinks(int signatureId, bool ignoreNeighborByLoopClosure, bool lookInDatabase) const
|
||||
std::list<NeighborLink> Memory::getNeighborLinks(int signatureId, bool ignoreNeighborByLoopClosure, bool lookInDatabase, bool onlyWithActions) const
|
||||
{
|
||||
std::list<NeighborLink> links;
|
||||
Signature * sTop = uValue(_signatures, signatureId, (Signature*)0);
|
||||
@@ -450,7 +433,10 @@ std::list<NeighborLink> Memory::getNeighborLinks(int signatureId, bool ignoreNei
|
||||
const NeighborsMultiMap & neighbors = s->getNeighbors();
|
||||
for(NeighborsMultiMap::const_iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter)
|
||||
{
|
||||
links.push_back(iter->second);
|
||||
if(!onlyWithActions || (onlyWithActions && iter->second.actuators().size()))
|
||||
{
|
||||
links.push_back(iter->second);
|
||||
}
|
||||
}
|
||||
if(!ignoreNeighborByLoopClosure)
|
||||
{
|
||||
@@ -486,7 +472,10 @@ std::list<NeighborLink> Memory::getNeighborLinks(int signatureId, bool ignoreNei
|
||||
const NeighborsMultiMap & neighbors = s->getNeighbors();
|
||||
for(NeighborsMultiMap::const_iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter)
|
||||
{
|
||||
links.push_back(iter->second);
|
||||
if(!onlyWithActions || (onlyWithActions && iter->second.actuators().size()))
|
||||
{
|
||||
links.push_back(iter->second);
|
||||
}
|
||||
}
|
||||
const std::set<int> & childIds = s->getChildLoopClosureIds();
|
||||
for(std::set<int>::const_iterator iter = childIds.begin(); iter!=childIds.end(); ++iter)
|
||||
@@ -506,7 +495,10 @@ std::list<NeighborLink> Memory::getNeighborLinks(int signatureId, bool ignoreNei
|
||||
_dbDriver->loadNeighbors(signatureId, neighbors);
|
||||
for(NeighborsMultiMap::iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter)
|
||||
{
|
||||
links.push_back(iter->second);
|
||||
if(!onlyWithActions || (onlyWithActions && iter->second.actuators().size()))
|
||||
{
|
||||
links.push_back(iter->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -536,7 +528,6 @@ std::map<int, int> Memory::getNeighborsId(double & dbAccessTime,
|
||||
{
|
||||
return ids;
|
||||
}
|
||||
bool someLoadedFromDb = false;
|
||||
int nbLoadedFromDb = 0;
|
||||
std::list<int> currentMargin;
|
||||
std::list<int> nextMargin;
|
||||
@@ -546,127 +537,118 @@ std::map<int, int> Memory::getNeighborsId(double & dbAccessTime,
|
||||
{
|
||||
currentMargin = nextMargin;
|
||||
nextMargin.clear();
|
||||
someLoadedFromDb = false;
|
||||
// first pass: count number of node in current margin in database
|
||||
for(std::list<int>::iterator jter = currentMargin.begin(); jter!=currentMargin.end();++jter)
|
||||
{
|
||||
if(!uContains(ids, *jter))
|
||||
{
|
||||
const Signature * s = this->getSignature(*jter);
|
||||
if(!s)
|
||||
{
|
||||
++nbLoadedFromDb;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for(std::list<int>::iterator jter = currentMargin.begin(); jter!=currentMargin.end(); ++jter)
|
||||
{
|
||||
if(ids.insert(std::pair<int, int>(*jter, m)).second)
|
||||
{
|
||||
// Look up in the short time memory if all ids are here, if not... load them from the database
|
||||
const Signature * s = this->getSignature(*jter);
|
||||
std::list<int> neighborIds;
|
||||
std::list<int> loopIds;
|
||||
std::list<int> childIds;
|
||||
std::set<int> tmpNeighborIds;
|
||||
std::set<int> tmpLoopClosureIds;
|
||||
std::set<int> tmpChildLoopClosureIds;
|
||||
const std::set<int> * neighborIds = &tmpNeighborIds;
|
||||
const std::set<int> * loopClosureIds = &tmpLoopClosureIds;
|
||||
const std::set<int> * childLoopClosureIds = &tmpChildLoopClosureIds;
|
||||
if(s)
|
||||
{
|
||||
const NeighborsMultiMap & neighbors = s->getNeighbors();
|
||||
const std::set<int> & loopClosureIds = s->getLoopClosureIds();
|
||||
const std::set<int> & childLoopClosureIds = s->getChildLoopClosureIds();
|
||||
int lastId = -1;
|
||||
for(NeighborsMultiMap::const_iterator iter=neighbors.begin(); iter!=neighbors.end(); ++iter)
|
||||
if(onlyWithActions)
|
||||
{
|
||||
if( (ignoreLoopIds || (loopClosureIds.find(iter->first) == loopClosureIds.end() && childLoopClosureIds.find(iter->first) == childLoopClosureIds.end())) &&
|
||||
(!onlyWithActions || iter->second.actions().size()) &&
|
||||
(!ignoreSTM || (!_stMem.size() || iter->first < *_stMem.begin()) ) &&
|
||||
lastId != iter->first)
|
||||
{
|
||||
neighborIds.push_back(iter->first);
|
||||
}
|
||||
lastId = iter->first; // just to ignore duplicates
|
||||
neighborIds = &s->getNeighborsWithActuators();
|
||||
}
|
||||
else
|
||||
{
|
||||
neighborIds = &s->getNeighborsAll();
|
||||
}
|
||||
if(!ignoreLoopIds)
|
||||
{
|
||||
for(std::set<int>::const_iterator iter=loopClosureIds.begin(); iter!=loopClosureIds.end(); ++iter)
|
||||
{
|
||||
if( *iter &&
|
||||
(!ignoreSTM || (!_stMem.size() || *iter < *_stMem.begin()) ))
|
||||
{
|
||||
loopIds.push_back(*iter);
|
||||
}
|
||||
}
|
||||
for(std::set<int>::const_iterator iter=childLoopClosureIds.begin(); iter!=childLoopClosureIds.end(); ++iter)
|
||||
{
|
||||
if( *iter &&
|
||||
(!ignoreSTM || (!_stMem.size() || *iter < *_stMem.begin()) ))
|
||||
{
|
||||
childIds.push_back(*iter);
|
||||
}
|
||||
}
|
||||
loopClosureIds = &s->getLoopClosureIds();
|
||||
childLoopClosureIds = &s->getChildLoopClosureIds();
|
||||
}
|
||||
}
|
||||
else if(maxCheckedInDatabase == -1 || (maxCheckedInDatabase > 0 && _dbDriver && nbLoadedFromDb < maxCheckedInDatabase))
|
||||
{
|
||||
someLoadedFromDb = true;
|
||||
std::set<int> loopClosureIds;
|
||||
std::set<int> childLoopClosureIds;
|
||||
UTimer timer;
|
||||
_dbDriver->getNeighborIds(*jter, tmpNeighborIds, onlyWithActions);
|
||||
if(!ignoreLoopIds)
|
||||
{
|
||||
UTimer timer;
|
||||
_dbDriver->getLoopClosureIds(*jter, loopClosureIds, childLoopClosureIds);
|
||||
dbAccessTime += timer.getElapsedTime();
|
||||
for(std::set<int>::const_iterator iter = loopClosureIds.begin(); iter!=loopClosureIds.end(); ++iter)
|
||||
{
|
||||
if( *iter &&
|
||||
(!ignoreSTM || (!_stMem.size() || *iter < *_stMem.begin()) ))
|
||||
{
|
||||
loopIds.push_back(*iter);
|
||||
}
|
||||
}
|
||||
for(std::set<int>::const_iterator iter = childLoopClosureIds.begin(); iter!=childLoopClosureIds.end(); ++iter)
|
||||
{
|
||||
if( *iter &&
|
||||
(!ignoreSTM || (!_stMem.size() || *iter < *_stMem.begin()) ))
|
||||
{
|
||||
childIds.push_back(*iter);
|
||||
}
|
||||
}
|
||||
_dbDriver->getLoopClosureIds(*jter, tmpLoopClosureIds, tmpChildLoopClosureIds);
|
||||
}
|
||||
UTimer timer;
|
||||
_dbDriver->getNeighborIds(*jter, neighborIds, onlyWithActions);
|
||||
dbAccessTime += timer.getElapsedTime();
|
||||
if(neighborIds.size() == 0)
|
||||
}
|
||||
|
||||
// Neighbor links
|
||||
for(std::set<int>::const_iterator iter=neighborIds->begin(); iter!=neighborIds->end(); ++iter)
|
||||
{
|
||||
if( (ignoreLoopIds || (loopClosureIds->find(*iter) == loopClosureIds->end() && childLoopClosureIds->find(*iter) == childLoopClosureIds->end())) &&
|
||||
(!ignoreSTM || (!_stMem.size() || *iter < *_stMem.begin()) ) &&
|
||||
!uContains(ids, *iter))
|
||||
{
|
||||
UERROR("Signature %d doesn't have neighbor!?", *jter);
|
||||
nextMargin.push_back(*iter);
|
||||
}
|
||||
for(std::list<int>::iterator iter = neighborIds.begin(); iter!=neighborIds.end();)
|
||||
}
|
||||
|
||||
// Parent links
|
||||
for(std::set<int>::const_iterator iter=loopClosureIds->begin(); iter!=loopClosureIds->end(); ++iter)
|
||||
{
|
||||
if( *iter &&
|
||||
(!ignoreSTM || (!_stMem.size() || *iter < *_stMem.begin()) ) &&
|
||||
!uContains(ids, *iter))
|
||||
{
|
||||
if( (ignoreLoopIds || (loopClosureIds.find(*iter) == loopClosureIds.end() && childLoopClosureIds.find(*iter) == childLoopClosureIds.end())) &&
|
||||
(!ignoreSTM || (!_stMem.size() || *iter < *_stMem.begin())))
|
||||
if(incrementMarginOnLoop)
|
||||
{
|
||||
++iter;
|
||||
nextMargin.push_back(*iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
iter = neighborIds.erase(iter);
|
||||
const Signature * s = this->getSignature(*iter);
|
||||
if(!s)
|
||||
{
|
||||
// update db count because it's on current margin
|
||||
++nbLoadedFromDb;
|
||||
}
|
||||
currentMargin.push_back(*iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Priority on neighbors
|
||||
nextMargin.insert(nextMargin.end(), neighborIds.rbegin(), neighborIds.rend());
|
||||
|
||||
if(incrementMarginOnLoop)
|
||||
//Child links
|
||||
for(std::set<int>::const_iterator iter=childLoopClosureIds->begin(); iter!=childLoopClosureIds->end(); ++iter)
|
||||
{
|
||||
//LoopIds
|
||||
nextMargin.insert(nextMargin.end(), loopIds.rbegin(), loopIds.rend());
|
||||
|
||||
//ChildIds
|
||||
nextMargin.insert(nextMargin.end(), childIds.rbegin(), childIds.rend());
|
||||
}
|
||||
else
|
||||
{
|
||||
//LoopIds
|
||||
currentMargin.insert(currentMargin.end(), loopIds.rbegin(), loopIds.rend());
|
||||
|
||||
//ChildIds
|
||||
currentMargin.insert(currentMargin.end(), childIds.rbegin(), childIds.rend());
|
||||
if( *iter &&
|
||||
(!ignoreSTM || (!_stMem.size() || *iter < *_stMem.begin()) ) &&
|
||||
!uContains(ids, *iter))
|
||||
{
|
||||
if(incrementMarginOnLoop)
|
||||
{
|
||||
nextMargin.push_back(*iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
const Signature * s = this->getSignature(*iter);
|
||||
if(!s)
|
||||
{
|
||||
// update db count because it's on current margin
|
||||
++nbLoadedFromDb;
|
||||
}
|
||||
currentMargin.push_back(*iter);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if(someLoadedFromDb)
|
||||
{
|
||||
// number of margin...
|
||||
++nbLoadedFromDb;
|
||||
}
|
||||
++m;
|
||||
}
|
||||
return ids;
|
||||
@@ -713,7 +695,7 @@ std::set<int> Memory::getAllSignatureIds() const
|
||||
std::set<int> ids;
|
||||
if(_dbDriver)
|
||||
{
|
||||
_dbDriver->getAllSignatureIds(ids);
|
||||
_dbDriver->getAllNodeIds(ids);
|
||||
for(std::map<int, Signature*>::const_iterator iter = _signatures.begin(); iter!=_signatures.end(); ++iter)
|
||||
{
|
||||
ids.insert(iter->first);
|
||||
@@ -736,35 +718,21 @@ void Memory::clear()
|
||||
if(_dbDriver && (_stMem.size() || _workingMem.size()))
|
||||
{
|
||||
unsigned int memSize = _workingMem.size() + _stMem.size();
|
||||
if(_workingMem.size() && *_workingMem.begin() < 0)
|
||||
{
|
||||
--memSize;
|
||||
}
|
||||
if(memSize != _signatures.size())
|
||||
{
|
||||
// this is only a safe check...not supposed to occur.
|
||||
ULOGGER_ERROR("The number of signatures don't match! _workingMem=%d, _stMem=%d, _signatures=%d", _workingMem.size(), _stMem.size(), _signatures.size());
|
||||
}
|
||||
if(_workingMem.size() && *_workingMem.begin() < 0)
|
||||
{
|
||||
--memSize;
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("Adding statistics after run...");
|
||||
_dbDriver->addStatisticsAfterRun(memSize, _lastSignature?_lastSignature->id():0, UProcessInfo::getMemoryUsage(), _dbDriver->getMemoryUsed());
|
||||
}
|
||||
ULOGGER_DEBUG("");
|
||||
|
||||
int minId = -1;
|
||||
std::map<int, Signature*>::iterator minIter = _signatures.begin();
|
||||
while(minIter != _signatures.end())
|
||||
{
|
||||
if(minIter->first > 0)
|
||||
{
|
||||
minId = minIter->first;
|
||||
break;
|
||||
}
|
||||
++minIter;
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("");
|
||||
|
||||
//Get the tree root (parents)
|
||||
std::map<int, Signature*> mem = _signatures;
|
||||
for(std::map<int, Signature *>::iterator i=mem.begin(); i!=mem.end(); ++i)
|
||||
@@ -776,7 +744,7 @@ void Memory::clear()
|
||||
}
|
||||
}
|
||||
|
||||
if(_workingMem.size() != 0)
|
||||
if(_workingMem.size() != 0 && !(_workingMem.size() == 1 && *_workingMem.begin() == kIdVirtual))
|
||||
{
|
||||
ULOGGER_ERROR("_workingMem must be empty here, size=%d", _workingMem.size());
|
||||
}
|
||||
@@ -804,6 +772,7 @@ void Memory::clear()
|
||||
|
||||
/**
|
||||
* Compute the likelihood of the signature with some others in the memory.
|
||||
* Important: Assuming that all other ids are under 'signature' id.
|
||||
* If an error occurs, the result is empty.
|
||||
*/
|
||||
std::map<int, float> Memory::computeLikelihood(const Signature * signature, const std::list<int> & ids, float & maximumScore)
|
||||
@@ -827,14 +796,24 @@ std::map<int, float> Memory::computeLikelihood(const Signature * signature, cons
|
||||
float sumSimilarity = 0.0f;
|
||||
float maxSim = 0.0f;
|
||||
int maxId = 0;
|
||||
std::map<int, std::map<int, float> >::iterator iterB = _similaritiesMap.find(signature->id());
|
||||
if(iterB == _similaritiesMap.end())
|
||||
{
|
||||
iterB = _similaritiesMap.insert(_similaritiesMap.end(), std::make_pair(signature->id(), std::map<int, float>()));
|
||||
}
|
||||
for(std::list<int>::const_iterator iter = ids.begin(); iter!=ids.end(); ++iter)
|
||||
{
|
||||
const Signature * sB = this->getSignature(*iter);
|
||||
if(!sB)
|
||||
float sim = 0;
|
||||
if(*iter > 0)
|
||||
{
|
||||
UFATAL("Signature %d not wfound in WM ?!?", *iter);
|
||||
const Signature * sB = this->getSignature(*iter);
|
||||
if(!sB)
|
||||
{
|
||||
UFATAL("Signature %d not wfound in WM ?!?", *iter);
|
||||
}
|
||||
sim = signature->compareTo(sB);
|
||||
iterB->second.insert(iterB->second.end(), std::make_pair(sB->id(), sim));
|
||||
}
|
||||
float sim = signature->compareTo(sB);
|
||||
likelihood.insert(likelihood.end(), std::pair<int, float>(*iter, sim));
|
||||
sumSimilarity += sim;
|
||||
UDEBUG("sim %d with %d = %f", signature->id(), *iter, sim);
|
||||
@@ -960,12 +939,15 @@ std::map<int, int> Memory::getWeights() const
|
||||
std::map<int, int> weights;
|
||||
for(std::set<int>::const_iterator iter=_workingMem.begin(); iter!=_workingMem.end(); ++iter)
|
||||
{
|
||||
const Signature * s = this->getSignature(*iter);
|
||||
if(!s)
|
||||
if(*iter > 0)
|
||||
{
|
||||
UFATAL("Location %d must exist in memory", *iter);
|
||||
const Signature * s = this->getSignature(*iter);
|
||||
if(!s)
|
||||
{
|
||||
UFATAL("Location %d must exist in memory", *iter);
|
||||
}
|
||||
weights.insert(weights.end(), std::make_pair(*iter, s->getWeight()));
|
||||
}
|
||||
weights.insert(weights.end(), std::make_pair(*iter, s->getWeight()));
|
||||
}
|
||||
return weights;
|
||||
}
|
||||
@@ -1007,7 +989,7 @@ int Memory::cleanup(const std::list<int> & ignoredIds)
|
||||
int signaturesRemoved = 0;
|
||||
|
||||
// bad signature
|
||||
if(_lastSignature->isBadSignature())
|
||||
if(_lastSignature->isBadSignature() || !_incrementalMemory)
|
||||
{
|
||||
moveToTrash(_lastSignature);
|
||||
++signaturesRemoved;
|
||||
@@ -1028,7 +1010,9 @@ void Memory::joinTrashThread()
|
||||
{
|
||||
if(_dbDriver)
|
||||
{
|
||||
UDEBUG("");
|
||||
_dbDriver->join();
|
||||
UDEBUG("");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1117,6 +1101,13 @@ std::list<Signature *> Memory::getRemovableSignatures(int count, const std::set<
|
||||
UDEBUG("currentRecentWmSize=%d, recentWmMaxSize=%d, _recentWmRatio=%f, end recent wM = %d", currentRecentWmSize, recentWmMaxSize, _recentWmRatio, _lastLoopClosureId);
|
||||
}
|
||||
|
||||
// Ignore neighbor of the last location in STM (for neighbor links redirection issue during Rehearsal).
|
||||
Signature * lastInSTM = 0;
|
||||
if(_stMem.size())
|
||||
{
|
||||
lastInSTM = _signatures.at(*_stMem.begin());
|
||||
}
|
||||
|
||||
for(std::set<int>::const_iterator memIter = wm.begin(); memIter != wm.end(); ++memIter)
|
||||
{
|
||||
if( (recentWmImmunized && *memIter > _lastLoopClosureId) ||
|
||||
@@ -1124,7 +1115,7 @@ std::list<Signature *> Memory::getRemovableSignatures(int count, const std::set<
|
||||
{
|
||||
// ignore recent memory
|
||||
}
|
||||
else if(*memIter > 0 && ignoredIds.find(*memIter) == ignoredIds.end())
|
||||
else if(*memIter > 0 && ignoredIds.find(*memIter) == ignoredIds.end() && (!lastInSTM || !lastInSTM->hasNeighbor(*memIter)))
|
||||
{
|
||||
Signature * s = this->_getSignature(*memIter);
|
||||
if(s)
|
||||
@@ -1140,6 +1131,18 @@ std::list<Signature *> Memory::getRemovableSignatures(int count, const std::set<
|
||||
break;
|
||||
}
|
||||
}
|
||||
// Its neighbors must not be in STM to be removable, rehearsal issue
|
||||
if(!foundInSTM)
|
||||
{
|
||||
for(std::set<int>::iterator iter = _stMem.begin(); iter!=_stMem.end(); ++iter)
|
||||
{
|
||||
if(s->hasNeighbor(*iter))
|
||||
{
|
||||
foundInSTM = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(!foundInSTM)
|
||||
{
|
||||
// looped signature priority to be transferred
|
||||
@@ -1167,16 +1170,6 @@ std::list<Signature *> Memory::getRemovableSignatures(int count, const std::set<
|
||||
++iter)
|
||||
{
|
||||
bool removable = true;
|
||||
const std::set<int> & childIds = iter->second->getChildLoopClosureIds();
|
||||
for(std::set<int>::const_iterator jter = childIds.begin(); jter != childIds.end(); ++jter)
|
||||
{
|
||||
// if the child is not in WM or if it is added to the removable list
|
||||
removable = _workingMem.find(*jter) == _workingMem.end() || addedSignatures.find(*jter) != addedSignatures.end();
|
||||
if(!removable)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
if(removable)
|
||||
{
|
||||
if(!recentWmImmunized)
|
||||
@@ -1336,16 +1329,13 @@ bool Memory::addLoopClosureLink(int oldId, int newId)
|
||||
for(std::set<int>::iterator iter=_stMem.begin(); iter!=_stMem.end(); ++iter)
|
||||
{
|
||||
Signature * s = _getSignature(*iter);
|
||||
if(s)
|
||||
// don't modify old links of oldS (cameraDatabase needs this info
|
||||
// to reload properly the actions).
|
||||
if(s && s->id() > oldS->id())
|
||||
{
|
||||
// don't modify old links (cameraDatabase needs this info
|
||||
// to reload properly the actions).
|
||||
if(s->id()!=oldS->id())
|
||||
{
|
||||
s->changeNeighborIds(oldS->id(), newS->id());
|
||||
}
|
||||
s->changeNeighborIds(oldS->id(), newS->id());
|
||||
}
|
||||
else
|
||||
else if(!s)
|
||||
{
|
||||
UERROR("Location %d is not in RAM?!?", *iter);
|
||||
}
|
||||
@@ -1358,7 +1348,8 @@ bool Memory::addLoopClosureLink(int oldId, int newId)
|
||||
{
|
||||
NeighborLink link = iter->second;
|
||||
link.updateIds(oldS->id(), newS->id());
|
||||
if(link.id() == newS->id() && link.baseIds().size())
|
||||
// Forward links have baseIds set, Backward links have baseIds null
|
||||
if(link.toId() == newS->id() && link.baseIds().size())
|
||||
{
|
||||
// Limit the number of self references to STM size (baseIds size)
|
||||
bool allSameIds = true;
|
||||
@@ -1374,16 +1365,33 @@ bool Memory::addLoopClosureLink(int oldId, int newId)
|
||||
if(!allSameIds || (allSameIds && !allSameIdsAdded))
|
||||
{
|
||||
newS->addNeighbor(link);
|
||||
allSameIdsAdded = true;
|
||||
if(allSameIds && !allSameIdsAdded)
|
||||
{
|
||||
allSameIdsAdded = true;
|
||||
}
|
||||
}
|
||||
else if (link.actions().size() && link.actions().front().size())
|
||||
else if (link.actuators().size() && link.actuators().size())
|
||||
{
|
||||
// Show warning when actions are used.
|
||||
UWARN("Ignored self reference link because base ids are all the same. (id=%d)", newS->id());
|
||||
}
|
||||
else
|
||||
{
|
||||
UDEBUG("Ignored self reference link because base ids are all the same. (id=%d)", newS->id());
|
||||
}
|
||||
}
|
||||
else
|
||||
else if(link.toId() != newS->id())
|
||||
{
|
||||
Signature * s = this->_getSignature(link.toId());
|
||||
if(s)
|
||||
{
|
||||
// modify neighbor "from"
|
||||
s->changeNeighborIds(oldS->id(), newS->id());
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("Didn't find neighbor %d of %d in RAM...", link.toId(), oldS->id());
|
||||
}
|
||||
newS->addNeighbor(link);
|
||||
}
|
||||
}
|
||||
@@ -1406,7 +1414,7 @@ bool Memory::addLoopClosureLink(int oldId, int newId)
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("A location (%d) in WM/STM cannot be transferred if its loop closure id is in STM", *iter);
|
||||
UERROR("A location (%d, child of %d) in WM/STM cannot be transferred if its loop closure id is in STM", *iter, oldS->id());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1423,7 +1431,26 @@ bool Memory::addLoopClosureLink(int oldId, int newId)
|
||||
{
|
||||
this->copyData(oldS, newS);
|
||||
// Set old image to new signature
|
||||
newS->setImage(oldS->getImage());
|
||||
if(this->isRawDataKept())
|
||||
{
|
||||
if(oldS->getRawData().size() == 0)
|
||||
{
|
||||
// try load from database
|
||||
if(oldS->isSaved() && _dbDriver)
|
||||
{
|
||||
std::list<Sensor> rawData;
|
||||
if(_dbDriver->getRawData(oldS->id(), rawData))
|
||||
{
|
||||
newS->setRawData(rawData);
|
||||
}
|
||||
UDEBUG("Loaded raw data from database");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
newS->setRawData(oldS->getRawData());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// remove old location
|
||||
@@ -1498,12 +1525,6 @@ void Memory::rehearsal(Signature * signature, std::map<std::string, float> & sta
|
||||
// Get parents to compare...
|
||||
std::set<int> mem = _stMem;
|
||||
mem.erase(signature->id());
|
||||
if(mem.size())
|
||||
{
|
||||
// A loop closure cannot happen on the last location of STM
|
||||
// (for neighbor links redirection issue).
|
||||
mem.erase(mem.begin());
|
||||
}
|
||||
|
||||
if(_similarityOnlyLast && mem.size())
|
||||
{
|
||||
@@ -1537,6 +1558,7 @@ void Memory::rehearsal(Signature * signature, std::map<std::string, float> & sta
|
||||
ULOGGER_DEBUG("Comparing with last signatures...");
|
||||
float value = 0;
|
||||
int id = 0;
|
||||
int nbMerged = 0;
|
||||
float maxValue = 0;
|
||||
int maxId = 0;
|
||||
for(std::map<int, float>::iterator iter=similarities.begin(); iter!=similarities.end(); ++iter)
|
||||
@@ -1548,53 +1570,50 @@ void Memory::rehearsal(Signature * signature, std::map<std::string, float> & sta
|
||||
maxId = id;
|
||||
maxValue = value;
|
||||
}
|
||||
}
|
||||
|
||||
if(maxValue > _similarityThreshold)
|
||||
{
|
||||
if(_incrementalMemory)
|
||||
if(value > _similarityThreshold)
|
||||
{
|
||||
this->addLoopClosureLink(maxId, signature->id());
|
||||
}
|
||||
else
|
||||
{
|
||||
Signature * s = _signatures.at(maxId);
|
||||
if(s)
|
||||
if(_incrementalMemory)
|
||||
{
|
||||
signature->setWeight(signature->getWeight() + 1 + s->getWeight());
|
||||
this->addLoopClosureLink(id, signature->id());
|
||||
}
|
||||
else
|
||||
{
|
||||
UFATAL("not supposed to happen");
|
||||
Signature * s = _signatures.at(id);
|
||||
if(s)
|
||||
{
|
||||
signature->setWeight(signature->getWeight() + 1 + s->getWeight());
|
||||
}
|
||||
else
|
||||
{
|
||||
UFATAL("not supposed to happen");
|
||||
}
|
||||
}
|
||||
++nbMerged;
|
||||
}
|
||||
stats.insert(std::pair<std::string, float>(std::string("Memory/Rehearsal Closure/"), 1.0f));
|
||||
}
|
||||
else
|
||||
{
|
||||
stats.insert(std::pair<std::string, float>(std::string("Memory/Rehearsal Closure/"), 0.0f));
|
||||
}
|
||||
|
||||
stats.insert(std::pair<std::string, float>(std::string("Memory/Rehearsal Max Id/"), maxId));
|
||||
stats.insert(std::pair<std::string, float>(std::string("Memory/Rehearsal Max Value/"), maxValue));
|
||||
|
||||
stats.insert(std::pair<std::string, float>(std::string("Memory/Rehearsal nbMerged/"), nbMerged));
|
||||
|
||||
UDEBUG("maxId=%d, maxSim=%f, t=%fs", maxId, maxValue, timer.ticks());
|
||||
}
|
||||
|
||||
// The data returned must be released
|
||||
IplImage * Memory::getImage(int id) const
|
||||
std::list<Sensor> Memory::getRawData(int id) const
|
||||
{
|
||||
IplImage * img = 0;
|
||||
std::list<Sensor> data;
|
||||
const Signature * s = this->getSignature(id);
|
||||
if(s && s->getImage())
|
||||
if(s && s->getRawData().size())
|
||||
{
|
||||
img = cvCloneImage(s->getImage());
|
||||
data = s->getRawData();
|
||||
}
|
||||
else if(_dbDriver)
|
||||
{
|
||||
_dbDriver->getImage(id, &img);
|
||||
_dbDriver->getRawData(id, data);
|
||||
}
|
||||
return img;
|
||||
return data;
|
||||
}
|
||||
|
||||
void Memory::generateGraph(const std::string & fileName, std::set<int> ids)
|
||||
@@ -1622,7 +1641,8 @@ void Memory::generateGraph(const std::string & fileName, std::set<int> ids)
|
||||
|
||||
if(ids.size() == 0)
|
||||
{
|
||||
_dbDriver->getAllSignatureIds(ids);
|
||||
_dbDriver->getAllNodeIds(ids);
|
||||
UDEBUG("ids.size()=%d", ids.size());
|
||||
for(std::map<int, Signature*>::iterator iter=_signatures.begin(); iter!=_signatures.end(); ++iter)
|
||||
{
|
||||
ids.insert(iter->first);
|
||||
@@ -1646,7 +1666,7 @@ void Memory::generateGraph(const std::string & fileName, std::set<int> ids)
|
||||
_dbDriver->getWeight(id, weight);
|
||||
for(NeighborsMultiMap::iterator iter = neighbors.begin(); iter!=neighbors.end(); ++iter)
|
||||
{
|
||||
if(_signatures.find(iter->first) == _signatures.end())
|
||||
if(id!=iter->first && _signatures.find(iter->first) == _signatures.end())
|
||||
{
|
||||
int weightNeighbor = 0;
|
||||
_dbDriver->getWeight(iter->first, weightNeighbor);
|
||||
@@ -1656,8 +1676,8 @@ void Memory::generateGraph(const std::string & fileName, std::set<int> ids)
|
||||
weight,
|
||||
iter->first,
|
||||
weightNeighbor,
|
||||
(int)iter->second.actions().size(),
|
||||
iter->second.actions().size()>0?colorA:colorB);
|
||||
(int)iter->second.actuators().size(),
|
||||
iter->second.actuators().size()>0?colorA:colorB);
|
||||
}
|
||||
}
|
||||
std::set<int> loopIds;
|
||||
@@ -1695,6 +1715,7 @@ void Memory::generateGraph(const std::string & fileName, std::set<int> ids)
|
||||
{
|
||||
//if(linksAdded.find(std::pair<int, int>(id, iter->first)) == linksAdded.end() &&
|
||||
// linksAdded.find(std::pair<int, int>(iter->first, id)) == linksAdded.end())
|
||||
if(id != iter->first)
|
||||
{
|
||||
int weightNeighbor = 0;
|
||||
const Signature * s = this->getSignature(iter->first);
|
||||
@@ -1712,8 +1733,8 @@ void Memory::generateGraph(const std::string & fileName, std::set<int> ids)
|
||||
weight,
|
||||
iter->first,
|
||||
weightNeighbor,
|
||||
(int)iter->second.actions().size(),
|
||||
iter->second.actions().size()>0?colorA:colorB);
|
||||
(int)iter->second.actuators().size(),
|
||||
iter->second.actuators().size()>0?colorA:colorB);
|
||||
}
|
||||
}
|
||||
const std::set<int> & loopIds = i->second->getLoopClosureIds();
|
||||
@@ -1784,7 +1805,7 @@ void Memory::cleanLTM(int maxDepth)
|
||||
}
|
||||
//Look in the database
|
||||
UDEBUG("highestWeightedSignatures.size()=%d", highestWeightedSignatures.size());
|
||||
_dbDriver->getHighestWeightedSignatures(wmSize, highestWeightedSignatures);
|
||||
_dbDriver->getHighestWeightedNodeIds(wmSize, highestWeightedSignatures);
|
||||
UDEBUG("highestWeightedSignatures.size()=%d", highestWeightedSignatures.size());
|
||||
|
||||
std::set<int> weightedSignatures;
|
||||
@@ -1820,8 +1841,8 @@ void Memory::cleanGraph(const Node * root)
|
||||
std::list<std::list<int> > paths;
|
||||
root->expand(paths);
|
||||
|
||||
int i=0;
|
||||
/*for(std::list<std::list<int> >::iterator iter=paths.begin(); iter!=paths.end();++iter)
|
||||
/*int i=0;
|
||||
for(std::list<std::list<int> >::iterator iter=paths.begin(); iter!=paths.end();++iter)
|
||||
{
|
||||
std::stringstream str;
|
||||
std::list<int> & path = *iter;
|
||||
@@ -1877,8 +1898,8 @@ void Memory::cleanGraph(const Node * root)
|
||||
}
|
||||
}
|
||||
|
||||
i=0;
|
||||
/*for(std::list<std::list<int> >::iterator iter=paths.begin(); iter!=paths.end();++iter)
|
||||
/*i=0;
|
||||
for(std::list<std::list<int> >::iterator iter=paths.begin(); iter!=paths.end();++iter)
|
||||
{
|
||||
std::stringstream str;
|
||||
std::list<int> & path = *iter;
|
||||
@@ -1987,9 +2008,9 @@ void Memory::cleanGraph(const Node * root)
|
||||
else if(_dbDriver)
|
||||
{
|
||||
// remove reference from active neighbors
|
||||
std::list<int> neighbors;
|
||||
std::set<int> neighbors;
|
||||
_dbDriver->getNeighborIds(*iter, neighbors);
|
||||
for(std::list<int>::iterator jter=neighbors.begin(); jter!=neighbors.end(); ++jter)
|
||||
for(std::set<int>::iterator jter=neighbors.begin(); jter!=neighbors.end(); ++jter)
|
||||
{
|
||||
s = this->_getSignature(*jter);
|
||||
if(s)
|
||||
@@ -2005,7 +2026,8 @@ void Memory::cleanGraph(const Node * root)
|
||||
UDEBUG("Removing %s", strToRemove.c_str());
|
||||
if(_dbDriver && !strToRemove.empty())
|
||||
{
|
||||
_dbDriver->executeNoResult(std::string("UPDATE Signature SET loopClosureId=-1 WHERE ") + strToRemove);
|
||||
UWARN("Not implemented...");
|
||||
//_dbDriver->executeNoResult(std::string("UPDATE Node SET loopClosureId=-1 WHERE ") + strToRemove);
|
||||
}
|
||||
|
||||
UDEBUG("time=%fs", timer.ticks());
|
||||
|
||||
@@ -0,0 +1,383 @@
|
||||
/*
|
||||
* Micro.cpp
|
||||
*
|
||||
* Created on: Mar 5, 2012
|
||||
* Author: MatLab
|
||||
*/
|
||||
|
||||
#include "rtabmap/core/Micro.h"
|
||||
|
||||
#include "utilite/UAudioRecorderMic.h"
|
||||
#include "utilite/UAudioRecorderFile.h"
|
||||
#include <utilite/UEventsManager.h>
|
||||
#include <utilite/UFile.h>
|
||||
#include <utilite/UMath.h>
|
||||
#include <fftw3.h>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
Micro::Micro(MicroEvent::Type eventType,
|
||||
int deviceId,
|
||||
int fs,
|
||||
int frameLength,
|
||||
int channels,
|
||||
int bytesPerSample,
|
||||
int id) :
|
||||
_eventType(eventType),
|
||||
_recorder(0),
|
||||
_simulateFreq(false),
|
||||
_out(0),
|
||||
_id(id)
|
||||
{
|
||||
UASSERT(eventType == MicroEvent::kTypeFrame || eventType == MicroEvent::kTypeFrameFreq || eventType == MicroEvent::kTypeFrameFreqSqrdMagn);
|
||||
UASSERT(deviceId >= 0);
|
||||
UASSERT(frameLength > 0 && frameLength % 2 == 0);
|
||||
|
||||
_recorder = new UAudioRecorderMic(deviceId, fs, frameLength, bytesPerSample, channels);
|
||||
}
|
||||
|
||||
Micro::Micro(MicroEvent::Type eventType,
|
||||
const std::string & path,
|
||||
bool simulateFrameRate,
|
||||
int frameLength,
|
||||
int id,
|
||||
bool playWhileRecording) :
|
||||
_eventType(eventType),
|
||||
_recorder(0),
|
||||
_simulateFreq(simulateFrameRate),
|
||||
_out(0),
|
||||
_id(id)
|
||||
{
|
||||
UASSERT(eventType == MicroEvent::kTypeFrame || eventType == MicroEvent::kTypeFrameFreq || eventType == MicroEvent::kTypeFrameFreqSqrdMagn);
|
||||
UASSERT(frameLength > 0 && frameLength % 2 == 0);
|
||||
|
||||
if(playWhileRecording)
|
||||
{
|
||||
simulateFrameRate = false;
|
||||
}
|
||||
_recorder = new UAudioRecorderFile(path, playWhileRecording, frameLength);
|
||||
}
|
||||
|
||||
Micro::~Micro()
|
||||
{
|
||||
UDEBUG("");
|
||||
join(true);
|
||||
if(_recorder)
|
||||
{
|
||||
delete _recorder;
|
||||
}
|
||||
|
||||
if(_out)
|
||||
{
|
||||
fftwf_destroy_plan((fftwf_plan)_p);
|
||||
fftwf_free(_out);
|
||||
_out = 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool Micro::init()
|
||||
{
|
||||
if(!_recorder->init())
|
||||
{
|
||||
UERROR("Recorder initialization failed!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// init FFTW stuff
|
||||
if(_out)
|
||||
{
|
||||
fftwf_destroy_plan((fftwf_plan)_p);
|
||||
fftwf_free(_out);
|
||||
_out = 0;
|
||||
_in.clear();
|
||||
}
|
||||
int N = _recorder->frameLength();
|
||||
_in.resize(N);
|
||||
_out = (fftwf_complex*) fftwf_malloc(sizeof(fftwf_complex) * N);
|
||||
_p = fftwf_plan_dft_r2c_1d(N, _in.data(), _out, 0);
|
||||
_window = uHamming(N);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Micro::stop()
|
||||
{
|
||||
if(this->isRunning())
|
||||
{
|
||||
this->kill();
|
||||
}
|
||||
else if(_recorder && _recorder->isRunning())
|
||||
{
|
||||
_recorder->join(true);
|
||||
}
|
||||
}
|
||||
|
||||
void Micro::startRecorder()
|
||||
{
|
||||
if(_recorder)
|
||||
{
|
||||
_recorder->start();
|
||||
_timer.start();
|
||||
}
|
||||
}
|
||||
|
||||
void Micro::mainLoopBegin()
|
||||
{
|
||||
this->startRecorder();
|
||||
}
|
||||
|
||||
void Micro::mainLoop()
|
||||
{
|
||||
if(!_recorder)
|
||||
{
|
||||
UERROR("Recorder not initialized");
|
||||
this->kill();
|
||||
return;
|
||||
}
|
||||
|
||||
if(this->isRunning())
|
||||
{
|
||||
bool noMoreFrames = true;
|
||||
if(_eventType == MicroEvent::kTypeFrame)
|
||||
{
|
||||
UDEBUG("");
|
||||
cv::Mat data = this->getFrame();
|
||||
if(!data.empty())
|
||||
{
|
||||
noMoreFrames = false;
|
||||
UEventsManager::post(new MicroEvent(data, 2, _recorder->fs(), _recorder->channels(), _id));
|
||||
}
|
||||
}
|
||||
else if(_eventType == MicroEvent::kTypeFrameFreq)
|
||||
{
|
||||
UDEBUG("");
|
||||
cv::Mat freq;
|
||||
cv::Mat data = this->getFrame(freq, false);
|
||||
if(!data.empty())
|
||||
{
|
||||
noMoreFrames = false;
|
||||
UEventsManager::post(new MicroEvent(MicroEvent::kTypeFrameFreq, freq, _recorder->fs(), _recorder->channels(), _id));
|
||||
}
|
||||
}
|
||||
else if(_eventType == MicroEvent::kTypeFrameFreqSqrdMagn)
|
||||
{
|
||||
UDEBUG("");
|
||||
cv::Mat freq;
|
||||
cv::Mat data = this->getFrame(freq, true);
|
||||
if(!data.empty())
|
||||
{
|
||||
noMoreFrames = false;
|
||||
UEventsManager::post(new MicroEvent(MicroEvent::kTypeFrameFreqSqrdMagn, freq, _recorder->fs(), _recorder->channels(), _id));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UFATAL("Not supposed to be here...");
|
||||
}
|
||||
|
||||
if(noMoreFrames)
|
||||
{
|
||||
if(this->isRunning())
|
||||
{
|
||||
UEventsManager::post(new MicroEvent(_id));
|
||||
}
|
||||
this->kill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Micro::mainLoopKill()
|
||||
{
|
||||
if(_recorder)
|
||||
{
|
||||
_recorder->join(true);
|
||||
}
|
||||
}
|
||||
|
||||
cv::Mat Micro::getFrame()
|
||||
{
|
||||
cv::Mat data;
|
||||
std::vector<char> frame;
|
||||
if(!_recorder)
|
||||
{
|
||||
UERROR("Micro is not initialized...");
|
||||
return data;
|
||||
}
|
||||
int frameLength = _recorder->frameLength();
|
||||
int fs = _recorder->fs();
|
||||
int channels = _recorder->channels();
|
||||
int bytesPerSample = _recorder->bytesPerSample();
|
||||
|
||||
if(_simulateFreq && fs)
|
||||
{
|
||||
int sleepTime = ((double(frameLength)/double(fs) - _timer.getElapsedTime()) * 1000.0) + 0.5;
|
||||
if(sleepTime > 2)
|
||||
{
|
||||
uSleep(sleepTime-2);
|
||||
}
|
||||
// Add precision at the cost of a small overhead
|
||||
while(_timer.getElapsedTime() < double(frameLength)/double(fs)-0.000001)
|
||||
{
|
||||
//
|
||||
}
|
||||
double slept = _timer.getElapsedTime();
|
||||
_timer.start();
|
||||
UDEBUG("slept=%fs vs target=%fs", slept, double(frameLength)/double(fs));
|
||||
}
|
||||
|
||||
if(_recorder->getNextFrame(frame, true) && int(frame.size()) == frameLength * channels * bytesPerSample)
|
||||
{
|
||||
UASSERT(bytesPerSample == 1 || bytesPerSample == 2 || bytesPerSample == 4);
|
||||
if(bytesPerSample == 1)
|
||||
{
|
||||
data = cv::Mat(channels, frameLength, CV_8S);
|
||||
// Split channels in rows
|
||||
for(unsigned int i = 0; i<frame.size(); i+=channels*bytesPerSample)
|
||||
{
|
||||
for(unsigned int j=0; j<(unsigned int)channels; ++j)
|
||||
{
|
||||
data.at<char>(j, i/(channels*bytesPerSample)) = *((char*)&frame[i + j*bytesPerSample]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(bytesPerSample == 2)
|
||||
{
|
||||
data = cv::Mat(channels, frameLength, CV_16S);
|
||||
// Split channels in rows
|
||||
for(unsigned int i = 0; i<frame.size(); i+=channels*bytesPerSample)
|
||||
{
|
||||
for(unsigned int j=0; j<(unsigned int)channels; ++j)
|
||||
{
|
||||
data.at<short>(j, i/(channels*bytesPerSample)) = *((short*)&frame[i + j*bytesPerSample]);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(bytesPerSample == 4)
|
||||
{
|
||||
data = cv::Mat(channels, frameLength, CV_32S);
|
||||
// Split channels in rows
|
||||
for(unsigned int i = 0; i<frame.size(); i+=channels*bytesPerSample)
|
||||
{
|
||||
for(unsigned int j=0; j<(unsigned int)channels; ++j)
|
||||
{
|
||||
data.at<int>(j, i/(channels*bytesPerSample)) = *((int*)&frame[i + j*bytesPerSample]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UDEBUG("No more frames...");
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
||||
cv::Mat Micro::getFrame(cv::Mat & frameFreq, bool sqrdMagn)
|
||||
{
|
||||
cv::Mat frame = this->getFrame();
|
||||
|
||||
if(!frame.empty())
|
||||
{
|
||||
UASSERT(frame.depth() == CV_8S || frame.depth() == CV_16S || frame.depth() == CV_32S);
|
||||
cv::Mat timeSample(frame.rows, frame.cols, CV_32F);
|
||||
for(int i=0; i<frame.cols; ++i)
|
||||
{
|
||||
// for each channels
|
||||
for(int j=0; j<frame.rows; ++j)
|
||||
{
|
||||
if(frame.depth() == CV_8S)
|
||||
{
|
||||
timeSample.at<float>(j, i) = _window[i] * (float)(frame.at<char>(j, i)) / float(1<<7); // between 0 and 1
|
||||
}
|
||||
else if(frame.depth() == CV_16S)
|
||||
{
|
||||
timeSample.at<float>(j, i) = _window[i] * (float)(frame.at<short>(j, i)) / float(1<<15); // between 0 and 1
|
||||
}
|
||||
else if(frame.depth() == CV_32S)
|
||||
{
|
||||
timeSample.at<float>(j, i) = _window[i] * (float)(frame.at<int>(j, i)) / float(1<<31); // between 0 and 1
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int size = timeSample.cols/2+1;
|
||||
if(sqrdMagn)
|
||||
{
|
||||
frameFreq = cv::Mat(timeSample.rows, size, CV_32F);
|
||||
}
|
||||
else
|
||||
{
|
||||
frameFreq = cv::Mat(timeSample.rows, size * 2, CV_32F); // [re, im, re, im, ...]
|
||||
}
|
||||
|
||||
// for each channels
|
||||
for(int j=0; j<timeSample.rows; ++j)
|
||||
{
|
||||
cv::Mat row = timeSample.row(j);
|
||||
cv::Mat rowFreq = frameFreq.row(j);
|
||||
memcpy(_in.data(), row.data, row.cols*sizeof(float));
|
||||
fftwf_execute((fftwf_plan)_p); /* repeat as needed */
|
||||
|
||||
float re;
|
||||
float im;
|
||||
for(int i=0; i<size; ++i)
|
||||
{
|
||||
re = float(_out[i][0]);
|
||||
im = float(_out[i][1]);
|
||||
if(sqrdMagn)
|
||||
{
|
||||
frameFreq.at<float>(0, i) = re*re+im*im; // squared magnitude
|
||||
}
|
||||
else
|
||||
{
|
||||
frameFreq.at<float>(0, i*2) = re;
|
||||
frameFreq.at<float>(0, i*2+1) = im;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return frame;
|
||||
}
|
||||
|
||||
int Micro::fs()
|
||||
{
|
||||
int fs = 0;
|
||||
if(_recorder)
|
||||
{
|
||||
fs = _recorder->fs();
|
||||
}
|
||||
return fs;
|
||||
}
|
||||
|
||||
int Micro::bytesPerSample()
|
||||
{
|
||||
int bytes = 0;
|
||||
if(_recorder)
|
||||
{
|
||||
bytes = _recorder->bytesPerSample();
|
||||
}
|
||||
return bytes;
|
||||
}
|
||||
|
||||
int Micro::channels()
|
||||
{
|
||||
int channels = 0;
|
||||
if(_recorder)
|
||||
{
|
||||
channels = _recorder->channels();
|
||||
}
|
||||
return channels;
|
||||
}
|
||||
|
||||
int Micro::nfft()
|
||||
{
|
||||
int n = 0;
|
||||
if(_recorder)
|
||||
{
|
||||
n = _recorder->frameLength();
|
||||
}
|
||||
return n?n/2+1:0;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "NearestNeighbor.h"
|
||||
#include "rtabmap/core/NearestNeighbor.h"
|
||||
#include "utilite/ULogger.h"
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
@@ -27,70 +27,30 @@ namespace rtabmap
|
||||
/////////////////////////
|
||||
// KdTreeNN
|
||||
/////////////////////////
|
||||
KdTreeNN::KdTreeNN(const ParametersMap & parameters) :
|
||||
_tree(0)
|
||||
KdTreeNN::KdTreeNN(const ParametersMap & parameters)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
this->parseParameters(parameters);
|
||||
}
|
||||
|
||||
KdTreeNN::~KdTreeNN()
|
||||
{
|
||||
if(_tree)
|
||||
{
|
||||
cvReleaseFeatureTree(_tree);
|
||||
}
|
||||
}
|
||||
|
||||
void KdTreeNN::setData(const cv::Mat & data)
|
||||
{
|
||||
if(_tree)
|
||||
{
|
||||
cvReleaseFeatureTree(_tree);
|
||||
_tree = 0;
|
||||
}
|
||||
|
||||
// convert to old style mat (data is not copied)
|
||||
_dataMat = data;
|
||||
_tree = cvCreateKDTree(&_dataMat);
|
||||
//(data is not copied)
|
||||
_tree.build(data);
|
||||
}
|
||||
|
||||
void KdTreeNN::search(const cv::Mat & queries, cv::Mat & indices, cv::Mat & dists, int knn, int emax)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
if(_tree)
|
||||
{
|
||||
// convert to old style mat (data is not copied)
|
||||
CvMat queriesMat = queries;
|
||||
CvMat indicesMat = indices;
|
||||
CvMat distsMat = dists;
|
||||
cvFindFeatures(_tree, &queriesMat, &indicesMat, &distsMat, knn, emax);
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_ERROR("The search tree is not created, setData() must be called first");
|
||||
}
|
||||
_tree.findNearest(queries, knn, emax, indices, cv::noArray(), dists);
|
||||
}
|
||||
|
||||
void KdTreeNN::search(const cv::Mat & data, const cv::Mat & queries, cv::Mat & indices, cv::Mat & dists, int knn, int emax) const
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
CvMat dataMat = data;
|
||||
CvFeatureTree * tree = cvCreateKDTree(&dataMat);
|
||||
|
||||
if(tree)
|
||||
{
|
||||
// convert to old style mat (data is not copied)
|
||||
CvMat queriesMat = queries;
|
||||
CvMat indicesMat = indices;
|
||||
CvMat distsMat = dists;
|
||||
cvFindFeatures(tree, &queriesMat, &indicesMat, &distsMat, knn, emax);
|
||||
cvReleaseFeatureTree(tree);
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_ERROR("The search tree creation failed ?!?");
|
||||
}
|
||||
cv::KDTree tree(data);
|
||||
tree.findNearest(queries, knn, emax, indices, cv::noArray(), dists);
|
||||
}
|
||||
|
||||
void KdTreeNN::parseParameters(const ParametersMap & parameters)
|
||||
|
||||
@@ -45,9 +45,9 @@ std::string Parameters::getDefaultWorkingDirectory()
|
||||
std::string path = UDirectory::homeDir();
|
||||
if(!path.empty())
|
||||
{
|
||||
UDirectory::makeDir(path += "/Documents");
|
||||
UDirectory::makeDir(path += "/RTAB-Map");
|
||||
path += "/"; // add trailing separator
|
||||
UDirectory::makeDir(path += UDirectory::separator() + "Documents");
|
||||
UDirectory::makeDir(path += UDirectory::separator() + "RTAB-Map");
|
||||
path += UDirectory::separator(); // add trailing separator
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
+199
-167
@@ -19,22 +19,24 @@
|
||||
|
||||
#include "rtabmap/core/Rtabmap.h"
|
||||
#include "rtabmap/core/RtabmapEvent.h"
|
||||
#include "rtabmap/core/CameraEvent.h"
|
||||
#include "rtabmap/core/Version.h"
|
||||
#include "rtabmap/core/SMState.h"
|
||||
#include "rtabmap/core/Sensor.h"
|
||||
#include "rtabmap/core/Actuator.h"
|
||||
#include "rtabmap/core/SensorimotorEvent.h"
|
||||
#include "rtabmap/core/KeypointDetector.h"
|
||||
|
||||
#include "rtabmap/core/Camera.h"
|
||||
#include "VWDictionary.h"
|
||||
#include "rtabmap/core/VWDictionary.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "rtabmap/core/Micro.h"
|
||||
|
||||
#include "VerifyHypotheses.h"
|
||||
#include "rtabmap/core/VerifyHypotheses.h"
|
||||
|
||||
#include "KeypointMemory.h"
|
||||
#include "SMMemory.h"
|
||||
#include "BayesFilter.h"
|
||||
#include "rtabmap/core/KeypointMemory.h"
|
||||
#include "rtabmap/core/SMMemory.h"
|
||||
#include "rtabmap/core/BayesFilter.h"
|
||||
|
||||
#include "utilite/UtiLite.h"
|
||||
#include <utilite/UtiLite.h>
|
||||
|
||||
#include "SimpleIni.h"
|
||||
|
||||
@@ -55,14 +57,14 @@ const char * Rtabmap::kDefaultDatabaseName = "LTM.db";
|
||||
|
||||
Rtabmap::Rtabmap() :
|
||||
_publishStats(Parameters::defaultRtabmapPublishStats()),
|
||||
_publishImages(Parameters::defaultRtabmapPublishImages()),
|
||||
_publishRawData(Parameters::defaultRtabmapPublishRawData()),
|
||||
_publishPdf(Parameters::defaultRtabmapPublishPdf()),
|
||||
_publishLikelihood(Parameters::defaultRtabmapPublishLikelihood()),
|
||||
_publishKeypoints(Parameters::defaultKpPublishKeypoints()),
|
||||
_publishMasks(Parameters::defaultSMPublishMasks()),
|
||||
_maxTimeAllowed(Parameters::defaultRtabmapTimeThr()), // 700 ms
|
||||
_maxMemoryAllowed(Parameters::defaultRtabmapMemoryThr()), // 0=inf
|
||||
_smStateBufferMaxSize(Parameters::defaultRtabmapSMStateBufferSize()),
|
||||
_sensorsBufferMaxSize(Parameters::defaultRtabmapSMStateBufferSize()),
|
||||
_loopThr(Parameters::defaultRtabmapLoopThr()),
|
||||
_loopRatio(Parameters::defaultRtabmapLoopRatio()),
|
||||
_retrievalThr(Parameters::defaultRtabmapRetrievalThr()),
|
||||
@@ -72,6 +74,7 @@ Rtabmap::Rtabmap() :
|
||||
_actionsSentRejectHyp(Parameters::defaultRtabmapActionsSentRejectHyp()),
|
||||
_confidenceThr(Parameters::defaultRtabmapConfidenceThr()),
|
||||
_likelihoodStdDevRemoved(Parameters::defaultRtabmapLikelihoodStdDevRemoved()),
|
||||
_likelihoodNullValuesIgnored(Parameters::defaultRtabmapLikelihoodNullValuesIgnored()),
|
||||
_lcHypothesisId(0),
|
||||
_reactivateId(0),
|
||||
_lastLcHypothesisValue(0),
|
||||
@@ -85,8 +88,6 @@ Rtabmap::Rtabmap() :
|
||||
{
|
||||
ULOGGER_DEBUG("Working directory=%s", Parameters::defaultRtabmapWorkingDirectory().c_str());
|
||||
this->setWorkingDirectory(Parameters::defaultRtabmapWorkingDirectory());
|
||||
|
||||
UEventsManager::addHandler(this);
|
||||
}
|
||||
|
||||
Rtabmap::~Rtabmap() {
|
||||
@@ -172,15 +173,6 @@ void Rtabmap::releaseAllStrategies()
|
||||
}
|
||||
}
|
||||
|
||||
void Rtabmap::startInit()
|
||||
{
|
||||
if(!_memory || !_vhStrategy || !_bayesFilter)
|
||||
{
|
||||
ULOGGER_DEBUG("Rtabmap thread started without all strategies defined...");
|
||||
//this->killSafely();
|
||||
}
|
||||
}
|
||||
|
||||
void Rtabmap::pushNewState(State newState, const ParametersMap & parameters)
|
||||
{
|
||||
ULOGGER_DEBUG("to %d", newState);
|
||||
@@ -192,7 +184,7 @@ void Rtabmap::pushNewState(State newState, const ParametersMap & parameters)
|
||||
}
|
||||
_stateMutex.unlock();
|
||||
|
||||
_newSMStateSem.release();
|
||||
_sensorimotorAdded.release();
|
||||
}
|
||||
|
||||
void Rtabmap::init(const ParametersMap & parameters)
|
||||
@@ -242,9 +234,9 @@ void Rtabmap::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
_publishStats = uStr2Bool(iter->second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kRtabmapPublishImages())) != parameters.end())
|
||||
if((iter=parameters.find(Parameters::kRtabmapPublishRawData())) != parameters.end())
|
||||
{
|
||||
_publishImages = uStr2Bool(iter->second.c_str());
|
||||
_publishRawData = uStr2Bool(iter->second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kRtabmapPublishPdf())) != parameters.end())
|
||||
{
|
||||
@@ -284,7 +276,7 @@ void Rtabmap::parseParameters(const ParametersMap & parameters)
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kRtabmapSMStateBufferSize())) != parameters.end())
|
||||
{
|
||||
_smStateBufferMaxSize = std::atoi(iter->second.c_str());
|
||||
_sensorsBufferMaxSize = std::atoi(iter->second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kRtabmapWorkingDirectory())) != parameters.end())
|
||||
{
|
||||
@@ -314,6 +306,10 @@ void Rtabmap::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
_likelihoodStdDevRemoved = uStr2Bool(iter->second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kRtabmapLikelihoodNullValuesIgnored())) != parameters.end())
|
||||
{
|
||||
_likelihoodNullValuesIgnored = uStr2Bool(iter->second.c_str());
|
||||
}
|
||||
int signatureType = -1;
|
||||
if((iter=parameters.find(Parameters::kMemSignatureType())) != parameters.end())
|
||||
{
|
||||
@@ -328,6 +324,11 @@ void Rtabmap::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
UEventsManager::post(new RtabmapEventInit(RtabmapEventInit::kInitializing));
|
||||
UEventsManager::post(new RtabmapEventInit("Creating memory..."));
|
||||
if(_memory)
|
||||
{
|
||||
delete _memory;
|
||||
_memory = 0;
|
||||
}
|
||||
if(signatureType == 1)
|
||||
{
|
||||
_memory = new SMMemory(parameters);
|
||||
@@ -459,20 +460,31 @@ int Rtabmap::getTotalMemSize() const
|
||||
return memSize;
|
||||
}
|
||||
|
||||
void Rtabmap::killCleanup()
|
||||
void Rtabmap::clearBufferedSensors()
|
||||
{
|
||||
_smStateBufferMutex.lock();
|
||||
_sensorimotorMutex.lock();
|
||||
{
|
||||
for(std::list<SMState *>::iterator i=_smStateBuffer.begin(); i!=_smStateBuffer.end(); ++i)
|
||||
{
|
||||
delete(*i);
|
||||
}
|
||||
_smStateBuffer.clear();
|
||||
_sensorimotorBuffer.clear();
|
||||
}
|
||||
_smStateBufferMutex.unlock();
|
||||
_sensorimotorMutex.unlock();
|
||||
}
|
||||
|
||||
//this->addImage(0); // this will post the newImage semaphore
|
||||
_newSMStateSem.release();
|
||||
|
||||
void Rtabmap::mainLoopBegin()
|
||||
{
|
||||
if(!_memory || !_vhStrategy || !_bayesFilter)
|
||||
{
|
||||
ULOGGER_DEBUG("Rtabmap thread started without all strategies defined...");
|
||||
//this->killSafely();
|
||||
}
|
||||
}
|
||||
|
||||
void Rtabmap::mainLoopKill()
|
||||
{
|
||||
this->clearBufferedSensors();
|
||||
|
||||
// this will post the newData semaphore
|
||||
_sensorimotorAdded.release();
|
||||
}
|
||||
|
||||
void Rtabmap::mainLoop()
|
||||
@@ -525,6 +537,9 @@ void Rtabmap::mainLoop()
|
||||
case kStateDeletingMemory:
|
||||
this->resetMemory(true);
|
||||
break;
|
||||
case kStateCleanSensorsBuffer:
|
||||
this->clearBufferedSensors();
|
||||
break;
|
||||
default:
|
||||
UFATAL("Invalid state !?!?");
|
||||
break;
|
||||
@@ -535,12 +550,9 @@ void Rtabmap::resetMemory(bool dbOverwritten)
|
||||
{
|
||||
if(_memory)
|
||||
{
|
||||
if(_memory)
|
||||
{
|
||||
UEventsManager::post(new RtabmapEventInit(RtabmapEventInit::kInitializing));
|
||||
_memory->init(DB_TYPE, _wDir + kDefaultDatabaseName, dbOverwritten);
|
||||
UEventsManager::post(new RtabmapEventInit(RtabmapEventInit::kInitialized));
|
||||
}
|
||||
UEventsManager::post(new RtabmapEventInit(RtabmapEventInit::kInitializing));
|
||||
_memory->init(DB_TYPE, _wDir + kDefaultDatabaseName, dbOverwritten);
|
||||
UEventsManager::post(new RtabmapEventInit(RtabmapEventInit::kInitialized));
|
||||
if(_bayesFilter)
|
||||
{
|
||||
_bayesFilter->reset();
|
||||
@@ -552,6 +564,7 @@ void Rtabmap::resetMemory(bool dbOverwritten)
|
||||
// May be memory should be already created here, and use init above...
|
||||
UFile::erase(_wDir + kDefaultDatabaseName);
|
||||
}
|
||||
this->clearBufferedSensors();
|
||||
_reactivateId = 0;
|
||||
_lastLcHypothesisValue = 0;
|
||||
this->setupLogFiles(dbOverwritten);
|
||||
@@ -559,11 +572,52 @@ void Rtabmap::resetMemory(bool dbOverwritten)
|
||||
|
||||
void Rtabmap::handleEvent(UEvent* event)
|
||||
{
|
||||
if(this->isRunning() && event->getClassName().compare("SMStateEvent") == 0)
|
||||
if(this->isRunning() && event->getClassName().compare("CameraEvent") == 0)
|
||||
{
|
||||
SMStateEvent * e = (SMStateEvent*)event;
|
||||
SMState * data = e->getSMStateOwnership();
|
||||
this->addSMState(data);
|
||||
std::list<Sensor> sensors;
|
||||
CameraEvent * e = (CameraEvent*)event;
|
||||
if(e->getCode() == CameraEvent::kCodeFeatures)
|
||||
{
|
||||
sensors.push_back(Sensor(e->descriptors(), e->keypoints(), e->cameraId()));
|
||||
sensors.push_back(Sensor(e->image(), Sensor::kTypeImage, e->cameraId()));
|
||||
}
|
||||
else if(e->getCode() == CameraEvent::kCodeImage)
|
||||
{
|
||||
sensors.push_back(Sensor(e->image(), Sensor::kTypeImage, e->cameraId()));
|
||||
}
|
||||
if(sensors.size())
|
||||
{
|
||||
this->addSensorimotor(sensors, std::list<Actuator>());
|
||||
}
|
||||
}
|
||||
else if(this->isRunning() && event->getClassName().compare("MicroEvent") == 0)
|
||||
{
|
||||
std::list<Sensor> sensors;
|
||||
MicroEvent * e = (MicroEvent*)event;
|
||||
if(e->getCode() == MicroEvent::kTypeFrameFreqSqrdMagn)
|
||||
{
|
||||
sensors.push_back(Sensor(e->frame(), Sensor::kTypeAudioFreqSqrdMagn, e->microId()));
|
||||
}
|
||||
else if(e->getCode() == MicroEvent::kTypeFrameFreq)
|
||||
{
|
||||
sensors.push_back(Sensor(e->frame(), Sensor::kTypeAudioFreq, e->microId()));
|
||||
}
|
||||
else if(e->getCode() == MicroEvent::kTypeFrame)
|
||||
{
|
||||
sensors.push_back(Sensor(e->frame(), Sensor::kTypeAudio, e->microId()));
|
||||
}
|
||||
if(sensors.size())
|
||||
{
|
||||
this->addSensorimotor(sensors, std::list<Actuator>());
|
||||
}
|
||||
}
|
||||
else if(this->isRunning() && event->getClassName().compare("SensorimotorEvent") == 0)
|
||||
{
|
||||
SensorimotorEvent * e = (SensorimotorEvent*)event;
|
||||
if(e->getCode() == SensorimotorEvent::kTypeData)
|
||||
{
|
||||
this->addSensorimotor(e->sensors(), e->actuators());
|
||||
}
|
||||
}
|
||||
else if(event->getClassName().compare("RtabmapEventCmd") == 0)
|
||||
{
|
||||
@@ -607,6 +661,11 @@ void Rtabmap::handleEvent(UEvent* event)
|
||||
ULOGGER_DEBUG("CMD_DELETE_MEMORY");
|
||||
pushNewState(kStateDeletingMemory);
|
||||
}
|
||||
else if(cmd == RtabmapEventCmd::kCmdCleanSensorsBuffer)
|
||||
{
|
||||
ULOGGER_DEBUG("CMD_CLEAN_SENSORS_BUFFER");
|
||||
pushNewState(kStateCleanSensorsBuffer);
|
||||
}
|
||||
}
|
||||
else if(event->getClassName().compare("ParamEvent") == 0)
|
||||
{
|
||||
@@ -617,7 +676,7 @@ void Rtabmap::handleEvent(UEvent* event)
|
||||
|
||||
void Rtabmap::process()
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
UDEBUG("");
|
||||
|
||||
//============================================================
|
||||
// Initialization
|
||||
@@ -655,10 +714,11 @@ void Rtabmap::process()
|
||||
|
||||
const Signature * signature = 0;
|
||||
const Signature * sLoop = 0;
|
||||
SMState * smState = 0;
|
||||
std::list<Sensor> sensors;
|
||||
std::list<Actuator> actuators;
|
||||
|
||||
_lcHypothesisId = 0;
|
||||
_actions.clear();
|
||||
_actuators.clear();
|
||||
int neighborSelected = _reactivateId;
|
||||
int actionsChosen = 0; // for stats
|
||||
|
||||
@@ -668,43 +728,33 @@ void Rtabmap::process()
|
||||
// Wait for an image...
|
||||
//============================================================
|
||||
ULOGGER_INFO("getting data...");
|
||||
smState = this->getSMState();
|
||||
if(!smState)
|
||||
this->getSensorimotor(sensors, actuators);
|
||||
if(!sensors.size())
|
||||
{
|
||||
ULOGGER_INFO("data is null...");
|
||||
return;
|
||||
}
|
||||
else if(!_state.empty())
|
||||
{
|
||||
ULOGGER_INFO("State changed while waiting.. aborting processing...");
|
||||
delete smState;
|
||||
return;
|
||||
}
|
||||
else if(!_memory || !_vhStrategy || !_bayesFilter)
|
||||
{
|
||||
delete smState;
|
||||
UWARN("RTAB-Map is not initialized, data received is ignored.");
|
||||
ULOGGER_INFO("sensors list is null...");
|
||||
return;
|
||||
}
|
||||
|
||||
timer.start();
|
||||
timerTotal.start();
|
||||
|
||||
if(!_memory || !_vhStrategy || !_bayesFilter)
|
||||
{
|
||||
UFATAL("RTAB-Map is not initialized, data received is ignored.");
|
||||
}
|
||||
|
||||
//============================================================
|
||||
// Memory Update : Location creation + Rehearsal
|
||||
//============================================================
|
||||
ULOGGER_INFO("Updating memory...");
|
||||
if(!_memory->update(smState, memUpdateStats))
|
||||
if(!_memory->update(sensors, actuators, memUpdateStats))
|
||||
{
|
||||
delete smState;
|
||||
return;
|
||||
}
|
||||
signature = _memory->getLastSignature();
|
||||
if(!signature)
|
||||
{
|
||||
ULOGGER_ERROR("Not supposed to be here...");
|
||||
delete smState;
|
||||
return;
|
||||
UFATAL("Not supposed to be here...last signature is null?!?");
|
||||
}
|
||||
ULOGGER_INFO("Processing signature %d", signature->id());
|
||||
refId = signature->id();
|
||||
@@ -845,33 +895,24 @@ void Rtabmap::process()
|
||||
// only send actions if rejectLoopReason!=3 (decreasing hypotheses)
|
||||
if(sLoop && (_actionsSentRejectHyp || !rejectedHypothesis) && (_lastLcHypothesisValue > _confidenceThr))
|
||||
{
|
||||
UTimer t1;
|
||||
std::list<NeighborLink> neighbors;
|
||||
// TODO to verify
|
||||
double dbAccessTime = 0.0;
|
||||
std::map<int, int> ids = _memory->getNeighborsId(dbAccessTime, sLoop->id(), _bayesFilter->getPredictionLC().size()-1, 0);
|
||||
for(std::map<int, int>::reverse_iterator iter = ids.rbegin(); iter!=ids.rend(); ++iter)
|
||||
{
|
||||
uAppend(neighbors, _memory->getNeighborLinks(iter->first, true));
|
||||
}
|
||||
std::list<NeighborLink> neighbors = _memory->getNeighborLinks(sLoop->id(), false, false, true);
|
||||
float currentMaxSim = -1;
|
||||
UINFO("Actions: neighbors.size=%d", neighbors.size());
|
||||
for(std::list<NeighborLink>::const_reverse_iterator iter=neighbors.rbegin(); iter!=neighbors.rend() && currentMaxSim!=1.0f; ++iter)
|
||||
{
|
||||
if(iter->actions().size() && iter->actions().front().size())
|
||||
float sim = _memory->compareOneToOne(iter->baseIds(), _memory->getLastBaseIds());
|
||||
UDEBUG("Neighbor baseIds comparison with %d = %f", iter->toId(), sim);
|
||||
if(sim > currentMaxSim)
|
||||
{
|
||||
float sim = _memory->compareOneToOne(iter->baseIds(), _memory->getLastBaseIds());
|
||||
UDEBUG("Neighbor baseIds comparison with %d = %f", iter->id(), sim);
|
||||
if(sim > currentMaxSim)
|
||||
currentMaxSim = sim;
|
||||
if(iter->actuators().size())
|
||||
{
|
||||
currentMaxSim = sim;
|
||||
if(iter->actions().front().size())
|
||||
{
|
||||
_actions = iter->actions();
|
||||
}
|
||||
neighborSelected = iter->id();
|
||||
_actuators = iter->actuators();
|
||||
}
|
||||
++actionsChosen;
|
||||
neighborSelected = iter->toId();
|
||||
}
|
||||
++actionsChosen;
|
||||
}
|
||||
_reactivateId = neighborSelected;
|
||||
}
|
||||
@@ -880,7 +921,9 @@ void Rtabmap::process()
|
||||
ULOGGER_INFO("timeActionSelection=%fs",timeActionSelection);
|
||||
}// !isBadSignature
|
||||
|
||||
//============================================================
|
||||
// Before retrieval, make sure the trash has finished
|
||||
//============================================================
|
||||
_memory->joinTrashThread();
|
||||
timeEmptyingTrash = _memory->getDbSavingTime();
|
||||
timeJoiningTrash = timer.ticks();
|
||||
@@ -903,9 +946,9 @@ void Rtabmap::process()
|
||||
double timeGetNeighborsSpaceDb = 0.0;
|
||||
|
||||
// Direct neighbors TIME
|
||||
std::map<int, int> neighbors = _memory->getNeighborsId(timeGetNeighborsTimeDb, _reactivateId, margin, -1, _bayesFilter->isPredictionOnNonNullActionsOnly(), true, true, true);
|
||||
std::map<int, int> neighbors = _memory->getNeighborsId(timeGetNeighborsTimeDb, _reactivateId, margin, _maxRetrieved, _bayesFilter->isPredictionOnNonNullActionsOnly(), true, true, true);
|
||||
unsigned int m = 0;
|
||||
//Priority to locations near in space (margin) then by time (index)
|
||||
//Priority to locations near in time (direct neighbor) then by space (loop closure)
|
||||
while(m < margin)
|
||||
{
|
||||
std::set<int> idsSorted;
|
||||
@@ -984,18 +1027,14 @@ void Rtabmap::process()
|
||||
// Data used for the statistics event and for the log files
|
||||
int processMemoryUsed = UProcessInfo::getMemoryUsage()/(1024*1024); // MB
|
||||
int databaseMemoryUsed = _memory->getDatabaseMemoryUsed(); // MB
|
||||
float responseThr = 0;
|
||||
int dictionarySize = 0;
|
||||
int refWordsCount = 0;
|
||||
int refUniqueWordsCount = 0;
|
||||
const KeypointSignature * ssRef = 0;
|
||||
const KeypointSignature * ssLoop = 0;
|
||||
const SMSignature * smRef = 0;
|
||||
const SMSignature * smLoop = 0;
|
||||
int lcHypothesisReactivated = 0;
|
||||
float rehearsalValue = uValue(memUpdateStats, std::string("Memory/Rehearsal Max Value/"), 0.0f);
|
||||
KeypointMemory * kpMem = dynamic_cast<KeypointMemory *>(_memory);
|
||||
SMMemory * smMem = dynamic_cast<SMMemory *>(_memory);
|
||||
if(sLoop)
|
||||
{
|
||||
lcHypothesisReactivated = sLoop->isSaved()?1.0f:0.0f;
|
||||
@@ -1007,7 +1046,6 @@ void Rtabmap::process()
|
||||
ssLoop = dynamic_cast<const KeypointSignature *>(sLoop);
|
||||
}
|
||||
ssRef = dynamic_cast<const KeypointSignature *>(signature);
|
||||
responseThr = (float)kpMem->getKeypointDetector()->getAdaptiveResponseThr();
|
||||
dictionarySize = kpMem->getVWD()->getVisualWords().size();
|
||||
if(ssRef)
|
||||
{
|
||||
@@ -1019,14 +1057,6 @@ void Rtabmap::process()
|
||||
ULOGGER_WARN("The new signature can't be casted to a KeypointSignature while the Memory is this type ?");
|
||||
}
|
||||
}
|
||||
if(smMem)
|
||||
{
|
||||
if(sLoop)
|
||||
{
|
||||
smLoop = dynamic_cast<const SMSignature *>(sLoop);
|
||||
}
|
||||
smRef = dynamic_cast<const SMSignature *>(signature);
|
||||
}
|
||||
|
||||
float vpLikelihood = 0.0f;
|
||||
if(adjustedLikelihood.size() && adjustedLikelihood.begin()->first == -1)
|
||||
@@ -1041,7 +1071,7 @@ void Rtabmap::process()
|
||||
|
||||
// only prepare statistics if required or when there is a loop closure
|
||||
Statistics * stat = 0;
|
||||
if(_lcHypothesisId || _actions.size() || _publishStats)
|
||||
if(_lcHypothesisId || _actuators.size() || _publishStats)
|
||||
{
|
||||
ULOGGER_INFO("sending stats...");
|
||||
stat = new Statistics();
|
||||
@@ -1051,9 +1081,9 @@ void Rtabmap::process()
|
||||
stat->setLoopClosureId(_lcHypothesisId);
|
||||
ULOGGER_INFO("Loop closure detected! With id=%d", _lcHypothesisId);
|
||||
}
|
||||
if(_actions.size())
|
||||
if(_actuators.size())
|
||||
{
|
||||
stat->setActions(_actions);
|
||||
stat->setActuators(_actuators);
|
||||
}
|
||||
if(_publishStats && refId != Memory::kIdInvalid)
|
||||
{
|
||||
@@ -1069,7 +1099,7 @@ void Rtabmap::process()
|
||||
stat->addStatistic(Statistics::kLoopVp_hypothesis(), vpHypothesis);
|
||||
stat->addStatistic(Statistics::kLoopReactivateId(), _reactivateId);
|
||||
stat->addStatistic(Statistics::kLoopHypothesis_ratio(), hypothesisRatio);
|
||||
stat->addStatistic(Statistics::kLoopActions(), (int)_actions.size());
|
||||
stat->addStatistic(Statistics::kLoopActions(), (int)_actuators.size());
|
||||
stat->addStatistic(Statistics::kLoopActions_of(), neighborSelected);
|
||||
stat->addStatistic(Statistics::kLoopActions_chosen(), actionsChosen);
|
||||
|
||||
@@ -1078,7 +1108,8 @@ void Rtabmap::process()
|
||||
stat->addStatistic(Statistics::kMemoryDatabase_size(), (float)databaseMemoryUsed);
|
||||
stat->addStatistic(Statistics::kMemoryProcess_memory_used(), (float)processMemoryUsed);
|
||||
stat->addStatistic(Statistics::kMemorySignatures_retrieved(), (float)signaturesRetrieved.size());
|
||||
stat->addStatistic(Statistics::kMemoryImages_buffered(), (float)_smStateBuffer.size());
|
||||
stat->addStatistic(Statistics::kMemoryImages_buffered(), (float)_sensorimotorBuffer.size());
|
||||
stat->addStatistic(Statistics::kMemorySimilarities_map(), (float)_memory->getSimilaritiesMap().size());
|
||||
|
||||
// timing...
|
||||
stat->addStatistic(Statistics::kTimingMemory_update(), timeMemoryUpdate*1000);
|
||||
@@ -1098,31 +1129,30 @@ void Rtabmap::process()
|
||||
|
||||
// Surf specific parameters
|
||||
stat->addStatistic(Statistics::kKeypointDictionary_size(), dictionarySize);
|
||||
stat->addStatistic(Statistics::kKeypointResponse_threshold(), responseThr);
|
||||
|
||||
//Epipolar geometry constraint
|
||||
stat->addStatistic(Statistics::kLoopRejectedHypothesis(), rejectedHypothesis?1.0f:0);
|
||||
|
||||
if(_publishImages)
|
||||
if(_publishRawData)
|
||||
{
|
||||
stat->setRefImage(smState->getImage());
|
||||
stat->setRefRawData(sensors); // raw data
|
||||
if(sLoop)
|
||||
{
|
||||
lcHypothesisReactivated = 0;
|
||||
if(sLoop && sLoop->isSaved())
|
||||
if(sLoop->isSaved())
|
||||
{
|
||||
lcHypothesisReactivated = 1;
|
||||
}
|
||||
|
||||
const IplImage * img = sLoop->getImage();
|
||||
if(!img && _memory->isRawDataKept())
|
||||
const std::list<Sensor> & data = sLoop->getRawData();
|
||||
if(data.empty() && _memory->isRawDataKept())
|
||||
{
|
||||
IplImage * image = _memory->getImage(sLoop->id());
|
||||
stat->setLoopClosureImage(&image); // The image will be released by the Statistics destructor
|
||||
std::list<Sensor> d = _memory->getRawData(sLoop->id());
|
||||
stat->setLoopClosureRawData(d);
|
||||
}
|
||||
else if(img)
|
||||
else if(!data.empty())
|
||||
{
|
||||
stat->setLoopClosureImage(img); // The image will be copied
|
||||
stat->setLoopClosureRawData(data);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1155,14 +1185,7 @@ void Rtabmap::process()
|
||||
if(_publishMasks)
|
||||
{
|
||||
// Copy mask
|
||||
if(smRef)
|
||||
{
|
||||
stat->setRefMotionMask(smRef->getMotionMask());
|
||||
}
|
||||
if(smLoop)
|
||||
{
|
||||
stat->setLoopMotionMask(smLoop->getMotionMask());
|
||||
}
|
||||
UWARN("Publish motion masks TODO");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1283,7 +1306,7 @@ void Rtabmap::process()
|
||||
_lcHypothesisId,
|
||||
hypothesis.first,
|
||||
signaturesRemoved,
|
||||
int(responseThr),
|
||||
0,
|
||||
refWordsCount,
|
||||
dictionarySize,
|
||||
int(_memory->getWorkingMemSize()),
|
||||
@@ -1296,62 +1319,59 @@ void Rtabmap::process()
|
||||
_reactivateId,
|
||||
int(nonNulls.size()));
|
||||
}
|
||||
ULOGGER_INFO("Time logging = %f...", timer.ticks());
|
||||
UINFO("Time logging = %f...", timer.ticks());
|
||||
//ULogger::flush();
|
||||
delete smState;
|
||||
|
||||
}
|
||||
|
||||
// ownership is transferred
|
||||
void Rtabmap::addSMState(SMState * data)
|
||||
void Rtabmap::addSensorimotor(const std::list<Sensor> & sensors, const std::list<Actuator> & actuators)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
if(!data)
|
||||
UDEBUG("sensors %d, actuators %d", sensors.size(), actuators.size());
|
||||
if(!sensors.size() && !actuators.size())
|
||||
{
|
||||
ULOGGER_ERROR("Data is null?!");
|
||||
ULOGGER_ERROR("Sensors and actuators empty !?");
|
||||
return;
|
||||
}
|
||||
|
||||
bool notify = true;
|
||||
|
||||
_smStateBufferMutex.lock();
|
||||
_sensorimotorMutex.lock();
|
||||
{
|
||||
while(_smStateBufferMaxSize > 0 && _smStateBuffer.size() >= (unsigned int)_smStateBufferMaxSize)
|
||||
_sensorimotorBuffer.push_back(std::make_pair(sensors, actuators));
|
||||
while(_sensorsBufferMaxSize > 0 && _sensorimotorBuffer.size() >= (unsigned int)_sensorsBufferMaxSize)
|
||||
{
|
||||
ULOGGER_WARN("Data buffer is full, the oldest data is removed to add the new one.");
|
||||
delete _smStateBuffer.front();
|
||||
_smStateBuffer.pop_front();
|
||||
_sensorimotorBuffer.pop_front();
|
||||
notify = false;
|
||||
}
|
||||
_smStateBuffer.push_back(data);
|
||||
}
|
||||
_smStateBufferMutex.unlock();
|
||||
_sensorimotorMutex.unlock();
|
||||
|
||||
if(notify)
|
||||
{
|
||||
_newSMStateSem.release();
|
||||
_sensorimotorAdded.release();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SMState * Rtabmap::getSMState()
|
||||
void Rtabmap::getSensorimotor(std::list<Sensor> & sensors, std::list<Actuator> & actuators)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
SMState * data = 0;
|
||||
sensors.clear();
|
||||
actuators.clear();
|
||||
|
||||
ULOGGER_INFO("waiting for data");
|
||||
_newSMStateSem.acquire();
|
||||
_sensorimotorAdded.acquire();
|
||||
ULOGGER_INFO("wake-up");
|
||||
|
||||
_smStateBufferMutex.lock();
|
||||
_sensorimotorMutex.lock();
|
||||
{
|
||||
if(!_smStateBuffer.empty())
|
||||
if(!_sensorimotorBuffer.empty())
|
||||
{
|
||||
data = _smStateBuffer.front();
|
||||
_smStateBuffer.pop_front();
|
||||
sensors = _sensorimotorBuffer.front().first;
|
||||
actuators = _sensorimotorBuffer.front().second;
|
||||
_sensorimotorBuffer.pop_front();
|
||||
}
|
||||
}
|
||||
_smStateBufferMutex.unlock();
|
||||
return data;
|
||||
_sensorimotorMutex.unlock();
|
||||
}
|
||||
|
||||
// SETTERS
|
||||
@@ -1375,11 +1395,11 @@ void Rtabmap::setDataBufferSize(int size)
|
||||
if(size < 0)
|
||||
{
|
||||
ULOGGER_WARN("size < 0, then setting it to 0 (inf).");
|
||||
_smStateBufferMaxSize = 0;
|
||||
_sensorsBufferMaxSize = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
_smStateBufferMaxSize = size;
|
||||
_sensorsBufferMaxSize = size;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1387,7 +1407,7 @@ void Rtabmap::setWorkingDirectory(std::string path)
|
||||
{
|
||||
if(path.size() && (path.at(path.size()-1) != '\\' || path.at(path.size()-1) != '/' ))
|
||||
{
|
||||
path += "/";
|
||||
path += UDirectory::separator();
|
||||
}
|
||||
|
||||
if(!path.empty() && UDirectory::exists(path))
|
||||
@@ -1398,14 +1418,12 @@ void Rtabmap::setWorkingDirectory(std::string path)
|
||||
_wDir = path;
|
||||
if(_memory)
|
||||
{
|
||||
//clear all buffered images
|
||||
join(true);
|
||||
UEventsManager::post(new RtabmapEventInit(RtabmapEventInit::kInitializing));
|
||||
_memory->init(DB_TYPE, _wDir + kDefaultDatabaseName);
|
||||
UEventsManager::post(new RtabmapEventInit(RtabmapEventInit::kInitialized));
|
||||
join(true); // this will clean a second time the image buffer (if some images were added during the memory initialization)
|
||||
setupLogFiles();
|
||||
this->start();
|
||||
//clear all buffered images
|
||||
this->clearBufferedSensors();
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1419,12 +1437,26 @@ void Rtabmap::setWorkingDirectory(std::string path)
|
||||
}
|
||||
}
|
||||
|
||||
// ownership is transferred
|
||||
void Rtabmap::process(SMState * data)
|
||||
void Rtabmap::process(const std::list<Sensor> & data)
|
||||
{
|
||||
if(!this->isRunning())
|
||||
{
|
||||
this->addSMState(data);
|
||||
this->addSensorimotor(data, std::list<Actuator>());
|
||||
this->process();
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("The core thread is running!");
|
||||
}
|
||||
}
|
||||
|
||||
void Rtabmap::process(const Sensor & data)
|
||||
{
|
||||
if(!this->isRunning())
|
||||
{
|
||||
std::list<Sensor> sensors;
|
||||
sensors.push_back(data);
|
||||
this->addSensorimotor(sensors, std::list<Actuator>());
|
||||
this->process();
|
||||
}
|
||||
else
|
||||
@@ -1490,7 +1522,7 @@ void Rtabmap::adjustLikelihood(std::map<int, float> & likelihood) const
|
||||
std::list<float> values;
|
||||
for(unsigned int i=0; i<allValues.size(); ++i)
|
||||
{
|
||||
if(allValues[i])
|
||||
if(!_likelihoodNullValuesIgnored || allValues[i])
|
||||
{
|
||||
values.push_back(allValues[i]);
|
||||
}
|
||||
@@ -1517,7 +1549,7 @@ void Rtabmap::adjustLikelihood(std::map<int, float> & likelihood) const
|
||||
for(std::map<int, float>::iterator iter=likelihood.begin(); iter!= likelihood.end(); ++iter)
|
||||
{
|
||||
float value = iter->second - min;
|
||||
if(value > mean+stdDev && mean)
|
||||
if(value > mean+(!_likelihoodStdDevRemoved?0:stdDev) && mean)
|
||||
{
|
||||
if(_likelihoodStdDevRemoved)
|
||||
{
|
||||
@@ -1656,7 +1688,7 @@ void Rtabmap::dumpPrediction() const
|
||||
if(_memory && _bayesFilter)
|
||||
{
|
||||
const std::set<int> & wm = _memory->getWorkingMem();
|
||||
CvMat * prediction = cvCreateMat(wm.size(), wm.size(), CV_32FC1);
|
||||
cv::Mat prediction(wm.size(), wm.size(), CV_32FC1);
|
||||
_bayesFilter->generatePrediction(prediction, _memory, std::vector<int>(wm.begin(), wm.end()));
|
||||
|
||||
FILE* fout = 0;
|
||||
@@ -1669,11 +1701,11 @@ void Rtabmap::dumpPrediction() const
|
||||
|
||||
if(fout)
|
||||
{
|
||||
for(int i=0; i<prediction->rows; ++i)
|
||||
for(int i=0; i<prediction.rows; ++i)
|
||||
{
|
||||
for(int j=0; j<prediction->cols; ++j)
|
||||
for(int j=0; j<prediction.cols; ++j)
|
||||
{
|
||||
fprintf(fout, "%f ", prediction->data.fl[j + i*prediction->cols]);
|
||||
fprintf(fout, "%f ",((float*)prediction.data)[j + i*prediction.cols]);
|
||||
}
|
||||
fprintf(fout, "\n");
|
||||
}
|
||||
|
||||
@@ -32,31 +32,13 @@ const std::map<std::string, float> & Statistics::defaultData()
|
||||
Statistics::Statistics() :
|
||||
_extended(0),
|
||||
_refImageId(0),
|
||||
_loopClosureId(0),
|
||||
_refImage(0),
|
||||
_loopClosureImage(0)
|
||||
_loopClosureId(0)
|
||||
{
|
||||
_defaultDataInitialized = true;
|
||||
}
|
||||
Statistics::Statistics(const Statistics & s) :
|
||||
_extended(0),
|
||||
_refImageId(0),
|
||||
_loopClosureId(0),
|
||||
_refImage(0),
|
||||
_loopClosureImage(0)
|
||||
{
|
||||
*this = s;
|
||||
}
|
||||
|
||||
Statistics::~Statistics()
|
||||
{
|
||||
if(_refImage)
|
||||
{
|
||||
cvReleaseImage(&_refImage);
|
||||
}
|
||||
if(_loopClosureImage)
|
||||
{
|
||||
cvReleaseImage(&_loopClosureImage);
|
||||
}
|
||||
}
|
||||
|
||||
// name format = "Grp/Name/unit"
|
||||
@@ -65,87 +47,14 @@ void Statistics::addStatistic(const std::string & name, float value)
|
||||
_data.insert(std::pair<std::string, float>(name, value));
|
||||
}
|
||||
|
||||
//take the ownership of the image, the image will be
|
||||
//deleted in the 'Statistics' destructor
|
||||
void Statistics::setRefImage(IplImage ** refImage)
|
||||
void Statistics::setRefRawData(const std::list<Sensor> & refRawData)
|
||||
{
|
||||
if(_refImage)
|
||||
cvReleaseImage(&_refImage);
|
||||
_refImage = *refImage;
|
||||
_refRawData = refRawData;
|
||||
}
|
||||
|
||||
// Copy the image
|
||||
void Statistics::setRefImage(const IplImage * refImage)
|
||||
void Statistics::setLoopClosureRawData(const std::list<Sensor> & loopClosureRawData)
|
||||
{
|
||||
if(_refImage)
|
||||
cvReleaseImage(&_refImage);
|
||||
if(refImage)
|
||||
{
|
||||
_refImage = cvCloneImage(refImage);
|
||||
}
|
||||
else
|
||||
{
|
||||
_refImage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//take the ownership of the image, the image will be
|
||||
//deleted in the 'Statistics' destructor
|
||||
void Statistics::setLoopClosureImage(IplImage ** loopClosureImage)
|
||||
{
|
||||
if(_loopClosureImage)
|
||||
cvReleaseImage(&_loopClosureImage);
|
||||
_loopClosureImage = *loopClosureImage;
|
||||
}
|
||||
|
||||
// Copy the image
|
||||
void Statistics::setLoopClosureImage(const IplImage * loopClosureImage)
|
||||
{
|
||||
if(_loopClosureImage)
|
||||
cvReleaseImage(&_loopClosureImage);
|
||||
if(loopClosureImage)
|
||||
{
|
||||
_loopClosureImage = cvCloneImage(loopClosureImage);
|
||||
}
|
||||
else
|
||||
{
|
||||
_loopClosureImage = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Statistics & Statistics::operator=(const Statistics & s)
|
||||
{
|
||||
_data = s.data();
|
||||
if(_refImage)
|
||||
{
|
||||
cvReleaseImage(&_refImage);
|
||||
_refImage = 0;
|
||||
}
|
||||
if(_loopClosureImage)
|
||||
{
|
||||
cvReleaseImage(&_loopClosureImage);
|
||||
_loopClosureImage = 0;
|
||||
}
|
||||
_extended = s.extended();
|
||||
_refImageId = s.refImageId();
|
||||
_loopClosureId = s.loopClosureId();
|
||||
if(s.refImage())
|
||||
{
|
||||
_refImage = cvCloneImage(s.refImage());
|
||||
}
|
||||
if(s.loopClosureImage())
|
||||
{
|
||||
_loopClosureImage = cvCloneImage(s.loopClosureImage());
|
||||
}
|
||||
_posterior = s.posterior();
|
||||
_likelihood = s.likelihood();
|
||||
_weights = s.weights();
|
||||
_refWords = s.refWords();
|
||||
_loopWords = s.loopWords();
|
||||
_refMotionMask = s.refMotionMask();
|
||||
_loopMotionMask = s.loopMotionMask();
|
||||
_actions = s.getActions();
|
||||
return *this;
|
||||
_loopClosureRawData = loopClosureRawData;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+145
-385
@@ -17,12 +17,11 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "SMMemory.h"
|
||||
#include "rtabmap/core/SMMemory.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
#include "utilite/UtiLite.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "rtabmap/core/SMState.h"
|
||||
#include "rtabmap/core/RtabmapEvent.h"
|
||||
#include "utilite/UStl.h"
|
||||
#include "utilite/UConversion.h"
|
||||
@@ -32,7 +31,7 @@
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include "ColorTable.h"
|
||||
#include "rtabmap/core/ColorTable.h"
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
@@ -40,15 +39,25 @@ namespace rtabmap {
|
||||
SMMemory::SMMemory(const ParametersMap & parameters) :
|
||||
Memory(parameters),
|
||||
_useLogPolar(Parameters::defaultSMLogPolarUsed()),
|
||||
_useVotingScheme(Parameters::defaultSMVotingSchemeUsed()),
|
||||
_colorTable(0),
|
||||
_useMotionMask(Parameters::defaultSMMotionMaskUsed())
|
||||
_useMotionMask(Parameters::defaultSMMotionMaskUsed()),
|
||||
_dBThreshold(Parameters::defaultSMAudioDBThreshold()),
|
||||
_dBIndexing(Parameters::defaultSMAudioDBIndexing()),
|
||||
_magnitudeInvariant(Parameters::defaultSMMagnitudeInvariant())
|
||||
{
|
||||
this->parseParameters(parameters);
|
||||
if(!_colorTable)
|
||||
{
|
||||
int i=1;
|
||||
this->setColorTable(i<<(Parameters::defaultSMColorTable() + 3));
|
||||
// index 0 = 8, index 1 = 16...
|
||||
if(Parameters::defaultSMColorTable() == 8)
|
||||
{
|
||||
setColorTable(65536);
|
||||
}
|
||||
else
|
||||
{
|
||||
int i=1;
|
||||
setColorTable(i<<(Parameters::defaultSMColorTable() + 3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,14 +78,22 @@ void SMMemory::parseParameters(const ParametersMap & parameters)
|
||||
{
|
||||
_useLogPolar = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSMVotingSchemeUsed())) != parameters.end())
|
||||
{
|
||||
this->setVotingScheme(uStr2Bool((*iter).second.c_str()));
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSMMotionMaskUsed())) != parameters.end())
|
||||
{
|
||||
_useMotionMask = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSMAudioDBThreshold())) != parameters.end())
|
||||
{
|
||||
_dBThreshold = atof((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSMAudioDBIndexing())) != parameters.end())
|
||||
{
|
||||
_dBIndexing = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSMMagnitudeInvariant())) != parameters.end())
|
||||
{
|
||||
_magnitudeInvariant = uStr2Bool((*iter).second.c_str());
|
||||
}
|
||||
if((iter=parameters.find(Parameters::kSMColorTable())) != parameters.end())
|
||||
{
|
||||
// index 0 = 8, index 1 = 16...
|
||||
@@ -94,20 +111,6 @@ void SMMemory::parseParameters(const ParametersMap & parameters)
|
||||
Memory::parseParameters(parameters);
|
||||
}
|
||||
|
||||
void SMMemory::setVotingScheme(bool useVotingScheme)
|
||||
{
|
||||
_useVotingScheme = useVotingScheme;
|
||||
_dictionary.clear();
|
||||
if(_useVotingScheme)
|
||||
{
|
||||
const std::map<int, Signature *> & signatures = this->getSignatures();
|
||||
for(std::map<int, Signature *>::const_iterator i=signatures.begin(); i!=signatures.end(); ++i)
|
||||
{
|
||||
this->updateDictionary(i->second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SMMemory::setColorTable(int size)
|
||||
{
|
||||
if(_colorTable)
|
||||
@@ -133,8 +136,7 @@ void SMMemory::copyData(const Signature * from, Signature * to)
|
||||
timer.start();
|
||||
if(sFrom && sTo)
|
||||
{
|
||||
sTo->setSensors(sFrom->getSensors());
|
||||
sTo->setMotionMask(sFrom->getMotionMask());
|
||||
sTo->setSensors(sFrom->getData());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -143,63 +145,46 @@ void SMMemory::copyData(const Signature * from, Signature * to)
|
||||
ULOGGER_DEBUG("Merging time = %fs", timer.ticks());
|
||||
}
|
||||
|
||||
Signature * SMMemory::createSignature(int id, const SMState * smState, bool keepRawData)
|
||||
Signature * SMMemory::createSignature(int id, const std::list<Sensor> & rawSensors, bool keepRawData)
|
||||
{
|
||||
if(_useMotionMask)
|
||||
{
|
||||
UWARN("Using motion mask TODO");
|
||||
}
|
||||
UDEBUG("");
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
UTimer timerDetails;
|
||||
timerDetails.start();
|
||||
std::vector<int> sensors;
|
||||
const std::vector<int> * sensorsPrevious = 0;
|
||||
std::vector<unsigned char> motionMask;
|
||||
const IplImage * image = 0;
|
||||
IplImage * polar = 0;
|
||||
IplImage * indexed = 0;
|
||||
const SMSignature * previousSignature = dynamic_cast<const SMSignature *>(this->getLastSignature());
|
||||
if(previousSignature)
|
||||
{
|
||||
UDEBUG("");
|
||||
sensorsPrevious = &previousSignature->getSensors();
|
||||
}
|
||||
if(smState)
|
||||
{
|
||||
image = smState->getImage();
|
||||
std::list<std::vector<int> > postData;
|
||||
//const SMSignature * previousSignature = dynamic_cast<const SMSignature *>(this->getLastSignature());
|
||||
|
||||
// sensors
|
||||
if(!smState->getSensors().empty() == 0 && image && image->imageSize)
|
||||
// Process all sensors
|
||||
for(std::list<Sensor>::const_iterator iter = rawSensors.begin(); iter!=rawSensors.end(); ++iter)
|
||||
{
|
||||
if(iter->type() == Sensor::kTypeImage)
|
||||
{
|
||||
if(image->depth != IPL_DEPTH_8U && image->nChannels != 3)
|
||||
{
|
||||
UFATAL("Only IplImage depth of IPL_DEPTH_8U and 3 channels (BGR) is supported.");
|
||||
}
|
||||
UASSERT(iter->data().type() == CV_8UC3 && iter->data().channels() == 3);
|
||||
|
||||
UDEBUG("depth=%d, alpha=%d, widthStep=%d, width=%d, height=%d, nChannels=%d, imageSize=%d,", image->depth, image->alphaChannel, image->widthStep, image->width, image->height, image->nChannels, image->imageSize);
|
||||
const cv::Mat & image = iter->data();
|
||||
UDEBUG("depth=%d, width=%d, height=%d, nChannels=%d, imageSize=%d,", image.type(), image.cols, image.rows, image.channels(), image.total());
|
||||
|
||||
if(_useLogPolar)
|
||||
{
|
||||
// Log-polar transform
|
||||
int radius = image->height < image->width ? image->height/2: image->width/2;
|
||||
int radius = image.rows < image.cols ? image.rows/2: image.cols/2;
|
||||
CvSize polarSize = cvSize(64, 128);
|
||||
float M = polarSize.width/std::log(radius);
|
||||
polar = cvCreateImage( polarSize, 8, 3 );
|
||||
cvLogPolar( image, polar, cvPoint2D32f(image->width/2,image->height/2), double(M), CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS );
|
||||
IplImage * polar = cvCreateImage( polarSize, 8, 3 );
|
||||
IplImage iplImg = image;
|
||||
cvLogPolar(&iplImg, polar, cvPoint2D32f(image.cols/2,image.rows/2), double(M), CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS );
|
||||
|
||||
UDEBUG("polar size= %d, %d, time=%fs", polar->width, polar->height, timerDetails.ticks());
|
||||
|
||||
// IND transform
|
||||
unsigned char * data = (unsigned char *)polar->imageData;
|
||||
sensors = std::vector<int>(polar->width*polar->height);
|
||||
if(_useVotingScheme && (_dictionary.empty() || _dictionary.size() != sensors.size()))
|
||||
{
|
||||
_dictionary = std::vector<std::map<int, std::set<int> > >(sensors.size());
|
||||
}
|
||||
if(_useMotionMask)
|
||||
{
|
||||
motionMask = std::vector<unsigned char>(sensors.size(), 0);
|
||||
}
|
||||
bool updateMask = sensorsPrevious && sensorsPrevious->size() == motionMask.size();
|
||||
int k=0;
|
||||
std::vector<int> sensors(polar->width*polar->height);
|
||||
for(int i=0; i<polar->height; ++i)
|
||||
{
|
||||
for(int j=0; j<polar->width; ++j)
|
||||
@@ -209,360 +194,135 @@ Signature * SMMemory::createSignature(int id, const SMState * smState, bool keep
|
||||
unsigned char & r = data[i*polar->widthStep+j*3+2];
|
||||
int index = (int)_colorTable->getIndex(r, g, b);
|
||||
sensors[k] = index;
|
||||
_colorTable->getRgb(index, r, g , b);
|
||||
|
||||
if(_useMotionMask && updateMask && sensorsPrevious->at(k) != sensors[k])
|
||||
{
|
||||
motionMask[k] = 1;
|
||||
}
|
||||
|
||||
if(!_dictionary.empty())
|
||||
{
|
||||
std::set<int> sensorId;
|
||||
sensorId.insert(id);
|
||||
std::pair<std::map<int, std::set<int> >::iterator, bool> ret;
|
||||
ret = _dictionary[k].insert(std::make_pair(sensors[k], sensorId));
|
||||
if(ret.second == false)
|
||||
{
|
||||
ret.first->second.insert(id);
|
||||
}
|
||||
}
|
||||
|
||||
++k;
|
||||
}
|
||||
}
|
||||
postData.push_back(sensors);
|
||||
cvReleaseImage(&polar);
|
||||
|
||||
UDEBUG("indexing time = %fs", timerDetails.ticks());
|
||||
|
||||
//cv::Mat indPolar;
|
||||
//fromIndPolar = cvCreateImage(cvGetSize(image), 8, 3);
|
||||
//cvLogPolar(polar, fromIndPolar, cvPoint2D32f(image->width/2,image->height/2), double(M), CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS+CV_WARP_INVERSE_MAP );
|
||||
//UDEBUG("back from polar time = %fs", timerDetails());
|
||||
|
||||
//image = polar;
|
||||
}
|
||||
else
|
||||
{
|
||||
// IND transform
|
||||
indexed = cvCloneImage(image);
|
||||
unsigned char * data = (unsigned char *)indexed->imageData;
|
||||
sensors = std::vector<int>(indexed->width*indexed->height);
|
||||
if(_useVotingScheme && (_dictionary.empty() || _dictionary.size() != sensors.size()))
|
||||
{
|
||||
_dictionary = std::vector<std::map<int, std::set<int> > >(sensors.size());
|
||||
}
|
||||
if(_useMotionMask)
|
||||
{
|
||||
motionMask = std::vector<unsigned char>(sensors.size(), 0);
|
||||
}
|
||||
bool updateMask = sensorsPrevious && sensorsPrevious->size() == motionMask.size();
|
||||
int k=0;
|
||||
std::vector<int> sensors(image.cols*image.rows);
|
||||
int sum=0;
|
||||
for(int i=0; i<indexed->height; ++i)
|
||||
for(int i=0; i<image.rows; ++i)
|
||||
{
|
||||
for(int j=0; j<indexed->width; ++j)
|
||||
cv::Mat row = image.row(i); // DON'T modify row! (it refers to const data)
|
||||
for(int j=0; j<row.cols; j+=3)
|
||||
{
|
||||
unsigned char & b = data[i*indexed->widthStep+j*3+0];
|
||||
unsigned char & g = data[i*indexed->widthStep+j*3+1];
|
||||
unsigned char & r = data[i*indexed->widthStep+j*3+2];
|
||||
int index = (int)_colorTable->getIndex(r, g, b);
|
||||
sensors[k] = index;
|
||||
_colorTable->getRgb(index, r, g , b);
|
||||
|
||||
if(_useMotionMask && updateMask && sensorsPrevious->at(k) != sensors[k])
|
||||
unsigned char b = row.at<unsigned char>(j+0);
|
||||
unsigned char g = row.at<unsigned char>(j+1);
|
||||
unsigned char r = row.at<unsigned char>(j+2);
|
||||
if(b && g && r)
|
||||
{
|
||||
motionMask[k] = 1;
|
||||
++sum;
|
||||
sensors[k] = (int)_colorTable->getIndex(r, g, b); // index
|
||||
}
|
||||
|
||||
if(!_dictionary.empty())
|
||||
else
|
||||
{
|
||||
std::set<int> sensorId;
|
||||
sensorId.insert(id);
|
||||
std::pair<std::map<int, std::set<int> >::iterator, bool> ret;
|
||||
ret = _dictionary[k].insert(std::make_pair(sensors[k], sensorId));
|
||||
if(ret.second == false)
|
||||
{
|
||||
ret.first->second.insert(id);
|
||||
}
|
||||
sensors[k] = 0; // null, will be ignored on likelihood computation
|
||||
}
|
||||
|
||||
++k;
|
||||
}
|
||||
}
|
||||
image = indexed;
|
||||
postData.push_back(sensors);
|
||||
|
||||
UDEBUG("sum=%d, indexing time = %fs", sum, timerDetails.ticks());
|
||||
}
|
||||
}
|
||||
} // end kTypeImage
|
||||
else if(iter->type() == Sensor::kTypeAudioFreqSqrdMagn)
|
||||
{
|
||||
UASSERT(iter->data().type() == CV_32FC1);
|
||||
|
||||
const cv::Mat & data = iter->data();
|
||||
int k = 0;
|
||||
std::vector<int> sensors(data.cols, 0);
|
||||
unsigned int index;
|
||||
float max = uMax((float*)data.data, data.cols, index);
|
||||
int maxLimit = -1; // FIXME Must be not hard coded
|
||||
float minDB = -1000;// FIXME Must be not hard coded
|
||||
|
||||
UDEBUG("data.rows=%d, data.cols=%d, data.type=%d, max=%f at %d", data.rows, data.cols, data.type(), max, index);
|
||||
|
||||
if(_dBThreshold > 0)
|
||||
{
|
||||
maxLimit = max / std::pow(10.0f, _dBThreshold/10);
|
||||
}
|
||||
for(int i=0; i<data.cols; ++i)
|
||||
{
|
||||
float val = data.at<float>(0, i);
|
||||
if(_dBIndexing && max)
|
||||
{
|
||||
if(val>=0.001f)
|
||||
{
|
||||
val = 10*std::log(val/max);// transform to dB
|
||||
}
|
||||
else
|
||||
{
|
||||
val = minDB;
|
||||
}
|
||||
|
||||
}
|
||||
if(!_dBIndexing && val <= maxLimit)
|
||||
{
|
||||
val = 0;
|
||||
}
|
||||
else if(_dBIndexing)
|
||||
{
|
||||
if(val <= minDB || (_dBThreshold && val <= -_dBThreshold))
|
||||
{
|
||||
val = 0;
|
||||
}
|
||||
else if(max)
|
||||
{
|
||||
if(_magnitudeInvariant)
|
||||
{
|
||||
val = -1; // ignore magnitude, just set it not null to say this frequency is here
|
||||
}
|
||||
else
|
||||
{
|
||||
val -= 1; // make sure high values are not null
|
||||
}
|
||||
}
|
||||
}
|
||||
sensors[k] = int(val);
|
||||
if((!_dBIndexing && sensors[k]<0) || (_dBIndexing && sensors[k]>0))
|
||||
{
|
||||
UERROR("sensors[%d]=%d %f", k, sensors[k], data.at<float>(0,i));
|
||||
}
|
||||
|
||||
++k;
|
||||
}
|
||||
postData.push_back(sensors);
|
||||
} // end kTypeAudioFreqSqrdMagn
|
||||
else if(iter->type() == Sensor::kTypeTwist)
|
||||
{
|
||||
UASSERT(iter->data().type() == CV_32FC1);
|
||||
|
||||
const cv::Mat & data = iter->data();
|
||||
std::vector<int> sensors(data.cols);
|
||||
for(int i=0; i<data.cols; ++i)
|
||||
{
|
||||
sensors[i] = (int)(data.at<float>(0, i)*100.0f);
|
||||
}
|
||||
postData.push_back(sensors);
|
||||
} //end kTypeTwist
|
||||
else
|
||||
{
|
||||
std::vector<float> sensorsMerged;
|
||||
int buf;
|
||||
smState->getSensorsMerged(sensorsMerged, buf);
|
||||
sensors = std::vector<int>(sensorsMerged.size());
|
||||
if(_useVotingScheme && (_dictionary.empty() || _dictionary.size() != sensorsMerged.size()))
|
||||
{
|
||||
_dictionary = std::vector<std::map<int, std::set<int> > >(sensorsMerged.size());
|
||||
}
|
||||
if(_useMotionMask)
|
||||
{
|
||||
motionMask = std::vector<unsigned char>(sensors.size(), 0);
|
||||
}
|
||||
bool updateMask = sensorsPrevious && sensorsPrevious->size() == motionMask.size();
|
||||
for(unsigned int i=0; i<sensorsMerged.size(); ++i)
|
||||
{
|
||||
if(sensorsMerged[i]>0 && sensorsMerged[i]<1)
|
||||
{
|
||||
UWARN("Conversion from float to int may lost precision...");
|
||||
}
|
||||
sensors[i] = (int)sensorsMerged[i];
|
||||
if(_useMotionMask && updateMask && sensorsPrevious->at(i) != sensors[i])
|
||||
{
|
||||
motionMask[i] = 1;
|
||||
}
|
||||
|
||||
if(!_dictionary.empty())
|
||||
{
|
||||
std::set<int> sensorId;
|
||||
sensorId.insert(id);
|
||||
std::pair<std::map<int, std::set<int> >::iterator, bool> ret;
|
||||
ret = _dictionary[i].insert(std::make_pair(sensors[i], sensorId));
|
||||
if(ret.second == false)
|
||||
{
|
||||
ret.first->second.insert(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
UWARN("Sensor type (%d) not handled!", iter->type());
|
||||
}
|
||||
}
|
||||
SMSignature * s = new SMSignature(sensors, motionMask, id, image, keepRawData);
|
||||
|
||||
if(polar)
|
||||
{
|
||||
cvReleaseImage(&polar);
|
||||
}
|
||||
if(indexed)
|
||||
{
|
||||
cvReleaseImage(&indexed);
|
||||
}
|
||||
|
||||
|
||||
ULOGGER_DEBUG("time new signature (id=%d) %fs", id, timer.ticks());
|
||||
return s;
|
||||
}
|
||||
|
||||
std::map<int, float> SMMemory::computeLikelihood(const Signature * signature, const std::list<int> & ids, float & maximumScore)
|
||||
{
|
||||
if(!_useVotingScheme)
|
||||
if(keepRawData)
|
||||
{
|
||||
return Memory::computeLikelihood(signature, ids, maximumScore);
|
||||
return new SMSignature(postData, id, rawSensors);
|
||||
}
|
||||
else
|
||||
{
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
std::map<int, float> likelihood;
|
||||
maximumScore = 0;
|
||||
|
||||
const SMSignature * query = dynamic_cast<const SMSignature *>(signature);
|
||||
if(!query)
|
||||
{
|
||||
ULOGGER_ERROR("The signature is not a SMSignature");
|
||||
return likelihood; // Must be a SMSignature *
|
||||
}
|
||||
else if(ids.empty())
|
||||
{
|
||||
UWARN("ids list is empty");
|
||||
return likelihood;
|
||||
}
|
||||
|
||||
UDEBUG("Likelihood for %d", query->id());
|
||||
|
||||
const std::vector<int> & sensors = query->getSensors();
|
||||
if(_dictionary.size() != sensors.size())
|
||||
{
|
||||
UERROR("Dictionary (%d) and sensor (%d) are not the same size!", (int)_dictionary.size(), (int)sensors.size());
|
||||
return likelihood;
|
||||
}
|
||||
const std::vector<unsigned char> & mask = query->getMotionMask();
|
||||
bool maskUsed = false;
|
||||
if(mask.size() != 0 && mask.size() != sensors.size())
|
||||
{
|
||||
UWARN("mask's size (%d) and sensor's size (%d) are not equal", (int)mask.size(), (int)sensors.size());
|
||||
}
|
||||
else if(mask.size())
|
||||
{
|
||||
maskUsed = true;
|
||||
}
|
||||
|
||||
// prepare likelihood
|
||||
for(std::list<int>::const_iterator iter = ids.begin(); iter!=ids.end(); ++iter)
|
||||
{
|
||||
likelihood.insert(likelihood.end(), std::make_pair(*iter, 0.0f));
|
||||
}
|
||||
|
||||
//float nwi; // nwi is the number of a specific word referenced by a place
|
||||
//float ni; // ni is the total of words referenced by a place
|
||||
float nw; // nw is the number of places referenced by a specific word
|
||||
float N; // N is the total number of places
|
||||
float logNnw;
|
||||
|
||||
N = this->getSignatures().size();
|
||||
|
||||
if(N)
|
||||
{
|
||||
for(unsigned int i=0; i<sensors.size(); ++i)
|
||||
{
|
||||
if(!maskUsed || mask[i])
|
||||
{
|
||||
// "Inverted index"
|
||||
std::map<int, std::set<int> >::iterator iter = _dictionary[i].find(sensors[i]);
|
||||
if(iter == _dictionary[i].end())
|
||||
{
|
||||
UERROR("Sensor %d not found in dictionary ?!?", sensors[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
nw = iter->second.size();
|
||||
if(nw)
|
||||
{
|
||||
if(nw > N)
|
||||
{
|
||||
for(std::set<int>::iterator jter = iter->second.begin(); jter!=iter->second.end(); ++jter)
|
||||
{
|
||||
UERROR("sensor pos %d, refid = %d", (int)i, *jter);
|
||||
}
|
||||
|
||||
UFATAL("id=%d, N = %f, nw=%f", signature->id(), N, nw);
|
||||
}
|
||||
logNnw = log10(N/nw);
|
||||
if(logNnw)
|
||||
{
|
||||
for(std::set<int>::iterator jter = iter->second.begin(); jter!=iter->second.end(); ++jter)
|
||||
{
|
||||
std::map<int, float>::iterator kter = likelihood.find(*jter);
|
||||
if(kter != likelihood.end())
|
||||
{
|
||||
kter->second += logNnw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(sensors.size())
|
||||
{
|
||||
maximumScore = log(N) * float(sensors.size());
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("compute likelihood, maximumScore=%f... %f s", maximumScore, timer.ticks());
|
||||
return likelihood;
|
||||
}
|
||||
}
|
||||
|
||||
void SMMemory::moveToTrash(Signature * s)
|
||||
{
|
||||
if(_useVotingScheme)
|
||||
{
|
||||
UTimer timer;
|
||||
SMSignature * sm = dynamic_cast<SMSignature *>(s);
|
||||
if(sm && sm->id() > 0)
|
||||
{
|
||||
const std::vector<int> & sensors = sm->getSensors();
|
||||
if(sensors.size() == _dictionary.size())
|
||||
{
|
||||
for(unsigned int i=0; i<sensors.size(); ++i)
|
||||
{
|
||||
std::map<int, std::set<int> >::iterator iter = _dictionary[i].find(sensors[i]);
|
||||
if(iter != _dictionary[i].end())
|
||||
{
|
||||
if(!iter->second.erase(sm->id()))
|
||||
{
|
||||
UWARN("Sensor id %d not found in dictionary at pos %d", sm->id(), (int)i);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Sensor value %d at sensor pos %d is not found in dictionary", sensors[i], (int)i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UWARN("Dictionary size (%d) is not the same as the sensor (%d), signId=%d", (int)_dictionary.size(), (int)sensors.size(), sm->id());
|
||||
}
|
||||
}
|
||||
UDEBUG("time=%fs", timer.ticks());
|
||||
}
|
||||
Memory::moveToTrash(s);
|
||||
}
|
||||
|
||||
Signature * SMMemory::getSignatureLtMem(int id)
|
||||
{
|
||||
Signature * s = Memory::getSignatureLtMem(id);
|
||||
if(_useVotingScheme && s)
|
||||
{
|
||||
this->updateDictionary(s);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
bool SMMemory::init(const std::string & dbDriverName, const std::string & dbUrl, bool dbOverwritten, const ParametersMap & parameters)
|
||||
{
|
||||
UDEBUG("");
|
||||
bool success = Memory::init(dbDriverName, dbUrl, dbOverwritten, parameters);
|
||||
|
||||
if(_useVotingScheme)
|
||||
{
|
||||
// Update sensory dictionary
|
||||
const std::map<int, Signature *> & signatures = this->getSignatures();
|
||||
for(std::map<int, Signature *>::const_iterator i=signatures.begin(); i!=signatures.end(); ++i)
|
||||
{
|
||||
this->updateDictionary(i->second);
|
||||
}
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
void SMMemory::updateDictionary(const Signature * s)
|
||||
{
|
||||
if(s)
|
||||
{
|
||||
const SMSignature * sm = dynamic_cast<const SMSignature *>(s);
|
||||
if(sm)
|
||||
{
|
||||
const std::vector<int> & sensors = sm->getSensors();
|
||||
if(_dictionary.empty())
|
||||
{
|
||||
_dictionary = std::vector<std::map<int, std::set<int> > >(sensors.size());
|
||||
}
|
||||
if(sensors.size() == _dictionary.size())
|
||||
{
|
||||
for(unsigned int i=0; i<sensors.size(); ++i)
|
||||
{
|
||||
std::set<int> sensorId;
|
||||
sensorId.insert(sm->id());
|
||||
std::pair<std::map<int, std::set<int> >::iterator, bool> ret;
|
||||
ret = _dictionary[i].insert(std::make_pair(sensors[i], sensorId));
|
||||
if(ret.second == false)
|
||||
{
|
||||
ret.first->second.insert(sm->id());
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(_dictionary.size())
|
||||
{
|
||||
UWARN("Loaded signature %d with size (%d) doesn't have the same size as the dicitonary (%d)", sm->id(), (int)sensors.size(), (int)_dictionary.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UFATAL("Signature must not be null!");
|
||||
return new SMSignature(postData, id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+120
-167
@@ -18,12 +18,12 @@
|
||||
*/
|
||||
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "Memory.h"
|
||||
#include "rtabmap/core/EpipolarGeometry.h"
|
||||
#include "rtabmap/core/Memory.h"
|
||||
#include <opencv2/highgui/highgui.hpp>
|
||||
#include "VerifyHypotheses.h"
|
||||
#include "rtabmap/core/SMState.h"
|
||||
#include "rtabmap/core/VerifyHypotheses.h"
|
||||
|
||||
#include "utilite/UtiLite.h"
|
||||
#include <utilite/UtiLite.h>
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
@@ -31,9 +31,9 @@ namespace rtabmap
|
||||
bool NeighborLink::updateIds(int idFrom, int idTo)
|
||||
{
|
||||
bool modified = false;
|
||||
if(_id == idFrom)
|
||||
if(_toId == idFrom)
|
||||
{
|
||||
_id = idTo;
|
||||
_toId = idTo;
|
||||
modified = true;
|
||||
}
|
||||
for(unsigned int i=0; i<_baseIds.size(); ++i)
|
||||
@@ -50,82 +50,23 @@ bool NeighborLink::updateIds(int idFrom, int idTo)
|
||||
Signature::~Signature()
|
||||
{
|
||||
ULOGGER_DEBUG("id=%d", _id);
|
||||
if(_image)
|
||||
{
|
||||
cvReleaseImage(&_image);
|
||||
}
|
||||
}
|
||||
|
||||
Signature::Signature(int id, const IplImage * image, bool keepImage) :
|
||||
Signature::Signature(int id) :
|
||||
_id(id),
|
||||
_weight(0),
|
||||
_image(0),
|
||||
_saved(false),
|
||||
_modified(true)
|
||||
{
|
||||
if(image)
|
||||
{
|
||||
if(keepImage)
|
||||
{
|
||||
_image = cvCloneImage(image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Warning, the image returned must be released
|
||||
const IplImage * Signature::getImage() const
|
||||
Signature::Signature(int id, const std::list<Sensor> & rawData) :
|
||||
_id(id),
|
||||
_weight(0),
|
||||
_rawData(rawData),
|
||||
_saved(false),
|
||||
_modified(true)
|
||||
{
|
||||
return _image;
|
||||
}
|
||||
|
||||
void Signature::setImage(const IplImage * image)
|
||||
{
|
||||
if(_image && image)
|
||||
{
|
||||
cvReleaseImage(&_image);
|
||||
_image = cvCloneImage(image);
|
||||
_modified = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UDEBUG("Parameter is null or no image is saved.");
|
||||
}
|
||||
}
|
||||
|
||||
// Warning, the matrix returned must be released
|
||||
CvMat * Signature::compressImage(const IplImage * image)
|
||||
{
|
||||
if(!image)
|
||||
{
|
||||
UERROR("The parameter must not be null.");
|
||||
return 0;
|
||||
}
|
||||
// Compress image
|
||||
int params[3] = {0};
|
||||
|
||||
//JPEG compression
|
||||
std::string format = "jpeg";
|
||||
params[0] = CV_IMWRITE_JPEG_QUALITY;
|
||||
params[1] = 80; // default: 80% quality
|
||||
|
||||
//PNG compression
|
||||
//std::string format = "png";
|
||||
//params[0] = CV_IMWRITE_PNG_COMPRESSION;
|
||||
//params[1] = 9; // default: maximum compression
|
||||
|
||||
std::string extension = '.' + format;
|
||||
return cvEncodeImage(extension.c_str(), image, params);
|
||||
}
|
||||
|
||||
// Warning, the image returned must be released
|
||||
IplImage * Signature::decompressImage(const CvMat * imageCompressed)
|
||||
{
|
||||
if(!imageCompressed)
|
||||
{
|
||||
UERROR("The parameter must not be null.");
|
||||
return 0;
|
||||
}
|
||||
return cvDecodeImage(imageCompressed, CV_LOAD_IMAGE_ANYCOLOR);
|
||||
}
|
||||
|
||||
void Signature::addNeighbors(const NeighborsMultiMap & neighbors)
|
||||
@@ -138,21 +79,30 @@ void Signature::addNeighbors(const NeighborsMultiMap & neighbors)
|
||||
|
||||
void Signature::addNeighbor(const NeighborLink & neighbor)
|
||||
{
|
||||
UDEBUG("Add neighbor %d to %d", neighbor.id(), this->id());
|
||||
/*std::string baseIdsDebug;
|
||||
const std::vector<int> & baseIds = neighbor.baseIds();
|
||||
for(unsigned int i=0; i<baseIds.size(); ++i)
|
||||
{
|
||||
baseIdsDebug.append(uNumber2str(baseIds[i]));
|
||||
if(i+1 < baseIds.size())
|
||||
{
|
||||
baseIdsDebug.append(", ");
|
||||
}
|
||||
}
|
||||
UDEBUG("Adding neighbor %d to %d with %d actions, %d baseIds = [%s]", neighbor.id(), this->id(), neighbor.actions().size(), neighbor.baseIds().size(), baseIdsDebug.c_str());
|
||||
*/
|
||||
UDEBUG("Add neighbor %d to %d", neighbor.toId(), this->id());
|
||||
|
||||
_neighbors.insert(std::pair<int, NeighborLink>(neighbor.id(), neighbor));
|
||||
if(ULogger::level() == ULogger::kDebug)
|
||||
{
|
||||
UTimer timer;
|
||||
std::string baseIdsDebug;
|
||||
const std::vector<int> & baseIds = neighbor.baseIds();
|
||||
for(unsigned int i=0; i<baseIds.size(); ++i)
|
||||
{
|
||||
baseIdsDebug.append(uFormat("%d", baseIds[i]));
|
||||
if(i+1 < baseIds.size())
|
||||
{
|
||||
baseIdsDebug.append(", ");
|
||||
}
|
||||
}
|
||||
UDEBUG("Adding neighbor %d to %d with %d actions, %d baseIds = [%s] (time print=%fs)", neighbor.toId(), this->id(), neighbor.actuators().size(), neighbor.baseIds().size(), baseIdsDebug.c_str(), timer.getElapsedTime());
|
||||
}
|
||||
|
||||
_neighbors.insert(std::pair<int, NeighborLink>(neighbor.toId(), neighbor));
|
||||
if(neighbor.actuators().size())
|
||||
{
|
||||
_neighborsWithActuators.insert(neighbor.toId());
|
||||
}
|
||||
_neighborsAll.insert(neighbor.toId());
|
||||
_neighborsModified = true;
|
||||
}
|
||||
|
||||
@@ -170,11 +120,17 @@ void Signature::changeNeighborIds(int idFrom, int idTo)
|
||||
linksToAdd.push_back(link);
|
||||
}
|
||||
_neighbors.erase(idFrom);
|
||||
_neighborsWithActuators.erase(idFrom);
|
||||
_neighborsAll.erase(idFrom);
|
||||
for(std::list<NeighborLink>::iterator iter=linksToAdd.begin(); iter!=linksToAdd.end(); ++iter)
|
||||
{
|
||||
_neighbors.insert(std::pair<int, NeighborLink>(iter->id(), *iter));
|
||||
_neighbors.insert(std::pair<int, NeighborLink>(iter->toId(), *iter));
|
||||
if(iter->actuators().size())
|
||||
{
|
||||
_neighborsWithActuators.insert(iter->toId());
|
||||
}
|
||||
_neighborsAll.insert(iter->toId());
|
||||
}
|
||||
_modified = true;
|
||||
_neighborsModified = true;
|
||||
UDEBUG("(%d) neighbor ids changed from %d to %d", _id, idFrom, idTo);
|
||||
}
|
||||
@@ -183,19 +139,24 @@ void Signature::changeNeighborIds(int idFrom, int idTo)
|
||||
|
||||
|
||||
//KeypointSignature
|
||||
KeypointSignature::KeypointSignature(
|
||||
const std::multimap<int, cv::KeyPoint> & words,
|
||||
int id,
|
||||
const IplImage * image,
|
||||
bool keepRawData) :
|
||||
Signature(id, image, keepRawData),
|
||||
KeypointSignature::KeypointSignature(int id) :
|
||||
Signature(id),
|
||||
_enabled(false)
|
||||
{
|
||||
}
|
||||
KeypointSignature::KeypointSignature(const std::multimap<int, cv::KeyPoint> & words,
|
||||
int id) :
|
||||
Signature(id),
|
||||
_words(words),
|
||||
_enabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
KeypointSignature::KeypointSignature(int id) :
|
||||
Signature(id),
|
||||
KeypointSignature::KeypointSignature(
|
||||
const std::multimap<int, cv::KeyPoint> & words,
|
||||
int id,
|
||||
const std::list<Sensor> & rawData) :
|
||||
Signature(id, rawData),
|
||||
_words(words),
|
||||
_enabled(false)
|
||||
{
|
||||
}
|
||||
@@ -215,10 +176,9 @@ float KeypointSignature::compareTo(const Signature * s) const
|
||||
|
||||
if(words.size() != 0 && _words.size() != 0)
|
||||
{
|
||||
std::list<std::pair<cv::KeyPoint, cv::KeyPoint> > pairs;
|
||||
std::list<int> pairsId;
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > pairs;
|
||||
int totalWords = _words.size()>words.size()?_words.size():words.size();
|
||||
HypVerificatorEpipolarGeo::findPairsDirect(words, _words, pairs, pairsId);
|
||||
findPairs(words, _words, pairs);
|
||||
|
||||
similarity = float(pairs.size()) / float(totalWords);
|
||||
}
|
||||
@@ -240,12 +200,9 @@ void KeypointSignature::changeWordsRef(int oldWordId, int activeWordId)
|
||||
}
|
||||
}
|
||||
|
||||
#define BAD_SIGNATURE_THRESHOLD 0 // elements
|
||||
bool KeypointSignature::isBadSignature() const
|
||||
{
|
||||
if(_words.size() <= BAD_SIGNATURE_THRESHOLD)
|
||||
return true;
|
||||
return false;
|
||||
return !_words.size();
|
||||
}
|
||||
|
||||
void KeypointSignature::removeAllWords()
|
||||
@@ -264,20 +221,21 @@ void KeypointSignature::removeWord(int wordId)
|
||||
|
||||
//SMSignature
|
||||
SMSignature::SMSignature(
|
||||
const std::vector<int> & sensors,
|
||||
const std::vector<unsigned char> & motionMask,
|
||||
int id,
|
||||
const IplImage * image,
|
||||
bool keepRawData) :
|
||||
Signature(id, image, keepRawData),
|
||||
_sensors(sensors),
|
||||
_motionMask(motionMask)
|
||||
const std::list<std::vector<int> > & data,
|
||||
int id) :
|
||||
Signature(id),
|
||||
_data(data)
|
||||
{
|
||||
if(_sensors.size() != _motionMask.size() && _motionMask.size() > 0)
|
||||
{
|
||||
UFATAL("Sensors and mask must have the same size (%d vs %d)", (int)_sensors.size(), (int)_motionMask.size());
|
||||
}
|
||||
UDEBUG("sensors=%d", (int)_sensors.size());
|
||||
UDEBUG("data=%d", (int)_data.size());
|
||||
}
|
||||
SMSignature::SMSignature(
|
||||
const std::list<std::vector<int> > & data,
|
||||
int id,
|
||||
const std::list<Sensor> & rawData) :
|
||||
Signature(id, rawData),
|
||||
_data(data)
|
||||
{
|
||||
UDEBUG("data=%d", (int)_data.size());
|
||||
}
|
||||
|
||||
SMSignature::SMSignature(int id) :
|
||||
@@ -296,63 +254,59 @@ float SMSignature::compareTo(const Signature * s) const
|
||||
|
||||
if(sm)
|
||||
{
|
||||
const std::vector<int> & sensorsB = sm->getSensors();
|
||||
const std::vector<unsigned char> & motionMaskB = sm->getMotionMask();
|
||||
const std::list<std::vector<int> > & dataB = sm->getData();
|
||||
//const std::vector<unsigned char> & motionMaskB = sm->getMotionMask();
|
||||
|
||||
if(_sensors.size() == sensorsB.size() && _sensors.size()) //Compatible
|
||||
//if(_data.size() == sensorsB.size() && _data.size()) //Compatible
|
||||
if(_data.size() == dataB.size()) //Compatible
|
||||
{
|
||||
bool appearanceOnly = false;
|
||||
if(appearanceOnly)
|
||||
std::vector<float> similarities(_data.size());
|
||||
// compare sensors
|
||||
std::list<std::vector<int> >::const_iterator iterA = _data.begin();
|
||||
std::list<std::vector<int> >::const_iterator iterB = dataB.begin();
|
||||
int j=0;
|
||||
while(iterA != _data.end() && iterB != dataB.end())
|
||||
{
|
||||
std::multiset<int> sensorsSetA(_sensors.begin(), _sensors.end());
|
||||
std::multiset<int> sensorsSetB(sensorsB.begin(), sensorsB.end());
|
||||
std::set<int> ids(_sensors.begin(), _sensors.end());
|
||||
std::multiset<int>::iterator iterA;
|
||||
std::multiset<int>::iterator iterB;
|
||||
float realPairsCount = 0;
|
||||
for(std::set<int>::iterator i=ids.begin(); i!=ids.end(); ++i)
|
||||
if(iterA->size() == iterB->size())
|
||||
{
|
||||
iterA = sensorsSetA.find(*i);
|
||||
iterB = sensorsSetB.find(*i);
|
||||
while(iterA != sensorsSetA.end() && iterB != sensorsSetB.end() && *iterA == *iterB && *iterA == *i)
|
||||
int sum = 0;
|
||||
int notNull = 0;
|
||||
for(unsigned int i=0; i<iterA->size(); ++i)
|
||||
{
|
||||
++iterA;
|
||||
++iterB;
|
||||
++realPairsCount;
|
||||
sum += iterA->at(i) && iterA->at(i) == iterB->at(i) ? 1 : 0;
|
||||
notNull += iterA->at(i) || iterB->at(i) ? 1 : 0;
|
||||
}
|
||||
if(notNull)
|
||||
{
|
||||
similarities[j] = float(sum)/float(notNull);
|
||||
}
|
||||
else
|
||||
{
|
||||
similarities[j] = 1.0f; // example, silence == 100% silence
|
||||
}
|
||||
}
|
||||
similarity = realPairsCount / float(_sensors.size());
|
||||
else
|
||||
{
|
||||
UERROR("Data are not the same size (%d vs %d)", (int)iterA->size(), (int)iterB->size());
|
||||
}
|
||||
++iterA;
|
||||
++iterB;
|
||||
++j;
|
||||
}
|
||||
else if(_motionMask.size() == _sensors.size() &&
|
||||
_motionMask.size() == motionMaskB.size())
|
||||
{
|
||||
int sum = 0;
|
||||
int maskSumA = 0;
|
||||
int maskSumB = 0;
|
||||
|
||||
// compare sensors
|
||||
for(unsigned int i=0; i<_sensors.size(); ++i)
|
||||
{
|
||||
maskSumA += _motionMask[i];
|
||||
maskSumB += motionMaskB[i];
|
||||
sum += _sensors.at(i) == sensorsB.at(i) && _motionMask[i] && motionMaskB[i] ? 1 : 0;
|
||||
}
|
||||
|
||||
int totalSize = maskSumA>maskSumB?maskSumA:maskSumB;
|
||||
if(totalSize)
|
||||
{
|
||||
similarity = float(sum)/float(totalSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
similarity = uMean(similarities);
|
||||
if(ULogger::level() == ULogger::kDebug)
|
||||
{
|
||||
int sum = 0;
|
||||
// compare sensors
|
||||
for(unsigned int i=0; i<_sensors.size(); ++i)
|
||||
std::string str;
|
||||
for(unsigned int i=0; i<similarities.size(); ++i)
|
||||
{
|
||||
sum += _sensors.at(i) == sensorsB.at(i) ? 1 : 0;
|
||||
str.append(uFormat("%f", similarities[i]));
|
||||
if(i<similarities.size()-1)
|
||||
{
|
||||
str.append(", ");
|
||||
}
|
||||
}
|
||||
similarity = float(sum)/float(_sensors.size());
|
||||
UDEBUG("similarities (%d vs %d) = [%s]", this->id(), s->id(), str.c_str());
|
||||
}
|
||||
|
||||
if(similarity<0 || similarity>1)
|
||||
@@ -362,12 +316,12 @@ float SMSignature::compareTo(const Signature * s) const
|
||||
}
|
||||
else if(!s->isBadSignature() && !this->isBadSignature())
|
||||
{
|
||||
UWARN("Not compatible signatures : nb sensors A=%d B=%d", (int)_sensors.size(), (int)sensorsB.size());
|
||||
UWARN("Not compatible nodes : nb sensors A=%d B=%d", (int)_data.size(), (int)dataB.size());
|
||||
}
|
||||
}
|
||||
else if(s)
|
||||
{
|
||||
UWARN("Only SM signatures are compared. (type tested=%s)", s->signatureType().c_str());
|
||||
UWARN("Only SM signatures are compared. (type tested=%s)", s->nodeType().c_str());
|
||||
}
|
||||
return similarity;
|
||||
}
|
||||
@@ -375,9 +329,8 @@ float SMSignature::compareTo(const Signature * s) const
|
||||
|
||||
bool SMSignature::isBadSignature() const
|
||||
{
|
||||
if(_sensors.size() == 0)
|
||||
return true;
|
||||
return false;
|
||||
//return uSum(_data) == 0;
|
||||
return !_data.size();
|
||||
}
|
||||
|
||||
} //namespace rtabmap
|
||||
|
||||
+133
-21
@@ -5,7 +5,7 @@
|
||||
<tr><th>File <td>SimpleIni.h
|
||||
<tr><th>Author <td>Brodie Thiesfield [code at jellycan dot com]
|
||||
<tr><th>Source <td>http://code.jellycan.com/simpleini/
|
||||
<tr><th>Version <td>4.12
|
||||
<tr><th>Version <td>4.15
|
||||
</table>
|
||||
|
||||
Jump to the @link CSimpleIniTempl CSimpleIni @endlink interface documentation.
|
||||
@@ -77,7 +77,7 @@
|
||||
#1 On Windows you are better to use CSimpleIniA with SI_CONVERT_WIN32.<br>
|
||||
#2 Only affects Windows. On Windows this uses MBCS functions and
|
||||
so may fold case incorrectly leading to uncertain results.
|
||||
-# Call Load() or LoadFile() to load and parse the INI configuration file
|
||||
-# Call LoadData() or LoadFile() to load and parse the INI configuration file
|
||||
-# Access and modify the data of the file using the following functions
|
||||
<table>
|
||||
<tr><td>GetAllSections <td>Return all section names
|
||||
@@ -162,13 +162,16 @@
|
||||
- Usage of the <mbstring.h> header on Windows can be disabled by defining
|
||||
SI_NO_MBCS. This is defined automatically on Windows CE platforms.
|
||||
|
||||
@section contrib CONTRIBUTIONS
|
||||
|
||||
- 2010/05/03: Tobias Gehrig: added GetDoubleValue()
|
||||
|
||||
@section licence MIT LICENCE
|
||||
|
||||
The licence text below is the boilerplate "MIT Licence" used from:
|
||||
http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
Copyright (c) 2006-2008, Brodie Thiesfield
|
||||
Copyright (c) 2006-2012, Brodie Thiesfield
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
@@ -418,7 +421,7 @@ public:
|
||||
return *this;
|
||||
}
|
||||
bool ConvertToStore(const SI_CHAR * a_pszString) {
|
||||
size_t uLen = SizeToStore(a_pszString);
|
||||
size_t uLen = SI_CONVERTER::SizeToStore(a_pszString);
|
||||
if (uLen == (size_t)(-1)) {
|
||||
return false;
|
||||
}
|
||||
@@ -456,6 +459,9 @@ public:
|
||||
/** Deallocate all memory stored by this object */
|
||||
void Reset();
|
||||
|
||||
/** Has any data been loaded */
|
||||
bool IsEmpty() const { return m_data.empty(); }
|
||||
|
||||
/*-----------------------------------------------------------------------*/
|
||||
/** @{ @name Settings */
|
||||
|
||||
@@ -578,7 +584,7 @@ public:
|
||||
|
||||
@return SI_Error See error definitions
|
||||
*/
|
||||
SI_Error Load(
|
||||
SI_Error LoadData(
|
||||
std::istream & a_istream
|
||||
);
|
||||
#endif // SI_SUPPORT_IOSTREAMS
|
||||
@@ -589,8 +595,8 @@ public:
|
||||
|
||||
@return SI_Error See error definitions
|
||||
*/
|
||||
SI_Error Load(const std::string & a_strData) {
|
||||
return Load(a_strData.c_str(), a_strData.size());
|
||||
SI_Error LoadData(const std::string & a_strData) {
|
||||
return LoadData(a_strData.c_str(), a_strData.size());
|
||||
}
|
||||
|
||||
/** Load INI file data direct from memory
|
||||
@@ -600,7 +606,7 @@ public:
|
||||
|
||||
@return SI_Error See error definitions
|
||||
*/
|
||||
SI_Error Load(
|
||||
SI_Error LoadData(
|
||||
const char * a_pData,
|
||||
size_t a_uDataLen
|
||||
);
|
||||
@@ -879,6 +885,26 @@ public:
|
||||
bool * a_pHasMultiple = NULL
|
||||
) const;
|
||||
|
||||
/** Retrieve a numeric value for a specific key. If multiple keys are enabled
|
||||
(see SetMultiKey) then only the first value associated with that key
|
||||
will be returned, see GetAllValues for getting all values with multikey.
|
||||
|
||||
@param a_pSection Section to search
|
||||
@param a_pKey Key to search for
|
||||
@param a_nDefault Value to return if the key is not found
|
||||
@param a_pHasMultiple Optionally receive notification of if there are
|
||||
multiple entries for this key.
|
||||
|
||||
@return a_nDefault Key was not found in the section
|
||||
@return other Value of the key
|
||||
*/
|
||||
double GetDoubleValue(
|
||||
const SI_CHAR * a_pSection,
|
||||
const SI_CHAR * a_pKey,
|
||||
double a_nDefault = 0,
|
||||
bool * a_pHasMultiple = NULL
|
||||
) const;
|
||||
|
||||
/** Retrieve a boolean value for a specific key. If multiple keys are enabled
|
||||
(see SetMultiKey) then only the first value associated with that key
|
||||
will be returned, see GetAllValues for getting all values with multikey.
|
||||
@@ -976,6 +1002,34 @@ public:
|
||||
bool a_bForceReplace = false
|
||||
);
|
||||
|
||||
/** Add or update a double value. This will always insert
|
||||
when multiple keys are enabled.
|
||||
|
||||
@param a_pSection Section to add or update
|
||||
@param a_pKey Key to add or update.
|
||||
@param a_nValue Value to set.
|
||||
@param a_pComment Comment to be associated with the key. See the
|
||||
notes on SetValue() for comments.
|
||||
@param a_bForceReplace Should all existing values in a multi-key INI
|
||||
file be replaced with this entry. This option has
|
||||
no effect if not using multi-key files. The
|
||||
difference between Delete/SetDoubleValue and
|
||||
SetDoubleValue with a_bForceReplace = true, is that
|
||||
the load order and comment will be preserved this
|
||||
way.
|
||||
|
||||
@return SI_Error See error definitions
|
||||
@return SI_UPDATED Value was updated
|
||||
@return SI_INSERTED Value was inserted
|
||||
*/
|
||||
SI_Error SetDoubleValue(
|
||||
const SI_CHAR * a_pSection,
|
||||
const SI_CHAR * a_pKey,
|
||||
double a_nValue,
|
||||
const SI_CHAR * a_pComment = NULL,
|
||||
bool a_bForceReplace = false
|
||||
);
|
||||
|
||||
/** Add or update a boolean value. This will always insert
|
||||
when multiple keys are enabled.
|
||||
|
||||
@@ -1312,14 +1366,14 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadFile(
|
||||
}
|
||||
|
||||
// convert the raw data to unicode
|
||||
SI_Error rc = Load(pData, uRead);
|
||||
SI_Error rc = LoadData(pData, uRead);
|
||||
delete[] pData;
|
||||
return rc;
|
||||
}
|
||||
|
||||
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
|
||||
SI_Error
|
||||
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Load(
|
||||
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadData(
|
||||
const char * a_pData,
|
||||
size_t a_uDataLen
|
||||
)
|
||||
@@ -1396,7 +1450,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Load(
|
||||
#ifdef SI_SUPPORT_IOSTREAMS
|
||||
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
|
||||
SI_Error
|
||||
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Load(
|
||||
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::LoadData(
|
||||
std::istream & a_istream
|
||||
)
|
||||
{
|
||||
@@ -1407,7 +1461,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Load(
|
||||
strData.append(szBuf);
|
||||
}
|
||||
while (a_istream.good());
|
||||
return Load(strData);
|
||||
return LoadData(strData);
|
||||
}
|
||||
#endif // SI_SUPPORT_IOSTREAMS
|
||||
|
||||
@@ -1878,7 +1932,7 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::AddEntry(
|
||||
if (a_pComment) {
|
||||
oKey.pComment = a_pComment;
|
||||
}
|
||||
typename TKeyVal::value_type oEntry(oKey, NULL);
|
||||
typename TKeyVal::value_type oEntry(oKey, static_cast<const SI_CHAR *>(NULL));
|
||||
iKey = keyval.insert(oEntry);
|
||||
bInserted = true;
|
||||
}
|
||||
@@ -1994,6 +2048,68 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetLongValue(
|
||||
return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
|
||||
}
|
||||
|
||||
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
|
||||
double
|
||||
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetDoubleValue(
|
||||
const SI_CHAR * a_pSection,
|
||||
const SI_CHAR * a_pKey,
|
||||
double a_nDefault,
|
||||
bool * a_pHasMultiple
|
||||
) const
|
||||
{
|
||||
// return the default if we don't have a value
|
||||
const SI_CHAR * pszValue = GetValue(a_pSection, a_pKey, NULL, a_pHasMultiple);
|
||||
if (!pszValue || !*pszValue) return a_nDefault;
|
||||
|
||||
// convert to UTF-8/MBCS which for a numeric value will be the same as ASCII
|
||||
char szValue[64] = { 0 };
|
||||
SI_CONVERTER c(m_bStoreIsUtf8);
|
||||
if (!c.ConvertToStore(pszValue, szValue, sizeof(szValue))) {
|
||||
return a_nDefault;
|
||||
}
|
||||
|
||||
char * pszSuffix = NULL;
|
||||
double nValue = strtod(szValue, &pszSuffix);
|
||||
|
||||
// any invalid strings will return the default value
|
||||
if (!pszSuffix || *pszSuffix) {
|
||||
return a_nDefault;
|
||||
}
|
||||
|
||||
return nValue;
|
||||
}
|
||||
|
||||
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
|
||||
SI_Error
|
||||
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::SetDoubleValue(
|
||||
const SI_CHAR * a_pSection,
|
||||
const SI_CHAR * a_pKey,
|
||||
double a_nValue,
|
||||
const SI_CHAR * a_pComment,
|
||||
bool a_bForceReplace
|
||||
)
|
||||
{
|
||||
// use SetValue to create sections
|
||||
if (!a_pSection || !a_pKey) return SI_FAIL;
|
||||
|
||||
// convert to an ASCII string
|
||||
char szInput[64];
|
||||
#if __STDC_WANT_SECURE_LIB__ && !_WIN32_WCE
|
||||
sprintf_s(szInput, "%f", a_nValue);
|
||||
#else // !__STDC_WANT_SECURE_LIB__
|
||||
sprintf(szInput, "%f", a_nValue);
|
||||
#endif // __STDC_WANT_SECURE_LIB__
|
||||
|
||||
// convert to output text
|
||||
SI_CHAR szOutput[64];
|
||||
SI_CONVERTER c(m_bStoreIsUtf8);
|
||||
c.ConvertFromStore(szInput, strlen(szInput) + 1,
|
||||
szOutput, sizeof(szOutput) / sizeof(SI_CHAR));
|
||||
|
||||
// actually add it
|
||||
return AddEntry(a_pSection, a_pKey, szOutput, a_pComment, a_bForceReplace, true);
|
||||
}
|
||||
|
||||
template<class SI_CHAR, class SI_STRLESS, class SI_CONVERTER>
|
||||
bool
|
||||
CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::GetBoolValue(
|
||||
@@ -2349,11 +2465,11 @@ CSimpleIniTempl<SI_CHAR,SI_STRLESS,SI_CONVERTER>::Save(
|
||||
if (m_bAllowMultiLine && IsMultiLineData(iValue->pItem)) {
|
||||
// multi-line data needs to be processed specially to ensure
|
||||
// that we use the correct newline format for the current system
|
||||
a_oOutput.Write("<<<SI-END-OF-MULTILINE-TEXT" SI_NEWLINE_A);
|
||||
a_oOutput.Write("<<<END_OF_TEXT" SI_NEWLINE_A);
|
||||
if (!OutputMultiLineText(a_oOutput, convert, iValue->pItem)) {
|
||||
return SI_FAIL;
|
||||
}
|
||||
a_oOutput.Write("SI-END-OF-MULTILINE-TEXT");
|
||||
a_oOutput.Write("END_OF_TEXT");
|
||||
}
|
||||
else {
|
||||
a_oOutput.Write(convert.Data());
|
||||
@@ -2923,10 +3039,9 @@ public:
|
||||
}
|
||||
|
||||
nError = U_ZERO_ERROR;
|
||||
ucnv_resetToUnicode(m_pConverter);
|
||||
int32_t nLen = ucnv_toUChars(m_pConverter, NULL, 0,
|
||||
a_pInputData, (int32_t) a_uInputDataLen, &nError);
|
||||
if (nError != U_BUFFER_OVERFLOW_ERROR) {
|
||||
if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
@@ -2963,7 +3078,6 @@ public:
|
||||
}
|
||||
|
||||
nError = U_ZERO_ERROR;
|
||||
ucnv_resetToUnicode(m_pConverter);
|
||||
ucnv_toUChars(m_pConverter,
|
||||
a_pOutputData, (int32_t) a_uOutputDataSize,
|
||||
a_pInputData, (int32_t) a_uInputDataLen, &nError);
|
||||
@@ -2998,10 +3112,9 @@ public:
|
||||
}
|
||||
|
||||
nError = U_ZERO_ERROR;
|
||||
ucnv_resetFromUnicode(m_pConverter);
|
||||
int32_t nLen = ucnv_fromUChars(m_pConverter, NULL, 0,
|
||||
a_pInputData, -1, &nError);
|
||||
if (nError != U_BUFFER_OVERFLOW_ERROR) {
|
||||
if (U_FAILURE(nError) && nError != U_BUFFER_OVERFLOW_ERROR) {
|
||||
return (size_t) -1;
|
||||
}
|
||||
|
||||
@@ -3037,7 +3150,6 @@ public:
|
||||
}
|
||||
|
||||
nError = U_ZERO_ERROR;
|
||||
ucnv_resetFromUnicode(m_pConverter);
|
||||
ucnv_fromUChars(m_pConverter,
|
||||
a_pOutputData, (int32_t) a_uOutputDataSize,
|
||||
a_pInputData, -1, &nError);
|
||||
|
||||
@@ -17,12 +17,12 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VWDictionary.h"
|
||||
#include "rtabmap/core/VWDictionary.h"
|
||||
#include "rtabmap/core/VisualWord.h"
|
||||
|
||||
#include "VisualWord.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
#include "NearestNeighbor.h"
|
||||
#include "rtabmap/core/NearestNeighbor.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
|
||||
#include "utilite/UtiLite.h"
|
||||
@@ -232,7 +232,11 @@ void VWDictionary::setNNStrategy(NNStrategy strategy, const ParametersMap & para
|
||||
switch(strategy)
|
||||
{
|
||||
case kNNKdTree:
|
||||
_nn = new KdTreeNN(parameters);
|
||||
//FIXME KdTreeNN is broken...
|
||||
//_nn = new KdTreeNN(parameters);
|
||||
//break;
|
||||
UWARN("KdTree OpenCV is broken, setting nearest neighbor strategy to KdForest FLANN...");
|
||||
_nn = new FlannKdTreeNN(parameters);
|
||||
break;
|
||||
case kNNFlannKdTree:
|
||||
_nn = new FlannKdTreeNN(parameters);
|
||||
@@ -248,9 +252,9 @@ void VWDictionary::setNNStrategy(NNStrategy strategy, const ParametersMap & para
|
||||
}
|
||||
else if(!_nn)
|
||||
{
|
||||
this->update();
|
||||
_dataTree = cv::Mat();
|
||||
}
|
||||
this->update();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,7 +368,10 @@ void VWDictionary::update()
|
||||
|
||||
void VWDictionary::clear()
|
||||
{
|
||||
ULOGGER_DEBUG("%d words destroyed", _visualWords.size());
|
||||
if(_visualWords.size())
|
||||
{
|
||||
UWARN("Visual dictionary would be already empty here (%d words still in dictionary).", _visualWords.size());
|
||||
}
|
||||
for(std::map<int, VisualWord *>::iterator i=_visualWords.begin(); i!=_visualWords.end(); ++i)
|
||||
{
|
||||
delete (*i).second;
|
||||
@@ -373,6 +380,9 @@ void VWDictionary::clear()
|
||||
_lastNewWordsAddedCount = 0;
|
||||
_totalActiveReferences = 0;
|
||||
_lastWordId = 0;
|
||||
_dataTree = cv::Mat();
|
||||
_mapIndexId.clear();
|
||||
_unusedWords.clear();
|
||||
}
|
||||
|
||||
int VWDictionary::getNextId()
|
||||
@@ -467,6 +477,7 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
|
||||
if(!_dataTree.empty())
|
||||
{
|
||||
//Find nearest neighbors
|
||||
UDEBUG("newPts.total()=%d ", newPts.total());
|
||||
_nn->search(newPts, results, dists, k, _maxLeafs);
|
||||
ULOGGER_DEBUG("Time to find nn = %f s", timerLocal.ticks());
|
||||
}
|
||||
@@ -537,6 +548,7 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
|
||||
_visualWords.insert(_visualWords.end(), std::pair<int, VisualWord *>(vw->id(), vw));
|
||||
newWords.push_back(vw);
|
||||
wordIds.push_back(vw->id());
|
||||
UASSERT(vw->id()>0);
|
||||
++newWordsCount;
|
||||
}
|
||||
else
|
||||
@@ -544,6 +556,7 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
|
||||
++dupWordsCount;
|
||||
this->addWordRef(fullResults.begin()->second, signatureId);
|
||||
wordIds.push_back(fullResults.begin()->second);
|
||||
UASSERT(fullResults.begin()->second>0);
|
||||
}
|
||||
}
|
||||
else if(fullResults.size())
|
||||
@@ -552,6 +565,7 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
|
||||
++dupWordsCount;
|
||||
this->addWordRef(fullResults.begin()->second, signatureId);
|
||||
wordIds.push_back(fullResults.begin()->second);
|
||||
UASSERT(fullResults.begin()->second>0);
|
||||
}
|
||||
}
|
||||
ULOGGER_DEBUG("naive search and add ref/words time = %f s", timerLocal.ticks());
|
||||
@@ -601,12 +615,14 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
|
||||
VisualWord * vw = new VisualWord(getNextId(), d, _dim, signatureId);
|
||||
_visualWords.insert(_visualWords.end(), std::pair<int, VisualWord *>(vw->id(), vw));
|
||||
wordIds.push_back(vw->id());
|
||||
UASSERT(vw->id()>0);
|
||||
}
|
||||
else
|
||||
{
|
||||
++dupWordsCount;
|
||||
this->addWordRef(results.begin()->second, signatureId);
|
||||
wordIds.push_back(results.begin()->second);
|
||||
UASSERT(results.begin()->second>0);
|
||||
}
|
||||
}
|
||||
else if(results.size())
|
||||
@@ -615,6 +631,7 @@ std::list<int> VWDictionary::addNewWords(const cv::Mat & descriptors,
|
||||
++dupWordsCount;
|
||||
this->addWordRef(results.begin()->second, signatureId);
|
||||
wordIds.push_back(results.begin()->second);
|
||||
UASSERT(results.begin()->second>0);
|
||||
}
|
||||
}
|
||||
ULOGGER_DEBUG("Naive search time = %fs", timer.ticks());
|
||||
|
||||
@@ -17,11 +17,12 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VerifyHypotheses.h"
|
||||
#include "rtabmap/core/VerifyHypotheses.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "rtabmap/core/EpipolarGeometry.h"
|
||||
#include <cstdlib>
|
||||
#include <opencv2/calib3d/calib3d.hpp>
|
||||
|
||||
|
||||
#include "utilite/UtiLite.h"
|
||||
|
||||
@@ -137,340 +138,29 @@ bool HypVerificatorEpipolarGeo::doEpipolarGeometry(const KeypointSignature * ssA
|
||||
}
|
||||
ULOGGER_DEBUG("id(%d,%d)", ssA->id(), ssB->id());
|
||||
|
||||
std::list<std::pair<cv::KeyPoint, cv::KeyPoint> > pairs;
|
||||
std::list<int> pairsId;
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > pairs;
|
||||
|
||||
//bool allPairs = true;
|
||||
int realPairsCount = 0;
|
||||
findPairsUnique(ssA->getWords(), ssB->getWords(), pairs);
|
||||
|
||||
|
||||
realPairsCount = findPairsOne(ssA->getWords(), ssB->getWords(), pairs, pairsId);
|
||||
ULOGGER_DEBUG("%d %d", pairs.size(), pairsId.size());
|
||||
int pairsCount = pairs.size();
|
||||
ULOGGER_DEBUG("id(%d,%d) realPairsCount found=%d, pairsCount=%d...", ssA->id(), ssB->id(), realPairsCount, pairsCount);
|
||||
|
||||
int similarities = this->getTotalSimilarities(ssA->getWords(), ssB->getWords());
|
||||
|
||||
ULOGGER_DEBUG("realPairsCount=%d, "
|
||||
"test1=%f%%, "
|
||||
"test2=%f%%, "
|
||||
"similarities/total=%f%%, "
|
||||
"realP/similarities=%f%%, "
|
||||
"(pairs/2)/similarities=%f%%",
|
||||
realPairsCount,
|
||||
float(realPairsCount)/(float(ssA->getWords().size() + ssB->getWords().size())/2),
|
||||
float(pairs.size())/(float(ssA->getWords().size() + ssB->getWords().size())/2),
|
||||
float(similarities)/float(ssA->getWords().size() + ssB->getWords().size()),
|
||||
float(realPairsCount) / float(similarities),
|
||||
float(pairs.size()) / float(similarities));
|
||||
if(pairsCount < _matchCountMinAccepted)
|
||||
if((int)pairs.size()<_matchCountMinAccepted)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Convert Keypoints to a structure that OpenCV understands
|
||||
//3 dimensions (Homogeneous vectors)
|
||||
cv::Mat points1(1, pairs.size(), CV_32FC2);
|
||||
cv::Mat points2(1, pairs.size(), CV_32FC2);
|
||||
std::vector<uchar> status;
|
||||
cv::Mat f = findFFromWords(pairs, status, _ransacParam1, _ransacParam2);
|
||||
|
||||
float * points1data = points1.ptr<float>(0);
|
||||
float * points2data = points2.ptr<float>(0);
|
||||
|
||||
// Fill the points here ...
|
||||
int i=0;
|
||||
for(std::list<std::pair<cv::KeyPoint, cv::KeyPoint> >::const_iterator iter = pairs.begin();
|
||||
iter != pairs.end();
|
||||
++iter )
|
||||
int inliers = uSum(status);
|
||||
if(inliers < _matchCountMinAccepted)
|
||||
{
|
||||
points1data[i*2] = (*iter).first.pt.x;
|
||||
points1data[i*2+1] = (*iter).first.pt.y;
|
||||
|
||||
points2data[i*2] = (*iter).second.pt.x;
|
||||
points2data[i*2+1] = (*iter).second.pt.y;
|
||||
|
||||
// the output of the correspondences can be easily copied in MatLab
|
||||
/*if(i==0)
|
||||
{
|
||||
ULOGGER_DEBUG("pt x=[%f;%f;1;%d];,xp=[%f;%f;1;%d];",
|
||||
(*iter).first.pt.x,
|
||||
(*iter).first.pt.y,
|
||||
Util::valueAt(pairsId,i),
|
||||
(*iter).second.pt.x,
|
||||
(*iter).second.pt.y,
|
||||
Util::valueAt(pairsId,i));
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_DEBUG("pt x=[x [%f;%f;1;%d]];,xp=[xp [%f;%f;1;%d]];",
|
||||
(*iter).first.pt.x,
|
||||
(*iter).first.pt.y,
|
||||
Util::valueAt(pairsId,i),
|
||||
(*iter).second.pt.x,
|
||||
(*iter).second.pt.y,
|
||||
Util::valueAt(pairsId,i));
|
||||
}*/
|
||||
++i;
|
||||
ULOGGER_DEBUG("Epipolar constraint failed A : not enough inliers (%d/%d), min is %d", inliers, pairs.size(), _matchCountMinAccepted);
|
||||
return false;
|
||||
}
|
||||
|
||||
UTimer timer;
|
||||
timer.start();
|
||||
|
||||
// Find the fundamental matrix
|
||||
cv::vector<uchar> status;
|
||||
cv::Mat fundamentalMatrix = cv::findFundamentalMat(
|
||||
points1,
|
||||
points2,
|
||||
status,
|
||||
CV_FM_RANSAC,
|
||||
_ransacParam1,
|
||||
_ransacParam2);
|
||||
|
||||
ULOGGER_DEBUG("Find fundamental matrix (OpenCV) time = %fs", timer.ticks());
|
||||
|
||||
// Fundamental matrix is valid ?
|
||||
bool fundMatFound = false;
|
||||
if(fundamentalMatrix.type() != CV_64FC1)
|
||||
else
|
||||
{
|
||||
ULOGGER_FATAL("fundamentalMatrix.type() != CV_64FC1");
|
||||
UDEBUG("inliers = %d/%d", inliers, pairs.size());
|
||||
return true;
|
||||
}
|
||||
if(fundamentalMatrix.cols==3 && fundamentalMatrix.rows==3 &&
|
||||
(fundamentalMatrix.at<double>(0,0) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(0,1) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(0,2) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(1,0) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(1,1) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(1,2) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(2,0) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(2,1) != 0.0 ||
|
||||
fundamentalMatrix.at<double>(2,2) != 0.0) )
|
||||
|
||||
{
|
||||
fundMatFound = true;
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("id(%d,%d) fm_count=%d...", ssA->id(), ssB->id(), fundMatFound);
|
||||
|
||||
if(fundMatFound)
|
||||
{
|
||||
std::list<std::pair<cv::KeyPoint, cv::KeyPoint> > inliers;
|
||||
std::list<int> inliersId;
|
||||
|
||||
int goodCount = 0;
|
||||
float total = 0;
|
||||
std::list<std::pair<float, float> > ptsAddedA;
|
||||
std::list<std::pair<float, float> > ptsAddedB;
|
||||
cv::Mat x(3, 1, fundamentalMatrix.type());
|
||||
cv::Mat xp(1, 3, fundamentalMatrix.type());
|
||||
int i=0;
|
||||
for(std::list<std::pair<cv::KeyPoint, cv::KeyPoint> >::iterator iter=pairs.begin(); iter!=pairs.end(); ++iter)
|
||||
{
|
||||
//if(status[i])
|
||||
{
|
||||
if(uContains(ptsAddedA, std::pair<float, float>((*iter).first.pt.x, (*iter).first.pt.y)))
|
||||
{
|
||||
ULOGGER_DEBUG("already added point [%f,%f,1]", (*iter).first.pt.x, (*iter).first.pt.y);
|
||||
}
|
||||
else if(uContains(ptsAddedB, std::pair<float, float>((*iter).second.pt.x, (*iter).second.pt.y)))
|
||||
{
|
||||
ULOGGER_DEBUG("already added point [%f,%f,1]", (*iter).second.pt.x, (*iter).second.pt.y);
|
||||
}
|
||||
else
|
||||
{
|
||||
double * xData = x.ptr<double>(0);
|
||||
double * xpData = xp.ptr<double>(0);
|
||||
xData[0] = (*iter).first.pt.x;
|
||||
xData[1] = (*iter).first.pt.y;
|
||||
xData[2] = 1;
|
||||
xpData[0] = (*iter).second.pt.x;
|
||||
xpData[1] = (*iter).second.pt.y;
|
||||
xpData[2] = 1;
|
||||
cv::Mat r = xp * (fundamentalMatrix * x);
|
||||
//if((r->data.fl[0] < 0 ? -r->data.fl[0]:r->data.fl[0]) < 1000000)
|
||||
{
|
||||
// Add only once a pair for the same id, used when a point matches with more than one...
|
||||
ptsAddedA.push_back(std::pair<float, float>((*iter).first.pt.x, (*iter).first.pt.y));
|
||||
ptsAddedB.push_back(std::pair<float, float>((*iter).second.pt.x, (*iter).second.pt.y));
|
||||
if(status[i])
|
||||
{
|
||||
inliers.push_back(*iter);
|
||||
inliersId.push_back(uValueAt(pairsId, i));
|
||||
goodCount++;
|
||||
}
|
||||
//ULOGGER_DEBUG("[%d] status=%d, r->data.fl[0]=%f, Added!", Util::valueAt(pairsId,i), status[i], r.ptr<double>(0)[0]);
|
||||
}
|
||||
/*else
|
||||
{
|
||||
ULOGGER_DEBUG("status=%d, r->data.fl[0]=%f, Not added!", status->data.ptr[i], r->data.fl[0]);
|
||||
}*/
|
||||
total+=(r.ptr<double>(0)[0] < 0 ? -r.ptr<double>(0)[0]:r.ptr<double>(0)[0]);
|
||||
}
|
||||
}
|
||||
/*else
|
||||
{
|
||||
ULOGGER_DEBUG("VHEpipolarGeo::doEpipolarGeometry() status=%d", status[i]);
|
||||
}*/
|
||||
++i;
|
||||
}
|
||||
|
||||
ULOGGER_DEBUG("pairs/realPairs=%d/%d -> %d%%, goodCount=%d -> %d%%, good/real = %d%%, totalMean=%f",
|
||||
pairsCount,
|
||||
realPairsCount,
|
||||
int(float(pairsCount)/float(realPairsCount*100)),
|
||||
goodCount,
|
||||
int(float(goodCount)/float(pairsCount*100)),
|
||||
int(float(goodCount)/float(realPairsCount*100)),
|
||||
total/float(realPairsCount));
|
||||
|
||||
// Show the fundamental matrix
|
||||
ULOGGER_DEBUG(
|
||||
"F = [%f %f %f;%f %f %f;%f %f %f]",
|
||||
fundamentalMatrix.ptr<double>(0)[0],
|
||||
fundamentalMatrix.ptr<double>(0)[1],
|
||||
fundamentalMatrix.ptr<double>(0)[2],
|
||||
fundamentalMatrix.ptr<double>(0)[3],
|
||||
fundamentalMatrix.ptr<double>(0)[4],
|
||||
fundamentalMatrix.ptr<double>(0)[5],
|
||||
fundamentalMatrix.ptr<double>(0)[6],
|
||||
fundamentalMatrix.ptr<double>(0)[7],
|
||||
fundamentalMatrix.ptr<double>(0)[8]);
|
||||
|
||||
if(goodCount < _matchCountMinAccepted)
|
||||
{
|
||||
ULOGGER_DEBUG("Epipolar constraint failed A : not enough inliers (%d), min is %d", goodCount, _matchCountMinAccepted);
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 HypVerificatorEpipolarGeo::findPairsDirect(const std::multimap<int, cv::KeyPoint> & wordsA,
|
||||
const std::multimap<int, cv::KeyPoint> & wordsB,
|
||||
std::list<std::pair<cv::KeyPoint, cv::KeyPoint> > & pairs,
|
||||
std::list<int> & pairsId)
|
||||
{
|
||||
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)
|
||||
{
|
||||
iterA = wordsA.find(*i);
|
||||
iterB = wordsB.find(*i);
|
||||
while(iterA != wordsA.end() && iterB != wordsB.end() && (*iterA).first == (*iterB).first && (*iterA).first == *i)
|
||||
{
|
||||
pairsId.push_back(*i);
|
||||
pairs.push_back(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 HypVerificatorEpipolarGeo::findPairsOne(const std::multimap<int, cv::KeyPoint> & wordsA,
|
||||
const std::multimap<int, cv::KeyPoint> & wordsB,
|
||||
std::list<std::pair<cv::KeyPoint, cv::KeyPoint> > & pairs,
|
||||
std::list<int> & pairsId)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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<cv::KeyPoint, cv::KeyPoint>(ptsA.front(), ptsB.front()));
|
||||
pairsId.push_back(*i);
|
||||
++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 HypVerificatorEpipolarGeo::findPairsAll(const std::multimap<int, cv::KeyPoint> & wordsA,
|
||||
const std::multimap<int, cv::KeyPoint> & wordsB,
|
||||
std::list<std::pair<cv::KeyPoint, cv::KeyPoint> > & pairs,
|
||||
std::list<int> & pairsId)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
pairsId.push_back(*iter);
|
||||
pairs.push_back(std::pair<cv::KeyPoint, cv::KeyPoint>(*jter, *kter));
|
||||
}
|
||||
}
|
||||
}
|
||||
ULOGGER_DEBUG("time = %f", timer.ticks());
|
||||
return realPairsCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [1 2 4 6]
|
||||
* return 4
|
||||
*/
|
||||
std::list<int> HypVerificatorEpipolarGeo::findSameIds(const std::multimap<int, cv::KeyPoint> & wordsA,
|
||||
const std::multimap<int, cv::KeyPoint> & wordsB)
|
||||
{
|
||||
std::list<int> sameIds;
|
||||
const std::list<int> & ids = uUniqueKeys(wordsA);
|
||||
for(std::list<int>::const_iterator i=ids.begin(); i!=ids.end(); ++i)
|
||||
{
|
||||
if(wordsB.find(*i) != wordsB.end())
|
||||
{
|
||||
sameIds.push_back(*i);
|
||||
}
|
||||
}
|
||||
return sameIds;
|
||||
}
|
||||
|
||||
int HypVerificatorEpipolarGeo::getTotalSimilarities(const std::multimap<int, cv::KeyPoint> & wordsA, const std::multimap<int, cv::KeyPoint> & wordsB)
|
||||
{
|
||||
const std::list<int> & ids = uUniqueKeys(wordsA);
|
||||
int total = 0;
|
||||
for(std::list<int>::const_iterator i=ids.begin(); i!=ids.end(); ++i)
|
||||
{
|
||||
total += uValues(wordsA, *i).size();
|
||||
total += uValues(wordsB, *i).size();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "VisualWord.h"
|
||||
#include "rtabmap/core/VisualWord.h"
|
||||
#include "utilite/ULogger.h"
|
||||
#include "utilite/UStl.h"
|
||||
|
||||
|
||||
@@ -1,221 +1,136 @@
|
||||
-- *******************************************************************
|
||||
-- construct_avpd_db: Script for creating the database
|
||||
-- Usage:
|
||||
-- $ sqlite3 AvpdDatabase.db < DatabaseSchema.sql
|
||||
-- $ sqlite3 LTM.db < DatabaseSchema.sql
|
||||
--
|
||||
-- *******************************************************************
|
||||
|
||||
-- *******************************************************************
|
||||
-- CLEAN
|
||||
-- *******************************************************************
|
||||
/*DROP TABLE Signature;
|
||||
DROP TABLE SignatureType;
|
||||
DROP TABLE Neighbor;
|
||||
DROP TABLE VisualWord;
|
||||
DROP TABLE Map_SS_VW;
|
||||
DROP TABLE StatisticsAfterRun;
|
||||
DROP TABLE StatisticsAfterRunSurf;*/
|
||||
/*DROP TABLE Node;
|
||||
DROP TABLE Link;
|
||||
DROP TABLE Sensor;
|
||||
DROP TABLE Actuator;
|
||||
DROP TABLE Word;
|
||||
DROP TABLE Map_Node_Word;
|
||||
DROP TABLE Statistics;
|
||||
DROP TABLE StatisticsSurf;*/
|
||||
|
||||
-- *******************************************************************
|
||||
-- CREATE
|
||||
-- *******************************************************************
|
||||
CREATE TABLE Signature (
|
||||
CREATE TABLE Node (
|
||||
id INTEGER NOT NULL,
|
||||
type VARCHAR NOT NULL,
|
||||
type INTEGER NOT NULL, -- 0=Keypoint, 1=Sensor
|
||||
weight INTEGER,
|
||||
loopClosureIds BLOB,
|
||||
childLoopClosureIds BLOB,
|
||||
timeEnter DATE,
|
||||
PRIMARY KEY (id),
|
||||
FOREIGN KEY (type) REFERENCES SignatureType(type)
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Image (
|
||||
CREATE TABLE Sensor (
|
||||
id INTEGER NOT NULL,
|
||||
num INTEGER NOT NULL,
|
||||
type INTEGER NOT NULL, -- kTypeImage=0, kTypeImageFeatures2d, kTypeAudio, kTypeAudioFreq, kTypeAudioFreqSqrdMagn, kTypeJointState, kTypeNotSpecified
|
||||
data BLOB, -- PostProcessed data (indexed integers)
|
||||
raw_width INTEGER NOT NULL,
|
||||
raw_height INTEGER NOT NULL,
|
||||
raw_data_type INTEGER NOT NULL,
|
||||
raw_compressed CHAR NOT NULL,
|
||||
raw_data BLOB,
|
||||
PRIMARY KEY (id, num)
|
||||
);
|
||||
|
||||
CREATE TABLE Link (
|
||||
from_id INTEGER NOT NULL,
|
||||
to_id INTEGER NOT NULL,
|
||||
type INTEGER NOT NULL, -- neighbor=0, loop=1, child=2
|
||||
actuator_id INTEGER,
|
||||
base_ids BLOB,
|
||||
FOREIGN KEY (from_id) REFERENCES Node(id),
|
||||
FOREIGN KEY (to_id) REFERENCES Node(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Actuator (
|
||||
id INTEGER NOT NULL,
|
||||
num INTEGER NOT NULL,
|
||||
type INTEGER NOT NULL, -- kTypeTwist=0, kTypeNotSpecified
|
||||
width INTEGER NOT NULL,
|
||||
height INTEGER NOT NULL,
|
||||
channels INTEGER NOT NULL,
|
||||
compressed CHAR NOT NULL,
|
||||
data_type INTEGER NOT NULL,
|
||||
data BLOB,
|
||||
timeEnter DATE,
|
||||
PRIMARY KEY (id)
|
||||
PRIMARY KEY (id, num)
|
||||
);
|
||||
|
||||
CREATE TABLE SMState (
|
||||
--
|
||||
CREATE TABLE Word (
|
||||
id INTEGER NOT NULL,
|
||||
sensors BLOB,
|
||||
motionMask BLOB,
|
||||
timeEnter DATE,
|
||||
FOREIGN KEY (id) REFERENCES Signature(id)
|
||||
);
|
||||
|
||||
CREATE TABLE Neighbor (
|
||||
sid INTEGER NOT NULL,
|
||||
nid INTEGER NOT NULL,
|
||||
actionSize INTEGER,
|
||||
actions BLOB,
|
||||
baseIds BLOB,
|
||||
FOREIGN KEY (sid) REFERENCES Signature(id),
|
||||
FOREIGN KEY (nid) REFERENCES Signature(id)
|
||||
);
|
||||
|
||||
CREATE TABLE SignatureType (
|
||||
type VARCHAR NOT NULL,
|
||||
PRIMARY KEY (type)
|
||||
);
|
||||
|
||||
CREATE TABLE VisualWord (
|
||||
id INTEGER NOT NULL,
|
||||
descriptorSize INTEGER NOT NULL,
|
||||
descriptor_size INTEGER NOT NULL,
|
||||
descriptor BLOB NOT NULL,
|
||||
timeEnter DATE,
|
||||
time_enter DATE,
|
||||
PRIMARY KEY (id)
|
||||
);
|
||||
|
||||
CREATE TABLE Map_SS_VW (
|
||||
signatureId INTEGER NOT NULL,
|
||||
visualWordId INTEGER NOT NULL,
|
||||
CREATE TABLE Map_Node_Word (
|
||||
node_id INTEGER NOT NULL,
|
||||
word_id INTEGER NOT NULL,
|
||||
pos_x FLOAT NOT NULL,
|
||||
pos_y FLOAT NOT NULL,
|
||||
laplacian INTEGER NOT NULL,
|
||||
size INTEGER NOT NULL,
|
||||
dir FLOAT NOT NULL,
|
||||
hessian FLOAT NOT NULL,
|
||||
FOREIGN KEY (signatureId) REFERENCES Signature(id),
|
||||
FOREIGN KEY (visualWordId) REFERENCES VisualWord(id)
|
||||
response FLOAT NOT NULL,
|
||||
FOREIGN KEY (node_id) REFERENCES Node(id),
|
||||
FOREIGN KEY (word_id) REFERENCES Word(id)
|
||||
);
|
||||
|
||||
CREATE TABLE StatisticsAfterRun (
|
||||
stMemSize INTEGER,
|
||||
lastSignAdded INTEGER,
|
||||
processMemUsed INTEGER,
|
||||
databaseMemUsed INTEGER,
|
||||
timeEnter DATE
|
||||
CREATE TABLE Statistics (
|
||||
STM_size INTEGER,
|
||||
last_sign_added INTEGER,
|
||||
process_mem_used INTEGER,
|
||||
database_mem_used INTEGER,
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
CREATE TABLE StatisticsAfterRunSurf (
|
||||
dictionarySize INTEGER,
|
||||
timeEnter DATE
|
||||
CREATE TABLE StatisticsDictionary (
|
||||
dictionary_size INTEGER,
|
||||
time_enter DATE
|
||||
);
|
||||
|
||||
-- *******************************************************************
|
||||
-- TRIGGERS
|
||||
-- *******************************************************************
|
||||
CREATE TRIGGER insert_Signature BEFORE INSERT ON Signature
|
||||
WHEN NOT EXISTS (SELECT type FROM SignatureType WHERE SignatureType.type = NEW.type)
|
||||
CREATE TRIGGER insert_Map_Node_Word BEFORE INSERT ON Map_Node_Word
|
||||
WHEN NOT EXISTS (SELECT type FROM Node WHERE Node.id = NEW.node_id AND type=0)
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key Signature.type constraint failed');
|
||||
SELECT RAISE(ABORT, 'Keypoint type constraint failed');
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_SMState BEFORE INSERT ON SMState
|
||||
WHEN NOT EXISTS (SELECT id FROM Signature WHERE Signature.id = NEW.id)
|
||||
-- Creating a trigger for time_enter
|
||||
CREATE TRIGGER insert_Node_timeEnter AFTER INSERT ON Node
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key SMState.id constraint failed');
|
||||
UPDATE Node SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
--CREATE TRIGGER insert_Neighbor_unique BEFORE INSERT ON Neighbor
|
||||
--WHEN NEW.sid = NEW.nid
|
||||
--BEGIN
|
||||
-- SELECT RAISE(ABORT, 'Cannot add self references');
|
||||
--END;
|
||||
|
||||
CREATE TRIGGER insert_Neighbor_sid BEFORE INSERT ON Neighbor
|
||||
WHEN NOT EXISTS (SELECT id FROM Signature WHERE Signature.id = NEW.sid)
|
||||
CREATE TRIGGER insert_Word_timeEnter AFTER INSERT ON Word
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'Foreign key Neighbor.sid constraint failed');
|
||||
UPDATE Word SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
--Commented before a link can be added before the neighbor is saved...
|
||||
--CREATE TRIGGER insert_Neighbor_nid BEFORE INSERT ON Neighbor
|
||||
--WHEN NOT EXISTS (SELECT id FROM Signature WHERE Signature.id = NEW.nid)
|
||||
--BEGIN
|
||||
-- SELECT RAISE(ABORT, 'Foreign key Neighbor.nid constraint failed');
|
||||
--END;
|
||||
|
||||
CREATE TRIGGER insert_Map_SS_VW BEFORE INSERT ON Map_SS_VW
|
||||
WHEN NOT EXISTS (SELECT type FROM Signature WHERE Signature.id = NEW.signatureId AND type='KeypointSignature')
|
||||
CREATE TRIGGER insert_Statistics_timeEnter AFTER INSERT ON Statistics
|
||||
BEGIN
|
||||
SELECT RAISE(ABORT, 'KeypointSignature type constraint failed');
|
||||
UPDATE Statistics SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
-- Creating a trigger for timeEnter
|
||||
CREATE TRIGGER insert_Signature_timeEnter AFTER INSERT ON Signature
|
||||
CREATE TRIGGER insert_StatisticsDictionary_timeEnter AFTER INSERT ON StatisticsDictionary
|
||||
BEGIN
|
||||
UPDATE Signature SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_VisualWord_timeEnter AFTER INSERT ON VisualWord
|
||||
BEGIN
|
||||
UPDATE VisualWord SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_StatisticsAfterRun_timeEnter AFTER INSERT ON StatisticsAfterRun
|
||||
BEGIN
|
||||
UPDATE StatisticsAfterRun SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
CREATE TRIGGER insert_StatisticsAfterRunSurf_timeEnter AFTER INSERT ON StatisticsAfterRunSurf
|
||||
BEGIN
|
||||
UPDATE StatisticsAfterRunSurf SET timeEnter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
UPDATE StatisticsDictionary SET time_enter = DATETIME('NOW') WHERE rowid = new.rowid;
|
||||
END;
|
||||
|
||||
|
||||
-- *******************************************************************
|
||||
-- INDEXES
|
||||
-- *******************************************************************
|
||||
CREATE INDEX IDX_Map_SS_VW_SignatureId on Map_SS_VW (signatureId);
|
||||
-- CREATE INDEX IDX_Map_SS_VW_VisualWordId on Map_SS_VW (visualWordId);
|
||||
-- CREATE INDEX IDX_Signature_Id on Signature (id);
|
||||
-- CREATE INDEX IDX_VisualWord_Id on VisualWord (id);
|
||||
CREATE INDEX IDX_SMState_Id on SMState (id);
|
||||
-- CREATE INDEX IDX_Signature_TimeEnter on Signature (timeEnter);
|
||||
-- CREATE INDEX IDX_VisualWord_TimeEnter on VisualWord (timeEnter);
|
||||
CREATE INDEX IDX_Neighbor_Sid on Neighbor (sid);
|
||||
CREATE INDEX IDX_Map_Node_Word_node_id on Map_Node_Word (node_id);
|
||||
CREATE INDEX IDX_Sensor_Id on Sensor (id);
|
||||
CREATE INDEX IDX_Link_from_id on Link (from_id);
|
||||
|
||||
-- *******************************************************************
|
||||
-- Data
|
||||
-- *******************************************************************
|
||||
INSERT INTO SignatureType(type) VALUES ('KeypointSignature');
|
||||
INSERT INTO SignatureType(type) VALUES ('SMSignature');
|
||||
|
||||
-- *******************************************************************
|
||||
-- TESTS
|
||||
-- *******************************************************************
|
||||
-- *** Data Test ***
|
||||
/*
|
||||
INSERT INTO Signature VALUES(1, 'surf', null, null, null);
|
||||
INSERT INTO Signature VALUES(2, 'surf', null, null, null);
|
||||
INSERT INTO Signature VALUES(3, 'surf', null, null, null);
|
||||
INSERT INTO VisualWord VALUES (1, 1, 2,'0.213213 0.4352323', null);
|
||||
INSERT INTO VisualWord VALUES (2, 1, 2,'0.213213 0.4352323', null);
|
||||
INSERT INTO VisualWord VALUES (3, 3, 2,'0.213213 0.4352323', null);
|
||||
INSERT INTO Map_SS_VW VALUES (1, 1, 0,0,0,0,0, null);
|
||||
INSERT INTO Map_SS_VW VALUES (2, 1, 0,0,0,0,0, null);
|
||||
INSERT INTO Map_SS_VW VALUES (2, 2, 0,0,0,0,0, null);
|
||||
*/
|
||||
|
||||
/*
|
||||
-- For loading words
|
||||
SELECT vw.id, vw.laplacian, vw.descriptorSize, vw.descriptor, m.signatureId FROM VisualWord as vw INNER JOIN Map_SS_VW as m on vw.id=m.visualWordId ORDER BY vw.id;
|
||||
*/
|
||||
|
||||
|
||||
-- Refreshing the dictionary
|
||||
/*SELECT * FROM Map_SS_VW;
|
||||
SELECT * FROM VisualWord;*/
|
||||
/*
|
||||
DELETE FROM VisualWord;
|
||||
INSERT INTO VisualWord VALUES (1, 1, 2,'0.213213 0.4352323', null);
|
||||
DELETE FROM Map_SS_VW WHERE NOT EXISTS (SELECT id FROM VisualWord WHERE id = Map_SS_VW.visualWordId);
|
||||
*/
|
||||
/*SELECT * FROM Map_SS_VW;
|
||||
SELECT * FROM VisualWord;*/
|
||||
|
||||
/*
|
||||
-- Loading only signatures on the last short time memory based on DATE
|
||||
INSERT INTO Signature VALUES(4, 'surf', null, null, null);
|
||||
INSERT INTO Signature VALUES(5, 'surf', 4, null, null);
|
||||
INSERT INTO Signature VALUES(6, 'surf', null, null, null);
|
||||
INSERT INTO Map_SS_VW VALUES (4, 1, 0,0,0,0,0, null);
|
||||
SELECT s.id FROM Signature AS s WHERE s.timeEnter >= (SELECT vw.timeEnter FROM VisualWord AS vw LIMIT 1) AND s.loopClosureId IS NULL;
|
||||
*/
|
||||
|
||||
|
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 2.4 MiB |
@@ -1,2 +1 @@
|
||||
ADD_SUBDIRECTORY( src )
|
||||
ADD_SUBDIRECTORY( ExamplePlot )
|
||||
ADD_SUBDIRECTORY( src )
|
||||
@@ -1,36 +0,0 @@
|
||||
|
||||
ADD_DEFINITIONS(-DPLOT_WIDGET_OUT_OF_LIB)
|
||||
|
||||
### Qt Gui stuff ###
|
||||
SET(headers_ui
|
||||
../src/Plot.h
|
||||
MainWindow.h
|
||||
)
|
||||
|
||||
#This will generate moc_* for Qt
|
||||
QT4_WRAP_CPP(moc_srcs ${headers_ui})
|
||||
### Qt Gui stuff end###
|
||||
|
||||
SET(SRC_FILES
|
||||
../src/Plot.cpp
|
||||
main.cpp
|
||||
${moc_srcs}
|
||||
)
|
||||
|
||||
SET(INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../src
|
||||
)
|
||||
|
||||
INCLUDE(${QT_USE_FILE})
|
||||
|
||||
SET(LIBRARIES
|
||||
${QT_LIBRARIES}
|
||||
)
|
||||
|
||||
#include files
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
|
||||
|
||||
# create an executable file named "examplePlot" from the source files
|
||||
ADD_EXECUTABLE(examplePlot ${SRC_FILES})
|
||||
# Linking with Qt libraries
|
||||
TARGET_LINK_LIBRARIES(examplePlot ${LIBRARIES})
|
||||
@@ -1,66 +0,0 @@
|
||||
|
||||
#ifndef MAINWINDOW_H_
|
||||
#define MAINWINDOW_H_
|
||||
|
||||
#include <QtGui/QMainWindow>
|
||||
#include <QtGui/QSlider>
|
||||
#include <QtGui/QHBoxLayout>
|
||||
#include <QtCore/QTimer>
|
||||
#include "Plot.h"
|
||||
|
||||
// Note : compiled with -DPLOT_WIDGET_OUT_OF_LIB to
|
||||
// remove rtabmap's namespace and UtiLite dependency of Plot.
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MainWindow() {
|
||||
//Plot
|
||||
Plot * plot = new Plot(this);
|
||||
plot->setObjectName("Figure 1");
|
||||
plot->setMaxVisibleItems(50);
|
||||
plot->showRefreshRate(true);
|
||||
PlotCurve * curveA = new PlotCurve("Curve A", this);
|
||||
PlotCurve * curveB = new PlotCurve("Curve B", this);
|
||||
curveA->setPen(QPen(Qt::red));
|
||||
curveB->setPen(QPen(Qt::blue));
|
||||
plot->addCurve(curveA); // ownership transferred
|
||||
plot->addCurve(curveB); // ownership transferred
|
||||
connect(this, SIGNAL(valueUpdatedA(float)), curveA, SLOT(addValue(float)));
|
||||
connect(this, SIGNAL(valueUpdatedB(float)), curveB, SLOT(addValue(float)));
|
||||
|
||||
//Control
|
||||
QSlider * slider = new QSlider(Qt::Vertical, this);
|
||||
slider->setMinimum(1); // Hz
|
||||
slider->setMaximum(100); // Hz
|
||||
slider->setValue(10);
|
||||
connect(slider, SIGNAL(valueChanged(int)), this, SLOT(setRate(int)));
|
||||
|
||||
// layout
|
||||
QWidget * placeHolder = new QWidget(this);
|
||||
this->setCentralWidget(placeHolder);
|
||||
QHBoxLayout * hlayout = new QHBoxLayout(placeHolder);
|
||||
hlayout->addWidget(plot, 1);
|
||||
hlayout->addWidget(slider);
|
||||
|
||||
connect(&timer_, SIGNAL(timeout()), this, SLOT(updateCounter()));
|
||||
setRate(slider->value());
|
||||
qsrand(1);
|
||||
}
|
||||
~MainWindow() {}
|
||||
public slots:
|
||||
void updateCounter() {
|
||||
emit valueUpdatedA(qrand() % 100);
|
||||
emit valueUpdatedB(qrand() % 50);
|
||||
}
|
||||
void setRate(int rate) {
|
||||
timer_.start(1000/rate);
|
||||
}
|
||||
signals:
|
||||
void valueUpdatedA(float);
|
||||
void valueUpdatedB(float);
|
||||
private:
|
||||
QTimer timer_;
|
||||
};
|
||||
|
||||
#endif /* MAINWINDOW_H_ */
|
||||
@@ -1,12 +0,0 @@
|
||||
|
||||
#include <QtGui/QApplication>
|
||||
#include "MainWindow.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
QApplication app(argc, argv);
|
||||
MainWindow mainWindow;
|
||||
mainWindow.show();
|
||||
app.connect( &app, SIGNAL( lastWindowClosed() ),
|
||||
&app, SLOT( quit() ) );
|
||||
return app.exec();
|
||||
}
|
||||
@@ -20,6 +20,8 @@
|
||||
#ifndef IMAGEVIEW_H_
|
||||
#define IMAGEVIEW_H_
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include <QtGui/QGraphicsView>
|
||||
#include <QtCore/QRectF>
|
||||
|
||||
@@ -28,7 +30,7 @@ class QMenu;
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
class ImageView : public QGraphicsView {
|
||||
class RTABMAP_EXP ImageView : public QGraphicsView {
|
||||
|
||||
Q_OBJECT
|
||||
|
||||
@@ -42,6 +44,9 @@ public:
|
||||
bool isFeaturesShown();
|
||||
bool isLinesShown();
|
||||
|
||||
void setFeaturesShown(bool shown);
|
||||
void setLinesShown(bool shown);
|
||||
|
||||
protected:
|
||||
virtual void contextMenuEvent(QContextMenuEvent * e);
|
||||
virtual void wheelEvent(QWheelEvent * e);
|
||||
@@ -20,6 +20,8 @@
|
||||
#ifndef KEYPOINTITEM_H_
|
||||
#define KEYPOINTITEM_H_
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include <QtGui/QGraphicsEllipseItem>
|
||||
#include <QtGui/QGraphicsTextItem>
|
||||
#include <QtGui/QPen>
|
||||
@@ -27,7 +29,7 @@
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
class KeypointItem : public QGraphicsEllipseItem
|
||||
class RTABMAP_EXP KeypointItem : public QGraphicsEllipseItem
|
||||
{
|
||||
public:
|
||||
KeypointItem(qreal x, qreal y, int r, const QString & info, const QColor & color = Qt::green, QGraphicsItem * parent = 0);
|
||||
@@ -30,6 +30,9 @@
|
||||
|
||||
namespace rtabmap {
|
||||
class Camera;
|
||||
class Micro;
|
||||
class CameraMicro;
|
||||
class DBReader;
|
||||
}
|
||||
|
||||
class QGraphicsScene;
|
||||
@@ -85,6 +88,7 @@ protected:
|
||||
virtual void resizeEvent(QResizeEvent* anEvent);
|
||||
|
||||
private slots:
|
||||
void beep();
|
||||
void startDetection();
|
||||
void pauseDetection();
|
||||
void stopDetection();
|
||||
@@ -95,6 +99,8 @@ private slots:
|
||||
void selectImages();
|
||||
void selectVideo();
|
||||
void selectStream();
|
||||
void selectMic();
|
||||
void selectAudioFile();
|
||||
void selectDatabase();
|
||||
void resetTheMemory();
|
||||
void dumpTheMemory();
|
||||
@@ -112,6 +118,15 @@ private slots:
|
||||
void changeImgRateSetting();
|
||||
void changeTimeLimitSetting();
|
||||
void captureScreen();
|
||||
void setAspectRatio(int w, int h);
|
||||
void setAspectRatio16_9();
|
||||
void setAspectRatio16_10();
|
||||
void setAspectRatio4_3();
|
||||
void setAspectRatio240p();
|
||||
void setAspectRatio360p();
|
||||
void setAspectRatio480p();
|
||||
void setAspectRatio720p();
|
||||
void setAspectRatio1080p();
|
||||
|
||||
signals:
|
||||
void statsReceived(const rtabmap::Statistics &);
|
||||
@@ -128,13 +143,18 @@ signals:
|
||||
private:
|
||||
void drawKeypoints(const std::multimap<int, cv::KeyPoint> & refWords, const std::multimap<int, cv::KeyPoint> & loopWords);
|
||||
void setupMainLayout(bool vertical);
|
||||
void updateSelectSourceMenu(int type);
|
||||
void updateSelectSourceImageMenu(int type);
|
||||
void updateSelectSourceAudioMenu(int type);
|
||||
void updateSelectSourceDatabase(bool used);
|
||||
|
||||
private:
|
||||
Ui_mainWindow * _ui;
|
||||
|
||||
State _state;
|
||||
rtabmap::Camera * _camera;
|
||||
rtabmap::Micro * _mic;
|
||||
rtabmap::CameraMicro * _cameraMic;
|
||||
rtabmap::DBReader * _dbReader;
|
||||
|
||||
SrcType _srcType;
|
||||
QString _srcPath;
|
||||
@@ -156,8 +176,13 @@ private:
|
||||
PdfPlotCurve * _posteriorCurve;
|
||||
PdfPlotCurve * _likelihoodCurve;
|
||||
|
||||
UPlotCurve * _audioCurve;
|
||||
UPlotCurve * _audioCurveLoop;
|
||||
|
||||
DetailedProgressDialog * _initProgressDialog;
|
||||
QActionGroup * _selectSourceGrp;
|
||||
QActionGroup * _selectSourceImageGrp;
|
||||
QActionGroup * _selectSourceAudioGrp;
|
||||
|
||||
|
||||
QString _graphSavingFileName;
|
||||
QString _autoScreenCaptureFormat;
|
||||
|
||||
@@ -38,11 +38,10 @@ class QMainWindow;
|
||||
class QLineEdit;
|
||||
class QSlider;
|
||||
class QProgressDialog;
|
||||
class UPlotCurve;
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
class PlotCurve;
|
||||
|
||||
class RTABMAP_EXP PreferencesDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -64,8 +63,13 @@ public:
|
||||
kSrcUndef,
|
||||
kSrcUsbDevice,
|
||||
kSrcImages,
|
||||
kSrcVideo,
|
||||
kSrcDatabase
|
||||
kSrcVideo
|
||||
};
|
||||
|
||||
enum SrcAudio {
|
||||
kSrcAudioUndef,
|
||||
kSrcAudioMicDevice,
|
||||
kSrcAudioFile
|
||||
};
|
||||
|
||||
public:
|
||||
@@ -102,13 +106,17 @@ public:
|
||||
QString getWorkingDirectory();
|
||||
|
||||
// source panel
|
||||
double getGeneralImageRate() const;
|
||||
double getGeneralInputRate() const;
|
||||
bool isSourceImageUsed() const;
|
||||
bool isSourceAudioUsed() const;
|
||||
bool isSourceDatabaseUsed() const;
|
||||
bool getGeneralAutoRestart() const;
|
||||
bool getGeneralCameraKeypoints() const;
|
||||
int getSourceType() const;
|
||||
QString getSourceTypeStr() const;
|
||||
int getSourceImageType() const;
|
||||
QString getSourceImageTypeStr() const;
|
||||
int getSourceWidth() const;
|
||||
int getSourceHeight() const;
|
||||
int getFramesDropped() const;
|
||||
QString getSourceImagesPath() const; //Images group
|
||||
QString getSourceImagesSuffix() const; //Images group
|
||||
int getSourceImagesSuffixIndex() const; //Images group
|
||||
@@ -116,31 +124,44 @@ public:
|
||||
bool getSourceImagesRefreshDir() const; //Images group
|
||||
QString getSourceVideoPath() const; //Video group
|
||||
int getSourceUsbDeviceId() const; //UsbDevice group
|
||||
QString getSourceDatabasePath() const; //Database group
|
||||
bool getSourceDatabaseIgnoreChildren() const; //Database group
|
||||
bool getSourceDatabaseLoadActions() const; //Database group
|
||||
int getSourceAudioType() const; //Audio group
|
||||
QString getSourceAudioTypeStr() const; //Audio group
|
||||
int getSourceMicDevice() const; //Audio group
|
||||
int getSourceMicFs() const; //Audio group
|
||||
int getSourceMicSampleSize() const; //Audio group
|
||||
QString getSourceAudioPath() const; //Audio group
|
||||
bool getSourceAudioPlayWhileRecording() const; //Audio group
|
||||
QString getSourceDatabasePath() const; //Database group
|
||||
|
||||
//
|
||||
bool isImagesKept() const;
|
||||
float getTimeLimit() const;
|
||||
int getMemoryType() const;
|
||||
|
||||
//specific
|
||||
bool isStatisticsPublished() const;
|
||||
double getLoopThr() const;
|
||||
double getRetrievalThr() const;
|
||||
double getVpThr() const;
|
||||
double getExpThr() const;
|
||||
|
||||
//
|
||||
void disableSourceAudio();
|
||||
void disableGeneralCameraKeypoints();
|
||||
|
||||
signals:
|
||||
void settingsChanged(PreferencesDialog::PANEL_FLAGS);
|
||||
void settingsChanged(rtabmap::ParametersMap);
|
||||
|
||||
public slots:
|
||||
void setInputRate(double value);
|
||||
void setHardThr(int value);
|
||||
void setRetrievalThr(int value);
|
||||
void setImgRate(double value);
|
||||
void setAutoRestart(bool value);
|
||||
void setTimeLimit(float value);
|
||||
void selectSource(Src src = kSrcUndef);
|
||||
void selectSourceImage(Src src = kSrcUndef);
|
||||
void selectSourceAudio(SrcAudio = kSrcAudioUndef);
|
||||
void selectSourceDatabase(bool user = false);
|
||||
|
||||
private slots:
|
||||
void closeDialog ( QAbstractButton * button );
|
||||
@@ -160,6 +181,7 @@ private slots:
|
||||
void changeDictionaryPath();
|
||||
void readSettingsEnd();
|
||||
void setupTreeView();
|
||||
void updateBasicParameter();
|
||||
|
||||
protected:
|
||||
virtual void showEvent ( QShowEvent * event );
|
||||
|
||||
@@ -20,12 +20,14 @@
|
||||
#ifndef QTIPL_H
|
||||
#define QTIPL_H
|
||||
|
||||
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
|
||||
|
||||
#include <QtGui/QImage>
|
||||
#include <opencv2/core/core.hpp>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
QImage Ipl2QImage(const IplImage *newImage);
|
||||
QImage RTABMAP_EXP Ipl2QImage(const IplImage *newImage, int alpha = 255);
|
||||
|
||||
}
|
||||
|
||||
@@ -6,8 +6,7 @@ SET(headers_ui
|
||||
../include/${PROJECT_PREFIX}/gui/PreferencesDialog.h
|
||||
./AboutDialog.h
|
||||
./ConsoleWidget.h
|
||||
./ImageView.h
|
||||
./Plot.h
|
||||
../include/${PROJECT_PREFIX}/gui/ImageView.h
|
||||
./PdfPlot.h
|
||||
./StatsToolBox.h
|
||||
./DetailedProgressDialog.h
|
||||
@@ -44,7 +43,6 @@ SET(SRC_FILES
|
||||
./KeypointItem.cpp
|
||||
./qtipl.cpp
|
||||
./ImageView.cpp
|
||||
./Plot.cpp
|
||||
./PdfPlot.cpp
|
||||
./StatsToolBox.cpp
|
||||
./DetailedProgressDialog.cpp
|
||||
@@ -57,6 +55,7 @@ SET(SRC_FILES
|
||||
)
|
||||
|
||||
SET(INCLUDE_DIRS
|
||||
${PROJECT_SOURCE_DIR}/corelib/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${UTILITE_INCLUDE_DIRS}
|
||||
@@ -75,27 +74,19 @@ SET(LIBRARIES
|
||||
#include files
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
|
||||
|
||||
IF(WIN32)
|
||||
IF(BUILD_SHARED_LIBS)
|
||||
ADD_DEFINITIONS(-DRTABMAP_EXPORTS)
|
||||
ELSE()
|
||||
ADD_DEFINITIONS(-DRTABMAP_EXPORTS_STATIC)
|
||||
ENDIF()
|
||||
ENDIF(WIN32)
|
||||
|
||||
# create an executable file named "AvpdGui" from the source files
|
||||
ADD_LIBRARY(guilib ${SRC_FILES})
|
||||
# create a library from the source files
|
||||
ADD_LIBRARY(rtabmap_guilib ${SRC_FILES})
|
||||
# Linking with Qt libraries
|
||||
TARGET_LINK_LIBRARIES(guilib corelib ${LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(rtabmap_guilib rtabmap_corelib ${LIBRARIES})
|
||||
|
||||
SET_TARGET_PROPERTIES(
|
||||
guilib
|
||||
rtabmap_guilib
|
||||
PROPERTIES
|
||||
OUTPUT_NAME ${PROJECT_PREFIX}_gui
|
||||
INSTALL_NAME_DIR ${CMAKE_INSTALL_PREFIX}/lib
|
||||
)
|
||||
|
||||
INSTALL(TARGETS guilib
|
||||
INSTALL(TARGETS rtabmap_guilib
|
||||
RUNTIME DESTINATION bin COMPONENT runtime
|
||||
LIBRARY DESTINATION lib COMPONENT devel
|
||||
ARCHIVE DESTINATION lib COMPONENT devel)
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* CameraMicro.h
|
||||
*
|
||||
* Created on: 2012-05-27
|
||||
* Author: mathieu
|
||||
*/
|
||||
|
||||
#ifndef CAMERAMICRO_H_
|
||||
#define CAMERAMICRO_H_
|
||||
|
||||
#include "rtabmap/core/Camera.h"
|
||||
#include "rtabmap/core/Micro.h"
|
||||
#include "rtabmap/core/SensorimotorEvent.h"
|
||||
#include <utilite/UThreadNode.h>
|
||||
#include <utilite/UEventsManager.h>
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
|
||||
class CameraMicro : public UThreadNode
|
||||
{
|
||||
public:
|
||||
CameraMicro(Camera * camera, Micro * micro) :
|
||||
camera_(camera),
|
||||
micro_(micro)
|
||||
{
|
||||
}
|
||||
|
||||
protected:
|
||||
void mainLoopBegin()
|
||||
{
|
||||
if(!camera_ || !micro_ )
|
||||
{
|
||||
UERROR("Camera and/or Micro are null");
|
||||
this->kill();
|
||||
return;
|
||||
}
|
||||
micro_->startRecorder();
|
||||
}
|
||||
|
||||
void mainLoop()
|
||||
{
|
||||
cv::Mat frameFreq;
|
||||
// frame rate should depend on micro and camera frame rate
|
||||
// (getFrame() and takeImage() are blocking calls)
|
||||
cv::Mat frame = micro_->getFrame(frameFreq, true);
|
||||
if(frame.empty())
|
||||
{
|
||||
if(this->isRunning())
|
||||
{
|
||||
UEventsManager::post(new MicroEvent(MicroEvent::kTypeNoMoreFrames));
|
||||
this->kill();
|
||||
}
|
||||
return;
|
||||
}
|
||||
cv::Mat image = camera_->takeImage();
|
||||
if(image.empty())
|
||||
{
|
||||
UEventsManager::post(new CameraEvent(CameraEvent::kCodeNoMoreImages));
|
||||
this->kill();
|
||||
return;
|
||||
}
|
||||
std::list<Sensor> sensors;
|
||||
sensors.push_back(Sensor(image, Sensor::kTypeImage));
|
||||
sensors.push_back(Sensor(frameFreq, Sensor::kTypeAudioFreqSqrdMagn));
|
||||
UEventsManager::post(new SensorimotorEvent(sensors, std::list<Actuator>()));
|
||||
}
|
||||
|
||||
void mainLoopKill()
|
||||
{
|
||||
if(micro_)
|
||||
{
|
||||
micro_->stop();
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
Camera * camera_;
|
||||
Micro * micro_;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif /* CAMERAMICRO_H_ */
|
||||
@@ -74,16 +74,16 @@ void ConsoleWidget::handleEvent(UEvent * anEvent)
|
||||
{
|
||||
if(logEvent->getCode() == ULogger::kFatal)
|
||||
{
|
||||
_timer.start(0);
|
||||
QMetaObject::invokeMethod(&_timer, "start", Q_ARG(int, 0));
|
||||
}
|
||||
else
|
||||
{
|
||||
_timer.start(OLD_TIME);
|
||||
QMetaObject::invokeMethod(&_timer, "start", Q_ARG(int, OLD_TIME));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_timer.start(0);
|
||||
QMetaObject::invokeMethod(&_timer, "start", Q_ARG(int, 0));
|
||||
}
|
||||
|
||||
if(logEvent->getCode() == ULogger::kFatal)
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "ImageView.h"
|
||||
#include "rtabmap/gui/ImageView.h"
|
||||
|
||||
#include <QtGui/QWheelEvent>
|
||||
#include <QtCore/qmath.h>
|
||||
@@ -26,7 +26,7 @@
|
||||
#include <QtCore/QDir>
|
||||
#include <QtGui/QAction>
|
||||
#include "utilite/ULogger.h"
|
||||
#include "KeypointItem.h"
|
||||
#include "rtabmap/gui/KeypointItem.h"
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
@@ -73,11 +73,23 @@ bool ImageView::isFeaturesShown()
|
||||
return _showFeatures->isChecked();
|
||||
}
|
||||
|
||||
void ImageView::setFeaturesShown(bool shown)
|
||||
{
|
||||
_showFeatures->setChecked(shown);
|
||||
this->updateItemsShown();
|
||||
}
|
||||
|
||||
bool ImageView::isLinesShown()
|
||||
{
|
||||
return _showLines->isChecked();
|
||||
}
|
||||
|
||||
void ImageView::setLinesShown(bool shown)
|
||||
{
|
||||
_showLines->setChecked(shown);
|
||||
this->updateItemsShown();
|
||||
}
|
||||
|
||||
void ImageView::contextMenuEvent(QContextMenuEvent * e)
|
||||
{
|
||||
QAction * action = _menu->exec(e->globalPos());
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "KeypointItem.h"
|
||||
#include "rtabmap/gui/KeypointItem.h"
|
||||
|
||||
#include <QtGui/QPen>
|
||||
#include <QtGui/QBrush>
|
||||
|
||||
+931
-389
File diff suppressed because it is too large
Load Diff
@@ -23,7 +23,7 @@
|
||||
namespace rtabmap {
|
||||
|
||||
PdfPlotItem::PdfPlotItem(float dataX, float dataY, float width, int childCount) :
|
||||
PlotItem(dataX, dataY, width),
|
||||
UPlotItem(dataX, dataY, width),
|
||||
_img(0),
|
||||
_imagesRef(0)
|
||||
{
|
||||
@@ -85,7 +85,7 @@ void PdfPlotItem::showDescription(bool shown)
|
||||
if(_img)
|
||||
_img->setVisible(false);
|
||||
}
|
||||
PlotItem::showDescription(shown);
|
||||
UPlotItem::showDescription(shown);
|
||||
}
|
||||
|
||||
|
||||
@@ -93,7 +93,7 @@ void PdfPlotItem::showDescription(bool shown)
|
||||
|
||||
|
||||
PdfPlotCurve::PdfPlotCurve(const QString & name, const QMap<int, QByteArray> * imagesMapRef = 0, QObject * parent) :
|
||||
PlotCurve(name, parent),
|
||||
UPlotCurve(name, parent),
|
||||
_imagesMapRef(imagesMapRef)
|
||||
{
|
||||
|
||||
@@ -106,7 +106,7 @@ PdfPlotCurve::~PdfPlotCurve()
|
||||
|
||||
void PdfPlotCurve::clear()
|
||||
{
|
||||
PlotCurve::clear();
|
||||
UPlotCurve::clear();
|
||||
}
|
||||
|
||||
void PdfPlotCurve::setData(const QMap<int, float> & dataMap, const QMap<int, int> & weightsMap, int lastId)
|
||||
|
||||
@@ -20,11 +20,11 @@
|
||||
#ifndef PDFPLOT_H_
|
||||
#define PDFPLOT_H_
|
||||
|
||||
#include "Plot.h"
|
||||
#include <utilite/UPlot.h>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
class PdfPlotItem : public PlotItem
|
||||
class PdfPlotItem : public UPlotItem
|
||||
{
|
||||
public:
|
||||
PdfPlotItem(float dataX, float dataY, float width, int childCount = -1);
|
||||
@@ -47,7 +47,7 @@ private:
|
||||
|
||||
};
|
||||
|
||||
class PdfPlotCurve : public PlotCurve
|
||||
class PdfPlotCurve : public UPlotCurve
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
|
||||
-2387
File diff suppressed because it is too large
Load Diff
@@ -1,393 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2010-2011, Mathieu Labbe and IntRoLab - Universite de Sherbrooke
|
||||
*
|
||||
* This file is part of RTAB-Map.
|
||||
*
|
||||
* RTAB-Map is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* RTAB-Map is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#ifndef PLOT_H_
|
||||
#define PLOT_H_
|
||||
|
||||
// Uncomment this to disable all references to RTAB-Map and UtiLite dependencies
|
||||
//#define PLOT_WIDGET_OUT_OF_LIB
|
||||
|
||||
#include <QtGui/QFrame>
|
||||
#include <QtCore/QList>
|
||||
#include <QtCore/QMap>
|
||||
#include <QtGui/QPen>
|
||||
#include <QtGui/QBrush>
|
||||
#include <QtGui/QGraphicsEllipseItem>
|
||||
#include <QtCore/QMutex>
|
||||
#include <QtGui/QLabel>
|
||||
#include <QtGui/QPushButton>
|
||||
#include <QtCore/QTime>
|
||||
|
||||
class QGraphicsView;
|
||||
class QGraphicsScene;
|
||||
class QGraphicsItem;
|
||||
class QFormLayout;
|
||||
|
||||
#ifndef PLOT_WIDGET_OUT_OF_LIB
|
||||
namespace rtabmap {
|
||||
#endif
|
||||
|
||||
class PlotItem : public QGraphicsEllipseItem
|
||||
{
|
||||
public:
|
||||
PlotItem(qreal dataX, qreal dataY, qreal width=2);
|
||||
PlotItem(const QPointF & data, qreal width=2);
|
||||
virtual ~PlotItem();
|
||||
|
||||
public:
|
||||
void setNextItem(PlotItem * nextItem);
|
||||
void setPreviousItem(PlotItem * previousItem);
|
||||
void setData(const QPointF & data);
|
||||
|
||||
PlotItem * nextItem() const {return _nextItem;}
|
||||
PlotItem * previousItem() const {return _previousItem;};
|
||||
const QPointF & data() const {return _data;}
|
||||
|
||||
protected:
|
||||
virtual void hoverEnterEvent(QGraphicsSceneHoverEvent * event);
|
||||
virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent * event);
|
||||
virtual void focusInEvent(QFocusEvent * event);
|
||||
virtual void focusOutEvent(QFocusEvent * event);
|
||||
virtual void keyReleaseEvent(QKeyEvent * keyEvent);
|
||||
|
||||
virtual void showDescription(bool shown);
|
||||
|
||||
private:
|
||||
QPointF _data;
|
||||
QGraphicsTextItem * _text;
|
||||
PlotItem * _previousItem;
|
||||
PlotItem * _nextItem;
|
||||
};
|
||||
|
||||
class Plot;
|
||||
|
||||
class PlotCurve : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PlotCurve(const QString & name, QObject * parent = 0);
|
||||
PlotCurve(const QString & name, const QVector<PlotItem *> data, QObject * parent = 0);
|
||||
PlotCurve(const QString & name, const QVector<float> & x, const QVector<float> & y, QObject * parent = 0);
|
||||
virtual ~PlotCurve();
|
||||
|
||||
const QPen & pen() const {return _pen;}
|
||||
const QBrush & brush() const {return _brush;}
|
||||
void setPen(const QPen & pen);
|
||||
void setBrush(const QBrush & brush);
|
||||
|
||||
void setDefaultStepX(float stepX) {_defaultStepX = stepX;}
|
||||
QString name() const {return _name;}
|
||||
int itemsSize() const;
|
||||
QPointF getItemData(int index);
|
||||
void setStartX(float startX) {_startX = startX;}
|
||||
bool isVisible() const {return _visible;}
|
||||
void setData(QVector<PlotItem*> & data); // take the ownership
|
||||
void setData(const QVector<float> & x, const QVector<float> & y);
|
||||
void getData(QVector<float> & x, QVector<float> & y) const; // only call in Qt MainThread
|
||||
void draw(QPainter * painter);
|
||||
|
||||
public slots:
|
||||
virtual void clear();
|
||||
void setVisible(bool visible);
|
||||
void addValue(PlotItem * data); // take the ownership
|
||||
void addValue(float y);
|
||||
void addValue(float x, float y);
|
||||
void addValue(const QString & y);
|
||||
void addValues(QVector<PlotItem *> & data); // take the ownership
|
||||
void addValues(const QVector<float> & xs, const QVector<float> & ys);
|
||||
void addValues(const QVector<float> & ys);
|
||||
|
||||
signals:
|
||||
void dataChanged(const PlotCurve *);
|
||||
|
||||
protected:
|
||||
friend class Plot;
|
||||
void attach(Plot * plot);
|
||||
void detach(Plot * plot);
|
||||
void updateMinMax();
|
||||
const QVector<float> & getMinMax() const {return _minMax;}
|
||||
int removeItem(int index);
|
||||
void _addValue(PlotItem * data);;
|
||||
virtual bool isMinMaxValid() const {return _minMax.size();}
|
||||
virtual void update(float scaleX, float scaleY, float offsetX, float offsetY, float xDir, float yDir, bool allDataKept);
|
||||
QList<QGraphicsItem *> _items;
|
||||
Plot * _plot;
|
||||
|
||||
private:
|
||||
void removeItem(PlotItem * item);
|
||||
|
||||
private:
|
||||
QString _name;
|
||||
QPen _pen;
|
||||
QBrush _brush;
|
||||
float _defaultStepX;
|
||||
float _startX;
|
||||
bool _visible;
|
||||
bool _valuesShown;
|
||||
QVector<float> _minMax; // minX, maxX, minY, maxY
|
||||
};
|
||||
|
||||
|
||||
class ThresholdCurve : public PlotCurve
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
ThresholdCurve(const QString & name, float thesholdValue, Qt::Orientation orientation = Qt::Horizontal, QObject * parent = 0);
|
||||
virtual ~ThresholdCurve();
|
||||
|
||||
public slots:
|
||||
void setThreshold(float threshold);
|
||||
void setOrientation(Qt::Orientation orientation);
|
||||
|
||||
protected:
|
||||
friend class Plot;
|
||||
virtual void update(float scaleX, float scaleY, float offsetX, float offsetY, float xDir, float yDir, bool allDataKept);
|
||||
virtual bool isMinMaxValid() const {return false;}
|
||||
|
||||
private:
|
||||
Qt::Orientation _orientation;
|
||||
};
|
||||
|
||||
|
||||
class PlotAxis : public QWidget
|
||||
{
|
||||
public:
|
||||
PlotAxis(Qt::Orientation orientation = Qt::Horizontal, float min=0, float max=1, QWidget * parent = 0);
|
||||
virtual ~PlotAxis();
|
||||
|
||||
public:
|
||||
void setAxis(float & min, float & max);
|
||||
int border() const {return _border;}
|
||||
int step() const {return _step;}
|
||||
int count() const {return _count;}
|
||||
void setReversed(bool reversed); // Vertical :bottom->up, horizontal :right->left
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent * event);
|
||||
|
||||
private:
|
||||
Qt::Orientation _orientation;
|
||||
float _min;
|
||||
float _max;
|
||||
int _count;
|
||||
int _step;
|
||||
bool _reversed;
|
||||
int _gradMaxDigits;
|
||||
int _border;
|
||||
};
|
||||
|
||||
|
||||
class PlotLegendItem : public QPushButton
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PlotLegendItem(const PlotCurve * curve, QWidget * parent = 0);
|
||||
virtual ~PlotLegendItem();
|
||||
const PlotCurve * curve() const {return _curve;}
|
||||
|
||||
signals:
|
||||
void legendItemRemoved(const PlotCurve *);
|
||||
|
||||
protected:
|
||||
virtual void contextMenuEvent(QContextMenuEvent * event);
|
||||
|
||||
private:
|
||||
const PlotCurve * _curve;
|
||||
QMenu * _menu;
|
||||
QAction * _aChangeText;
|
||||
QAction * _aResetText;
|
||||
QAction * _aRemoveCurve;
|
||||
QAction * _aCopyToClipboard;
|
||||
};
|
||||
|
||||
|
||||
class PlotLegend : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PlotLegend(QWidget * parent = 0);
|
||||
virtual ~PlotLegend();
|
||||
|
||||
void setFlat(bool on);
|
||||
bool isFlat() const {return _flat;}
|
||||
void addItem(const PlotCurve * curve);
|
||||
QPixmap createSymbol(const QPen & pen, const QBrush & brush);
|
||||
bool remove(const PlotCurve * curve);
|
||||
|
||||
public slots:
|
||||
void removeLegendItem(const PlotCurve * curve);
|
||||
|
||||
signals:
|
||||
void legendItemRemoved(const PlotCurve * curve);
|
||||
void legendItemToggled(const PlotCurve * curve, bool toggled);
|
||||
|
||||
protected:
|
||||
virtual void contextMenuEvent(QContextMenuEvent * event);
|
||||
|
||||
private slots:
|
||||
void redirectToggled(bool);
|
||||
|
||||
private:
|
||||
bool _flat;
|
||||
QMenu * _menu;
|
||||
QAction * _aUseFlatButtons;
|
||||
};
|
||||
|
||||
|
||||
class OrientableLabel : public QLabel
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
OrientableLabel(const QString & text, Qt::Orientation orientation = Qt::Horizontal, QWidget * parent = 0);
|
||||
virtual ~OrientableLabel();
|
||||
Qt::Orientation orientation() const {return _orientation;}
|
||||
void setOrientation(Qt::Orientation orientation);
|
||||
QSize sizeHint() const;
|
||||
QSize minimumSizeHint() const;
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent* event);
|
||||
private:
|
||||
Qt::Orientation _orientation;
|
||||
};
|
||||
|
||||
/*
|
||||
* TODO It could be cool to right-click on a dot in the
|
||||
* plot to create a new plot to monitor the dot value changes.
|
||||
*/
|
||||
class Plot : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Plot(QWidget * parent = 0);
|
||||
virtual ~Plot();
|
||||
|
||||
PlotCurve * addCurve(const QString & curveName);
|
||||
bool addCurve(PlotCurve * curves);
|
||||
QStringList curveNames();
|
||||
bool contains(const QString & curveName);
|
||||
void removeCurves();
|
||||
ThresholdCurve * addThreshold(const QString & name, float value, Qt::Orientation orientation = Qt::Horizontal);
|
||||
QString title() const {return this->objectName();}
|
||||
QPen getRandomPenColored();
|
||||
void showLegend(bool shown);
|
||||
void showGrid(bool shown);
|
||||
void showRefreshRate(bool shown);
|
||||
void keepAllData(bool kept);
|
||||
void showXAxis(bool shown) {_horizontalAxis->setVisible(shown);}
|
||||
void showYAxis(bool shown) {_verticalAxis->setVisible(shown);}
|
||||
void setVariableXAxis() {_fixedAxis[0] = false;}
|
||||
void setVariableYAxis() {_fixedAxis[1] = false;}
|
||||
void setFixedXAxis(float x1, float x2);
|
||||
void setFixedYAxis(float y1, float y2);
|
||||
void setMaxVisibleItems(int maxVisibleItems);
|
||||
void setTitle(const QString & text);
|
||||
void setXLabel(const QString & text);
|
||||
void setYLabel(const QString & text, Qt::Orientation orientation = Qt::Vertical);
|
||||
void setWorkingDirectory(const QString & workingDirectory);
|
||||
void setGraphicsView(bool on);
|
||||
QRectF sceneRect() const;
|
||||
|
||||
public slots:
|
||||
void removeCurve(const PlotCurve * curve);
|
||||
void showCurve(const PlotCurve * curve, bool shown);
|
||||
void updateAxis(); //reset axis and recompute it with all curves minMax
|
||||
void clearData();
|
||||
|
||||
private slots:
|
||||
void captureScreen();
|
||||
void updateAxis(const PlotCurve * curve);
|
||||
|
||||
protected:
|
||||
virtual void contextMenuEvent(QContextMenuEvent * event);
|
||||
virtual void paintEvent(QPaintEvent * event);
|
||||
virtual void resizeEvent(QResizeEvent * event);
|
||||
|
||||
private:
|
||||
friend class PlotCurve;
|
||||
void addItem(QGraphicsItem * item);
|
||||
|
||||
private:
|
||||
void replot(QPainter * painter);
|
||||
bool updateAxis(float x, float y);
|
||||
bool updateAxis(float x1, float x2, float y1, float y2);
|
||||
void setupUi();
|
||||
void createActions();
|
||||
void createMenus();
|
||||
void selectScreenCaptureFormat();
|
||||
|
||||
private:
|
||||
PlotLegend * _legend;
|
||||
QGraphicsView * _view;
|
||||
QGraphicsItem * _sceneRoot;
|
||||
QWidget * _graphicsViewHolder;
|
||||
float _axisMaximums[4]; // {x1->x2, y1->y2}
|
||||
bool _axisMaximumsSet[4]; // {x1->x2, y1->y2}
|
||||
bool _fixedAxis[2];
|
||||
PlotAxis * _verticalAxis;
|
||||
PlotAxis * _horizontalAxis;
|
||||
int _penStyleCount;
|
||||
int _maxVisibleItems;
|
||||
QList<QGraphicsLineItem *> hGridLines;
|
||||
QList<QGraphicsLineItem *> vGridLines;
|
||||
QList<PlotCurve*> _curves;
|
||||
QLabel * _title;
|
||||
QLabel * _xLabel;
|
||||
OrientableLabel * _yLabel;
|
||||
QLabel * _refreshRate;
|
||||
QString _workingDirectory;
|
||||
QTime _refreshIntervalTime;
|
||||
int _lowestRefreshRate;
|
||||
QTime _refreshStartTime;
|
||||
QString _autoScreenCaptureFormat;
|
||||
|
||||
QMenu * _menu;
|
||||
QAction * _aShowLegend;
|
||||
QAction * _aShowGrid;
|
||||
QAction * _aKeepAllData;
|
||||
QAction * _aLimit0;
|
||||
QAction * _aLimit10;
|
||||
QAction * _aLimit50;
|
||||
QAction * _aLimit100;
|
||||
QAction * _aLimit500;
|
||||
QAction * _aLimit1000;
|
||||
QAction * _aLimitCustom;
|
||||
QAction * _aAddVerticalLine;
|
||||
QAction * _aAddHorizontalLine;
|
||||
QAction * _aChangeTitle;
|
||||
QAction * _aChangeXLabel;
|
||||
QAction * _aChangeYLabel;
|
||||
QAction * _aYLabelVertical;
|
||||
QAction * _aShowRefreshRate;
|
||||
QAction * _aSaveFigure;
|
||||
QAction * _aAutoScreenCapture;
|
||||
QAction * _aClearData;
|
||||
QAction * _aGraphicsView;
|
||||
};
|
||||
|
||||
#ifndef PLOT_WIDGET_OUT_OF_LIB
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* PLOT_H_ */
|
||||
@@ -26,13 +26,13 @@
|
||||
#include <QtGui/QMainWindow>
|
||||
#include <QtCore/QTimer>
|
||||
#include <QtGui/QProgressDialog>
|
||||
#include "utilite/ULogger.h"
|
||||
#include "ui_preferencesDialog.h"
|
||||
#include "rtabmap/core/Rtabmap.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "utilite/UConversion.h"
|
||||
#include "Plot.h"
|
||||
#include "utilite/UStl.h"
|
||||
#include <utilite/ULogger.h>
|
||||
#include <utilite/UConversion.h>
|
||||
#include <utilite/UPlot.h>
|
||||
#include <utilite/UStl.h>
|
||||
|
||||
#define DEFAULT_GUI_IMAGES_KEPT true
|
||||
#define DEFAULT_LOGGER_LEVEL 2
|
||||
@@ -80,42 +80,64 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
connect(_ui->horizontalSlider_keypointsOpacity, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteGeneralPanel()));
|
||||
|
||||
//Source panel
|
||||
_ui->stackedWidget_2->setCurrentIndex(_ui->source_comboBox_type->currentIndex());
|
||||
connect(_ui->source_comboBox_type, SIGNAL(currentIndexChanged(int)), _ui->stackedWidget_2, SLOT(setCurrentIndex(int)));
|
||||
connect(_ui->source_comboBox_type, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->general_doubleSpinBox_imgRate, SIGNAL(valueChanged(double)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
//Image source
|
||||
connect(_ui->groupBox_sourceImage, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
_ui->stackedWidget_image->setCurrentIndex(_ui->source_comboBox_image_type->currentIndex());
|
||||
connect(_ui->source_comboBox_image_type, SIGNAL(currentIndexChanged(int)), _ui->stackedWidget_image, SLOT(setCurrentIndex(int)));
|
||||
connect(_ui->source_comboBox_image_type, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->general_checkBox_autoRestart, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->general_checkBox_cameraKeypoints, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
//usbDevice group
|
||||
connect(_ui->source_usbDevice_spinBox_id, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->source_spinBox_imgWidth, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->source_spinBox_imgheight, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->source_spinBox_framesDropped, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
//images group
|
||||
connect(_ui->source_images_toolButton_selectSource, SIGNAL(clicked()), this, SLOT(selectSource()));
|
||||
connect(_ui->source_images_toolButton_selectSource, SIGNAL(clicked()), this, SLOT(selectSourceImage()));
|
||||
connect(_ui->source_images_lineEdit_path, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->source_images_spinBox_startPos, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->source_images_refreshDir, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
//video group
|
||||
connect(_ui->source_video_toolButton_selectSource, SIGNAL(clicked()), this, SLOT(selectSource()));
|
||||
connect(_ui->source_video_toolButton_selectSource, SIGNAL(clicked()), this, SLOT(selectSourceImage()));
|
||||
connect(_ui->source_video_lineEdit_path, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
//Audio source
|
||||
connect(_ui->groupBox_sourceAudio, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
_ui->stackedWidget_audio->setCurrentIndex(_ui->source_comboBox_audio_type->currentIndex());
|
||||
connect(_ui->source_comboBox_audio_type, SIGNAL(currentIndexChanged(int)), _ui->stackedWidget_audio, SLOT(setCurrentIndex(int)));
|
||||
connect(_ui->source_comboBox_audio_type, SIGNAL(currentIndexChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
//audioDevice group
|
||||
connect(_ui->source_audio_toolButton_selectSource, SIGNAL(clicked()), this, SLOT(selectSourceAudio()));
|
||||
connect(_ui->source_micDevice, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->source_micFs, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->source_micSampleSize, SIGNAL(valueChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->source_audio_lineEdit_path, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->source_checkBox_playWhileRecording, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
//database group
|
||||
connect(_ui->source_database_toolButton_selectSource, SIGNAL(clicked()), this, SLOT(selectSource()));
|
||||
connect(_ui->source_database_lineEdit_path, SIGNAL(textChanged(const QString &)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->source_database_checkBox_loadActions, SIGNAL(stateChanged(int)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
connect(_ui->source_database_toolButton_selectSource, SIGNAL(clicked()), this, SLOT(selectSourceDatabase()));
|
||||
connect(_ui->groupBox_sourceDatabase, SIGNAL(toggled(bool)), this, SLOT(makeObsoleteSourcePanel()));
|
||||
|
||||
//Rtabmap basic
|
||||
connect(_ui->general_doubleSpinBox_timeThr, SIGNAL(valueChanged(double)), _ui->general_doubleSpinBox_timeThr_2, SLOT(setValue(double)));
|
||||
connect(_ui->general_doubleSpinBox_hardThr, SIGNAL(valueChanged(double)), _ui->general_doubleSpinBox_hardThr_2, SLOT(setValue(double)));
|
||||
connect(_ui->surf_doubleSpinBox_hessianThr, SIGNAL(valueChanged(double)), _ui->surf_doubleSpinBox_hessianThr_2, SLOT(setValue(double)));
|
||||
connect(_ui->general_doubleSpinBox_similarityThr, SIGNAL(valueChanged(double)), _ui->general_doubleSpinBox_similarityThr_2, SLOT(setValue(double)));
|
||||
connect(_ui->general_spinBox_imagesBufferSize, SIGNAL(valueChanged(int)), _ui->general_spinBox_imagesBufferSize_2, SLOT(setValue(int)));
|
||||
connect(_ui->general_checkBox_publishStats, SIGNAL(clicked(bool)), _ui->general_checkBox_publishStats_2, SLOT(setChecked(bool)));
|
||||
connect(_ui->general_spinBox_maxStMemSize, SIGNAL(valueChanged(int)), _ui->general_spinBox_maxStMemSize_2, SLOT(setValue(int)));
|
||||
|
||||
connect(_ui->comboBox_signatureType, SIGNAL(currentIndexChanged(int)), _ui->comboBox_signatureType_2, SLOT(setCurrentIndex(int)));
|
||||
connect(_ui->lineEdit_workingDirectory, SIGNAL(textChanged(const QString &)), _ui->lineEdit_workingDirectory_2, SLOT(setText(const QString &)));
|
||||
|
||||
connect(_ui->general_doubleSpinBox_timeThr_2, SIGNAL(valueChanged(double)), _ui->general_doubleSpinBox_timeThr, SLOT(setValue(double)));
|
||||
connect(_ui->general_doubleSpinBox_hardThr_2, SIGNAL(valueChanged(double)), _ui->general_doubleSpinBox_hardThr, SLOT(setValue(double)));
|
||||
connect(_ui->surf_doubleSpinBox_hessianThr_2, SIGNAL(valueChanged(double)), _ui->surf_doubleSpinBox_hessianThr, SLOT(setValue(double)));
|
||||
connect(_ui->general_spinBox_imagesBufferSize_2, SIGNAL(valueChanged(int)), _ui->general_spinBox_imagesBufferSize, SLOT(setValue(int)));
|
||||
connect(_ui->general_checkBox_publishStats_2, SIGNAL(clicked(bool)), _ui->general_checkBox_publishStats, SLOT(setChecked(bool)));
|
||||
connect(_ui->general_doubleSpinBox_timeThr_2, SIGNAL(editingFinished()), this, SLOT(updateBasicParameter()));
|
||||
connect(_ui->general_doubleSpinBox_hardThr_2, SIGNAL(editingFinished()), this, SLOT(updateBasicParameter()));
|
||||
connect(_ui->surf_doubleSpinBox_hessianThr_2, SIGNAL(editingFinished()), this, SLOT(updateBasicParameter()));
|
||||
connect(_ui->general_doubleSpinBox_similarityThr_2, SIGNAL(editingFinished()), this, SLOT(updateBasicParameter()));
|
||||
connect(_ui->general_spinBox_imagesBufferSize_2, SIGNAL(editingFinished()), this, SLOT(updateBasicParameter()));
|
||||
connect(_ui->general_spinBox_maxStMemSize_2, SIGNAL(editingFinished()), this, SLOT(updateBasicParameter()));
|
||||
connect(_ui->general_checkBox_publishStats, SIGNAL(stateChanged(int)), this, SLOT(updateBasicParameter()));
|
||||
connect(_ui->general_checkBox_publishStats_2, SIGNAL(stateChanged(int)), this, SLOT(updateBasicParameter()));
|
||||
|
||||
connect(_ui->comboBox_signatureType_2, SIGNAL(currentIndexChanged(int)), _ui->comboBox_signatureType, SLOT(setCurrentIndex(int)));
|
||||
connect(_ui->lineEdit_workingDirectory_2, SIGNAL(textChanged(const QString &)), _ui->lineEdit_workingDirectory, SLOT(setText(const QString &)));
|
||||
connect(_ui->toolButton_workingDirectory_2, SIGNAL(clicked()), this, SLOT(changeWorkingDirectory()));
|
||||
|
||||
@@ -123,7 +145,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
//Rtabmap
|
||||
_ui->general_doubleSpinBox_retrievalThr->setObjectName(Parameters::kRtabmapRetrievalThr().c_str());
|
||||
_ui->general_checkBox_publishStats->setObjectName(Parameters::kRtabmapPublishStats().c_str());
|
||||
_ui->general_checkBox_publishImages->setObjectName(Parameters::kRtabmapPublishImages().c_str());
|
||||
_ui->general_checkBox_publishRawData->setObjectName(Parameters::kRtabmapPublishRawData().c_str());
|
||||
_ui->general_checkBox_publishPdf->setObjectName(Parameters::kRtabmapPublishPdf().c_str());
|
||||
_ui->general_checkBox_publishLikelihood->setObjectName(Parameters::kRtabmapPublishLikelihood().c_str());
|
||||
_ui->general_doubleSpinBox_timeThr->setObjectName(Parameters::kRtabmapTimeThr().c_str());
|
||||
@@ -133,6 +155,7 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->general_checkBox_neighborhoodSummation->setObjectName(Parameters::kRtabmapSelectionNeighborhoodSummationUsed().c_str());
|
||||
_ui->general_checkBox_likelihoodUsed->setObjectName(Parameters::kRtabmapSelectionLikelihoodUsed().c_str());
|
||||
_ui->general_checkBox_likelihoodStdDevRemoved->setObjectName(Parameters::kRtabmapLikelihoodStdDevRemoved().c_str());
|
||||
_ui->general_checkBox_likelihoodNullValuesIgnored->setObjectName(Parameters::kRtabmapLikelihoodNullValuesIgnored().c_str());
|
||||
_ui->general_checkBox_actionsSentRejectHyp->setObjectName(Parameters::kRtabmapActionsSentRejectHyp().c_str());
|
||||
_ui->general_doubleSpinBox_confidenceThr->setObjectName(Parameters::kRtabmapConfidenceThr().c_str());
|
||||
_ui->lineEdit_workingDirectory->setObjectName(Parameters::kRtabmapWorkingDirectory().c_str());
|
||||
@@ -182,7 +205,6 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->surf_spinBox_maxLeafs->setObjectName(Parameters::kKpMaxLeafs().c_str());
|
||||
_ui->surf_spinBox_wordsPerImageTarget->setObjectName(Parameters::kKpWordsPerImage().c_str());
|
||||
_ui->surf_doubleSpinBox_ratioBadSign->setObjectName(Parameters::kKpBadSignRatio().c_str());
|
||||
_ui->checkBox_kp_usingAdaptiveResponseThr->setObjectName(Parameters::kKpUsingAdaptiveResponseThr().c_str());
|
||||
_ui->general_checkBox_reactivatedWordsComparedToNewWords->setObjectName(Parameters::kKpReactivatedWordsComparedToNewWords().c_str());
|
||||
_ui->checkBox_kp_tfIdfLikelihoodUsed->setObjectName(Parameters::kKpTfIdfLikelihoodUsed().c_str());
|
||||
_ui->checkBox_kp_tfIdfNormalized->setObjectName(Parameters::kKpTfIdfNormalized().c_str());
|
||||
@@ -196,8 +218,8 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->surf_spinBox_octaves->setObjectName(Parameters::kSURFOctaves().c_str());
|
||||
_ui->surf_spinBox_octaveLayers->setObjectName(Parameters::kSURFOctaveLayers().c_str());
|
||||
_ui->checkBox_surfExtended->setObjectName(Parameters::kSURFExtended().c_str());
|
||||
_ui->surf_checkBox_gpuVersion->setObjectName(Parameters::kSURFGpuVersion().c_str());
|
||||
_ui->surf_checkBox_upright->setObjectName(Parameters::kSURFUpright().c_str());
|
||||
_ui->surf_checkBox_gpuVersion->setObjectName(Parameters::kSURFGpuVersion().c_str());
|
||||
|
||||
//Star detector
|
||||
_ui->star_spinBox_maxSize->setObjectName(Parameters::kStarMaxSize().c_str());
|
||||
@@ -207,8 +229,11 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->star_spinBox_suppressNonmaxSize->setObjectName(Parameters::kStarSuppressNonmaxSize().c_str());
|
||||
|
||||
//SIFT detector
|
||||
_ui->sift_doubleSpinBox_Thr->setObjectName(Parameters::kSIFTThreshold().c_str());
|
||||
_ui->sift_spinBox_nFeatures->setObjectName(Parameters::kSIFTNFeatures().c_str());
|
||||
_ui->sift_spinBox_nOctaveLayers->setObjectName(Parameters::kSIFTNOctaveLayers().c_str());
|
||||
_ui->sift_doubleSpinBox_contrastThr->setObjectName(Parameters::kSIFTContrastThreshold().c_str());
|
||||
_ui->sift_doubleSpinBox_edgeThr->setObjectName(Parameters::kSIFTEdgeThreshold().c_str());
|
||||
_ui->sift_doubleSpinBox_sigma->setObjectName(Parameters::kSIFTSigma().c_str());
|
||||
|
||||
//FAST detector
|
||||
_ui->fast_spinBox_Threshold->setObjectName(Parameters::kFASTThreshold().c_str());
|
||||
@@ -221,8 +246,10 @@ PreferencesDialog::PreferencesDialog(QWidget * parent) :
|
||||
_ui->checkBox_publishMasks->setObjectName(Parameters::kSMPublishMasks().c_str());
|
||||
_ui->checkBox_motionMaskUsed->setObjectName(Parameters::kSMMotionMaskUsed().c_str());
|
||||
_ui->checkBox_logpolar->setObjectName(Parameters::kSMLogPolarUsed().c_str());
|
||||
_ui->checkBox_votingScheme->setObjectName(Parameters::kSMVotingSchemeUsed().c_str());
|
||||
_ui->sm_colorTable_comboBox->setObjectName(Parameters::kSMColorTable().c_str());
|
||||
_ui->sm_audioDBThreshold->setObjectName(Parameters::kSMAudioDBThreshold().c_str());
|
||||
_ui->checkBox_dBIndexing->setObjectName(Parameters::kSMAudioDBIndexing().c_str());
|
||||
_ui->checkBox_audioMagnitudeInvariant->setObjectName(Parameters::kSMMagnitudeInvariant().c_str());
|
||||
|
||||
// verifyHypotheses
|
||||
_ui->comboBox_vh_strategy->setObjectName(Parameters::kRtabmapVhStrategy().c_str());
|
||||
@@ -438,6 +465,7 @@ void PreferencesDialog::closeDialog ( QAbstractButton * button )
|
||||
break;
|
||||
|
||||
case QDialogButtonBox::AcceptRole:
|
||||
updateBasicParameter();// make that changes without editing finished signal are updated.
|
||||
if((_obsoletePanels & kPanelAll) || _parameters.size())
|
||||
{
|
||||
if(validateForm())
|
||||
@@ -463,6 +491,7 @@ void PreferencesDialog::resetApply ( QAbstractButton * button )
|
||||
switch(role)
|
||||
{
|
||||
case QDialogButtonBox::ApplyRole:
|
||||
updateBasicParameter();// make that changes without editing finished signal are updated.
|
||||
if(validateForm())
|
||||
{
|
||||
writeSettings();
|
||||
@@ -493,20 +522,38 @@ void PreferencesDialog::resetSettings(int panelNumber)
|
||||
}
|
||||
else if(boxes.at(panelNumber)->objectName() == "groupBox_source0")
|
||||
{
|
||||
_ui->groupBox_sourceImage->setChecked(true);
|
||||
_ui->general_doubleSpinBox_imgRate->setValue(1.0);
|
||||
_ui->source_spinBox_imgWidth->setValue(0);
|
||||
_ui->source_spinBox_imgheight->setValue(0);
|
||||
_ui->source_spinBox_framesDropped->setValue(0);
|
||||
_ui->general_checkBox_autoRestart->setChecked(false);
|
||||
_ui->general_checkBox_cameraKeypoints->setChecked(false);
|
||||
|
||||
_ui->groupBox_sourceAudio->setChecked(false);
|
||||
_ui->source_micDevice->setValue(0);
|
||||
_ui->source_micFs->setValue(48000);
|
||||
_ui->source_micSampleSize->setValue(2);
|
||||
|
||||
_ui->groupBox_sourceDatabase->setChecked(false);
|
||||
}
|
||||
else if(boxes.at(panelNumber)->objectName() == "groupBox_rtabmap_basic0")
|
||||
{
|
||||
_ui->general_doubleSpinBox_timeThr_2->setValue(Parameters::defaultRtabmapTimeThr());
|
||||
_ui->general_doubleSpinBox_hardThr_2->setValue(Parameters::defaultRtabmapLoopThr());
|
||||
_ui->surf_doubleSpinBox_hessianThr_2->setValue(Parameters::defaultSURFHessianThreshold());
|
||||
_ui->general_doubleSpinBox_similarityThr_2->setValue(Parameters::defaultMemSimilarityThr());
|
||||
_ui->general_spinBox_imagesBufferSize_2->setValue(Parameters::defaultRtabmapSMStateBufferSize());
|
||||
_ui->general_spinBox_maxStMemSize_2->setValue(Parameters::defaultMemMaxStMemSize());
|
||||
_ui->general_checkBox_publishStats_2->setChecked(Parameters::defaultRtabmapPublishStats());
|
||||
_ui->lineEdit_workingDirectory_2->setText(Parameters::defaultRtabmapWorkingDirectory().c_str());
|
||||
// match the advanced (spin and doubleSpin boxes)
|
||||
_ui->general_doubleSpinBox_timeThr->setValue(Parameters::defaultRtabmapTimeThr());
|
||||
_ui->general_doubleSpinBox_hardThr->setValue(Parameters::defaultRtabmapLoopThr());
|
||||
_ui->surf_doubleSpinBox_hessianThr->setValue(Parameters::defaultSURFHessianThreshold());
|
||||
_ui->general_doubleSpinBox_similarityThr->setValue(Parameters::defaultMemSimilarityThr());
|
||||
_ui->general_spinBox_imagesBufferSize->setValue(Parameters::defaultRtabmapSMStateBufferSize());
|
||||
_ui->general_spinBox_maxStMemSize->setValue(Parameters::defaultMemMaxStMemSize());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -600,12 +647,14 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
|
||||
QSettings settings(path, QSettings::IniFormat);
|
||||
|
||||
settings.beginGroup("Camera");
|
||||
_ui->groupBox_sourceImage->setChecked(settings.value("imageUsed", _ui->groupBox_sourceImage->isChecked()).toBool());
|
||||
_ui->general_doubleSpinBox_imgRate->setValue(settings.value("imgRate", _ui->general_doubleSpinBox_imgRate->value()).toDouble());
|
||||
_ui->general_checkBox_autoRestart->setChecked(settings.value("autoRestart", _ui->general_checkBox_autoRestart->isChecked()).toBool());
|
||||
_ui->general_checkBox_cameraKeypoints->setChecked(settings.value("cameraKeypoints", _ui->general_checkBox_cameraKeypoints->isChecked()).toBool());
|
||||
_ui->source_comboBox_type->setCurrentIndex(settings.value("type", _ui->source_comboBox_type->currentIndex()).toInt());
|
||||
_ui->source_comboBox_image_type->setCurrentIndex(settings.value("type", _ui->source_comboBox_image_type->currentIndex()).toInt());
|
||||
_ui->source_spinBox_imgWidth->setValue(settings.value("imgWidth",_ui->source_spinBox_imgWidth->value()).toInt());
|
||||
_ui->source_spinBox_imgheight->setValue(settings.value("imgHeight",_ui->source_spinBox_imgheight->value()).toInt());
|
||||
_ui->source_spinBox_framesDropped->setValue(settings.value("framesDropped",_ui->source_spinBox_framesDropped->value()).toInt());
|
||||
//usbDevice group
|
||||
settings.beginGroup("usbDevice");
|
||||
_ui->source_usbDevice_spinBox_id->setValue(settings.value("id",_ui->source_usbDevice_spinBox_id->value()).toInt());
|
||||
@@ -620,12 +669,22 @@ void PreferencesDialog::readCameraSettings(const QString & filePath)
|
||||
settings.beginGroup("video");
|
||||
_ui->source_video_lineEdit_path->setText(settings.value("path", _ui->source_video_lineEdit_path->text()).toString());
|
||||
settings.endGroup(); // video
|
||||
//database group
|
||||
settings.beginGroup("database");
|
||||
_ui->source_database_lineEdit_path->setText(settings.value("path",_ui->source_database_lineEdit_path->text()).toString());
|
||||
_ui->source_database_checkBox_loadActions->setChecked(settings.value("loadActions",_ui->source_database_checkBox_loadActions->isChecked()).toBool());
|
||||
settings.endGroup(); // usbDevice
|
||||
settings.endGroup(); // Camera
|
||||
|
||||
settings.beginGroup("Audio");
|
||||
_ui->groupBox_sourceAudio->setChecked(settings.value("audioUsed", _ui->groupBox_sourceAudio->isChecked()).toBool());
|
||||
_ui->source_comboBox_audio_type->setCurrentIndex(settings.value("type", _ui->source_comboBox_audio_type->currentIndex()).toInt());
|
||||
_ui->source_micDevice->setValue(settings.value("id",_ui->source_micDevice->value()).toInt());
|
||||
_ui->source_micFs->setValue(settings.value("fs",_ui->source_micFs->value()).toInt());
|
||||
_ui->source_micSampleSize->setValue(settings.value("sampleSize",_ui->source_micSampleSize->value()).toInt());
|
||||
_ui->source_audio_lineEdit_path->setText(settings.value("path",_ui->source_audio_lineEdit_path->text()).toString());
|
||||
_ui->source_checkBox_playWhileRecording->setChecked(settings.value("playWhileRecording",_ui->source_checkBox_playWhileRecording->isChecked()).toBool());
|
||||
settings.endGroup(); // Audio
|
||||
|
||||
settings.beginGroup("Database");
|
||||
_ui->groupBox_sourceDatabase->setChecked(settings.value("databaseUsed", _ui->groupBox_sourceDatabase->isChecked()).toBool());
|
||||
_ui->source_database_lineEdit_path->setText(settings.value("path",_ui->source_database_lineEdit_path->text()).toString());
|
||||
settings.endGroup(); // Database
|
||||
}
|
||||
|
||||
void PreferencesDialog::readCoreSettings(const QString & filePath)
|
||||
@@ -740,13 +799,14 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath)
|
||||
}
|
||||
QSettings settings(path, QSettings::IniFormat);
|
||||
settings.beginGroup("Camera");
|
||||
|
||||
settings.setValue("imageUsed", _ui->groupBox_sourceImage->isChecked());
|
||||
settings.setValue("imgRate", _ui->general_doubleSpinBox_imgRate->value());
|
||||
settings.setValue("autoRestart", _ui->general_checkBox_autoRestart->isChecked());
|
||||
settings.setValue("cameraKeypoints", _ui->general_checkBox_cameraKeypoints->isChecked());
|
||||
settings.setValue("type", _ui->source_comboBox_type->currentIndex());
|
||||
settings.setValue("type", _ui->source_comboBox_image_type->currentIndex());
|
||||
settings.setValue("imgWidth", _ui->source_spinBox_imgWidth->value());
|
||||
settings.setValue("imgHeight", _ui->source_spinBox_imgheight->value());
|
||||
settings.setValue("framesDropped", _ui->source_spinBox_framesDropped->value());
|
||||
//usbDevice group
|
||||
settings.beginGroup("usbDevice");
|
||||
settings.setValue("id", _ui->source_usbDevice_spinBox_id->value());
|
||||
@@ -761,13 +821,24 @@ void PreferencesDialog::writeCameraSettings(const QString & filePath)
|
||||
settings.beginGroup("video");
|
||||
settings.setValue("path", _ui->source_video_lineEdit_path->text());
|
||||
settings.endGroup(); //video
|
||||
//database group
|
||||
settings.beginGroup("database");
|
||||
settings.setValue("path", _ui->source_database_lineEdit_path->text());
|
||||
settings.setValue("loadActions", _ui->source_database_checkBox_loadActions->isChecked());
|
||||
settings.endGroup(); //usbDevice
|
||||
|
||||
settings.endGroup(); // Camera
|
||||
|
||||
settings.beginGroup("Audio");
|
||||
settings.setValue("audioUsed", _ui->groupBox_sourceAudio->isChecked());
|
||||
settings.setValue("type", _ui->source_comboBox_audio_type->currentIndex());
|
||||
settings.setValue("id", _ui->source_micDevice->value());
|
||||
settings.setValue("fs", _ui->source_micFs->value());
|
||||
settings.setValue("sampleSize", _ui->source_micSampleSize->value());
|
||||
|
||||
settings.setValue("path", _ui->source_audio_lineEdit_path->text());
|
||||
settings.setValue("playWhileRecording", _ui->source_checkBox_playWhileRecording->isChecked());
|
||||
settings.endGroup(); // Audio
|
||||
|
||||
settings.beginGroup("Database");
|
||||
settings.setValue("databaseUsed", _ui->groupBox_sourceDatabase->isChecked());
|
||||
settings.setValue("path", _ui->source_database_lineEdit_path->text());
|
||||
settings.endGroup();
|
||||
}
|
||||
|
||||
void PreferencesDialog::writeCoreSettings(const QString & filePath)
|
||||
@@ -940,32 +1011,33 @@ QString PreferencesDialog::loadCustomConfig(const QString & section, const QStri
|
||||
return value;
|
||||
}
|
||||
|
||||
void PreferencesDialog::selectSource(Src src)
|
||||
void PreferencesDialog::selectSourceImage(Src src)
|
||||
{
|
||||
ULOGGER_DEBUG("PreferencesDialog::selectSource()");
|
||||
ULOGGER_DEBUG("");
|
||||
|
||||
bool fromPrefDialog = false;
|
||||
//bool modified = false;
|
||||
if(src == kSrcUndef)
|
||||
{
|
||||
fromPrefDialog = true;
|
||||
if(_ui->source_comboBox_type->currentIndex() == 1)
|
||||
if(_ui->source_comboBox_image_type->currentIndex() == 1)
|
||||
{
|
||||
src = kSrcImages;
|
||||
}
|
||||
else if(_ui->source_comboBox_type->currentIndex() == 2)
|
||||
else if(_ui->source_comboBox_image_type->currentIndex() == 2)
|
||||
{
|
||||
src = kSrcVideo;
|
||||
}
|
||||
else if(_ui->source_comboBox_type->currentIndex() == 3)
|
||||
{
|
||||
src = kSrcDatabase;
|
||||
}
|
||||
else
|
||||
{
|
||||
src = kSrcUsbDevice;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// from user
|
||||
_ui->groupBox_sourceImage->setChecked(true);
|
||||
}
|
||||
|
||||
if(src == kSrcImages)
|
||||
{
|
||||
@@ -979,7 +1051,7 @@ void PreferencesDialog::selectSource(Src src)
|
||||
QFileInfoList files = dir.entryInfoList();
|
||||
if(!files.empty())
|
||||
{
|
||||
_ui->source_comboBox_type->setCurrentIndex(1);
|
||||
_ui->source_comboBox_image_type->setCurrentIndex(1);
|
||||
_ui->source_images_lineEdit_path->setText(path);
|
||||
_ui->source_images_spinBox_startPos->setValue(1);
|
||||
_ui->source_images_refreshDir->setChecked(false);
|
||||
@@ -994,31 +1066,107 @@ void PreferencesDialog::selectSource(Src src)
|
||||
}
|
||||
else if(src == kSrcVideo)
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), _ui->source_video_lineEdit_path->text(), tr("Videos (*.avi *.mpg)"));
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), _ui->source_video_lineEdit_path->text(), tr("Videos (*.avi *.mpg *.mp4)"));
|
||||
QFile file(path);
|
||||
if(!path.isEmpty() && file.exists())
|
||||
{
|
||||
_ui->source_comboBox_type->setCurrentIndex(2);
|
||||
_ui->source_comboBox_image_type->setCurrentIndex(2);
|
||||
_ui->source_video_lineEdit_path->setText(path);
|
||||
}
|
||||
}
|
||||
else if(src == kSrcDatabase)
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), _ui->source_database_lineEdit_path->text(), tr("Databases (*.db)"));
|
||||
QFile file(path);
|
||||
if(!path.isEmpty() && file.exists())
|
||||
{
|
||||
_ui->source_comboBox_type->setCurrentIndex(3);
|
||||
_ui->source_database_lineEdit_path->setText(path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_ui->source_comboBox_type->setCurrentIndex(0);
|
||||
_ui->source_comboBox_image_type->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
if(!fromPrefDialog && _obsoletePanels)
|
||||
{
|
||||
_ui->groupBox_sourceDatabase->setChecked(false);
|
||||
if(validateForm())
|
||||
{
|
||||
this->writeSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->readSettingsBegin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::selectSourceAudio(SrcAudio src)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
|
||||
bool fromPrefDialog = false;
|
||||
//bool modified = false;
|
||||
if(src == kSrcAudioUndef)
|
||||
{
|
||||
fromPrefDialog = true;
|
||||
if(_ui->source_comboBox_audio_type->currentIndex() == 1)
|
||||
{
|
||||
src = kSrcAudioFile;
|
||||
}
|
||||
else
|
||||
{
|
||||
src = kSrcAudioMicDevice;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// from user
|
||||
_ui->groupBox_sourceAudio->setChecked(true);
|
||||
}
|
||||
|
||||
if(src == kSrcAudioFile)
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), _ui->source_audio_lineEdit_path->text(), tr("Audio files (*.wav *.mp3)"));
|
||||
QFile file(path);
|
||||
if(!path.isEmpty() && file.exists())
|
||||
{
|
||||
_ui->source_comboBox_audio_type->setCurrentIndex(1);
|
||||
_ui->source_audio_lineEdit_path->setText(path);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_ui->source_comboBox_audio_type->setCurrentIndex(0);
|
||||
}
|
||||
|
||||
if(!fromPrefDialog && _obsoletePanels)
|
||||
{
|
||||
_ui->groupBox_sourceDatabase->setChecked(false);
|
||||
if(validateForm())
|
||||
{
|
||||
this->writeSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->readSettingsBegin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::selectSourceDatabase(bool user)
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
|
||||
if(user)
|
||||
{
|
||||
// from user
|
||||
_ui->groupBox_sourceDatabase->setChecked(true);
|
||||
}
|
||||
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), _ui->source_database_lineEdit_path->text(), tr("RTAB-Map database files (*.db)"));
|
||||
QFile file(path);
|
||||
if(!path.isEmpty() && file.exists())
|
||||
{
|
||||
_ui->source_database_lineEdit_path->setText(path);
|
||||
}
|
||||
|
||||
if(user && _obsoletePanels)
|
||||
{
|
||||
_ui->groupBox_sourceImage->setChecked(false);
|
||||
_ui->groupBox_sourceAudio->setChecked(false);
|
||||
if(validateForm())
|
||||
{
|
||||
this->writeSettings();
|
||||
@@ -1166,13 +1314,13 @@ void PreferencesDialog::addParameter(const QObject * object, int value)
|
||||
{
|
||||
if(value == 0) // 0 surf
|
||||
{
|
||||
this->addParameters(_ui->groupBox_descriptor_surf2);
|
||||
this->addParameters(_ui->groupBox_detector_surf2);
|
||||
}
|
||||
else if(value == 3) // 1 sift
|
||||
else if(value == 1) // 1 sift
|
||||
{
|
||||
// no panel
|
||||
this->addParameters(_ui->groupBox_detector_sift2);
|
||||
}
|
||||
else if(value == 5) // 2 brief
|
||||
else if(value == 2) // 2 brief
|
||||
{
|
||||
this->addParameters(_ui->groupBox_descriptor_brief2);
|
||||
}
|
||||
@@ -1284,6 +1432,55 @@ void PreferencesDialog::addParameters(const QGroupBox * box)
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::updateBasicParameter()
|
||||
{
|
||||
// This method is used to update basic/advanced referred parameters, see above editingFinished()
|
||||
|
||||
// basic to advanced (advanced to basic must be done by connecting signal valueChanged())
|
||||
if(sender() == _ui->general_doubleSpinBox_timeThr_2)
|
||||
{
|
||||
_ui->general_doubleSpinBox_timeThr->setValue(_ui->general_doubleSpinBox_timeThr_2->value());
|
||||
}
|
||||
else if(sender() == _ui->general_doubleSpinBox_hardThr_2)
|
||||
{
|
||||
_ui->general_doubleSpinBox_hardThr->setValue(_ui->general_doubleSpinBox_hardThr_2->value());
|
||||
}
|
||||
else if(sender() == _ui->surf_doubleSpinBox_hessianThr_2)
|
||||
{
|
||||
_ui->surf_doubleSpinBox_hessianThr->setValue(_ui->surf_doubleSpinBox_hessianThr_2->value());
|
||||
}
|
||||
else if(sender() == _ui->general_doubleSpinBox_similarityThr_2)
|
||||
{
|
||||
_ui->general_doubleSpinBox_similarityThr->setValue(_ui->general_doubleSpinBox_similarityThr_2->value());
|
||||
}
|
||||
else if(sender() == _ui->general_spinBox_imagesBufferSize_2)
|
||||
{
|
||||
_ui->general_spinBox_imagesBufferSize->setValue(_ui->general_spinBox_imagesBufferSize_2->value());
|
||||
}
|
||||
else if(sender() == _ui->general_spinBox_maxStMemSize_2)
|
||||
{
|
||||
_ui->general_spinBox_maxStMemSize->setValue(_ui->general_spinBox_maxStMemSize_2->value());
|
||||
}
|
||||
else if(sender() == _ui->general_checkBox_publishStats)
|
||||
{
|
||||
_ui->general_checkBox_publishStats_2->setChecked(_ui->general_checkBox_publishStats->isChecked());
|
||||
}
|
||||
else if(sender() == _ui->general_checkBox_publishStats_2)
|
||||
{
|
||||
_ui->general_checkBox_publishStats->setChecked(_ui->general_checkBox_publishStats_2->isChecked());
|
||||
}
|
||||
else
|
||||
{
|
||||
//update all values (only those using editingFinished signal)
|
||||
_ui->general_doubleSpinBox_timeThr->setValue(_ui->general_doubleSpinBox_timeThr_2->value());
|
||||
_ui->general_doubleSpinBox_hardThr->setValue(_ui->general_doubleSpinBox_hardThr_2->value());
|
||||
_ui->surf_doubleSpinBox_hessianThr->setValue(_ui->surf_doubleSpinBox_hessianThr_2->value());
|
||||
_ui->general_doubleSpinBox_similarityThr->setValue(_ui->general_doubleSpinBox_similarityThr_2->value());
|
||||
_ui->general_spinBox_imagesBufferSize->setValue(_ui->general_spinBox_imagesBufferSize_2->value());
|
||||
_ui->general_spinBox_maxStMemSize->setValue(_ui->general_spinBox_maxStMemSize_2->value());
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::makeObsoleteGeneralPanel()
|
||||
{
|
||||
ULOGGER_DEBUG("");
|
||||
@@ -1292,6 +1489,16 @@ void PreferencesDialog::makeObsoleteGeneralPanel()
|
||||
|
||||
void PreferencesDialog::makeObsoleteSourcePanel()
|
||||
{
|
||||
if(sender() == _ui->groupBox_sourceDatabase && _ui->groupBox_sourceDatabase->isChecked())
|
||||
{
|
||||
_ui->groupBox_sourceImage->setChecked(false);
|
||||
_ui->groupBox_sourceAudio->setChecked(false);
|
||||
}
|
||||
else if((sender() == _ui->groupBox_sourceImage && _ui->groupBox_sourceImage->isChecked()) ||
|
||||
(sender() == _ui->groupBox_sourceAudio && _ui->groupBox_sourceAudio->isChecked()))
|
||||
{
|
||||
_ui->groupBox_sourceDatabase->setChecked(false);
|
||||
}
|
||||
ULOGGER_DEBUG("");
|
||||
_obsoletePanels = _obsoletePanels | kPanelSource;
|
||||
}
|
||||
@@ -1399,7 +1606,7 @@ void PreferencesDialog::updatePredictionPlot()
|
||||
}
|
||||
|
||||
_ui->predictionPlot->removeCurves();
|
||||
_ui->predictionPlot->addCurve(new PlotCurve("Prediction", dataX, dataY, _ui->predictionPlot));
|
||||
_ui->predictionPlot->addCurve(new UPlotCurve("Prediction", dataX, dataY, _ui->predictionPlot));
|
||||
}
|
||||
|
||||
void PreferencesDialog::setupKpRoiPanel()
|
||||
@@ -1501,10 +1708,22 @@ int PreferencesDialog::getKeypointsOpacity() const
|
||||
}
|
||||
|
||||
// Source
|
||||
double PreferencesDialog::getGeneralImageRate() const
|
||||
double PreferencesDialog::getGeneralInputRate() const
|
||||
{
|
||||
return _ui->general_doubleSpinBox_imgRate->value();
|
||||
}
|
||||
bool PreferencesDialog::isSourceImageUsed() const
|
||||
{
|
||||
return _ui->groupBox_sourceImage->isChecked();
|
||||
}
|
||||
bool PreferencesDialog::isSourceAudioUsed() const
|
||||
{
|
||||
return _ui->groupBox_sourceAudio->isChecked();
|
||||
}
|
||||
bool PreferencesDialog::isSourceDatabaseUsed() const
|
||||
{
|
||||
return _ui->groupBox_sourceDatabase->isChecked();
|
||||
}
|
||||
bool PreferencesDialog::getGeneralAutoRestart() const
|
||||
{
|
||||
return _ui->general_checkBox_autoRestart->isChecked();
|
||||
@@ -1513,13 +1732,13 @@ bool PreferencesDialog::getGeneralCameraKeypoints() const
|
||||
{
|
||||
return _ui->general_checkBox_cameraKeypoints->isChecked();
|
||||
}
|
||||
int PreferencesDialog::getSourceType() const
|
||||
int PreferencesDialog::getSourceImageType() const
|
||||
{
|
||||
return _ui->source_comboBox_type->currentIndex();
|
||||
return _ui->source_comboBox_image_type->currentIndex();
|
||||
}
|
||||
QString PreferencesDialog::getSourceTypeStr() const
|
||||
QString PreferencesDialog::getSourceImageTypeStr() const
|
||||
{
|
||||
return _ui->source_comboBox_type->currentText();
|
||||
return _ui->source_comboBox_image_type->currentText();
|
||||
}
|
||||
int PreferencesDialog::getSourceWidth() const
|
||||
{
|
||||
@@ -1529,6 +1748,10 @@ int PreferencesDialog::getSourceHeight() const
|
||||
{
|
||||
return _ui->source_spinBox_imgheight->value();
|
||||
}
|
||||
int PreferencesDialog::getFramesDropped() const
|
||||
{
|
||||
return _ui->source_spinBox_framesDropped->value();
|
||||
}
|
||||
QString PreferencesDialog::getSourceImagesPath() const
|
||||
{
|
||||
return _ui->source_images_lineEdit_path->text();
|
||||
@@ -1549,15 +1772,43 @@ int PreferencesDialog::getSourceUsbDeviceId() const
|
||||
{
|
||||
return _ui->source_usbDevice_spinBox_id->value();
|
||||
}
|
||||
int PreferencesDialog::getSourceAudioType() const
|
||||
{
|
||||
return _ui->source_comboBox_audio_type->currentIndex();
|
||||
}
|
||||
QString PreferencesDialog::getSourceAudioTypeStr() const
|
||||
{
|
||||
return _ui->source_comboBox_audio_type->currentText();
|
||||
}
|
||||
int PreferencesDialog::getSourceMicDevice() const
|
||||
{
|
||||
return _ui->source_micDevice->value();
|
||||
}
|
||||
int PreferencesDialog::getSourceMicFs() const
|
||||
{
|
||||
return _ui->source_micFs->value();
|
||||
}
|
||||
int PreferencesDialog::getSourceMicSampleSize() const
|
||||
{
|
||||
return _ui->source_micSampleSize->value();
|
||||
}
|
||||
QString PreferencesDialog::getSourceAudioPath() const
|
||||
{
|
||||
return _ui->source_audio_lineEdit_path->text();
|
||||
}
|
||||
bool PreferencesDialog::getSourceAudioPlayWhileRecording() const
|
||||
{
|
||||
return _ui->source_checkBox_playWhileRecording->isChecked();
|
||||
}
|
||||
QString PreferencesDialog::getSourceDatabasePath() const
|
||||
{
|
||||
return _ui->source_database_lineEdit_path->text();
|
||||
}
|
||||
bool PreferencesDialog::getSourceDatabaseLoadActions() const
|
||||
{
|
||||
return _ui->source_database_checkBox_loadActions->isChecked();
|
||||
}
|
||||
|
||||
bool PreferencesDialog::isStatisticsPublished() const
|
||||
{
|
||||
return _ui->general_checkBox_publishStats->isChecked();
|
||||
}
|
||||
double PreferencesDialog::getLoopThr() const
|
||||
{
|
||||
return _ui->general_doubleSpinBox_hardThr->value();
|
||||
@@ -1579,6 +1830,10 @@ float PreferencesDialog::getTimeLimit() const
|
||||
{
|
||||
return _ui->general_doubleSpinBox_timeThr->value();
|
||||
}
|
||||
int PreferencesDialog::getMemoryType() const
|
||||
{
|
||||
return _ui->comboBox_signatureType->currentIndex();
|
||||
}
|
||||
|
||||
/*** SETTERS ***/
|
||||
void PreferencesDialog::setHardThr(int value)
|
||||
@@ -1617,7 +1872,7 @@ void PreferencesDialog::setRetrievalThr(int value)
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::setImgRate(double value)
|
||||
void PreferencesDialog::setInputRate(double value)
|
||||
{
|
||||
ULOGGER_DEBUG("imgRate=%2.2f", value);
|
||||
if(_ui->general_doubleSpinBox_imgRate->value() != value)
|
||||
@@ -1668,4 +1923,36 @@ void PreferencesDialog::setTimeLimit(float value)
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::disableSourceAudio()
|
||||
{
|
||||
if(_ui->groupBox_sourceAudio->isChecked())
|
||||
{
|
||||
_ui->groupBox_sourceAudio->setChecked(false);
|
||||
if(validateForm())
|
||||
{
|
||||
this->writeSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->readSettingsBegin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PreferencesDialog::disableGeneralCameraKeypoints()
|
||||
{
|
||||
if(_ui->general_checkBox_cameraKeypoints->isChecked())
|
||||
{
|
||||
_ui->general_checkBox_cameraKeypoints->setChecked(false);
|
||||
if(validateForm())
|
||||
{
|
||||
this->writeSettings();
|
||||
}
|
||||
else
|
||||
{
|
||||
this->readSettingsBegin();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+11
-11
@@ -31,8 +31,8 @@
|
||||
#include <QtGui/QToolBox>
|
||||
#include <QtGui/QDialog>
|
||||
|
||||
#include "Plot.h"
|
||||
#include "utilite/ULogger.h"
|
||||
#include <utilite/UPlot.h>
|
||||
#include <utilite/ULogger.h>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
@@ -54,7 +54,7 @@ StatItem::~StatItem()
|
||||
|
||||
void StatItem::setValue(float x, float y)
|
||||
{
|
||||
_value->setText(QString::number(y, 'g', 4));
|
||||
_value->setText(QString::number(y, 'g', 3));
|
||||
_xValue = x;
|
||||
emit valueChanged(x,y);
|
||||
}
|
||||
@@ -247,17 +247,17 @@ void StatsToolBox::updateStat(const QString & statFullName, float x, float y)
|
||||
void StatsToolBox::plot(const StatItem * stat, const QString & plotName)
|
||||
{
|
||||
QWidget * fig = _figures.value(plotName, (QWidget*)0);
|
||||
Plot * plot = 0;
|
||||
UPlot * plot = 0;
|
||||
if(fig)
|
||||
{
|
||||
plot = fig->findChild<Plot *>(plotName);
|
||||
plot = fig->findChild<UPlot *>(plotName);
|
||||
}
|
||||
if(plot)
|
||||
{
|
||||
// if not already in the plot
|
||||
if(!plot->contains(stat->objectName()))
|
||||
{
|
||||
PlotCurve * curve = new PlotCurve(stat->objectName(), plot);
|
||||
UPlotCurve * curve = new UPlotCurve(stat->objectName(), plot);
|
||||
curve->setPen(plot->getRandomPenColored());
|
||||
connect(stat, SIGNAL(valueChanged(float, float)), curve, SLOT(addValue(float, float)));
|
||||
if(!plot->addCurve(curve))
|
||||
@@ -289,7 +289,7 @@ void StatsToolBox::plot(const StatItem * stat, const QString & plotName)
|
||||
figure->setAttribute(Qt::WA_DeleteOnClose, true);
|
||||
connect(figure, SIGNAL(destroyed(QObject*)), this, SLOT(figureDeleted(QObject*)));
|
||||
//Plot
|
||||
Plot * newPlot = new Plot(figure);
|
||||
UPlot * newPlot = new UPlot(figure);
|
||||
newPlot->setWorkingDirectory(_workingDirectory);
|
||||
newPlot->setMaxVisibleItems(50);
|
||||
newPlot->setObjectName(newPlotName);
|
||||
@@ -298,7 +298,7 @@ void StatsToolBox::plot(const StatItem * stat, const QString & plotName)
|
||||
figure->setSizeGripEnabled(true);
|
||||
|
||||
//Add a new curve linked to the statBox
|
||||
PlotCurve * curve = new PlotCurve(stat->objectName(), newPlot);
|
||||
UPlotCurve * curve = new UPlotCurve(stat->objectName(), newPlot);
|
||||
curve->setPen(newPlot->getRandomPenColored());
|
||||
connect(stat, SIGNAL(valueChanged(float, float)), curve, SLOT(addValue(float, float)));
|
||||
if(!newPlot->addCurve(curve))
|
||||
@@ -358,7 +358,7 @@ void StatsToolBox::contextMenuEvent(QContextMenuEvent * event)
|
||||
{
|
||||
for(QMap<QString, QWidget*>::iterator i=_figures.begin(); i!=_figures.end(); ++i)
|
||||
{
|
||||
QList<Plot *> plots = i.value()->findChildren<Plot *>();
|
||||
QList<UPlot *> plots = i.value()->findChildren<UPlot *>();
|
||||
if(plots.size() == 1)
|
||||
{
|
||||
QStringList names = plots[0]->curveNames();
|
||||
@@ -403,7 +403,7 @@ void StatsToolBox::getFiguresSetup(QList<int> & curvesPerFigure, QStringList & c
|
||||
curveNames.clear();
|
||||
for(QMap<QString, QWidget*>::iterator i=_figures.begin(); i!=_figures.end(); ++i)
|
||||
{
|
||||
QList<Plot *> plots = i.value()->findChildren<Plot *>();
|
||||
QList<UPlot *> plots = i.value()->findChildren<UPlot *>();
|
||||
if(plots.size() == 1)
|
||||
{
|
||||
QStringList names = plots[0]->curveNames();
|
||||
@@ -449,7 +449,7 @@ void StatsToolBox::setWorkingDirectory(const QString & workingDirectory)
|
||||
_workingDirectory = workingDirectory;
|
||||
for(QMap<QString, QWidget*>::iterator i=_figures.begin(); i!=_figures.end(); ++i)
|
||||
{
|
||||
QList<Plot *> plots = i.value()->findChildren<Plot *>();
|
||||
QList<UPlot *> plots = i.value()->findChildren<UPlot *>();
|
||||
if(plots.size() == 1)
|
||||
{
|
||||
plots[0]->setWorkingDirectory(_workingDirectory);
|
||||
|
||||
+15
-14
@@ -30,22 +30,26 @@ void TwistGridWidget::addTwist(float x, float y, float z, float roll, float pitc
|
||||
{
|
||||
if(_grid->itemAtPosition(row, col+1))
|
||||
{
|
||||
QLayoutItem * item = _grid->itemAtPosition(row, col+1);
|
||||
if(item)
|
||||
{
|
||||
QWidget * w = item->widget();
|
||||
if(w)
|
||||
{
|
||||
_grid->removeItem(item);
|
||||
w->deleteLater();
|
||||
}
|
||||
}
|
||||
TwistWidget * w = (TwistWidget*)_grid->itemAtPosition(row, col+1)->widget();
|
||||
w->setData(x, y, z, roll, pitch, yaw);
|
||||
this->update();
|
||||
}
|
||||
else
|
||||
{
|
||||
_grid->addWidget(new TwistWidget(x, y, z, roll, pitch, yaw, this), row, col+1);
|
||||
}
|
||||
_grid->addWidget(new TwistWidget(x, y, z, roll, pitch, yaw, this), row, col+1);
|
||||
}
|
||||
|
||||
TwistWidget::TwistWidget(float x, float y, float z, float roll, float pitch, float yaw, QWidget * parent, Qt::WindowFlags f) :
|
||||
QWidget(parent, f)
|
||||
{
|
||||
this->setData(x, y, z, roll, pitch, yaw);
|
||||
|
||||
this->setFixedSize(SIZE,SIZE);
|
||||
this->setMinimumSize(SIZE,SIZE);
|
||||
}
|
||||
|
||||
void TwistWidget::setData(float x, float y, float z, float roll, float pitch, float yaw)
|
||||
{
|
||||
if(qAbs(z) > 0.00001)
|
||||
{
|
||||
@@ -60,9 +64,6 @@ TwistWidget::TwistWidget(float x, float y, float z, float roll, float pitch, flo
|
||||
_roll = roll;
|
||||
_pitch = pitch;
|
||||
_yaw = yaw;
|
||||
|
||||
this->setFixedSize(SIZE,SIZE);
|
||||
this->setMinimumSize(SIZE,SIZE);
|
||||
}
|
||||
|
||||
void TwistWidget::paintEvent(QPaintEvent * event)
|
||||
|
||||
@@ -36,6 +36,8 @@ public:
|
||||
TwistWidget(float x, float y, float z, float roll, float pitch, float yaw, QWidget * parent, Qt::WindowFlags f = 0);
|
||||
virtual ~TwistWidget() {}
|
||||
|
||||
void setData(float x, float y, float z, float roll, float pitch, float yaw);
|
||||
|
||||
protected:
|
||||
virtual void paintEvent(QPaintEvent * event);
|
||||
|
||||
|
||||
@@ -17,14 +17,14 @@
|
||||
* along with RTAB-Map. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "qtipl.h"
|
||||
#include "rtabmap/gui/qtipl.h"
|
||||
#include "utilite/ULogger.h"
|
||||
#include <opencv2/core/core_c.h>
|
||||
|
||||
namespace rtabmap {
|
||||
|
||||
// TODO : support only from gray 8bits ?
|
||||
QImage Ipl2QImage(const IplImage *newImage)
|
||||
QImage Ipl2QImage(const IplImage *newImage, int alpha)
|
||||
{
|
||||
QImage qtemp;
|
||||
if (newImage && newImage->depth == IPL_DEPTH_8U && cvGetSize(newImage).width>0)
|
||||
@@ -33,13 +33,13 @@ QImage Ipl2QImage(const IplImage *newImage)
|
||||
int y;
|
||||
char* data = newImage->imageData;
|
||||
|
||||
qtemp= QImage(newImage->width, newImage->height,QImage::Format_RGB32 );
|
||||
qtemp= QImage(newImage->width, newImage->height,QImage::Format_ARGB32 );
|
||||
for( y = 0; y < newImage->height; y++, data +=newImage->widthStep )
|
||||
{
|
||||
for( x = 0; x < newImage->width; x++)
|
||||
{
|
||||
uint *p = (uint*)qtemp.scanLine (y) + x;
|
||||
*p = qRgb(data[x * newImage->nChannels+2], data[x * newImage->nChannels+1],data[x * newImage->nChannels]);
|
||||
*p = qRgba(data[x * newImage->nChannels+2], data[x * newImage->nChannels+1],data[x * newImage->nChannels], alpha);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+229
-155
@@ -6,8 +6,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>842</width>
|
||||
<height>457</height>
|
||||
<width>1056</width>
|
||||
<height>642</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
@@ -21,7 +21,7 @@
|
||||
<set>QMainWindow::AllowNestedDocks|QMainWindow::AllowTabbedDocks|QMainWindow::AnimatedDocks|QMainWindow::VerticalTabs</set>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
@@ -29,100 +29,70 @@
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Box</enum>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_9">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_refId">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="rtabmap::ImageView" name="imageView_source">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_refId">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="rtabmap::ImageView" name="imageView_source">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QFrame" name="frame_2">
|
||||
<property name="frameShape">
|
||||
<enum>QFrame::Box</enum>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="frameShadow">
|
||||
<enum>QFrame::Raised</enum>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="spacing">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="margin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_4">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_matchId">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="rtabmap::ImageView" name="imageView_loopClosure">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_matchId">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>18</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="rtabmap::ImageView" name="imageView_loopClosure">
|
||||
<property name="verticalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollBarPolicy">
|
||||
<enum>Qt::ScrollBarAlwaysOff</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -131,8 +101,8 @@
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>842</width>
|
||||
<height>22</height>
|
||||
<width>1056</width>
|
||||
<height>25</height>
|
||||
</rect>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuFile">
|
||||
@@ -145,6 +115,20 @@
|
||||
<property name="title">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
<widget class="QMenu" name="menuAspect_ratio">
|
||||
<property name="title">
|
||||
<string>Aspect ratio</string>
|
||||
</property>
|
||||
<addaction name="action16_9"/>
|
||||
<addaction name="action16_10"/>
|
||||
<addaction name="action4_3"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action1080p"/>
|
||||
<addaction name="action720p"/>
|
||||
<addaction name="action480p"/>
|
||||
<addaction name="action360p"/>
|
||||
<addaction name="action240p"/>
|
||||
</widget>
|
||||
<addaction name="actionApply_settings_to_the_detector"/>
|
||||
<addaction name="actionClear_cache"/>
|
||||
<addaction name="separator"/>
|
||||
@@ -157,6 +141,7 @@
|
||||
<addaction name="actionReset_the_memory"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionAuto_screen_capture"/>
|
||||
<addaction name="menuAspect_ratio"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu6">
|
||||
<property name="title">
|
||||
@@ -174,9 +159,23 @@
|
||||
<property name="title">
|
||||
<string>Select source</string>
|
||||
</property>
|
||||
<addaction name="actionStream"/>
|
||||
<addaction name="actionImages"/>
|
||||
<addaction name="actionVideo"/>
|
||||
<widget class="QMenu" name="menuImage">
|
||||
<property name="title">
|
||||
<string>Image</string>
|
||||
</property>
|
||||
<addaction name="actionUsbCamera"/>
|
||||
<addaction name="actionImageFiles"/>
|
||||
<addaction name="actionVideo"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuAudio">
|
||||
<property name="title">
|
||||
<string>Audio</string>
|
||||
</property>
|
||||
<addaction name="actionMic"/>
|
||||
<addaction name="actionAudioFile"/>
|
||||
</widget>
|
||||
<addaction name="menuImage"/>
|
||||
<addaction name="menuAudio"/>
|
||||
<addaction name="actionDatabase"/>
|
||||
</widget>
|
||||
<addaction name="menuSelect_source"/>
|
||||
@@ -230,7 +229,7 @@
|
||||
<widget class="QWidget" name="dockWidgetContents">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="rtabmap::Plot" name="posteriorPlot" native="true"/>
|
||||
<widget class="UPlot" name="posteriorPlot" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -491,7 +490,7 @@
|
||||
<widget class="QWidget" name="dockWidgetContents_4">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="rtabmap::Plot" name="likelihoodPlot" native="true"/>
|
||||
<widget class="UPlot" name="likelihoodPlot" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
@@ -529,55 +528,41 @@
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="dockWidget_audioProcessedFrames">
|
||||
<property name="windowTitle">
|
||||
<string>Audio Processed Frames</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>2</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents_9">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_10">
|
||||
<item>
|
||||
<widget class="USpectrogram" name="widget_audioProcessedFrames" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QDockWidget" name="dockWidget_audioLoopFrames">
|
||||
<property name="windowTitle">
|
||||
<string>Audio Loop Frames</string>
|
||||
</property>
|
||||
<attribute name="dockWidgetArea">
|
||||
<number>2</number>
|
||||
</attribute>
|
||||
<widget class="QWidget" name="dockWidgetContents_10">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_11">
|
||||
<item>
|
||||
<widget class="USpectrogram" name="widget_audioLoopFrames" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<action name="actionExit">
|
||||
<property name="text">
|
||||
<string>Exit</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionStream">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Usb device</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionVideo">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Video...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImages">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Images...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSURF">
|
||||
<property name="text">
|
||||
<string>SURF</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionFourier">
|
||||
<property name="text">
|
||||
<string>Fourier</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSIFT">
|
||||
<property name="text">
|
||||
<string>SIFT</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionCenSurE">
|
||||
<property name="text">
|
||||
<string>CenSurE</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionHelp">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
@@ -616,6 +601,9 @@
|
||||
<property name="text">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Pause</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPause_on_match">
|
||||
<property name="checkable">
|
||||
@@ -653,14 +641,6 @@
|
||||
<string>Dump the memory</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDatabase">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Database...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionPause_when_a_loop_hypothesis_is_rejected">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
@@ -716,18 +696,106 @@
|
||||
<string>Show working directory in file browser</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action16_9">
|
||||
<property name="text">
|
||||
<string>16:9</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action16_10">
|
||||
<property name="text">
|
||||
<string>16:10</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action4_3">
|
||||
<property name="text">
|
||||
<string>4:3</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action360p">
|
||||
<property name="text">
|
||||
<string>360p</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action480p">
|
||||
<property name="text">
|
||||
<string>480p</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action720p">
|
||||
<property name="text">
|
||||
<string>720p</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action1080p">
|
||||
<property name="text">
|
||||
<string>1080p</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="action240p">
|
||||
<property name="text">
|
||||
<string>240p</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionUsbCamera">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Usb camera</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionImageFiles">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Images...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionVideo">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Video...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionMic">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Mic</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionAudioFile">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>File...</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDatabase">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Database...</string>
|
||||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>rtabmap::Plot</class>
|
||||
<class>UPlot</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>Plot.h</header>
|
||||
<header>utilite/UPlot.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>rtabmap::ImageView</class>
|
||||
<extends>QGraphicsView</extends>
|
||||
<header>ImageView.h</header>
|
||||
<header>../include/rtabmap/gui/ImageView.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>rtabmap::StatsToolBox</class>
|
||||
@@ -747,6 +815,12 @@
|
||||
<header>TwistWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>USpectrogram</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>utilite/USpectrogram.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../GuiLib.qrc"/>
|
||||
|
||||
+1044
-719
File diff suppressed because it is too large
Load Diff
@@ -5,9 +5,7 @@ SET(SRC_FILES
|
||||
)
|
||||
|
||||
SET(INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../src
|
||||
${PROJECT_SOURCE_DIR}/corelib/include
|
||||
${CPPUNIT_INCLUDE_DIR}
|
||||
${UTILITE_INCLUDE_DIRS}
|
||||
${OpenCV_INCLUDE_DIRS}
|
||||
@@ -29,7 +27,7 @@ ADD_DEFINITIONS(${CPPUNIT_DEFINITIONS})
|
||||
# Add binary called "testAvpdCore" that is built from the source file "main.cpp".
|
||||
# The extension is automatically found.
|
||||
ADD_EXECUTABLE(testCoreLib ${SRC_FILES})
|
||||
TARGET_LINK_LIBRARIES(testCoreLib corelib ${LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(testCoreLib rtabmap_corelib ${LIBRARIES})
|
||||
|
||||
SET_TARGET_PROPERTIES( testCoreLib
|
||||
PROPERTIES
|
||||
@@ -23,17 +23,16 @@
|
||||
//Headers for the test BEGIN
|
||||
#include "rtabmap/core/Camera.h"
|
||||
#include "rtabmap/core/Signature.h"
|
||||
#include "VWDictionary.h"
|
||||
#include "rtabmap/core/VWDictionary.h"
|
||||
#include "rtabmap/core/EpipolarGeometry.h"
|
||||
#include "rtabmap/core/Rtabmap.h"
|
||||
#include "rtabmap/core/SMState.h"
|
||||
#include "VerifyHypotheses.h"
|
||||
#include "rtabmap/core/VerifyHypotheses.h"
|
||||
#include "rtabmap/core/Parameters.h"
|
||||
#include "BayesFilter.h"
|
||||
#include "KeypointMemory.h"
|
||||
#include "rtabmap/core/BayesFilter.h"
|
||||
#include "rtabmap/core/KeypointMemory.h"
|
||||
#include "rtabmap/core/VisualWord.h"
|
||||
|
||||
#include "rtabmap/core/RtabmapEvent.h"
|
||||
#include "rtabmap/core/CameraEvent.h"
|
||||
|
||||
#include "rtabmap/core/DBDriverFactory.h"
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
@@ -68,7 +67,7 @@ void Tests::testAvpd()
|
||||
CPPUNIT_ASSERT_MESSAGE("Camera initialization failed!\n", camera.init());
|
||||
|
||||
/* Create tasks */
|
||||
Rtabmap ctabmap;
|
||||
Rtabmap rtabmap;
|
||||
ParametersMap parameters;
|
||||
parameters.insert(ParametersPair(Parameters::kRtabmapSMStateBufferSize(), "0"));
|
||||
parameters.insert(ParametersPair(Parameters::kDbSqlite3InMemory(), "true"));
|
||||
@@ -77,31 +76,26 @@ void Tests::testAvpd()
|
||||
parameters.insert(ParametersPair(Parameters::kRtabmapTimeThr(), "0"));
|
||||
parameters.insert(ParametersPair(Parameters::kSURFHessianThreshold(), "500"));
|
||||
UDirectory::makeDir("./LogTestAvpdCore/");
|
||||
ctabmap.setWorkingDirectory("./LogTestAvpdCore/");
|
||||
ctabmap.init(parameters);
|
||||
rtabmap.setWorkingDirectory("./LogTestAvpdCore/");
|
||||
rtabmap.init(parameters);
|
||||
|
||||
|
||||
/* Start thread's task */
|
||||
SMState * smState = 0;
|
||||
cv::Mat image;
|
||||
|
||||
smState = camera.takeSMState();
|
||||
image = camera.takeImage();
|
||||
int imgCount = 0;
|
||||
while(smState)
|
||||
while(!image.empty())
|
||||
{
|
||||
++imgCount;
|
||||
printf("Processing image %d/84...\n", imgCount);
|
||||
ctabmap.process(smState);
|
||||
smState = camera.takeSMState();
|
||||
}
|
||||
if(smState)
|
||||
{
|
||||
delete smState;
|
||||
smState = 0;
|
||||
rtabmap.process(Sensor(image, Sensor::kTypeImage));
|
||||
image = camera.takeImage();
|
||||
}
|
||||
|
||||
CPPUNIT_ASSERT(imgCount == 84);
|
||||
|
||||
ctabmap.dumpData();
|
||||
rtabmap.dumpData();
|
||||
|
||||
ULogger::write("testSurfStrategy end...");
|
||||
//ULOGGER_INFO("\nTime = %fs", timer.ticks());
|
||||
@@ -115,7 +109,7 @@ void Tests::testAvpd()
|
||||
likelihood.insert(std::pair<int, float>(1, 0));
|
||||
likelihood.insert(std::pair<int, float>(2, 0));
|
||||
likelihood.insert(std::pair<int, float>(3, 0));
|
||||
ctabmap.adjustLikelihood(likelihood);
|
||||
rtabmap.adjustLikelihood(likelihood);
|
||||
CPPUNIT_ASSERT(likelihood.size() == 4);
|
||||
std::vector<float> values = uValues(likelihood);
|
||||
for(unsigned int i=0; i<values.size(); ++i)
|
||||
@@ -127,7 +121,7 @@ void Tests::testAvpd()
|
||||
likelihood.insert(std::pair<int, float>(1, 0.4));
|
||||
likelihood.insert(std::pair<int, float>(2, 0.2));
|
||||
likelihood.insert(std::pair<int, float>(3, 0.9));
|
||||
ctabmap.adjustLikelihood(likelihood);
|
||||
rtabmap.adjustLikelihood(likelihood);
|
||||
CPPUNIT_ASSERT(likelihood.size() == 4);
|
||||
values = uValues(likelihood);
|
||||
// Result wanted generated by the TestAdjustLikelihood.m script (MatLab/Tests)
|
||||
@@ -142,7 +136,7 @@ void Tests::testAvpd()
|
||||
void Tests::testCamera()
|
||||
{
|
||||
std::string path;
|
||||
SMState * smState = 0;
|
||||
cv::Mat image;
|
||||
int count;
|
||||
|
||||
//CameraVideo class FIXME add a video in svn and reactivate this test
|
||||
@@ -172,33 +166,14 @@ void Tests::testCamera()
|
||||
CameraImages cameraImages(path, 1, false, 0, false, 80);
|
||||
CPPUNIT_ASSERT( cameraImages.init() );
|
||||
CPPUNIT_ASSERT( cameraImages.isIdle() == true);
|
||||
smState = cameraImages.takeSMState();
|
||||
image = cameraImages.takeImage();
|
||||
count = 0;
|
||||
while(smState)
|
||||
while(!image.empty())
|
||||
{
|
||||
delete smState;
|
||||
smState = 0;
|
||||
++count;
|
||||
smState = cameraImages.takeSMState();
|
||||
image = cameraImages.takeImage();
|
||||
}
|
||||
CPPUNIT_ASSERT( count == 84 );
|
||||
|
||||
//CameraDatabase class
|
||||
path = "./data/samples.db";
|
||||
CameraDatabase cameraDatabase(path, false, false); // ignoreChildren=false; loadActions=false
|
||||
CPPUNIT_ASSERT( cameraDatabase.init() );
|
||||
CPPUNIT_ASSERT( cameraDatabase.isIdle() == true);
|
||||
smState = cameraDatabase.takeSMState();
|
||||
count = 0;
|
||||
while(smState)
|
||||
{
|
||||
++count;
|
||||
delete smState;
|
||||
smState = 0;
|
||||
smState = cameraDatabase.takeSMState();
|
||||
}
|
||||
//ULOGGER_INFO("%d", count);
|
||||
CPPUNIT_ASSERT( count == 82 );
|
||||
}
|
||||
|
||||
void Tests::testDBDriverFactory()
|
||||
@@ -232,26 +207,26 @@ void Tests::testSqlite3Database()
|
||||
driver = DBDriverFactory::createDBDriver("sqlite3", parameters);
|
||||
CPPUNIT_ASSERT(driver);
|
||||
CPPUNIT_ASSERT(driver->openConnection("LogTestAvpdCore/tmpDatabase.db"));
|
||||
std::vector<int> sensors;
|
||||
std::vector<unsigned char> motionMask;
|
||||
std::vector<int> sensors1;
|
||||
std::vector<int> sensors2;
|
||||
bool keepRawData = true;
|
||||
std::list<std::vector<int> > sensors;
|
||||
std::list<std::vector<int> > sensors1;
|
||||
std::list<std::vector<int> > sensors2;
|
||||
CameraImages camera("./data/samples");
|
||||
CPPUNIT_ASSERT_MESSAGE("Camera initialization failed!\n", camera.init());
|
||||
|
||||
IplImage * image = camera.takeImage();
|
||||
CPPUNIT_ASSERT(image);
|
||||
SMSignature * sm1 = new SMSignature(sensors, motionMask, 1, image, keepRawData);
|
||||
sensors1 = sm1->getSensors();
|
||||
cvReleaseImage(&image);
|
||||
cv::Mat image = camera.takeImage();
|
||||
CPPUNIT_ASSERT(!image.empty());
|
||||
std::list<Sensor> rawData;
|
||||
rawData.push_back(Sensor(image, Sensor::kTypeImage));
|
||||
SMSignature * sm1 = new SMSignature(sensors, 1, rawData);
|
||||
sensors1 = sm1->getData();
|
||||
sm1->addNeighbor(NeighborLink(2));
|
||||
|
||||
image = camera.takeImage();
|
||||
CPPUNIT_ASSERT(image);
|
||||
SMSignature * sm2 = new SMSignature(sensors, motionMask, 2, image, keepRawData);
|
||||
sensors2 = sm2->getSensors();
|
||||
cvReleaseImage(&image);
|
||||
CPPUNIT_ASSERT(!image.empty());
|
||||
rawData.clear();
|
||||
rawData.push_back(Sensor(image, Sensor::kTypeImage));
|
||||
SMSignature * sm2 = new SMSignature(sensors, 2, rawData);
|
||||
sensors2 = sm2->getData();
|
||||
sm2->addNeighbor(NeighborLink(1));
|
||||
|
||||
//save them
|
||||
@@ -274,16 +249,8 @@ void Tests::testSqlite3Database()
|
||||
CPPUNIT_ASSERT(sm2);
|
||||
|
||||
//compare
|
||||
CPPUNIT_ASSERT(sensors1.size() > 0 && sensors1.size() == sm1->getSensors().size());
|
||||
CPPUNIT_ASSERT(sensors2.size() > 0 && sensors2.size() == sm2->getSensors().size());
|
||||
for(unsigned int i=0; i<sensors1.size(); ++i)
|
||||
{
|
||||
CPPUNIT_ASSERT(sensors1.at(i) == sm1->getSensors().at(i));
|
||||
}
|
||||
for(unsigned int i=0; i<sensors2.size(); ++i)
|
||||
{
|
||||
CPPUNIT_ASSERT(sensors2.at(i) == sm2->getSensors().at(i));
|
||||
}
|
||||
CPPUNIT_ASSERT(sensors1.size() > 0 && sensors1.size() == sm1->getData().size());
|
||||
CPPUNIT_ASSERT(sensors2.size() > 0 && sensors2.size() == sm2->getData().size());
|
||||
CPPUNIT_ASSERT(sm1->getNeighbors().size() == 1);
|
||||
CPPUNIT_ASSERT(sm2->getNeighbors().size() == 1);
|
||||
|
||||
@@ -346,7 +313,9 @@ void Tests::testBayesFilter()
|
||||
{
|
||||
//ULOGGER_DEBUG("--- %d ---", i);
|
||||
std::map<std::string, float> memStats;
|
||||
mem.update(0, memStats);
|
||||
std::list<Sensor> emptySensors;
|
||||
std::list<Actuator> emptyActuators;
|
||||
mem.update(emptySensors, emptyActuators, memStats);
|
||||
posterior = bayes.computePosterior(&mem, likelihood);
|
||||
likelihood.insert(std::pair<int, float>(i, 1));
|
||||
sum = uSum(uValues(posterior));
|
||||
@@ -510,8 +479,7 @@ void Tests::testVerifyHypotheses()
|
||||
{
|
||||
std::multimap<int, cv::KeyPoint> wordsA;
|
||||
std::multimap<int, cv::KeyPoint> wordsB;
|
||||
std::list<std::pair<cv::KeyPoint, cv::KeyPoint> > pairs;
|
||||
std::list<int> pairsId;
|
||||
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > pairs;
|
||||
|
||||
wordsA.insert(std::pair<int, cv::KeyPoint>(1, cv::KeyPoint(0, 0, 1)));
|
||||
wordsA.insert(std::pair<int, cv::KeyPoint>(2, cv::KeyPoint(2, 2, 1)));
|
||||
@@ -528,16 +496,9 @@ void Tests::testVerifyHypotheses()
|
||||
wordsB.insert(std::pair<int, cv::KeyPoint>(6, cv::KeyPoint(5, 5, 1)));
|
||||
wordsB.insert(std::pair<int, cv::KeyPoint>(6, cv::KeyPoint(6, 6, 1)));
|
||||
|
||||
int total = HypVerificatorEpipolarGeo::findPairsAll(wordsA, wordsB, pairs, pairsId);
|
||||
int total = findPairsAll(wordsA, wordsB, pairs);
|
||||
|
||||
//printf("[%d,%d]\n", total, (int)pairs.size());
|
||||
CPPUNIT_ASSERT(total == 5);
|
||||
CPPUNIT_ASSERT(pairs.size() == 8 && pairsId.size() == 8);
|
||||
|
||||
std::list<std::pair<cv::KeyPoint, cv::KeyPoint> >::iterator pairsIter=pairs.begin();
|
||||
std::list<int>::iterator idIter = pairsId.begin();
|
||||
for(;pairsIter!=pairs.end() && idIter != pairsId.end(); ++pairsIter, ++idIter)
|
||||
{
|
||||
//printf("(%d)[%f,%f] [%f,%f]\n", *idIter, pairsIter->first.pt.x, pairsIter->first.pt.y, pairsIter->second.pt.x, pairsIter->second.pt.x);
|
||||
}
|
||||
CPPUNIT_ASSERT(pairs.size() == 8);
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
|
||||
ADD_SUBDIRECTORY( ConsoleApp )
|
||||
ADD_SUBDIRECTORY( ImagesJoiner )
|
||||
ADD_SUBDIRECTORY( WebcamCapture )
|
||||
ADD_SUBDIRECTORY( Polar )
|
||||
ADD_SUBDIRECTORY( ImagesDbExtractor )
|
||||
ADD_SUBDIRECTORY( ColorIndexesGenerator )
|
||||
|
||||
IF(QT4_FOUND AND QT_QTCORE_FOUND AND QT_QTGUI_FOUND)
|
||||
ADD_SUBDIRECTORY( DatabaseViewer )
|
||||
ADD_SUBDIRECTORY( EpipolarGeometry )
|
||||
ELSE()
|
||||
MESSAGE(STATUS "[WARNING] Qt4 not found, the databaseViewer and epipolarGeometry programs will not be built...")
|
||||
ENDIF()
|
||||
+2
-3
@@ -4,11 +4,10 @@ SET(SRC_FILES
|
||||
)
|
||||
|
||||
SET(INCLUDE_DIRS
|
||||
${PROJECT_SOURCE_DIR}/corelib/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${UTILITE_INCLUDE_DIRS}
|
||||
${OpenCV_INCLUDE_DIRS}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../src
|
||||
${ZLIB_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
@@ -21,7 +20,7 @@ SET(LIBRARIES
|
||||
INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
|
||||
|
||||
ADD_EXECUTABLE(colorIndexesGenerator ${SRC_FILES})
|
||||
TARGET_LINK_LIBRARIES(colorIndexesGenerator corelib ${LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(colorIndexesGenerator rtabmap_corelib ${LIBRARIES})
|
||||
|
||||
SET_TARGET_PROPERTIES( colorIndexesGenerator
|
||||
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-colorIndexesGenerator)
|
||||
@@ -3,8 +3,8 @@
|
||||
#include <fstream>
|
||||
#include <utilite/ULogger.h>
|
||||
#include <utilite/UTimer.h>
|
||||
#include "ColorTable.h"
|
||||
#include "NearestNeighbor.h"
|
||||
#include "rtabmap/core/ColorTable.h"
|
||||
#include "rtabmap/core/NearestNeighbor.h"
|
||||
#include <zlib.h>
|
||||
#include <utilite/UConversion.h>
|
||||
|
||||
@@ -61,6 +61,7 @@ void zerr(int ret)
|
||||
break;
|
||||
case Z_VERSION_ERROR:
|
||||
fputs("zlib version mismatch!\n", stderr);
|
||||
break;
|
||||
}
|
||||
UFATAL("");
|
||||
}
|
||||
@@ -190,7 +191,7 @@ int main(int argc, char** argv)
|
||||
cv::Mat indices = cv::Mat(queries.rows, 1, CV_32S);
|
||||
|
||||
UINFO("Nearest neighbor searching (queries=%d, indexes=%d)...", queries.rows, data.rows);
|
||||
//nn.search(data, queries, indices, dists);
|
||||
nn.search(data, queries, indices, dists);
|
||||
UINFO("Nearest neighbor searching (queries=%d, indexes=%d)... done!", queries.rows, data.rows);
|
||||
|
||||
std::string fileName = uFormat("%s%d%s", FILE_NAME_PREFIX, size, FILE_NAME_SUFFIX);
|
||||
@@ -4,6 +4,7 @@ SET(SRC_FILES
|
||||
)
|
||||
|
||||
SET(INCLUDE_DIRS
|
||||
${PROJECT_SOURCE_DIR}/corelib/include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${UTILITE_INCLUDE_DIRS}
|
||||
${OpenCV_INCLUDE_DIRS}
|
||||
@@ -21,7 +22,7 @@ INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
|
||||
# Add binary called "consoleApp" that is built from the source file "main.cpp".
|
||||
# The extension is automatically found.
|
||||
ADD_EXECUTABLE(consoleApp ${SRC_FILES})
|
||||
TARGET_LINK_LIBRARIES(consoleApp corelib ${LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(consoleApp rtabmap_corelib ${LIBRARIES})
|
||||
|
||||
SET_TARGET_PROPERTIES( consoleApp
|
||||
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-console)
|
||||
@@ -21,7 +21,6 @@
|
||||
#include <utilite/UTimer.h>
|
||||
#include "rtabmap/core/Rtabmap.h"
|
||||
#include "rtabmap/core/Camera.h"
|
||||
#include "rtabmap/core/SMState.h"
|
||||
#include <utilite/UDirectory.h>
|
||||
#include <utilite/UFile.h>
|
||||
#include <utilite/UConversion.h>
|
||||
@@ -51,7 +50,8 @@ void showUsage()
|
||||
" The height must be also specified if changed.\n"
|
||||
" -image_height # Force an image height (Default 0: original size used)\n"
|
||||
" The height must be also specified if changed.\n"
|
||||
" -start_at # When \"path\" is a directory of images, set this parameter "
|
||||
" -frames_dropped # Frames dropped from source (Default 0: no frames dropped)\n"
|
||||
" -start_at # When \"path\" is a directory of images, set this parameter\n"
|
||||
" to start processing at image # (default 1)."
|
||||
" -\"parameter name\" \"value\" Overwrite a specific RTAB-Map's parameter :\n"
|
||||
" -SURF/HessianThreshold 150\n"
|
||||
@@ -117,6 +117,7 @@ int main(int argc, char * argv[])
|
||||
int imageWidth = 0;
|
||||
int imageHeight = 0;
|
||||
int startAt = 1;
|
||||
int framesDropped = 0;
|
||||
ParametersMap pm;
|
||||
ULogger::Level logLevel = ULogger::kError;
|
||||
ULogger::Level exitLevel = ULogger::kFatal;
|
||||
@@ -241,6 +242,23 @@ int main(int argc, char * argv[])
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(strcmp(argv[i], "-frames_dropped") == 0)
|
||||
{
|
||||
++i;
|
||||
if(i < argc)
|
||||
{
|
||||
framesDropped = std::atoi(argv[i]);
|
||||
if(framesDropped < 0)
|
||||
{
|
||||
showUsage();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
showUsage();
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if(strcmp(argv[i], "-start_at") == 0)
|
||||
{
|
||||
++i;
|
||||
@@ -342,19 +360,11 @@ int main(int argc, char * argv[])
|
||||
Camera * camera = 0;
|
||||
if(UDirectory::exists(path))
|
||||
{
|
||||
camera = new CameraImages(path, startAt, false, 0.0f, false, imageWidth, imageHeight);
|
||||
camera = new CameraImages(path, startAt, false, 1/rate, false, imageWidth, imageHeight, framesDropped);
|
||||
}
|
||||
else
|
||||
{
|
||||
std::list<std::string> list = uSplit(path, '.');
|
||||
if(list.size() == 2 && list.back().compare("db") == 0)
|
||||
{
|
||||
camera = new CameraDatabase(path, true, 0.0f, false, imageWidth, imageHeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
camera = new CameraVideo(path, 0.0f, false, imageWidth, imageHeight);
|
||||
}
|
||||
camera = new CameraVideo(path, 1/rate, false, imageWidth, imageHeight, framesDropped);
|
||||
}
|
||||
|
||||
if(!camera || !camera->init())
|
||||
@@ -383,7 +393,6 @@ int main(int argc, char * argv[])
|
||||
printf("Avpd init time = %fs\n", timer.ticks());
|
||||
|
||||
// Start thread's task
|
||||
IplImage * image = 0;
|
||||
int loopClosureId;
|
||||
int count = 0;
|
||||
int countLoopDetected=0;
|
||||
@@ -395,6 +404,7 @@ int main(int argc, char * argv[])
|
||||
printf(" Repeating data set = %s\n", repeat?"true":"false");
|
||||
printf(" Camera width=%d, height=%d (0 is default)\n", imageWidth, imageHeight);
|
||||
printf(" Camera starts at image %d (default 1)\n", startAt);
|
||||
printf(" Camera frames dropped %d (default 0)\n", framesDropped);
|
||||
if(createGT)
|
||||
{
|
||||
printf(" Creating the ground truth matrix.\n");
|
||||
@@ -418,45 +428,29 @@ int main(int argc, char * argv[])
|
||||
ParametersMap allParam;
|
||||
Rtabmap::readParameters(rtabmap->getIniFilePath().c_str(), allParam);
|
||||
pm.insert(allParam.begin(), allParam.end());
|
||||
CamKeypointTreatment imageToSMState(pm);
|
||||
camera->setFeaturesExtracted(true);
|
||||
camera->parseParameters(pm);
|
||||
|
||||
UTimer iterationTimer;
|
||||
int imagesProcessed = 0;
|
||||
std::list<std::vector<float> > teleopActions;
|
||||
int maxTeleopActions = 0; // TEST Lip6Indoor with 190, 0->disabled
|
||||
std::list<std::vector<float> > actions;
|
||||
while(loopDataset <= repeat && g_forever)
|
||||
{
|
||||
SMState * smState = camera->takeSMState();
|
||||
cv::Mat descriptors;
|
||||
std::vector<cv::KeyPoint> keypoints;
|
||||
cv::Mat img = camera->takeImage(descriptors, keypoints);
|
||||
int i=0;
|
||||
while(smState && g_forever)
|
||||
while(!img.empty() && g_forever)
|
||||
{
|
||||
imageToSMState.process(smState);
|
||||
++imagesProcessed;
|
||||
iterationTimer.start();
|
||||
if(i<maxTeleopActions)
|
||||
{
|
||||
// ONLY TESTING HERE if maxTeleopActions>0
|
||||
std::vector<float> v(2);
|
||||
v[0] = 2;
|
||||
v[1] = 0;
|
||||
teleopActions.push_back(v);
|
||||
smState->setActuators(teleopActions);
|
||||
smState->setImage(image);
|
||||
}
|
||||
else
|
||||
{
|
||||
smState->setActuators(actions);
|
||||
smState->setImage(image);
|
||||
}
|
||||
rtabmap->process(smState);
|
||||
rtabmap->process(Sensor(descriptors, keypoints));
|
||||
loopClosureId = rtabmap->getLoopClosureId();
|
||||
actions = rtabmap->getActions();
|
||||
if(rtabmap->getLoopClosureId())
|
||||
{
|
||||
++countLoopDetected;
|
||||
}
|
||||
smState = camera->takeSMState();
|
||||
img = camera->takeImage(descriptors, keypoints);
|
||||
if(++count % 100 == 0)
|
||||
{
|
||||
printf(" count = %d, loop closures = %d\n", count, countLoopDetected);
|
||||
@@ -488,43 +482,17 @@ int main(int argc, char * argv[])
|
||||
|
||||
ULogger::flush();
|
||||
|
||||
if(rate)
|
||||
if(rtabmap->getLoopClosureId())
|
||||
{
|
||||
float delta = rate - iterationTime;
|
||||
if(delta > 0)
|
||||
{
|
||||
uSleep(delta*1000);
|
||||
}
|
||||
printf(" iteration(%d) loop(%d) time=%fs *\n", count, rtabmap->getLoopClosureId(), iterationTime);
|
||||
}
|
||||
if(actions.size())
|
||||
else if(rtabmap->getReactivatedId())
|
||||
{
|
||||
if(rtabmap->getLoopClosureId())
|
||||
{
|
||||
printf(" iteration(%d) actions=%d loop(%d) time=%fs *\n", count, (int)actions.size(), rtabmap->getLoopClosureId(), iterationTime);
|
||||
}
|
||||
else if(rtabmap->getReactivatedId())
|
||||
{
|
||||
printf(" iteration(%d) actions=%d high(%d) time=%fs\n", count, (int)actions.size(), rtabmap->getReactivatedId(), iterationTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" iteration(%d) actions=%d time=%fs\n", count, (int)actions.size(), iterationTime);
|
||||
}
|
||||
printf(" iteration(%d) high(%d) time=%fs\n", count, rtabmap->getReactivatedId(), iterationTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(rtabmap->getLoopClosureId())
|
||||
{
|
||||
printf(" iteration(%d) loop(%d) time=%fs *\n", count, rtabmap->getLoopClosureId(), iterationTime);
|
||||
}
|
||||
else if(rtabmap->getReactivatedId())
|
||||
{
|
||||
printf(" iteration(%d) high(%d) time=%fs\n", count, rtabmap->getReactivatedId(), iterationTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
printf(" iteration(%d) time=%fs\n", count, iterationTime);
|
||||
}
|
||||
printf(" iteration(%d) time=%fs\n", count, iterationTime);
|
||||
}
|
||||
|
||||
if(timeThreshold && iterationTime > timeThreshold*100.0f)
|
||||
@@ -18,15 +18,13 @@ QT4_WRAP_CPP(moc_srcs ${headers_ui})
|
||||
SET(SRC_FILES
|
||||
./main.cpp
|
||||
./MainWindow.cpp
|
||||
../../guilib/src/KeypointItem.cpp
|
||||
${moc_srcs}
|
||||
${moc_uis}
|
||||
)
|
||||
|
||||
SET(INCLUDE_DIRS
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../include
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/../src
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${PROJECT_SOURCE_DIR}/corelib/include
|
||||
${PROJECT_SOURCE_DIR}/guilib/include
|
||||
${UTILITE_INCLUDE_DIRS}
|
||||
${OpenCV_INCLUDE_DIRS}
|
||||
${CMAKE_CURRENT_BINARY_DIR} # for qt ui generated in binary dir
|
||||
@@ -47,7 +45,7 @@ INCLUDE_DIRECTORIES(${INCLUDE_DIRS})
|
||||
# Add binary called "databaseViewer" that is built from the source file "main.cpp".
|
||||
# The extension is automatically found.
|
||||
ADD_EXECUTABLE(databaseViewer WIN32 ${SRC_FILES})
|
||||
TARGET_LINK_LIBRARIES(databaseViewer corelib ${LIBRARIES})
|
||||
TARGET_LINK_LIBRARIES(databaseViewer rtabmap_corelib rtabmap_guilib ${LIBRARIES})
|
||||
|
||||
SET_TARGET_PROPERTIES( databaseViewer
|
||||
PROPERTIES OUTPUT_NAME ${PROJECT_PREFIX}-databaseViewer)
|
||||
@@ -29,9 +29,10 @@
|
||||
#include <utilite/UConversion.h>
|
||||
#include <opencv2/core/core_c.h>
|
||||
#include <utilite/UTimer.h>
|
||||
#include "KeypointMemory.h"
|
||||
#include "rtabmap/core/KeypointMemory.h"
|
||||
#include "rtabmap/core/SMMemory.h"
|
||||
#include "rtabmap/core/DBDriver.h"
|
||||
#include "../../guilib/src/KeypointItem.h"
|
||||
#include "rtabmap/gui/KeypointItem.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget * parent) :
|
||||
QMainWindow(parent),
|
||||
@@ -80,33 +81,47 @@ MainWindow::~MainWindow()
|
||||
|
||||
void MainWindow::openDatabase()
|
||||
{
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), pathDatabase_, tr("Databases (*.db)"));
|
||||
if(!path.isEmpty())
|
||||
QStringList types;
|
||||
types << "Keypoint" << "Sensorimotor";
|
||||
bool ok = false;
|
||||
QString type = QInputDialog::getItem(this, tr("Select database type"), tr("Type"), types, 0, false, &ok);
|
||||
if(ok && !type.isEmpty())
|
||||
{
|
||||
if(memory_)
|
||||
QString path = QFileDialog::getOpenFileName(this, tr("Select file"), pathDatabase_, tr("Databases (*.db)"));
|
||||
if(!path.isEmpty())
|
||||
{
|
||||
delete memory_;
|
||||
memory_ = 0;
|
||||
imagesMap_.clear();
|
||||
ids_.clear();
|
||||
}
|
||||
if(memory_)
|
||||
{
|
||||
delete memory_;
|
||||
memory_ = 0;
|
||||
imagesMap_.clear();
|
||||
ids_.clear();
|
||||
}
|
||||
|
||||
std::string driverType = "sqlite3";
|
||||
rtabmap::ParametersMap parameters;
|
||||
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kDbSqlite3InMemory(), "false"));
|
||||
memory_ = new rtabmap::KeypointMemory(parameters);
|
||||
if(!memory_)
|
||||
{
|
||||
QMessageBox::warning(this, "Database error", tr("Can't create database driver \"%1\"").arg(driverType.c_str()));
|
||||
}
|
||||
else if(!memory_->init(driverType, path.toStdString()))
|
||||
{
|
||||
QMessageBox::warning(this, "Database error", tr("Can't open database \"%1\"").arg(path));
|
||||
}
|
||||
else
|
||||
{
|
||||
pathDatabase_ = path;
|
||||
updateIds();
|
||||
std::string driverType = "sqlite3";
|
||||
rtabmap::ParametersMap parameters;
|
||||
parameters.insert(rtabmap::ParametersPair(rtabmap::Parameters::kDbSqlite3InMemory(), "false"));
|
||||
if(type.compare("Keypoint") == 0)
|
||||
{
|
||||
memory_ = new rtabmap::KeypointMemory(parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
memory_ = new rtabmap::SMMemory(parameters);
|
||||
}
|
||||
if(!memory_)
|
||||
{
|
||||
QMessageBox::warning(this, "Database error", tr("Can't create database driver \"%1\"").arg(driverType.c_str()));
|
||||
}
|
||||
else if(!memory_->init(driverType, path.toStdString()))
|
||||
{
|
||||
QMessageBox::warning(this, "Database error", tr("Can't open database \"%1\"").arg(path));
|
||||
}
|
||||
else
|
||||
{
|
||||
pathDatabase_ = UDirectory::getDir(path.toStdString()).c_str();
|
||||
updateIds();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -238,30 +253,24 @@ void MainWindow::generateLocalGraph()
|
||||
QString path = QFileDialog::getSaveFileName(this, tr("Save File"), pathDatabase_+"/Graph" + QString::number(id) + ".dot", tr("Graphiz file (*.dot)"));
|
||||
if(!path.isEmpty())
|
||||
{
|
||||
if(memory_->getSignature(id) > 0)
|
||||
double dbAccessTime = 0.0;
|
||||
std::map<int, int> ids = memory_->getNeighborsId(dbAccessTime, id, margin, -1, false, false, false);
|
||||
|
||||
if(ids.size() > 0)
|
||||
{
|
||||
double dbAccessTime = 0.0;
|
||||
std::map<int, int> ids = memory_->getNeighborsId(dbAccessTime, id, margin, -1, false, false, false);
|
||||
if(ids.size() > 0)
|
||||
ids.insert(std::pair<int,int>(id, 0));
|
||||
std::set<int> idsSet;
|
||||
for(std::map<int, int>::iterator iter = ids.begin(); iter!=ids.end(); ++iter)
|
||||
{
|
||||
ids.insert(std::pair<int,int>(id, 0));
|
||||
std::set<int> idsSet;
|
||||
for(std::map<int, int>::iterator iter = ids.begin(); iter!=ids.end(); ++iter)
|
||||
{
|
||||
idsSet.insert(idsSet.end(), iter->first);
|
||||
UINFO("Node %d", iter->first);
|
||||
}
|
||||
UINFO("idsSet=%d", idsSet.size());
|
||||
memory_->generateGraph(path.toStdString(), idsSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("No neighbors found for signature %1.").arg(id));
|
||||
idsSet.insert(idsSet.end(), iter->first);
|
||||
UINFO("Node %d", iter->first);
|
||||
}
|
||||
UINFO("idsSet=%d", idsSet.size());
|
||||
memory_->generateGraph(path.toStdString(), idsSet);
|
||||
}
|
||||
else
|
||||
{
|
||||
QMessageBox::critical(this, tr("Error"), tr("Signature %1 not found in database.").arg(id));
|
||||
QMessageBox::critical(this, tr("Error"), tr("No neighbors found for signature %1.").arg(id));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -298,139 +307,44 @@ void MainWindow::drawKeypoints(const std::multimap<int, cv::KeyPoint> & refWords
|
||||
|
||||
void MainWindow::sliderAValueChanged(int value)
|
||||
{
|
||||
ui_->label_indexA->setText(QString::number(value));
|
||||
ui_->label_actionsA->clear();
|
||||
ui_->label_parentsA->clear();
|
||||
ui_->label_childrenA->clear();
|
||||
if(value >= 0 && value < ids_.size())
|
||||
{
|
||||
ui_->graphicsView_A->scene()->clear();
|
||||
int id = ids_.at(value);
|
||||
ui_->label_idA->setText(QString::number(id));
|
||||
if(id>0)
|
||||
{
|
||||
// image
|
||||
QImage img;
|
||||
QMap<int, QByteArray>::iterator iter = imagesMap_.find(id);
|
||||
if(iter == imagesMap_.end())
|
||||
{
|
||||
if(memory_)
|
||||
{
|
||||
IplImage * image = memory_->getImage(id);
|
||||
if(image)
|
||||
{
|
||||
img = ipl2QImage(image);
|
||||
cvReleaseImage(&image);
|
||||
if(!img.isNull())
|
||||
{
|
||||
QByteArray ba;
|
||||
QBuffer buffer(&ba);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
img.save(&buffer, "BMP"); // writes image into ba in BMP format
|
||||
imagesMap_.insert(id, ba);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
img.loadFromData(iter.value(), "BMP");
|
||||
}
|
||||
|
||||
if(memory_)
|
||||
{
|
||||
std::multimap<int, cv::KeyPoint> words = memory_->getWords(id);
|
||||
if(words.size())
|
||||
{
|
||||
drawKeypoints(words, ui_->graphicsView_A->scene());
|
||||
}
|
||||
}
|
||||
|
||||
if(!img.isNull())
|
||||
{
|
||||
ui_->graphicsView_A->scene()->addPixmap(QPixmap::fromImage(img));
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_DEBUG("Image is empty");
|
||||
}
|
||||
|
||||
// actions
|
||||
if(id-1 > 0)
|
||||
{
|
||||
std::list<rtabmap::NeighborLink> links = memory_->getNeighborLinks(id-1, true, true);
|
||||
for(std::list<rtabmap::NeighborLink>::iterator iter = links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
if(iter->id()>id-1 && iter->actions().size())
|
||||
{
|
||||
QString str;
|
||||
const std::list<std::vector<float> > & actions = iter->actions();
|
||||
unsigned int j=0;
|
||||
for(std::list<std::vector<float> >::const_iterator jter=actions.begin(); jter!=actions.end(); ++jter)
|
||||
{
|
||||
for(unsigned int i=0; i<jter->size(); ++i)
|
||||
{
|
||||
str.append(QString("%1 ").arg(jter->at(i)));
|
||||
}
|
||||
if(j+1 < actions.size())
|
||||
{
|
||||
str.append(QString("\n"));
|
||||
}
|
||||
++j;
|
||||
}
|
||||
if(str.size())
|
||||
{
|
||||
ui_->label_actionsA->setText(str);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// loops
|
||||
std::set<int> parents;
|
||||
std::set<int> children;
|
||||
memory_->getLoopClosureIds(id, parents, children, true);
|
||||
if(parents.size())
|
||||
{
|
||||
QString str;
|
||||
for(std::set<int>::iterator iter=parents.begin(); iter!=parents.end(); ++iter)
|
||||
{
|
||||
str.append(QString("%1 ").arg(*iter));
|
||||
}
|
||||
ui_->label_parentsA->setText(str);
|
||||
}
|
||||
if(children.size())
|
||||
{
|
||||
QString str;
|
||||
for(std::set<int>::iterator iter=children.begin(); iter!=children.end(); ++iter)
|
||||
{
|
||||
str.append(QString("%1 ").arg(*iter));
|
||||
}
|
||||
ui_->label_childrenA->setText(str);
|
||||
}
|
||||
}
|
||||
|
||||
ui_->label_idA->setText(QString::number(id));
|
||||
ui_->graphicsView_A->fitInView(ui_->graphicsView_A->scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_ERROR("Slider index out of range ?");
|
||||
}
|
||||
this->update(value,
|
||||
ui_->label_indexA,
|
||||
ui_->label_actionsA,
|
||||
ui_->label_parentsA,
|
||||
ui_->label_childrenA,
|
||||
ui_->graphicsView_A,
|
||||
ui_->label_idA);
|
||||
}
|
||||
|
||||
void MainWindow::sliderBValueChanged(int value)
|
||||
{
|
||||
ui_->label_indexB->setText(QString::number(value));
|
||||
ui_->label_actionsB->clear();
|
||||
ui_->label_parentsB->clear();
|
||||
ui_->label_childrenB->clear();
|
||||
this->update(value,
|
||||
ui_->label_indexB,
|
||||
ui_->label_actionsB,
|
||||
ui_->label_parentsB,
|
||||
ui_->label_childrenB,
|
||||
ui_->graphicsView_B,
|
||||
ui_->label_idB);
|
||||
}
|
||||
|
||||
void MainWindow::update(int value,
|
||||
QLabel * labelIndex,
|
||||
QLabel * labelActions,
|
||||
QLabel * labelParents,
|
||||
QLabel * labelChildren,
|
||||
QGraphicsView * view,
|
||||
QLabel * labelId)
|
||||
{
|
||||
UTimer timer;
|
||||
labelIndex->setText(QString::number(value));
|
||||
labelActions->clear();
|
||||
labelParents->clear();
|
||||
labelChildren->clear();
|
||||
if(value >= 0 && value < ids_.size())
|
||||
{
|
||||
ui_->graphicsView_B->scene()->clear();
|
||||
view->scene()->clear();
|
||||
int id = ids_.at(value);
|
||||
ui_->label_idB->setText(QString::number(id));
|
||||
labelId->setText(QString::number(id));
|
||||
if(id>0)
|
||||
{
|
||||
//image
|
||||
@@ -440,19 +354,29 @@ void MainWindow::sliderBValueChanged(int value)
|
||||
{
|
||||
if(memory_)
|
||||
{
|
||||
IplImage * image = memory_->getImage(id);
|
||||
if(image)
|
||||
std::list<rtabmap::Sensor> sensors = memory_->getRawData(id);
|
||||
if(sensors.size())
|
||||
{
|
||||
img = ipl2QImage(image);
|
||||
cvReleaseImage(&image);
|
||||
|
||||
if(!img.isNull())
|
||||
std::list<rtabmap::Sensor>::const_iterator jter = sensors.begin();
|
||||
for(; jter!=sensors.end(); ++jter)
|
||||
{
|
||||
QByteArray ba;
|
||||
QBuffer buffer(&ba);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
img.save(&buffer, "BMP"); // writes image into ba in BMP format
|
||||
imagesMap_.insert(id, ba);
|
||||
if(jter->type() == rtabmap::Sensor::kTypeImage)
|
||||
{
|
||||
break; //Stop to first
|
||||
}
|
||||
}
|
||||
if(jter != sensors.end())
|
||||
{
|
||||
IplImage iplImg = jter->data();
|
||||
img = ipl2QImage(&iplImg);
|
||||
if(!img.isNull())
|
||||
{
|
||||
QByteArray ba;
|
||||
QBuffer buffer(&ba);
|
||||
buffer.open(QIODevice::WriteOnly);
|
||||
img.save(&buffer, "BMP"); // writes image into ba in BMP format
|
||||
imagesMap_.insert(id, ba);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -462,18 +386,18 @@ void MainWindow::sliderBValueChanged(int value)
|
||||
img.loadFromData(iter.value(), "BMP");
|
||||
}
|
||||
|
||||
if(memory_)
|
||||
if(memory_ && dynamic_cast<rtabmap::KeypointMemory*>(memory_))
|
||||
{
|
||||
std::multimap<int, cv::KeyPoint> words = memory_->getWords(id);
|
||||
std::multimap<int, cv::KeyPoint> words = dynamic_cast<rtabmap::KeypointMemory*>(memory_)->getWords(id);
|
||||
if(words.size())
|
||||
{
|
||||
drawKeypoints(words, ui_->graphicsView_B->scene());
|
||||
drawKeypoints(words, view->scene());
|
||||
}
|
||||
}
|
||||
|
||||
if(!img.isNull())
|
||||
{
|
||||
ui_->graphicsView_B->scene()->addPixmap(QPixmap::fromImage(img));
|
||||
view->scene()->addPixmap(QPixmap::fromImage(img));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -486,18 +410,47 @@ void MainWindow::sliderBValueChanged(int value)
|
||||
std::list<rtabmap::NeighborLink> links = memory_->getNeighborLinks(id-1, true, true);
|
||||
for(std::list<rtabmap::NeighborLink>::iterator iter = links.begin(); iter!=links.end(); ++iter)
|
||||
{
|
||||
if(iter->id()>id-1 && iter->actions().size())
|
||||
if(iter->toId()>id-1 && iter->actuators().size())
|
||||
{
|
||||
QString str("");
|
||||
const std::list<std::vector<float> > & actions = iter->actions();
|
||||
QString str;
|
||||
const std::list<rtabmap::Actuator> & actuators = iter->actuators();
|
||||
unsigned int j=0;
|
||||
for(std::list<std::vector<float> >::const_iterator jter=actions.begin(); jter!=actions.end(); ++jter)
|
||||
for(std::list<rtabmap::Actuator>::const_iterator jter=actuators.begin(); jter!=actuators.end(); ++jter)
|
||||
{
|
||||
for(unsigned int i=0; i<jter->size(); ++i)
|
||||
if(jter->data().elemSize() == 1)
|
||||
{
|
||||
str.append(QString("%1 ").arg(jter->at(i)));
|
||||
for(unsigned int i=0; i<jter->data().total() * jter->data().elemSize(); i+=jter->data().elemSize())
|
||||
{
|
||||
str.append(QString("%1 ").arg(*(char*)(jter->data().data + i)));
|
||||
}
|
||||
}
|
||||
if(j+1 < actions.size())
|
||||
else if(jter->data().elemSize() == 2)
|
||||
{
|
||||
for(unsigned int i=0; i<jter->data().total() * jter->data().elemSize(); i+=jter->data().elemSize())
|
||||
{
|
||||
str.append(QString("%1 ").arg(*(short*)(jter->data().data + i)));
|
||||
}
|
||||
}
|
||||
else if(jter->data().elemSize() == 4)
|
||||
{
|
||||
for(unsigned int i=0; i<jter->data().total() * jter->data().elemSize(); i+=jter->data().elemSize())
|
||||
{
|
||||
if(jter->data().type() & CV_32F)
|
||||
{
|
||||
str.append(QString("%1 ").arg(*(float*)(jter->data().data + i)));
|
||||
}
|
||||
else
|
||||
{
|
||||
str.append(QString("%1 ").arg(*(int*)(jter->data().data + i)));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
UERROR("not handled element size %d", jter->data().elemSize());
|
||||
break;
|
||||
}
|
||||
if(j+1 < actuators.size())
|
||||
{
|
||||
str.append(QString("\n"));
|
||||
}
|
||||
@@ -505,7 +458,7 @@ void MainWindow::sliderBValueChanged(int value)
|
||||
}
|
||||
if(str.size())
|
||||
{
|
||||
ui_->label_actionsB->setText(str);
|
||||
labelActions->setText(str);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -523,7 +476,7 @@ void MainWindow::sliderBValueChanged(int value)
|
||||
{
|
||||
str.append(QString("%1 ").arg(*iter));
|
||||
}
|
||||
ui_->label_parentsB->setText(str);
|
||||
labelParents->setText(str);
|
||||
}
|
||||
if(children.size())
|
||||
{
|
||||
@@ -532,17 +485,18 @@ void MainWindow::sliderBValueChanged(int value)
|
||||
{
|
||||
str.append(QString("%1 ").arg(*iter));
|
||||
}
|
||||
ui_->label_childrenB->setText(str);
|
||||
labelChildren->setText(str);
|
||||
}
|
||||
}
|
||||
|
||||
ui_->label_idB->setText(QString::number(id));
|
||||
ui_->graphicsView_B->fitInView(ui_->graphicsView_B->scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
|
||||
labelId->setText(QString::number(id));
|
||||
view->fitInView(view->scene()->itemsBoundingRect(), Qt::KeepAspectRatio);
|
||||
}
|
||||
else
|
||||
{
|
||||
ULOGGER_ERROR("Slider index out of range ?");
|
||||
}
|
||||
UINFO("Time = %fs", timer.ticks());
|
||||
}
|
||||
|
||||
void MainWindow::sliderAMoved(int value)
|
||||
@@ -571,7 +525,7 @@ void MainWindow::sliderBMoved(int value)
|
||||
}
|
||||
}
|
||||
|
||||
QImage MainWindow::ipl2QImage(const IplImage *newImage) //fct recuperer sur le net, converti un ldImage en QImage
|
||||
QImage MainWindow::ipl2QImage(const IplImage *newImage)
|
||||
{
|
||||
QImage qtemp;
|
||||
if (newImage && newImage->depth == IPL_DEPTH_8U && cvGetSize(newImage).width>0)
|
||||
@@ -31,10 +31,12 @@
|
||||
|
||||
class Ui_MainWindow;
|
||||
class QGraphicsScene;
|
||||
class QGraphicsView;
|
||||
class QLabel;
|
||||
|
||||
namespace rtabmap
|
||||
{
|
||||
class KeypointMemory;
|
||||
class Memory;
|
||||
}
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
@@ -60,12 +62,19 @@ private:
|
||||
void updateIds();
|
||||
QImage ipl2QImage(const IplImage *newImage);
|
||||
void drawKeypoints(const std::multimap<int, cv::KeyPoint> & refWords, QGraphicsScene * scene);
|
||||
void update(int value,
|
||||
QLabel * labelIndex,
|
||||
QLabel * labelActions,
|
||||
QLabel * labelParents,
|
||||
QLabel * labelChildren,
|
||||
QGraphicsView * view,
|
||||
QLabel * labelId);
|
||||
|
||||
private:
|
||||
Ui_MainWindow * ui_;
|
||||
QMap<int, QByteArray> imagesMap_;
|
||||
QList<int> ids_;
|
||||
rtabmap::KeypointMemory * memory_;
|
||||
rtabmap::Memory * memory_;
|
||||
QString pathDatabase_;
|
||||
};
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user