├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── Doxyfile.in ├── LICENSE ├── README.md ├── cfg ├── euroc_cam0.yaml ├── euroc_cam1.yaml ├── p22021_equidist.yaml └── rovio.info ├── include └── rovio │ ├── Camera.hpp │ ├── CoordinateTransform │ ├── FeatureOutput.hpp │ ├── FeatureOutputReadable.hpp │ ├── LandmarkOutput.hpp │ ├── PixelOutput.hpp │ ├── RovioOutput.hpp │ └── YprOutput.hpp │ ├── FeatureCoordinates.hpp │ ├── FeatureDistance.hpp │ ├── FeatureManager.hpp │ ├── FeatureStatistics.hpp │ ├── FilterStates.hpp │ ├── ImagePyramid.hpp │ ├── ImgUpdate.hpp │ ├── ImuPrediction.hpp │ ├── MultiCamera.hpp │ ├── MultilevelPatch.hpp │ ├── MultilevelPatchAlignment.hpp │ ├── Patch.hpp │ ├── PoseUpdate.hpp │ ├── RobocentricFeatureElement.hpp │ ├── RovioFilter.hpp │ ├── RovioNode.hpp │ ├── RovioScene.hpp │ ├── Scene.hpp │ ├── VelocityUpdate.hpp │ ├── ZeroVelocityUpdate.hpp │ ├── exceptions.hpp │ └── featureTracker.hpp ├── launch ├── rovio_node.launch ├── rovio_rosbag_node.launch └── valgrind_rovio.launch ├── mainpage.dox ├── package.xml ├── shaders ├── shader.fs └── shader.vs ├── src ├── Camera.cpp ├── FeatureCoordinates.cpp ├── FeatureDistance.cpp ├── Scene.cpp ├── feature_tracker_node.cpp ├── rovio_node.cpp ├── rovio_rosbag_loader.cpp ├── test_mlp.cpp └── test_patch.cpp └── srv └── SrvResetToPose.srv /.gitignore: -------------------------------------------------------------------------------- 1 | # CMake 2 | CMakeCache.txt 3 | CMakeFiles 4 | Makefile 5 | cmake_install.cmake 6 | install_manifest.txt 7 | gtest 8 | rovio_custom.info 9 | *.bag 10 | *.active 11 | 12 | # Compiled Object files 13 | *.slo 14 | *.lo 15 | *.o 16 | 17 | # Compiled Dynamic libraries 18 | *.so 19 | *.dylib 20 | 21 | # Compiled Static libraries 22 | *.lai 23 | *.la 24 | *.a 25 | 26 | *~ 27 | .* 28 | 29 | html/ 30 | latex/ 31 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lightweight_filtering"] 2 | path = lightweight_filtering 3 | url = https://bitbucket.org/bloesch/lightweight_filtering.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.6) 2 | project(rovio) 3 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x -march=native") 4 | set(ROVIO_NMAXFEATURE 25 CACHE STRING "Number of features for ROVIO") 5 | set(ROVIO_NCAM 1 CACHE STRING "Number of enabled cameras") 6 | set(ROVIO_NLEVELS 4 CACHE STRING "Number of image leavels for the features") 7 | set(ROVIO_PATCHSIZE 6 CACHE STRING "Size of patch (edge length in pixel)") 8 | set(ROVIO_NPOSE 0 CACHE STRING "Additional estimated poses for external pose measurements") 9 | add_definitions(-DROVIO_NMAXFEATURE=${ROVIO_NMAXFEATURE}) 10 | add_definitions(-DROVIO_NCAM=${ROVIO_NCAM}) 11 | add_definitions(-DROVIO_NLEVELS=${ROVIO_NLEVELS}) 12 | add_definitions(-DROVIO_PATCHSIZE=${ROVIO_PATCHSIZE}) 13 | add_definitions(-DROVIO_NPOSE=${ROVIO_NPOSE}) 14 | 15 | add_subdirectory(lightweight_filtering) 16 | 17 | ##################### Find, include, and compile library ##################### 18 | set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/cmake) 19 | if(0) 20 | find_package(OpenMP REQUIRED) 21 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") 22 | endif() 23 | find_package(Eigen3 REQUIRED) 24 | include_directories(${EIGEN3_INCLUDE_DIR}) 25 | 26 | find_package(OpenCV REQUIRED COMPONENTS core highgui imgproc features2d) 27 | 28 | if(MAKE_SCENE) 29 | message(STATUS "Building ROVIO with openGL Scene Visualization") 30 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DMAKE_SCENE=1") 31 | find_package(GLEW REQUIRED) 32 | include_directories(${GLEW_INCLUDE_DIRS}) 33 | 34 | find_package(GLUT REQUIRED) 35 | include_directories(${GLUT_INCLUDE_DIRS}) 36 | link_directories(${GLUT_LIBRARY_DIRS}) 37 | add_definitions(${GLUT_DEFINITIONS}) 38 | 39 | find_package(OpenGL REQUIRED) 40 | include_directories(${OpenGL_INCLUDE_DIRS}) 41 | link_directories(${OpenGL_LIBRARY_DIRS}) 42 | add_definitions(${OpenGL_DEFINITIONS}) 43 | endif() 44 | 45 | find_package(PkgConfig) 46 | 47 | find_package(yaml_cpp_catkin QUIET) 48 | if(${yaml_cpp_catkin_FOUND}) 49 | message(STATUS "Found yaml_cpp_catkin, using instead of system library.") 50 | set(YamlCpp_LIBRARIES ${yaml_cpp_catkin_LIBRARIES}) 51 | set(YamlCpp_INCLUDE_DIRS ${yaml_cpp_catkin_INCLUDE_DIRS}) 52 | else() 53 | message(STATUS "No yaml_cpp_catkin, using yaml-cpp system library instead.") 54 | pkg_check_modules(YamlCpp REQUIRED yaml-cpp>=0.5) 55 | endif() 56 | 57 | 58 | ##################### Install ROS stuff ##################### 59 | find_package(catkin REQUIRED COMPONENTS 60 | lightweight_filtering 61 | kindr 62 | roscpp 63 | roslib 64 | cv_bridge 65 | message_generation 66 | nav_msgs 67 | geometry_msgs 68 | sensor_msgs 69 | std_msgs 70 | tf 71 | rosbag 72 | ) 73 | 74 | add_service_files( 75 | DIRECTORY srv 76 | FILES SrvResetToPose.srv 77 | ) 78 | 79 | generate_messages(DEPENDENCIES 80 | std_msgs 81 | geometry_msgs 82 | ) 83 | 84 | catkin_package( 85 | INCLUDE_DIRS include ${catkin_INCLUDE_DIRS} 86 | LIBRARIES ${PROJECT_NAME} 87 | CATKIN_DEPENDS 88 | lightweight_filtering 89 | kindr 90 | roscpp 91 | roslib 92 | cv_bridge 93 | message_runtime 94 | nav_msgs 95 | geometry_msgs 96 | sensor_msgs 97 | std_msgs 98 | tf 99 | rosbag 100 | yaml_cpp_catkin 101 | ) 102 | 103 | include_directories(include ${catkin_INCLUDE_DIRS} ${YamlCpp_INCLUDE_DIRS}) 104 | 105 | if(MAKE_SCENE) 106 | add_library(${PROJECT_NAME} src/Camera.cpp src/FeatureCoordinates.cpp src/FeatureDistance.cpp src/Scene.cpp) 107 | else() 108 | add_library(${PROJECT_NAME} src/Camera.cpp src/FeatureCoordinates.cpp src/FeatureDistance.cpp) 109 | endif() 110 | target_link_libraries(${PROJECT_NAME} ${catkin_LIBRARIES} ${YamlCpp_LIBRARIES} ${OpenMP_EXE_LINKER_FLAGS} ${OPENGL_LIBRARIES} ${GLUT_LIBRARY} ${GLEW_LIBRARY} ${OpenCV_LIBRARIES}) 111 | add_dependencies(${PROJECT_NAME} ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS} rovio_generate_messages_cpp) 112 | 113 | add_executable(rovio_node src/rovio_node.cpp) 114 | target_link_libraries(rovio_node ${PROJECT_NAME}) 115 | 116 | add_executable(rovio_rosbag_loader src/rovio_rosbag_loader.cpp) 117 | target_link_libraries(rovio_rosbag_loader ${PROJECT_NAME}) 118 | add_dependencies(rovio_rosbag_loader ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 119 | 120 | add_executable(feature_tracker_node src/feature_tracker_node.cpp) 121 | target_link_libraries(feature_tracker_node ${PROJECT_NAME}) 122 | add_dependencies(feature_tracker_node ${${PROJECT_NAME}_EXPORTED_TARGETS} ${catkin_EXPORTED_TARGETS}) 123 | 124 | if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/gtest/") 125 | message(STATUS "Building GTests!") 126 | option(BUILD_GTEST "build gtest" ON) 127 | #add_subdirectory(gtest gtest) 128 | enable_testing() 129 | include_directories(${gtest_SOURCE_DIR}/include ${gtest_SOURCE_DIR}) 130 | add_executable(test_patch src/test_patch.cpp src/Camera.cpp src/FeatureCoordinates.cpp src/FeatureDistance.cpp) 131 | target_link_libraries(test_patch gtest_main gtest pthread ${catkin_LIBRARIES} ${YamlCpp_LIBRARIES}) 132 | add_test(test_patch test_patch) 133 | add_executable(test_mlp src/test_mlp.cpp src/Camera.cpp src/FeatureCoordinates.cpp src/FeatureDistance.cpp) 134 | target_link_libraries(test_mlp gtest_main gtest pthread ${catkin_LIBRARIES} ${YamlCpp_LIBRARIES}) 135 | add_test(test_mlp test_mlp) 136 | endif() 137 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2014, Autonomous Systems Lab 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without 5 | modification, are permitted provided that the following conditions are met: 6 | * Redistributions of source code must retain the above copyright 7 | notice, this list of conditions and the following disclaimer. 8 | * Redistributions in binary form must reproduce the above copyright 9 | notice, this list of conditions and the following disclaimer in the 10 | documentation and/or other materials provided with the distribution. 11 | * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 12 | names of its contributors may be used to endorse or promote products 13 | derived from this software without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # README # 2 | 3 | This repository contains the ROVIO (Robust Visual Inertial Odometry) framework. The code is open-source (BSD License). Please remember that it is strongly coupled to on-going research and thus some parts are not fully mature yet. Furthermore, the code will also be subject to changes in the future which could include greater re-factoring of some parts. 4 | 5 | Video: https://youtu.be/ZMAISVy-6ao 6 | 7 | Papers: 8 | * http://dx.doi.org/10.3929/ethz-a-010566547 (IROS 2015) 9 | * http://dx.doi.org/10.1177/0278364917728574 (IJRR 2017) 10 | 11 | Please also have a look at the wiki: https://github.com/ethz-asl/rovio/wiki 12 | 13 | ### Install without opengl scene ### 14 | Dependencies: 15 | * ros 16 | * kindr (https://github.com/ethz-asl/kindr) 17 | * lightweight_filtering (as submodule, use "git submodule update --init --recursive") 18 | 19 | ``` 20 | #!command 21 | 22 | catkin build rovio --cmake-args -DCMAKE_BUILD_TYPE=Release 23 | ``` 24 | 25 | ### Install with opengl scene ### 26 | Additional dependencies: opengl, glut, glew (sudo apt-get install freeglut3-dev, sudo apt-get install libglew-dev) 27 | ``` 28 | #!command 29 | 30 | catkin build rovio --cmake-args -DCMAKE_BUILD_TYPE=Release -DMAKE_SCENE=ON 31 | ``` 32 | 33 | ### Euroc Datasets ### 34 | The rovio_node.launch file loads parameters such that ROVIO runs properly on the Euroc datasets. The datasets are available under: 35 | http://projects.asl.ethz.ch/datasets/doku.php?id=kmavvisualinertialdatasets 36 | 37 | ### Further notes ### 38 | * Camera matrix and distortion parameters should be provided by a yaml file or loaded through rosparam 39 | * The cfg/rovio.info provides most parameters for rovio. The camera extrinsics qCM (quaternion from IMU to camera frame, Hamilton-convention) and MrMC (Translation between IMU and Camera expressed in the IMU frame) should also be set there. They are being estimated during runtime so only a rough guess should be sufficient. 40 | * Especially for application with little motion fixing the IMU-camera extrinsics can be beneficial. This can be done by setting the parameter doVECalibration to false. Please be carefull that the overall robustness and accuracy can be very sensitive to bad extrinsic calibrations. 41 | -------------------------------------------------------------------------------- /cfg/euroc_cam0.yaml: -------------------------------------------------------------------------------- 1 | ###### Camera Calibration File For Cam 0 of Euroc Datasets ###### 2 | image_width: 752 3 | image_height: 480 4 | camera_name: cam0 5 | camera_matrix: 6 | rows: 3 7 | cols: 3 8 | data: [458.654, 0.0, 367.215, 0.0, 457.296, 248.375, 0.0, 0.0, 1.0] 9 | distortion_model: plumb_bob 10 | distortion_coefficients: 11 | rows: 1 12 | cols: 5 13 | data: [-0.28340811, 0.07395907, 0.00019359, 1.76187114e-05, 0.0] 14 | 15 | ###### Original Calibration File ###### 16 | ## General sensor definitions. 17 | #sensor_type: camera 18 | #comment: VI-Sensor cam0 (MT9M034) 19 | # 20 | ## Sensor extrinsics wrt. the body-frame. 21 | #T_BS: 22 | # cols: 4 23 | # rows: 4 24 | # data: [0.0148655429818, -0.999880929698, 0.00414029679422, -0.0216401454975, 25 | # 0.999557249008, 0.0149672133247, 0.025715529948, -0.064676986768, 26 | # -0.0257744366974, 0.00375618835797, 0.999660727178, 0.00981073058949, 27 | # 0.0, 0.0, 0.0, 1.0] 28 | # 29 | ## Camera specific definitions. 30 | #rate_hz: 20 31 | #resolution: [752, 480] 32 | #camera_model: pinhole 33 | #intrinsics: [458.654, 457.296, 367.215, 248.375] #fu, fv, cu, cv 34 | #distortion_model: radial-tangential 35 | #distortion_coefficients: [-0.28340811, 0.07395907, 0.00019359, 1.76187114e-05] 36 | 37 | 38 | -------------------------------------------------------------------------------- /cfg/euroc_cam1.yaml: -------------------------------------------------------------------------------- 1 | ###### Camera Calibration File For Cam 1 of Euroc Datasets ###### 2 | image_width: 752 3 | image_height: 480 4 | camera_name: cam1 5 | camera_matrix: 6 | rows: 3 7 | cols: 3 8 | data: [457.587, 0.0, 379.999, 0.0, 456.134, 255.238, 0.0, 0.0, 1.0] 9 | distortion_model: plumb_bob 10 | distortion_coefficients: 11 | rows: 1 12 | cols: 5 13 | data: [-0.28368365, 0.07451284, -0.00010473, -3.55590700e-05, 0.0] 14 | 15 | ###### Original Calibration File ###### 16 | ## General sensor definitions. 17 | #sensor_type: camera 18 | #comment: VI-Sensor cam1 (MT9M034) 19 | # 20 | ## Sensor extrinsics wrt. the body-frame. 21 | #T_BS: 22 | # cols: 4 23 | # rows: 4 24 | # data: [0.0125552670891, -0.999755099723, 0.0182237714554, -0.0198435579556, 25 | # 0.999598781151, 0.0130119051815, 0.0251588363115, 0.0453689425024, 26 | # -0.0253898008918, 0.0179005838253, 0.999517347078, 0.00786212447038, 27 | # 0.0, 0.0, 0.0, 1.0] 28 | # 29 | ## Camera specific definitions. 30 | #rate_hz: 20 31 | #resolution: [752, 480] 32 | #camera_model: pinhole 33 | #intrinsics: [457.587, 456.134, 379.999, 255.238] #fu, fv, cu, cv 34 | #distortion_model: radial-tangential 35 | #distortion_coefficients: [-0.28368365, 0.07451284, -0.00010473, -3.55590700e-05] 36 | -------------------------------------------------------------------------------- /cfg/p22021_equidist.yaml: -------------------------------------------------------------------------------- 1 | image_width: 752 2 | image_height: 480 3 | camera_name: cam0 4 | camera_matrix: 5 | rows: 3 6 | cols: 3 7 | data: [470.3492376936415, 0.0, 369.1539326770507, 0.0, 468.5354540935562, 243.7389899263136, 0.0, 0.0, 1.0] 8 | distortion_model: equidistant 9 | distortion_coefficients: 10 | rows: 1 11 | cols: 4 12 | data: [-0.0028217288073635748, 0.01424046033816201, -0.017070691627755135, 13 | 0.01198286934702205] 14 | rectification_matrix: 15 | rows: 3 16 | cols: 3 17 | data: [0.9999662253908055, 0.0012167240196736123, -0.008128201543077645, -0.00123142707670882, 0.9999976143402003, -0.0018041344913520734, 0.008125987018183612, 0.0018140828448797777, 0.9999653381184831] 18 | projection_matrix: 19 | rows: 3 20 | cols: 4 21 | data: [431.8121136491133, 0.0, 395.5353126525879, 0.0, 0.0, 431.8121136491133, 235.97241592407227, 0.0, 0.0, 0.0, 1.0, 0.0] 22 | -------------------------------------------------------------------------------- /include/rovio/Camera.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_CAMERA_HPP_ 30 | #define ROVIO_CAMERA_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include <opencv2/features2d/features2d.hpp> 34 | #include "lightweight_filtering/State.hpp" 35 | 36 | namespace rovio{ 37 | 38 | class Camera{ 39 | public: 40 | /** \brief Distortion model of the camera. 41 | * */ 42 | enum ModelType{ 43 | RADTAN, //!< Radial tangential distortion model. 44 | EQUIDIST, //!< Equidistant distortion model. 45 | DS //!< Double sphere distortion model. 46 | } type_; 47 | 48 | Eigen::Matrix3d K_; //!< Intrinsic parameter matrix. 49 | 50 | //@{ 51 | /** \brief Distortion Parameter. */ 52 | double k1_,k2_,k3_,k4_,k5_,k6_; 53 | double p1_,p2_,s1_,s2_,s3_,s4_; 54 | //@} 55 | 56 | //@{ 57 | /** \brief Radius (as ratio of images shortest side) within which features can be initalized. */ 58 | double valid_radius_; 59 | //@} 60 | 61 | /** \brief Constructor. 62 | * 63 | * Initializes the camera object as pinhole camera, i.e. all distortion coefficients are set to zero. 64 | * The intrinsic parameter matrix is set equal to the identity matrix. 65 | * */ 66 | Camera(); 67 | 68 | /** \brief Destructor. 69 | * */ 70 | virtual ~Camera(); 71 | 72 | /** \brief Loads and sets the intrinsic parameter matrix K_ from yaml-file. 73 | * 74 | * @param filename - Path to the yaml-file, containing the intrinsic parameter matrix coefficients. 75 | */ 76 | void loadCameraMatrix(const std::string& filename); 77 | 78 | /** \brief Loads and sets the distortion parameters {k1_, k2_, k3_, p1_, p2_} for the Radtan distortion model from 79 | * yaml-file. 80 | * @param filename - Path to the yaml-file, containing the distortion coefficients. 81 | */ 82 | void loadRadtan(const std::string& filename); 83 | 84 | /** \brief Loads and sets the distortion parameters {k1_, k2_, k3_, k4_} for the Equidistant distortion model from 85 | * yaml-file. 86 | * @param filename - Path to the yaml-file, containing the distortion coefficients. 87 | */ 88 | void loadEquidist(const std::string& filename); 89 | 90 | /** \brief Loads and sets the distortion parameters {k1_, k2_} for the Double Sphere distortion model from 91 | * yaml-file. 92 | * @param filename - Path to the yaml-file, containing the distortion coefficients. 93 | */ 94 | void loadDoubleSphere(const std::string& filename); 95 | 96 | /** \brief Loads and sets the distortion model and the corresponding distortion coefficients from yaml-file. 97 | * 98 | * @param filename - Path to the yaml-file, containing the distortion model and distortion coefficient data. 99 | */ 100 | void load(const std::string& filename); 101 | 102 | /** \brief Distorts a point on the unit plane (in camera coordinates) according to the Radtan distortion model. 103 | * 104 | * @param in - Undistorted point coordinates on the unit plane (in camera coordinates). 105 | * @param out - Distorted point coordinates on the unit plane (in camera coordinates). 106 | */ 107 | void distortRadtan(const Eigen::Vector2d& in, Eigen::Vector2d& out) const; 108 | 109 | /** \brief Distorts a point on the unit plane (in camera coordinates) according to the Radtan distortion model and 110 | * outputs additionally the corresponding jacobian matrix (input to output). 111 | * 112 | * @param in - Undistorted point coordinates on the unit plane (in camera coordinates). 113 | * @param out - Distorted point coordinates on the unit plane (in camera coordinates). 114 | * @param J - Jacobian matrix of the distortion process (input to output). 115 | */ 116 | void distortRadtan(const Eigen::Vector2d& in, Eigen::Vector2d& out, Eigen::Matrix2d& J) const; 117 | 118 | /** \brief Distorts a point on the unit plane (in camera coordinates) according to the Equidistant distortion model. 119 | * 120 | * @param in - Undistorted point coordinates on the unit plane (in camera coordinates). 121 | * @param out - Distorted point coordinates on the unit plane (in camera coordinates). 122 | */ 123 | void distortEquidist(const Eigen::Vector2d& in, Eigen::Vector2d& out) const; 124 | 125 | /** \brief Distorts a point on the unit plane (in camera coordinates) according to the Equidistant distortion model 126 | * and outputs additionally the corresponding jacobian matrix (input to output). 127 | * 128 | * @param in - Undistorted point coordinates on the unit plane (in camera coordinates). 129 | * @param out - Distorted point coordinates on the unit plane (in camera coordinates). 130 | * @param J - Jacobian matrix of the distortion process (input to output). 131 | */ 132 | void distortEquidist(const Eigen::Vector2d& in, Eigen::Vector2d& out, Eigen::Matrix2d& J) const; 133 | 134 | /** \brief Distorts a point on the unit plane (in camera coordinates) according to the Double Sphere distortion model. 135 | * 136 | * @param in - Undistorted point coordinates on the unit plane (in camera coordinates). 137 | * @param out - Distorted point coordinates on the unit plane (in camera coordinates). 138 | */ 139 | void distortDoubleSphere(const Eigen::Vector2d& in, Eigen::Vector2d& out) const; 140 | 141 | /** \brief Distorts a point on the unit plane (in camera coordinates) according to the Double Sphere distortion model 142 | * and outputs additionally the corresponding jacobian matrix (input to output). 143 | * 144 | * @param in - Undistorted point coordinates on the unit plane (in camera coordinates). 145 | * @param out - Distorted point coordinates on the unit plane (in camera coordinates). 146 | * @param J - Jacobian matrix of the distortion process (input to output). 147 | */ 148 | void distortDoubleSphere(const Eigen::Vector2d& in, Eigen::Vector2d& out, Eigen::Matrix2d& J) const; 149 | 150 | /** \brief Distorts a point on the unit plane, according to the set distortion model (#ModelType) and to the set 151 | * distortion coefficients. 152 | * 153 | * @param in - Undistorted point coordinates on the unit plane (in camera coordinates). 154 | * @param out - Distorted point coordinates on the unit plane (in camera coordinates). 155 | */ 156 | void distort(const Eigen::Vector2d& in, Eigen::Vector2d& out) const; 157 | 158 | /** \brief Distorts a point on the unit plane, according to the set distortion model (#ModelType) and to the set 159 | * distortion coefficients. Outputs additionally the corresponding jacobian matrix (input to output). 160 | * 161 | * @param in - Undistorted point coordinates on the unit plane (in camera coordinates). 162 | * @param out - Distorted point coordinates on the unit plane (in camera coordinates). 163 | * @param J - Jacobian matrix of the distortion process (input to output). 164 | */ 165 | void distort(const Eigen::Vector2d& in, Eigen::Vector2d& out, Eigen::Matrix2d& J) const; 166 | 167 | /** \brief Outputs the (distorted) pixel coordinates corresponding to a given bearing vector, 168 | * using the set distortion model. 169 | * 170 | * @param vec - Bearing vector (in camera coordinates | unit length not necessary). 171 | * @param c - (Distorted) pixel coordinates. 172 | * @return True, if process successful. 173 | */ 174 | bool bearingToPixel(const Eigen::Vector3d& vec, cv::Point2f& c) const; 175 | 176 | /** \brief Outputs the (distorted) pixel coordinates corresponding to a given bearing vector, 177 | * using the set distortion model. Outputs additionally the corresponding jacobian matrix (input to output). 178 | * 179 | * @param vec - Bearing vector (in camera coordinates | unit length not necessary). 180 | * @param c - (Distorted) pixel coordinates. 181 | * @param J - Jacobian matrix of the distortion process (input to output). 182 | * @return True, if process successful. 183 | */ 184 | bool bearingToPixel(const Eigen::Vector3d& vec, cv::Point2f& c, Eigen::Matrix<double,2,3>& J) const; 185 | 186 | /** \brief Outputs the (distorted) pixel coordinates corresponding to a given NormalVectorElement-Object 187 | * (bearing vector), using the set distortion model. 188 | * 189 | * @param n - NormalVectorElement-Object. 190 | * @param c - (Distorted pixel) coordinates. 191 | * @return True, if process successful. 192 | */ 193 | bool bearingToPixel(const LWF::NormalVectorElement& n, cv::Point2f& c) const; 194 | 195 | /** \brief Outputs the (distorted) pixel coordinates corresponding to a given NormalVectorElement-Object 196 | * (bearing vector), using the set distortion model. 197 | * 198 | * @param n - NormalVectorElement-Object. 199 | * @param c - (Distorted) pixel coordinates. 200 | * @param J - Jacobian matrix of the distortion process (input to output). 201 | * @return True, if process successful. 202 | */ 203 | bool bearingToPixel(const LWF::NormalVectorElement& n, cv::Point2f& c, Eigen::Matrix<double,2,2>& J) const; 204 | 205 | /** \brief Get the bearing vector, corresponding to a specific (distorted) pixel. 206 | * 207 | * @param c - (Distorted) pixel. 208 | * @param vec - Bearing vector (unit length). 209 | * @return True, if process successful. 210 | */ 211 | bool pixelToBearing(const cv::Point2f& c,Eigen::Vector3d& vec) const; 212 | 213 | /** \brief Get the NormalVectorElement-Object (bearing vector) corresponding to a specific (distorted) pixel. 214 | * 215 | * @param c - (Distorted) pixel. 216 | * @param vec - NormalVectorElement-Object. 217 | * @return True, if process successful. 218 | */ 219 | bool pixelToBearing(const cv::Point2f& c,LWF::NormalVectorElement& n) const; 220 | 221 | /** \brief Function testing the camera model by randomly mapping bearing vectors to pixel coordinates and vice versa. 222 | */ 223 | void testCameraModel(); 224 | }; 225 | 226 | } 227 | 228 | 229 | #endif /* ROVIO_CAMERA_HPP_ */ 230 | -------------------------------------------------------------------------------- /include/rovio/CoordinateTransform/FeatureOutput.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_FEATUREOUTPUT_HPP_ 30 | #define ROVIO_FEATUREOUTPUT_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "lightweight_filtering/CoordinateTransform.hpp" 34 | #include "rovio/RobocentricFeatureElement.hpp" 35 | #include "rovio/MultiCamera.hpp" 36 | 37 | namespace rovio { 38 | 39 | class FeatureOutput: public LWF::State<RobocentricFeatureElement>{ 40 | public: 41 | static constexpr unsigned int _fea = 0; 42 | FeatureOutput(){ 43 | static_assert(_fea+1==E_,"Error with indices"); 44 | this->template getName<_fea>() = "fea"; 45 | } 46 | virtual ~FeatureOutput(){}; 47 | 48 | //@{ 49 | /** \brief Get/Set the distance parameter 50 | * 51 | * @return a reference to distance parameter of the feature. 52 | */ 53 | inline FeatureDistance& d(){ 54 | return this->template get<_fea>().distance_; 55 | } 56 | inline const FeatureDistance& d() const{ 57 | return this->template get<_fea>().distance_; 58 | } 59 | //@} 60 | 61 | //@{ 62 | /** \brief Get/Set the feature coordinates 63 | * 64 | * @return a reference to the feature coordinates 65 | */ 66 | inline FeatureCoordinates& c() { 67 | return this->template get<_fea>().coordinates_; 68 | } 69 | inline const FeatureCoordinates& c() const{ 70 | return this->template get<_fea>().coordinates_; 71 | } 72 | //@} 73 | }; 74 | 75 | template<typename STATE> 76 | class FeatureOutputCT:public LWF::CoordinateTransform<STATE,FeatureOutput>{ 77 | public: 78 | typedef LWF::CoordinateTransform<STATE,FeatureOutput> Base; 79 | typedef typename Base::mtInput mtInput; 80 | typedef typename Base::mtOutput mtOutput; 81 | int ID_; 82 | FeatureOutputCT(){ 83 | ID_ = -1; 84 | }; 85 | virtual ~FeatureOutputCT(){}; 86 | void setFeatureID(int ID){ 87 | ID_ = ID; 88 | } 89 | void evalTransform(mtOutput& output, const mtInput& input) const{ 90 | output.template get<mtOutput::_fea>() = input.template get<mtInput::_fea>(ID_); 91 | } 92 | void jacTransform(MXD& J, const mtInput& input) const{ 93 | J.setIdentity(); 94 | } 95 | }; 96 | 97 | template<typename STATE> 98 | class TransformFeatureOutputCT:public LWF::CoordinateTransform<STATE,FeatureOutput>{ 99 | public: 100 | typedef LWF::CoordinateTransform<STATE,FeatureOutput> Base; 101 | typedef typename Base::mtInput mtInput; 102 | typedef typename Base::mtOutput mtOutput; 103 | int outputCamID_; 104 | int ID_; 105 | bool ignoreDistanceOutput_; 106 | MultiCamera<STATE::nCam_>* mpMultiCamera_; 107 | TransformFeatureOutputCT(MultiCamera<STATE::nCam_>* mpMultiCamera){ 108 | mpMultiCamera_ = mpMultiCamera; 109 | outputCamID_ = 0; 110 | ID_ = -1; 111 | ignoreDistanceOutput_ = false; 112 | }; 113 | virtual ~TransformFeatureOutputCT(){}; 114 | void setFeatureID(int ID){ 115 | ID_ = ID; 116 | } 117 | void setOutputCameraID(int camID){ 118 | outputCamID_ = camID; 119 | } 120 | void evalTransform(mtOutput& output, const mtInput& input) const{ 121 | input.updateMultiCameraExtrinsics(mpMultiCamera_); 122 | mpMultiCamera_->transformFeature(outputCamID_,input.CfP(ID_),input.dep(ID_),output.c(),output.d()); 123 | if(input.CfP(ID_).trackWarping_ && input.CfP(ID_).com_warp_nor()){ 124 | const int& camID = input.CfP(ID_).camID_; 125 | const QPD qDC = input.qCM(outputCamID_)*input.qCM(camID).inverted(); // TODO: avoid double computation 126 | const V3D CrCD = input.qCM(camID).rotate(V3D(input.MrMC(outputCamID_)-input.MrMC(camID))); 127 | const V3D CrCP = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getVec(); 128 | const V3D DrDP = qDC.rotate(V3D(CrCP-CrCD)); 129 | const double d_out = DrDP.norm(); 130 | const LWF::NormalVectorElement nor_out(DrDP); 131 | const Eigen::Matrix<double,2,3> J_nor_DrDP = nor_out.getM().transpose()/d_out; 132 | const Eigen::Matrix<double,3,3> J_DrDP_CrCP = MPD(qDC).matrix(); 133 | const Eigen::Matrix<double,3,2> J_CrCP_nor = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getM(); 134 | output.c().set_warp_nor(J_nor_DrDP*J_DrDP_CrCP*J_CrCP_nor*input.CfP(ID_).get_warp_nor()); 135 | } 136 | } 137 | void jacTransform(MXD& J, const mtInput& input) const{ 138 | J.setZero(); 139 | const int& camID = input.CfP(ID_).camID_; 140 | if(camID != outputCamID_){ 141 | input.updateMultiCameraExtrinsics(mpMultiCamera_); 142 | const QPD qDC = input.qCM(outputCamID_)*input.qCM(camID).inverted(); // TODO: avoid double computation 143 | const V3D CrCD = input.qCM(camID).rotate(V3D(input.MrMC(outputCamID_)-input.MrMC(camID))); 144 | const V3D CrCP = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getVec(); 145 | const V3D DrDP = qDC.rotate(V3D(CrCP-CrCD)); 146 | const double d_out = DrDP.norm(); 147 | const LWF::NormalVectorElement nor_out(DrDP); // TODO: test if Jacobian works, this new setting of vector is dangerous 148 | 149 | const Eigen::Matrix<double,1,3> J_d_DrDP = nor_out.getVec().transpose(); 150 | const Eigen::Matrix<double,2,3> J_nor_DrDP = nor_out.getM().transpose()/d_out; 151 | const Eigen::Matrix<double,3,3> J_DrDP_qDC = gSM(DrDP); 152 | const Eigen::Matrix<double,3,3> J_DrDP_CrCP = MPD(qDC).matrix(); 153 | const Eigen::Matrix<double,3,3> J_DrDP_CrCD = -MPD(qDC).matrix(); 154 | 155 | const Eigen::Matrix<double,3,3> J_qDC_qDB = Eigen::Matrix3d::Identity(); 156 | const Eigen::Matrix<double,3,3> J_qDC_qCB = -MPD(qDC).matrix(); 157 | const Eigen::Matrix<double,3,3> J_CrCD_qCB = gSM(CrCD); 158 | const Eigen::Matrix<double,3,3> J_CrCD_BrBC = -MPD(input.qCM(camID)).matrix(); 159 | const Eigen::Matrix<double,3,3> J_CrCD_BrBD = MPD(input.qCM(camID)).matrix(); 160 | 161 | const Eigen::Matrix<double,3,1> J_CrCP_d = input.CfP(ID_).get_nor().getVec()*input.dep(ID_).getDistanceDerivative(); 162 | const Eigen::Matrix<double,3,2> J_CrCP_nor = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getM(); 163 | 164 | J.template block<2,2>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_fea>(ID_)) = J_nor_DrDP*J_DrDP_CrCP*J_CrCP_nor; 165 | J.template block<2,1>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_fea>(ID_)+2) = J_nor_DrDP*J_DrDP_CrCP*J_CrCP_d; 166 | if(!ignoreDistanceOutput_){ 167 | J.template block<1,2>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_fea>(ID_)) = J_d_DrDP*J_DrDP_CrCP*J_CrCP_nor; 168 | J.template block<1,1>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_fea>(ID_)+2) = J_d_DrDP*J_DrDP_CrCP*J_CrCP_d; 169 | } 170 | 171 | if(input.aux().doVECalibration_ && camID != outputCamID_){ 172 | J.template block<2,3>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_vea>(camID)) = J_nor_DrDP*(J_DrDP_qDC*J_qDC_qCB+J_DrDP_CrCD*J_CrCD_qCB); 173 | J.template block<2,3>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_vea>(outputCamID_)) = J_nor_DrDP*J_DrDP_qDC*J_qDC_qDB; 174 | J.template block<2,3>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_vep>(camID)) = J_nor_DrDP*J_DrDP_CrCD*J_CrCD_BrBC; 175 | J.template block<2,3>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_vep>(outputCamID_)) = J_nor_DrDP*J_DrDP_CrCD*J_CrCD_BrBD; 176 | if(!ignoreDistanceOutput_){ 177 | J.template block<1,3>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_vea>(camID)) = J_d_DrDP*(J_DrDP_qDC*J_qDC_qCB+J_DrDP_CrCD*J_CrCD_qCB); 178 | J.template block<1,3>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_vea>(outputCamID_)) = J_d_DrDP*J_DrDP_qDC*J_qDC_qDB; 179 | J.template block<1,3>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_vep>(camID)) = J_d_DrDP*J_DrDP_CrCD*J_CrCD_BrBC; 180 | J.template block<1,3>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_vep>(outputCamID_)) = J_d_DrDP*J_DrDP_CrCD*J_CrCD_BrBD; 181 | } 182 | } 183 | } else { 184 | J.template block<2,2>(mtOutput::template getId<mtOutput::_fea>(),mtInput::template getId<mtInput::_fea>(ID_)) = Eigen::Matrix2d::Identity(); 185 | J.template block<1,1>(mtOutput::template getId<mtOutput::_fea>()+2,mtInput::template getId<mtInput::_fea>(ID_)+2) = Eigen::Matrix<double,1,1>::Identity(); 186 | } 187 | } 188 | }; 189 | 190 | } 191 | 192 | 193 | #endif /* ROVIO_FEATUREOUTPUT_HPP_ */ 194 | -------------------------------------------------------------------------------- /include/rovio/CoordinateTransform/FeatureOutputReadable.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_FEATUREOUTPUTREADABLE_HPP_ 30 | #define ROVIO_FEATUREOUTPUTREADABLE_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "lightweight_filtering/CoordinateTransform.hpp" 34 | #include "rovio/CoordinateTransform/FeatureOutput.hpp" 35 | 36 | namespace rovio { 37 | 38 | class FeatureOutputReadable: public LWF::State<LWF::VectorElement<3>,LWF::ScalarElement>{ 39 | public: 40 | static constexpr unsigned int _bea = 0; 41 | static constexpr unsigned int _dis = _bea+1; 42 | FeatureOutputReadable(){ 43 | static_assert(_dis+1==E_,"Error with indices"); 44 | this->template getName<_bea>() = "bea"; 45 | this->template getName<_dis>() = "dis"; 46 | } 47 | virtual ~FeatureOutputReadable(){}; 48 | 49 | //@{ 50 | /** \brief Get/Set the distance parameter 51 | * 52 | * @return a reference to distance parameter of the feature. 53 | */ 54 | inline Eigen::Vector3d& bea(){ 55 | return this->template get<_bea>(); 56 | } 57 | inline const Eigen::Vector3d& bea() const{ 58 | return this->template get<_bea>(); 59 | } 60 | //@} 61 | 62 | //@{ 63 | /** \brief Get/Set the feature coordinates 64 | * 65 | * @return a reference to the feature coordinates 66 | */ 67 | inline double& dis(){ 68 | return this->template get<_dis>(); 69 | } 70 | inline const double& dis() const{ 71 | return this->template get<_dis>(); 72 | } 73 | //@} 74 | }; 75 | 76 | class FeatureOutputReadableCT:public LWF::CoordinateTransform<FeatureOutput,FeatureOutputReadable>{ 77 | public: 78 | typedef LWF::CoordinateTransform<FeatureOutput,FeatureOutputReadable> Base; 79 | typedef typename Base::mtInput mtInput; 80 | typedef typename Base::mtOutput mtOutput; 81 | FeatureOutputReadableCT(){}; 82 | virtual ~FeatureOutputReadableCT(){}; 83 | void evalTransform(mtOutput& output, const mtInput& input) const{ 84 | output.bea() = input.c().get_nor().getVec(); 85 | output.dis() = input.d().getDistance(); 86 | } 87 | void jacTransform(MXD& J, const mtInput& input) const{ 88 | J.setZero(); 89 | J.template block<3,2>(mtOutput::template getId<mtOutput::_bea>(),mtInput::template getId<mtInput::_fea>()) = input.c().get_nor().getM(); 90 | J(mtOutput::template getId<mtOutput::_dis>(),mtInput::template getId<mtInput::_fea>()+2) = input.d().getDistanceDerivative(); 91 | } 92 | }; 93 | 94 | } 95 | 96 | 97 | #endif /* ROVIO_FEATUREOUTPUTREADABLE_HPP_ */ 98 | -------------------------------------------------------------------------------- /include/rovio/CoordinateTransform/LandmarkOutput.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_LANDMARKOUTPUTIMU_HPP_ 30 | #define ROVIO_LANDMARKOUTPUTIMU_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "lightweight_filtering/CoordinateTransform.hpp" 34 | #include "rovio/MultiCamera.hpp" 35 | 36 | namespace rovio { 37 | 38 | class LandmarkOutput: public LWF::State<LWF::VectorElement<3>>{ 39 | public: 40 | static constexpr unsigned int _lmk = 0; 41 | LandmarkOutput(){ 42 | static_assert(_lmk+1==E_,"Error with indices"); 43 | this->template getName<_lmk>() = "lmk"; 44 | } 45 | virtual ~LandmarkOutput(){}; 46 | 47 | //@{ 48 | /** \brief Get/Set the feature as 3D vector 49 | * 50 | * @return a reference to the landmark 51 | */ 52 | inline V3D& lmk(){ 53 | return this->template get<_lmk>(); 54 | } 55 | inline const V3D& lmk() const{ 56 | return this->template get<_lmk>(); 57 | } 58 | //@} 59 | }; 60 | 61 | template<typename STATE> 62 | class LandmarkOutputImuCT:public LWF::CoordinateTransform<STATE,LandmarkOutput>{ 63 | public: 64 | typedef LWF::CoordinateTransform<STATE,LandmarkOutput> Base; 65 | typedef typename Base::mtInput mtInput; 66 | typedef typename Base::mtOutput mtOutput; 67 | int ID_; 68 | MultiCamera<STATE::nCam_>* mpMultiCamera_; 69 | LandmarkOutputImuCT(MultiCamera<STATE::nCam_>* mpMultiCamera){ 70 | mpMultiCamera_ = mpMultiCamera; 71 | ID_ = -1; 72 | }; 73 | virtual ~LandmarkOutputImuCT(){}; 74 | void setFeatureID(int ID){ 75 | ID_ = ID; 76 | } 77 | void evalTransform(mtOutput& output, const mtInput& input) const{ 78 | input.updateMultiCameraExtrinsics(mpMultiCamera_); 79 | // BrBP = BrBC + qCB^T(d_in*nor_in) 80 | const V3D CrCP = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getVec(); 81 | output.template get<mtOutput::_lmk>() = mpMultiCamera_->BrBC_[input.CfP(ID_).camID_] + mpMultiCamera_->qCB_[input.CfP(ID_).camID_].inverseRotate(CrCP); 82 | } 83 | void jacTransform(MXD& J, const mtInput& input) const{ 84 | J.setZero(); 85 | input.updateMultiCameraExtrinsics(mpMultiCamera_); 86 | const V3D CrCP = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getVec(); 87 | const Eigen::Matrix<double,3,2> J_CrCP_nor = input.dep(ID_).getDistance()*input.CfP(ID_).get_nor().getM(); 88 | const Eigen::Matrix<double,3,1> J_CrCP_d = input.CfP(ID_).get_nor().getVec()*input.dep(ID_).getDistanceDerivative(); 89 | const M3D mBC = MPD(mpMultiCamera_->qCB_[input.CfP(ID_).camID_].inverted()).matrix(); 90 | 91 | J.template block<3,2>(mtOutput::template getId<mtOutput::_lmk>(),mtInput::template getId<mtInput::_fea>(ID_)) = mBC*J_CrCP_nor; 92 | J.template block<3,1>(mtOutput::template getId<mtOutput::_lmk>(),mtInput::template getId<mtInput::_fea>(ID_)+2) = mBC*J_CrCP_d; 93 | 94 | if(input.aux().doVECalibration_){ 95 | J.template block<3,3>(mtOutput::template getId<mtOutput::_lmk>(),mtInput::template getId<mtInput::_vep>()) = M3D::Identity(); 96 | J.template block<3,3>(mtOutput::template getId<mtOutput::_lmk>(),mtInput::template getId<mtInput::_vea>()) = mBC*gSM(CrCP); 97 | } 98 | } 99 | }; 100 | 101 | } 102 | 103 | 104 | #endif /* ROVIO_LANDMARKOUTPUTIMU_HPP_ */ 105 | -------------------------------------------------------------------------------- /include/rovio/CoordinateTransform/PixelOutput.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_PIXELOUTPUT_HPP_ 30 | #define ROVIO_PIXELOUTPUT_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "lightweight_filtering/CoordinateTransform.hpp" 34 | #include "rovio/CoordinateTransform/FeatureOutput.hpp" 35 | 36 | namespace rovio { 37 | 38 | class PixelOutput: public LWF::State<LWF::VectorElement<2>>{ 39 | public: 40 | static constexpr unsigned int _pix = 0; 41 | PixelOutput(){ 42 | } 43 | virtual ~PixelOutput(){}; 44 | cv::Point2f getPoint2f() const{ 45 | return cv::Point2f(static_cast<float>(this->get<_pix>()(0)),static_cast<float>(this->get<_pix>()(1))); 46 | } 47 | }; 48 | 49 | class PixelOutputCT:public LWF::CoordinateTransform<FeatureOutput,PixelOutput>{ 50 | public: 51 | typedef LWF::CoordinateTransform<FeatureOutput,PixelOutput> Base; 52 | typedef typename Base::mtInput mtInput; 53 | typedef typename Base::mtOutput mtOutput; 54 | PixelOutputCT(){ 55 | }; 56 | virtual ~PixelOutputCT(){}; 57 | void evalTransform(mtOutput& output, const mtInput& input) const{ 58 | cv::Point2f c = input.c().get_c(); 59 | output.template get<mtOutput::_pix>() = Eigen::Vector2d(c.x,c.y); 60 | } 61 | void jacTransform(MXD& J, const mtInput& input) const{ 62 | J.setZero(); 63 | J.template block<2,2>(mtOutput::template getId<mtOutput::_pix>(),mtInput::template getId<mtInput::_fea>()) = input.c().get_J(); 64 | } 65 | }; 66 | 67 | } 68 | 69 | 70 | #endif /* ROVIO_PIXELOUTPUT_HPP_ */ 71 | -------------------------------------------------------------------------------- /include/rovio/CoordinateTransform/RovioOutput.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIOOUTPUT_HPP_ 30 | #define ROVIOOUTPUT_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "lightweight_filtering/CoordinateTransform.hpp" 34 | 35 | namespace rovio { 36 | 37 | class StandardOutput: public LWF::State<LWF::TH_multiple_elements<LWF::VectorElement<3>,3>,LWF::QuaternionElement>{ 38 | public: 39 | static constexpr unsigned int _pos = 0; /**<Idx. Position Vector WrWB: Pointing from the World-Frame to the Body-Frame, expressed in World-Coordinates.*/ 40 | static constexpr unsigned int _vel = _pos+1; /**<Idx. Velocity Vector BvB: Absolute velocity of the of the Body-Frame, expressed in Body-Coordinates.*/ 41 | static constexpr unsigned int _ror = _vel+1; /**<Idx. Angular velocity BwWB: Absolute angular velocity of the Body frame (of the solid), expressed in Body coordinates.*/ 42 | static constexpr unsigned int _att = _ror+1; /**<Idx. Quaternion qBW: World coordinates to Body coordinates.*/ 43 | StandardOutput(){ 44 | } 45 | virtual ~StandardOutput(){}; 46 | 47 | //@{ 48 | /** \brief Get the position vector pointing from the World-Frame to the Body-Frame, expressed in World-Coordinates (World->%Body, expressed in World). 49 | * 50 | * @return the position vector WrWB (World->Body, expressed in World). 51 | */ 52 | inline V3D& WrWB(){ 53 | return this->template get<_pos>(); 54 | } 55 | inline const V3D& WrWB() const{ 56 | return this->template get<_pos>(); 57 | } 58 | //@} 59 | 60 | //@{ 61 | /** \brief Get the absolute velocity vector of the camera, expressed in camera coordinates. 62 | * 63 | * @return the absolute velocity vector of the Body-Frame BvB, expressed in Body-Coordinates. 64 | */ 65 | inline V3D& BvB(){ 66 | return this->template get<_vel>(); 67 | } 68 | inline const V3D& BvB() const{ 69 | return this->template get<_vel>(); 70 | } 71 | //@} 72 | 73 | //@{ 74 | /** \brief Get the absolute angular velocity of the camera (angular velocity of the solid), expressed in camera coordinates. 75 | * 76 | * @return the absolute angular velocity of the Body-Frame BwWB, expressed in Body-Coordinates. 77 | */ 78 | inline V3D& BwWB(){ 79 | return this->template get<_ror>(); 80 | } 81 | inline const V3D& BwWB() const{ 82 | return this->template get<_ror>(); 83 | } 84 | //@} 85 | 86 | //@{ 87 | /** \brief Get the quaternion qBW, expressing the World-Frame in Body-Coordinates (World Coordinates->Body Coordinates). 88 | * 89 | * @return the quaternion qBW (World Coordinates->Body Coordinates). 90 | */ 91 | inline QPD& qBW(){ 92 | return this->template get<_att>(); 93 | } 94 | inline const QPD& qBW() const{ 95 | return this->template get<_att>(); 96 | } 97 | //@} 98 | }; 99 | 100 | template<typename STATE> 101 | class CameraOutputCT:public LWF::CoordinateTransform<STATE,StandardOutput>{ 102 | public: 103 | typedef LWF::CoordinateTransform<STATE,StandardOutput> Base; 104 | typedef typename Base::mtInput mtInput; 105 | typedef typename Base::mtOutput mtOutput; 106 | int camID_; 107 | CameraOutputCT(){ 108 | camID_ = 0; 109 | }; 110 | virtual ~CameraOutputCT(){}; 111 | void evalTransform(mtOutput& output, const mtInput& input) const{ 112 | // WrWC = WrWM + qWM*(MrMC) 113 | // CwWC = qCM*MwWM 114 | // CvC = qCM*(MvM + MwWM x MrMC) 115 | // qCW = qCM*qWM^T 116 | output.WrWB() = input.WrWM()+input.qWM().rotate(input.MrMC(camID_)); 117 | output.BwWB() = input.qCM(camID_).rotate(V3D(input.aux().MwWMmeas_-input.gyb())); 118 | output.BvB() = input.qCM(camID_).rotate(V3D(-input.MvM() + gSM(V3D(input.aux().MwWMmeas_-input.gyb()))*input.MrMC(camID_))); 119 | output.qBW() = input.qCM(camID_)*input.qWM().inverted(); 120 | } 121 | void jacTransform(MXD& J, const mtInput& input) const{ 122 | J.setZero(); 123 | J.template block<3,3>(mtOutput::template getId<mtOutput::_pos>(),mtInput::template getId<mtInput::_pos>()) = M3D::Identity(); 124 | J.template block<3,3>(mtOutput::template getId<mtOutput::_pos>(),mtInput::template getId<mtInput::_att>()) = 125 | -gSM(input.qWM().rotate(input.MrMC(camID_))); 126 | J.template block<3,3>(mtOutput::template getId<mtOutput::_att>(),mtInput::template getId<mtInput::_att>()) = 127 | -MPD(input.qCM(camID_)*input.qWM().inverted()).matrix(); 128 | J.template block<3,3>(mtOutput::template getId<mtOutput::_vel>(),mtInput::template getId<mtInput::_vel>()) = -MPD(input.qCM(camID_)).matrix(); 129 | J.template block<3,3>(mtOutput::template getId<mtOutput::_vel>(),mtInput::template getId<mtInput::_gyb>()) = MPD(input.qCM(camID_)).matrix() 130 | * gSM(input.MrMC(camID_)); 131 | J.template block<3,3>(mtOutput::template getId<mtOutput::_ror>(),mtInput::template getId<mtInput::_gyb>()) = -MPD(input.qCM(camID_)).matrix(); 132 | if(input.aux().doVECalibration_){ 133 | J.template block<3,3>(mtOutput::template getId<mtOutput::_pos>(),mtInput::template getId<mtInput::_vep>(camID_)) = 134 | MPD(input.qWM()).matrix(); 135 | J.template block<3,3>(mtOutput::template getId<mtOutput::_vel>(),mtInput::template getId<mtInput::_vep>(camID_)) = 136 | MPD(input.qCM(camID_)).matrix()*gSM(V3D(input.aux().MwWMmeas_-input.gyb())); 137 | J.template block<3,3>(mtOutput::template getId<mtOutput::_ror>(),mtInput::template getId<mtInput::_vea>(camID_)) = 138 | -gSM(input.qCM(camID_).rotate(V3D(input.aux().MwWMmeas_-input.gyb()))); 139 | J.template block<3,3>(mtOutput::template getId<mtOutput::_vel>(),mtInput::template getId<mtInput::_vea>(camID_)) = 140 | -gSM(input.qCM(camID_).rotate(V3D(-input.MvM() + gSM(V3D(input.aux().MwWMmeas_-input.gyb()))*input.MrMC()))); 141 | J.template block<3,3>(mtOutput::template getId<mtOutput::_att>(),mtInput::template getId<mtInput::_vea>(camID_)) = 142 | M3D::Identity(); 143 | } 144 | } 145 | void postProcess(MXD& cov,const mtInput& input){ 146 | cov.template block<3,3>(mtOutput::template getId<mtOutput::_ror>(),mtOutput::template getId<mtOutput::_ror>()) += input.aux().wMeasCov_; 147 | } 148 | }; 149 | 150 | template<typename STATE> 151 | class ImuOutputCT:public LWF::CoordinateTransform<STATE,StandardOutput>{ 152 | public: 153 | typedef LWF::CoordinateTransform<STATE,StandardOutput> Base; 154 | typedef typename Base::mtInput mtInput; 155 | typedef typename Base::mtOutput mtOutput; 156 | ImuOutputCT(){}; 157 | virtual ~ImuOutputCT(){}; 158 | void evalTransform(mtOutput& output, const mtInput& input) const{ 159 | // WrWM = WrWM 160 | // MwWM = MwWM 161 | // MvM = MvM 162 | // qMW = qWM^T 163 | output.WrWB() = input.WrWM(); 164 | output.BwWB() = input.aux().MwWMmeas_-input.gyb(); 165 | output.BvB() = -input.MvM(); // minus is required! 166 | output.qBW() = input.qWM().inverted(); 167 | } 168 | void jacTransform(MXD& J, const mtInput& input) const{ 169 | J.setZero(); 170 | J.template block<3,3>(mtOutput::template getId<mtOutput::_pos>(),mtInput::template getId<mtInput::_pos>()) = M3D::Identity(); 171 | J.template block<3,3>(mtOutput::template getId<mtOutput::_att>(),mtInput::template getId<mtInput::_att>()) = -MPD(input.qWM().inverted()).matrix(); 172 | J.template block<3,3>(mtOutput::template getId<mtOutput::_vel>(),mtInput::template getId<mtInput::_vel>()) = -M3D::Identity(); 173 | J.template block<3,3>(mtOutput::template getId<mtOutput::_ror>(),mtInput::template getId<mtInput::_gyb>()) = -M3D::Identity(); 174 | } 175 | void postProcess(MXD& cov,const mtInput& input){ 176 | cov.template block<3,3>(mtOutput::template getId<mtOutput::_ror>(),mtOutput::template getId<mtOutput::_ror>()) += input.aux().wMeasCov_; 177 | } 178 | }; 179 | 180 | } 181 | 182 | 183 | #endif /* ROVIOOUTPUT_HPP_ */ 184 | -------------------------------------------------------------------------------- /include/rovio/CoordinateTransform/YprOutput.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_YPROUTPUT_HPP_ 30 | #define ROVIO_YPROUTPUT_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "lightweight_filtering/CoordinateTransform.hpp" 34 | 35 | namespace rovio { 36 | 37 | class AttitudeOutput: public LWF::State<LWF::QuaternionElement>{ 38 | public: 39 | static constexpr unsigned int _att = 0; 40 | AttitudeOutput(){ 41 | } 42 | virtual ~AttitudeOutput(){}; 43 | }; 44 | 45 | class YprOutput: public LWF::State<LWF::VectorElement<3>>{ 46 | public: 47 | static constexpr unsigned int _ypr = 0; 48 | YprOutput(){ 49 | } 50 | virtual ~YprOutput(){}; 51 | 52 | 53 | }; 54 | 55 | class AttitudeToYprCT:public LWF::CoordinateTransform<AttitudeOutput,YprOutput>{ 56 | public: 57 | typedef LWF::CoordinateTransform<AttitudeOutput,YprOutput> Base; 58 | typedef typename Base::mtInput mtInput; 59 | typedef typename Base::mtOutput mtOutput; 60 | AttitudeToYprCT(){}; 61 | virtual ~AttitudeToYprCT(){}; 62 | void evalTransform(mtOutput& output, const mtInput& input) const{ 63 | output.template get<mtOutput::_ypr>() = kindr::EulerAnglesZyxD(input.template get<mtInput::_att>()).vector(); 64 | } 65 | void jacTransform(MXD& J, const mtInput& input) const{ 66 | kindr::EulerAnglesZyxD zyx(input.template get<mtInput::_att>()); 67 | J = zyx.getMappingFromLocalAngularVelocityToDiff()*MPD(input.template get<mtInput::_att>().inverted()).matrix(); 68 | } 69 | }; 70 | 71 | } 72 | 73 | 74 | #endif /* ROVIO_YPROUTPUT_HPP_ */ 75 | -------------------------------------------------------------------------------- /include/rovio/FeatureDistance.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef FEATUREDISTANCE_HPP_ 30 | #define FEATUREDISTANCE_HPP_ 31 | 32 | namespace rovio { 33 | 34 | /** \brief Class allowing the computation of some distance. Different parametrizations are implemented. 35 | */ 36 | class FeatureDistance{ 37 | public: 38 | double p_; /**<Distance parameter*/ 39 | 40 | /** \brief Specifies the parametrization type 41 | */ 42 | enum Type{ 43 | REGULAR, /**<Regular distance p = d*/ 44 | INVERSE, /**<Inverse distance p = 1/d*/ 45 | LOG, /**<Logarithmic distance p = ln(d)*/ 46 | HYPERBOLIC /**<Hyperbolic distance p = asinh(d)*/ 47 | } type_; 48 | 49 | /** \brief Constructor. Create a FeatureDistance object with a desired \ref Type. 50 | * 51 | * @param type - enum \ref Type. 52 | */ 53 | FeatureDistance(const Type& type = REGULAR); 54 | 55 | /** \brief Destructor 56 | */ 57 | virtual ~FeatureDistance(); 58 | 59 | /** \brief Set the \ref Type type_ using the enum \ref Type. 60 | * 61 | * @param type - Enum \ref Type. 62 | */ 63 | void setType(const Type& type); 64 | 65 | /** \brief Get the set \ref Type. 66 | * 67 | * @return the set \ref Type. 68 | */ 69 | Type getType(); 70 | 71 | /** \brief Set the \ref Type type_ using the integer value of the enum \ref Type. 72 | * 73 | * @param type - Integer value of the enum \ref Type. 74 | */ 75 | void setType(const int& type); 76 | 77 | /** \brief Returns the distance based on the set \ref Type type_. 78 | * 79 | * @return Distance value. 80 | */ 81 | void setParameter(const double& d); 82 | 83 | /** \brief Returns the distance based on the set \ref Type type_. 84 | * 85 | * @return Distance value. 86 | */ 87 | double getDistance() const; 88 | 89 | /** \brief Returns the derivative of the distance w.r.t. the parameter. 90 | * 91 | * @return d derived w.r.t. p 92 | */ 93 | double getDistanceDerivative() const; 94 | 95 | /** \brief Returns the derivative of the parameter w.r.t. the distance. 96 | * 97 | * @return p derived w.r.t. d 98 | */ 99 | double getParameterDerivative() const; 100 | 101 | /** \brief Returns the derivative of the parameter w.r.t. the distance w.r.t. the parameter. 102 | * 103 | * @return p derived w.r.t. d and then derived w.r.t. p 104 | */ 105 | double getParameterDerivativeCombined() const; 106 | 107 | /** \brief Converts from an other feature distance parametrization 108 | * 109 | * @param other "other" feature distance, the type is beeing considered during conversion 110 | */ 111 | void getParameterDerivativeCombined(FeatureDistance other); 112 | 113 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 114 | 115 | /** \brief Set the distance parameter for a desired distance for a regular parametrization. 116 | * 117 | * @param Distance value. 118 | */ 119 | void setParameterRegular(const double& d); 120 | 121 | /** \brief Returns the distance based for a regular parametrization. 122 | * 123 | * @return Distance value. 124 | */ 125 | double getDistanceRegular() const; 126 | 127 | /** \brief Returns the derivative of the distance w.r.t. the parameter based for a regular parametrization. 128 | * 129 | * @return d derived w.r.t. p 130 | */ 131 | double getDistanceDerivativeRegular() const; 132 | 133 | /** \brief Returns the derivative of the parameter w.r.t. the distance based for a regular parametrization. 134 | * 135 | * @return p derived w.r.t. d 136 | */ 137 | double getParameterDerivativeRegular() const; 138 | 139 | /** \brief Returns the derivative of the parameter w.r.t. the distance w.r.t. the parameter based for a regular parametrization. 140 | * 141 | * @return p derived w.r.t. d and then derived w.r.t. p 142 | */ 143 | double getParameterDerivativeCombinedRegular() const; 144 | 145 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 146 | 147 | /** \brief Ensures that a value is non-zero by setting it to a small value 148 | * 149 | * @param p - Input 150 | * @return Garanteed non-zero output 151 | */ 152 | double makeNonZero(const double& p) const; 153 | 154 | /** \brief Set the distance parameter for a desired distance for a inverse parametrization. 155 | * 156 | * @param Distance value. 157 | */ 158 | void setParameterInverse(const double& d); 159 | 160 | /** \brief Returns the distance based for a Inverse parametrization. 161 | * 162 | * @return Distance value. 163 | */ 164 | double getDistanceInverse() const; 165 | 166 | /** \brief Returns the derivative of the distance w.r.t. the parameter based for a Inverse parametrization. 167 | * 168 | * @return d derived w.r.t. p 169 | */ 170 | double getDistanceDerivativeInverse() const; 171 | 172 | /** \brief Returns the derivative of the parameter w.r.t. the distance based for a Inverse parametrization. 173 | * 174 | * @return p derived w.r.t. d 175 | */ 176 | double getParameterDerivativeInverse() const; 177 | 178 | /** \brief Returns the derivative of the parameter w.r.t. the distance w.r.t. the parameter based for a Inverse parametrization. 179 | * 180 | * @return p derived w.r.t. d and then derived w.r.t. p 181 | */ 182 | double getParameterDerivativeCombinedInverse() const; 183 | 184 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 185 | 186 | /** \brief Set the distance parameter for a desired distance for a log parametrization. 187 | * 188 | * @param Distance value. 189 | */ 190 | void setParameterLog(const double& d); 191 | 192 | /** \brief Returns the distance based for a Log parametrization. 193 | * 194 | * @return Distance value. 195 | */ 196 | double getDistanceLog() const; 197 | 198 | /** \brief Returns the derivative of the distance w.r.t. the parameter based for a Log parametrization. 199 | * 200 | * @return d derived w.r.t. p 201 | */ 202 | double getDistanceDerivativeLog() const; 203 | 204 | /** \brief Returns the derivative of the parameter w.r.t. the distance based for a Log parametrization. 205 | * 206 | * @return p derived w.r.t. d 207 | */ 208 | double getParameterDerivativeLog() const; 209 | 210 | /** \brief Returns the derivative of the parameter w.r.t. the distance w.r.t. the parameter based for a Log parametrization. 211 | * 212 | * @return p derived w.r.t. d and then derived w.r.t. p 213 | */ 214 | double getParameterDerivativeCombinedLog() const; 215 | 216 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 217 | 218 | /** \brief Set the distance parameter for a desired distance for a hyperbolic parametrization. 219 | * 220 | * @param Distance value. 221 | */ 222 | void setParameterHyperbolic(const double& d); 223 | 224 | /** \brief Returns the distance based for a Hyperbolic parametrization. 225 | * 226 | * @return Distance value. 227 | */ 228 | double getDistanceHyperbolic() const; 229 | 230 | /** \brief Returns the derivative of the distance w.r.t. the parameter based for a Hyperbolic parametrization. 231 | * 232 | * @return d derived w.r.t. p 233 | */ 234 | double getDistanceDerivativeHyperbolic() const; 235 | 236 | /** \brief Returns the derivative of the parameter w.r.t. the distance based for a Hyperbolic parametrization. 237 | * 238 | * @return p derived w.r.t. d 239 | */ 240 | double getParameterDerivativeHyperbolic() const; 241 | 242 | /** \brief Returns the derivative of the parameter w.r.t. the distance w.r.t. the parameter based for a Hyperbolic parametrization. 243 | * 244 | * @return p derived w.r.t. d and then derived w.r.t. p 245 | */ 246 | double getParameterDerivativeCombinedHyperbolic() const; 247 | }; 248 | 249 | } 250 | 251 | 252 | #endif /* FEATUREDISTANCE_HPP_ */ 253 | -------------------------------------------------------------------------------- /include/rovio/ImagePyramid.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef IMAGEPYRAMID_HPP_ 30 | #define IMAGEPYRAMID_HPP_ 31 | 32 | #include <opencv2/features2d/features2d.hpp> 33 | #include <opencv2/imgproc/imgproc.hpp> 34 | #include <opencv2/highgui/highgui.hpp> 35 | #include "rovio/FeatureCoordinates.hpp" 36 | 37 | namespace rovio{ 38 | 39 | /** \brief Halfsamples an image. 40 | * 41 | * @param imgIn - Input image. 42 | * @param imgOut - Output image (halfsampled). 43 | */ 44 | void halfSample(const cv::Mat& imgIn,cv::Mat& imgOut){ 45 | imgOut.create(imgIn.rows/2,imgIn.cols/2,imgIn.type()); 46 | const int refStepIn = imgIn.step.p[0]; 47 | const int refStepOut = imgOut.step.p[0]; 48 | uint8_t* imgPtrInTop; 49 | uint8_t* imgPtrInBot; 50 | uint8_t* imgPtrOut; 51 | for(int y=0; y<imgOut.rows; ++y){ 52 | imgPtrInTop = imgIn.data + 2*y*refStepIn; 53 | imgPtrInBot = imgIn.data + (2*y+1)*refStepIn; 54 | imgPtrOut = imgOut.data + y*refStepOut; 55 | for(int x=0; x<imgOut.cols; ++x, ++imgPtrOut, imgPtrInTop += 2, imgPtrInBot += 2) 56 | { 57 | *imgPtrOut = (imgPtrInTop[0]+imgPtrInTop[1]+imgPtrInBot[0]+imgPtrInBot[1])/4; 58 | } 59 | } 60 | } 61 | 62 | /** \brief Image pyramid with selectable number of levels. 63 | * 64 | * @tparam n_levels - Number of pyramid levels. 65 | * @todo: complete rule of three 66 | */ 67 | template<int n_levels> 68 | class ImagePyramid{ 69 | public: 70 | ImagePyramid(){}; 71 | virtual ~ImagePyramid(){}; 72 | cv::Mat imgs_[n_levels]; /**<Array, containing the pyramid images.*/ 73 | cv::Point2f centers_[n_levels]; /**<Array, containing the image center coordinates (in pixel), defined in an 74 | image centered coordinate system of the image at level 0.*/ 75 | 76 | /** \brief Initializes the image pyramid from an input image (level 0). 77 | * 78 | * @param img - Input image (level 0). 79 | * @param useCv - Set to true, if opencv (cv::pyrDown) should be used for the pyramid creation. 80 | */ 81 | void computeFromImage(const cv::Mat& img, const bool useCv = false){ 82 | img.copyTo(imgs_[0]); 83 | centers_[0] = cv::Point2f(0,0); 84 | for(int i=1; i<n_levels; ++i){ 85 | if(!useCv){ 86 | halfSample(imgs_[i-1],imgs_[i]); 87 | centers_[i].x = centers_[i-1].x-pow(0.5,2-i)*(float)(imgs_[i-1].rows%2); 88 | centers_[i].y = centers_[i-1].y-pow(0.5,2-i)*(float)(imgs_[i-1].cols%2); 89 | } else { 90 | cv::pyrDown(imgs_[i-1],imgs_[i],cv::Size(imgs_[i-1].cols/2, imgs_[i-1].rows/2)); 91 | centers_[i].x = centers_[i-1].x-pow(0.5,2-i)*(float)((imgs_[i-1].rows%2)+1); 92 | centers_[i].y = centers_[i-1].y-pow(0.5,2-i)*(float)((imgs_[i-1].cols%2)+1); 93 | } 94 | } 95 | } 96 | 97 | /** \brief Copies the image pyramid. 98 | */ 99 | ImagePyramid<n_levels>& operator=(const ImagePyramid<n_levels> &rhs) { 100 | for(unsigned int i=0;i<n_levels;i++){ 101 | rhs.imgs_[i].copyTo(imgs_[i]); 102 | centers_[i] = rhs.centers_[i]; 103 | } 104 | return *this; 105 | } 106 | 107 | /** \brief Transforms pixel coordinates between two pyramid levels. 108 | * 109 | * @Note Invalidates camera and bearing vector, since the camera model is not valid for arbitrary image levels. 110 | * @param cIn - Input coordinates 111 | * @param cOut - Output coordinates 112 | * @param l1 - Input pyramid level. 113 | * @param l2 - Output pyramid level. 114 | * @return the corresponding pixel coordinates on pyramid level l2. 115 | */ 116 | FeatureCoordinates levelTranformCoordinates(const FeatureCoordinates& cIn, const int l1, const int l2) const{ 117 | assert(l1<n_levels && l2<n_levels && l1>=0 && l2>=0); 118 | 119 | FeatureCoordinates cOut; 120 | cOut.set_c((centers_[l1]-centers_[l2])*pow(0.5,l2)+cIn.get_c()*pow(0.5,l2-l1)); 121 | if(cIn.mpCamera_ != nullptr){ 122 | if(cIn.com_warp_c()){ 123 | cOut.set_warp_c(cIn.get_warp_c()); 124 | } 125 | } 126 | cOut.camID_ = -1; 127 | cOut.mpCamera_ = nullptr; 128 | return cOut; 129 | } 130 | 131 | /** \brief Extract FastCorner coordinates 132 | * 133 | * @param candidates - List of the extracted corner coordinates (defined on pyramid level 0). 134 | * @param l - Pyramid level at which the corners should be extracted. 135 | * @param detectionThreshold - Detection threshold of the used cv::FastFeatureDetector. 136 | * See http://docs.opencv.org/trunk/df/d74/classcv_1_1FastFeatureDetector.html 137 | * @param valid_radius - Radius inside which a feature is considered valid (as ratio of shortest image side) 138 | */ 139 | void detectFastCorners(FeatureCoordinatesVec & candidates, int l, int detectionThreshold, double valid_radius = std::numeric_limits<double>::max()) const{ 140 | std::vector<cv::KeyPoint> keypoints; 141 | #if (CV_MAJOR_VERSION < 3) 142 | cv::FastFeatureDetector feature_detector_fast(detectionThreshold, true); 143 | feature_detector_fast.detect(imgs_[l], keypoints); 144 | #else 145 | auto feature_detector_fast = cv::FastFeatureDetector::create(detectionThreshold, true); 146 | feature_detector_fast->detect(imgs_[l], keypoints); 147 | #endif 148 | 149 | candidates.reserve(candidates.size()+keypoints.size()); 150 | for (auto it = keypoints.cbegin(), end = keypoints.cend(); it != end; ++it) { 151 | 152 | const double x_dist = it->pt.x - imgs_[l].cols/2.0; 153 | const double y_dist = it->pt.y - imgs_[l].rows/2.0; 154 | const double max_valid_dist = valid_radius*std::min(imgs_[l].cols, imgs_[l].rows); 155 | 156 | if((x_dist*x_dist + y_dist*y_dist) > (max_valid_dist*max_valid_dist)){ 157 | continue; 158 | } 159 | 160 | candidates.push_back( 161 | levelTranformCoordinates(FeatureCoordinates(cv::Point2f(it->pt.x, it->pt.y)),l,0)); 162 | } 163 | } 164 | }; 165 | 166 | } 167 | 168 | 169 | #endif /* IMAGEPYRAMID_HPP_ */ 170 | -------------------------------------------------------------------------------- /include/rovio/MultiCamera.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_MULTICAMERA_HPP_ 30 | #define ROVIO_MULTICAMERA_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "rovio/Camera.hpp" 34 | #include "rovio/FeatureCoordinates.hpp" 35 | 36 | namespace rovio{ 37 | 38 | template<int nCam> 39 | class MultiCamera{ 40 | public: 41 | V3D BrBC_[nCam]; //!< Translational extrinsic parameter 42 | QPD qCB_[nCam]; //!< Rotational extrinsic parameter 43 | Camera cameras_[nCam]; //!< Camera array 44 | 45 | /** \brief Constructor. 46 | * 47 | * Initializes the multicamera object with all cameras at the same point 48 | * */ 49 | MultiCamera(){ 50 | for(unsigned int i=0;i<nCam;i++){ 51 | qCB_[i].setIdentity(); 52 | BrBC_[i].setZero(); 53 | } 54 | }; 55 | virtual ~MultiCamera(){}; 56 | 57 | /** \brief Sets the extrinsics of the i'th camera 58 | * 59 | * @param i - Camera index 60 | * @param BrBC - Translational extrinsic parameter 61 | * @param qCB - Rotational extrinsic parameter 62 | */ 63 | void setExtrinsics(const int i, const V3D& BrBC, const QPD& qCB){ 64 | BrBC_[i] = BrBC; 65 | qCB_[i] = qCB; 66 | } 67 | 68 | /** \brief Loads and sets the distortion model and the corresponding distortion coefficients from yaml-file for camera i 69 | * 70 | * @param i - Camera index 71 | * @param filename - Path to the yaml-file, containing the distortion model and distortion coefficient data. 72 | */ 73 | void load(const int i, const std::string& filename){ 74 | cameras_[i].load(filename); 75 | } 76 | 77 | /** \brief Transforms feature coordinates from one camera frame to another 78 | * 79 | * @param u - Camera index of output frame 80 | * @param cIn - Feature coordinates to be transformed 81 | * @param dIn - Corresponding distance 82 | * @param cOut - Transformed feature coordinates 83 | * @param dOut - Corresponding distance of output 84 | * @todo avoid double computation 85 | */ 86 | void transformFeature(const int i, const FeatureCoordinates& vecIn, const FeatureDistance& dIn, FeatureCoordinates& vecOut, FeatureDistance& dOut) const{ 87 | if(vecIn.camID_ != i){ 88 | // D = Destination camera frame. 89 | // qDC = qDM*qCM^T 90 | // CrCD = qCM*(MrMD-MrMC) 91 | // DrDP = qDC*(d_in*nor_in-CrCD) 92 | // d_out = ||DrDP|| 93 | // nor_out = DrDP/d_out 94 | const QPD qDC = qCB_[i]*qCB_[vecIn.camID_].inverted(); 95 | const V3D CrCD = qCB_[vecIn.camID_].rotate(V3D(BrBC_[i]-BrBC_[vecIn.camID_])); 96 | const V3D CrCP = dIn.getDistance()*vecIn.get_nor().getVec(); 97 | const V3D DrDP = qDC.rotate(V3D(CrCP-CrCD)); 98 | dOut.setParameter(DrDP.norm()); 99 | vecOut.nor_.setFromVector(DrDP); 100 | vecOut.valid_c_ = false; 101 | vecOut.valid_nor_ = true; 102 | vecOut.camID_ = i; 103 | vecOut.mpCamera_ = &cameras_[i]; 104 | vecOut.trackWarping_ = vecIn.trackWarping_; 105 | vecOut.pixelCov_.setZero(); 106 | vecOut.eigenVector1_.setZero(); 107 | vecOut.eigenVector2_.setZero(); 108 | vecOut.sigma1_ = 0.0; 109 | vecOut.sigma2_ = 0.0; 110 | vecOut.sigmaAngle_ = 0.0; 111 | if(vecIn.trackWarping_){ // Invalidate warping 112 | vecOut.valid_warp_c_ = false; 113 | vecOut.valid_warp_nor_ = false; 114 | vecOut.isWarpIdentity_ = false; 115 | } else { 116 | vecOut.warp_c_ = vecIn.warp_c_; 117 | vecOut.valid_warp_c_ = vecIn.valid_warp_c_; 118 | vecOut.warp_nor_ = vecIn.warp_nor_; 119 | vecOut.valid_warp_nor_ = vecIn.valid_warp_nor_; 120 | vecOut.isWarpIdentity_ = vecIn.isWarpIdentity_; 121 | } 122 | } else { 123 | vecOut = vecIn; 124 | dOut = dIn; 125 | } 126 | } 127 | }; 128 | 129 | } 130 | 131 | 132 | #endif /* ROVIO_MULTICAMERA_HPP_ */ 133 | -------------------------------------------------------------------------------- /include/rovio/MultilevelPatch.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_MULTILEVELPATCH_HPP_ 30 | #define ROVIO_MULTILEVELPATCH_HPP_ 31 | 32 | #include "rovio/Patch.hpp" 33 | #include "rovio/FeatureCoordinates.hpp" 34 | #include "rovio/ImagePyramid.hpp" 35 | 36 | namespace rovio{ 37 | 38 | /** \brief A multilevel patch class. 39 | * 40 | * @tparam nLevels - Number of pyramid levels on which the feature is defined. 41 | * @tparam patchSize - Edge length of the patches in pixels. Value must be a multiple of 2!. 42 | * Note: The patches edge length (in pixels) is the same for each patch, independently from the pyramid level. 43 | */ 44 | template<int nLevels,int patchSize> 45 | class MultilevelPatch{ 46 | public: 47 | static const int nLevels_ = nLevels; /**<Number of pyramid levels on which the feature is defined.*/ 48 | Patch<patchSize> patches_[nLevels_]; /**<Array, holding the patches on each pyramid level.*/ 49 | bool isValidPatch_[nLevels_]; /**<Array, specifying if there is a valid patch stored at the corresponding location in \ref patches_.*/ 50 | mutable Eigen::Matrix3f H_; /**<Hessian matrix, corresponding to the multilevel patches.*/ 51 | mutable float e0_; /**<Smaller eigenvalue of H_.*/ 52 | mutable float e1_; /**<Larger eigenvalue of H_.*/ 53 | mutable float s_; /**<Shi-Tomasi score of the multilevel patch feature. @todo define and store method of computation*/ 54 | 55 | /** Constructor 56 | */ 57 | MultilevelPatch(){ 58 | reset(); 59 | } 60 | 61 | /** Destructor 62 | */ 63 | virtual ~MultilevelPatch(){} 64 | 65 | /** \brief Resets the MultilevelPatch. 66 | * 67 | * @param idx - feature ID 68 | * @initTime - Time at initialization. 69 | */ 70 | void reset(){ 71 | H_.setIdentity(); 72 | e0_ = 0; 73 | e1_ = 0; 74 | s_ = 0; 75 | for(unsigned int i = 0;i<nLevels_;i++){ 76 | isValidPatch_[i] = false; 77 | } 78 | } 79 | 80 | /** \brief Computes and sets the multilevel Shi-Tomasi Score \ref s_, considering a defined pyramid level interval. 81 | * 82 | * @param l1 - Start level (l1<l2) 83 | * @param l2 - End level (l1<l2) 84 | */ 85 | void computeMultilevelShiTomasiScore(const int l1 = 0, const int l2 = nLevels_-1) const{ 86 | H_.setZero(); 87 | int count = 0; 88 | for(int i=l1;i<=l2;i++){ 89 | if(isValidPatch_[i]){ 90 | H_ += pow(0.25,i)*patches_[i].getHessian(); 91 | count++; 92 | } 93 | } 94 | if(count > 0){ 95 | const float dXX = H_(0,0)/(count*patchSize*patchSize); 96 | const float dYY = H_(1,1)/(count*patchSize*patchSize); 97 | const float dXY = H_(0,1)/(count*patchSize*patchSize); 98 | e0_ = 0.5 * (dXX + dYY - sqrtf((dXX + dYY) * (dXX + dYY) - 4 * (dXX * dYY - dXY * dXY))); 99 | e1_ = 0.5 * (dXX + dYY + sqrtf((dXX + dYY) * (dXX + dYY) - 4 * (dXX * dYY - dXY * dXY))); 100 | s_ = e0_+e1_; 101 | } else { 102 | e0_ = 0; 103 | e1_ = 0; 104 | s_ = -1; 105 | } 106 | } 107 | 108 | /** \brief Computes and sets the Shi-Tomasi Score \ref s_, considering only one specific pyramid level. 109 | * 110 | * @param l - Considered pyramid level. 111 | */ 112 | void getSpecificLevelScore(const int l) const{ 113 | if(isValidPatch_[l]){ 114 | s_ = patches_[l].getScore(); 115 | } else { 116 | s_ = -1; 117 | } 118 | } 119 | 120 | /** \brief Draws the patches of the MultilevelPatch into an image. 121 | * 122 | * @param drawImg - Image in which should be drawn. 123 | * @param c - Center pixel coordinates of the patch (on level 0) 124 | * @param stretch - %Patch drawing magnification factor. 125 | * @param withBorder - Draw either the patches Patch::patch_ (withBorder = false) or the expanded patches 126 | * Patch::patchWithBorder_ (withBorder = true) . 127 | */ 128 | void drawMultilevelPatch(cv::Mat& drawImg,const cv::Point2i& c,int stretch = 1,const bool withBorder = false) const{ 129 | for(int l=nLevels_-1;l>=0;l--){ 130 | if(isValidPatch_[l]){ 131 | cv::Point2i corner = cv::Point2i((patchSize/2+(int)withBorder)*(pow(2,nLevels_-1)-pow(2,l)),(patchSize/2+(int)withBorder)*(pow(2,nLevels_-1)-pow(2,l))); 132 | patches_[l].drawPatch(drawImg,c+corner,stretch*pow(2,l),withBorder); 133 | } 134 | } 135 | } 136 | 137 | /** \brief Draws the patch borders into an image. 138 | * 139 | * @param drawImg - Image in which the patch borders should be drawn. 140 | * @param s - Scaling factor. 141 | * @param color - Line color. 142 | */ 143 | void drawMultilevelPatchBorder(cv::Mat& drawImg,const FeatureCoordinates& c,const float s, const cv::Scalar& color) const{ 144 | patches_[0].drawPatchBorder(drawImg,c,s*pow(2.0,nLevels-1),color); 145 | } 146 | 147 | /** \brief Computes the RMSE (Root Mean Squared Error) with respect to the patches of an other MultilevelPatch 148 | * for an specific pyramid level interval. 149 | * 150 | * @param mp - \ref MultilevelPatch, which patches should be used for the RMSE computation. 151 | * @param l1 - Start pyramid level (l1<l2) 152 | * @param l2 - End pyramid level (l1<l2) 153 | * @return the RMSE value for the patches in the set pyramid level interval. 154 | */ 155 | float computeAverageDifference(const MultilevelPatch<nLevels,patchSize>& mp, const int l1, const int l2) const{ 156 | float offset = 0.0f; 157 | for(int l = l1; l <= l2; l++){ 158 | const float* it_patch = patches_[l].patch_; 159 | const float* it_patch_in = mp.patches_[l].patch_; 160 | for(int y=0; y<patchSize; ++y){ 161 | for(int x=0; x<patchSize; ++x, ++it_patch, ++it_patch_in){ 162 | offset += *it_patch - *it_patch_in; 163 | } 164 | } 165 | } 166 | offset = offset/(patchSize*patchSize*(l2-l1+1)); 167 | float error = 0.0f; 168 | for(int l = l1; l <= l2; l++){ 169 | const float* it_patch = patches_[l].patch_; 170 | const float* it_patch_in = mp.patches_[l].patch_; 171 | for(int y=0; y<patchSize; ++y){ 172 | for(int x=0; x<patchSize; ++x, ++it_patch, ++it_patch_in){ 173 | error += std::pow(*it_patch - *it_patch_in - offset,2); 174 | } 175 | } 176 | } 177 | error = error/(patchSize*patchSize*(l2-l1+1)); 178 | return std::sqrt(error); 179 | } 180 | 181 | /** \brief Checks if the MultilevelPatchFeature's patches are fully located within the corresponding images. 182 | * 183 | * @param pyr - Image pyramid, which should be checked to fully contain the patches. 184 | * @param l - Maximal pyramid level which should be checked (Note: The maximal level is the critical level.) 185 | * @param mpCoor - Coordinates of the patch in the reference image (subpixel coordinates possible). 186 | * @param mpWarp - Affine warping matrix. If nullptr not warping is considered. 187 | * @param withBorder - If true, the check is executed with the expanded patch dimensions (incorporates the general patch dimensions). 188 | * If false, the check is only executed with the general patch dimensions. 189 | */ 190 | static bool isMultilevelPatchInFrame(const ImagePyramid<nLevels>& pyr,const FeatureCoordinates& c, const int l = nLevels-1,const bool withBorder = false){ 191 | if(!c.isInFront() || !c.com_warp_c()) return false; 192 | const auto coorTemp = pyr.levelTranformCoordinates(c,0,l); 193 | return Patch<patchSize>::isPatchInFrame(pyr.imgs_[l],coorTemp,withBorder); 194 | } 195 | 196 | /** \brief Extracts a multilevel patch from a given image pyramid. 197 | * 198 | * @param pyr - Image pyramid from which the patch data should be extracted. 199 | * @param l - Patches are extracted from pyramid level 0 to l. 200 | * @param mpCoor - Coordinates of the patch in the reference image (subpixel coordinates possible). 201 | * @param mpWarp - Affine warping matrix. If nullptr not warping is considered. 202 | * @param withBorder - If true, both, the general patches and the corresponding expanded patches are extracted. 203 | */ 204 | void extractMultilevelPatchFromImage(const ImagePyramid<nLevels>& pyr,const FeatureCoordinates& c, const int l = nLevels-1,const bool withBorder = false){ 205 | for(unsigned int i=0;i<=l;i++){ 206 | const auto coorTemp = pyr.levelTranformCoordinates(c,0,i); 207 | isValidPatch_[i] = true; 208 | patches_[i].extractPatchFromImage(pyr.imgs_[i],coorTemp,withBorder); 209 | } 210 | } 211 | }; 212 | 213 | } 214 | 215 | 216 | #endif /* ROVIO_MULTILEVELPATCH_HPP_ */ 217 | -------------------------------------------------------------------------------- /include/rovio/Patch.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_PATCH_HPP_ 30 | #define ROVIO_PATCH_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "rovio/FeatureCoordinates.hpp" 34 | 35 | namespace rovio{ 36 | 37 | /** \brief %Patch with selectable patchSize. 38 | * 39 | * @tparam patchSize - Edge length of the patch in pixels. Value must be a multiple of 2! 40 | */ 41 | template<int patchSize> 42 | class Patch { 43 | public: 44 | float patch_[patchSize*patchSize] __attribute__ ((aligned (16))); /**<Array, containing the intensity values of the patch.*/ 45 | float patchWithBorder_[(patchSize+2)*(patchSize+2)] __attribute__ ((aligned (16))); /**<Array, containing the intensity values of the expanded patch. 46 | This expanded patch is necessary for the intensity gradient calculation.*/ 47 | mutable float dx_[patchSize*patchSize] __attribute__ ((aligned (16))); /**<Array, containing the intensity gradient component in x-direction for each patch pixel.*/ 48 | mutable float dy_[patchSize*patchSize] __attribute__ ((aligned (16))); /**<Array, containing the intensity gradient component in y-direction for each patch pixel.*/ 49 | mutable Eigen::Matrix3f H_; /**<Hessian matrix of the patch (necessary for the patch alignment).*/ 50 | mutable float s_; /**<Shi-Tomasi Score (smaller eigenvalue of H_).*/ 51 | mutable float e0_; /**<Smaller eigenvalue of H_.*/ 52 | mutable float e1_; /**<Larger eigenvalue of H_.*/ 53 | mutable bool validGradientParameters_; /**<True, if the gradient parameters (patch gradient components dx_ dy_, Hessian H_, Shi-Thomasi Score s_) have been computed. 54 | \see computeGradientParameters()*/ 55 | /** \brief Constructor 56 | */ 57 | Patch(){ 58 | static_assert(patchSize%2==0,"Patch patchSize must be a multiple of 2"); 59 | validGradientParameters_ = false; 60 | s_ = 0.0; 61 | e0_ = 0.0; 62 | e1_ = 0.0; 63 | } 64 | /** \brief Destructor 65 | */ 66 | virtual ~Patch(){} 67 | 68 | /** \brief Computes the gradient parameters of the patch (patch gradient components dx_ dy_, Hessian H_, Shi-Tomasi Score s_, Eigenvalues of the Hessian e0_ and e1_). 69 | * The expanded patch patchWithBorder_ must be set. 70 | * Sets validGradientParameters_ afterwards to true. 71 | */ 72 | void computeGradientParameters() const{ 73 | if(!validGradientParameters_){ 74 | H_.setZero(); 75 | const int refStep = patchSize+2; 76 | float* it_dx = dx_; 77 | float* it_dy = dy_; 78 | const float* it; 79 | Eigen::Vector3f J; 80 | J.setZero(); 81 | for(int y=0; y<patchSize; ++y){ 82 | it = patchWithBorder_ + (y+1)*refStep + 1; 83 | for(int x=0; x<patchSize; ++x, ++it, ++it_dx, ++it_dy){ 84 | J[0] = 0.5 * (it[1] - it[-1]); 85 | J[1] = 0.5 * (it[refStep] - it[-refStep]); 86 | J[2] = 1; 87 | *it_dx = J[0]; 88 | *it_dy = J[1]; 89 | H_ += J*J.transpose(); 90 | } 91 | } 92 | const float dXX = H_(0,0)/(patchSize*patchSize); 93 | const float dYY = H_(1,1)/(patchSize*patchSize); 94 | const float dXY = H_(0,1)/(patchSize*patchSize); 95 | 96 | e0_ = 0.5 * (dXX + dYY - sqrtf((dXX + dYY) * (dXX + dYY) - 4 * (dXX * dYY - dXY * dXY))); 97 | e1_ = 0.5 * (dXX + dYY + sqrtf((dXX + dYY) * (dXX + dYY) - 4 * (dXX * dYY - dXY * dXY))); 98 | s_ = e0_+e1_; 99 | validGradientParameters_ = true; 100 | } 101 | } 102 | 103 | /** \brief Extracts and sets the patch intensity values (patch_) from the intensity values of the 104 | * expanded patch (patchWithBorder_). 105 | */ 106 | void extractPatchFromPatchWithBorder(){ 107 | float* it_patch = patch_; 108 | float* it_patchWithBorder; 109 | for(int y=1; y<patchSize+1; ++y, it_patch += patchSize){ 110 | it_patchWithBorder = patchWithBorder_ + y*(patchSize+2) + 1; 111 | for(int x=0; x<patchSize; ++x) 112 | it_patch[x] = it_patchWithBorder[x]; 113 | } 114 | } 115 | 116 | /** \brief Returns the Shi-Tomasi Score s_. 117 | * 118 | * Computes and sets the gradient parameters, which are the patch gradient components dx_ dy_, the Hessian H_ and the Shi-Tomasi Score s_. 119 | * \see computeGradientParameters() 120 | * @return the Shi-Tomasi Score s_ ( smaller eigenvalue of the Hessian H_ ). 121 | */ 122 | float getScore() const{ 123 | computeGradientParameters(); 124 | return s_; 125 | } 126 | 127 | /** \brief Returns the Hessian Matrix H_. 128 | * 129 | * Computes and sets the gradient parameters, which are the patch gradient components dx_ dy_, the Hessian H_ and the Shi-Tomasi Score s_. 130 | * @return the Hessian Matrix H_ . 131 | */ 132 | Eigen::Matrix3f getHessian() const{ 133 | computeGradientParameters(); 134 | return H_; 135 | } 136 | 137 | /** \brief Draws the patch into an image. 138 | * 139 | * @param drawImg - Image in which the patch should be drawn. 140 | * @param c - Pixel coordinates of the left upper patch corner. 141 | * @param stretch - %Patch drawing magnification factor. 142 | * @param withBorder - Draw either the patch patch_ (withBorder = false) or the expanded patch 143 | * patchWithBorder_ (withBorder = true). 144 | */ 145 | void drawPatch(cv::Mat& drawImg,const cv::Point2i& c,int stretch = 1,const bool withBorder = false) const{ 146 | const int refStepY = drawImg.step.p[0]; 147 | const int refStepX = drawImg.step.p[1]; 148 | uint8_t* img_ptr; 149 | const float* it_patch; 150 | if(withBorder){ 151 | it_patch = patchWithBorder_; 152 | } else { 153 | it_patch = patch_; 154 | } 155 | for(int y=0; y<patchSize+2*(int)withBorder; ++y, it_patch += patchSize+2*(int)withBorder){ 156 | img_ptr = (uint8_t*) drawImg.data + (c.y+y*stretch)*refStepY + c.x*refStepX; 157 | for(int x=0; x<patchSize+2*(int)withBorder; ++x) 158 | for(int i=0;i<stretch;++i){ 159 | for(int j=0;j<stretch;++j){ 160 | img_ptr[x*stretch*refStepX+i*refStepY+j*refStepX+0] = (uint8_t)(it_patch[x]); 161 | if(drawImg.channels() == 3){ 162 | img_ptr[x*stretch*refStepX+i*refStepY+j*refStepX+1] = (uint8_t)(it_patch[x]); 163 | img_ptr[x*stretch*refStepX+i*refStepY+j*refStepX+2] = (uint8_t)(it_patch[x]); 164 | } 165 | } 166 | } 167 | } 168 | } 169 | 170 | /** \brief Draws the patch borders into an image. 171 | * 172 | * @param drawImg - Image in which the patch borders should be drawn. 173 | * @param c - Coordinates of the patch in the reference image. 174 | * @param s - Scaling factor. 175 | * @param color - Line color. 176 | */ 177 | void drawPatchBorder(cv::Mat& drawImg,const FeatureCoordinates& c,const float s, const cv::Scalar& color) const{ 178 | const double half_length = s*patchSize/2; 179 | if(c.isInFront() && c.com_warp_c()){ 180 | cv::Point2f c1 = c.get_patchCorner(half_length,half_length).get_c(); 181 | cv::Point2f c2 = c.get_patchCorner(half_length,-half_length).get_c(); 182 | cv::line(drawImg,c1,c2,color,1); 183 | c1 = c.get_patchCorner(-half_length,-half_length).get_c(); 184 | cv::line(drawImg,c2,c1,color,1); 185 | c2 = c.get_patchCorner(-half_length,half_length).get_c(); 186 | cv::line(drawImg,c1,c2,color,1); 187 | c1 = c.get_patchCorner(half_length,half_length).get_c(); 188 | cv::line(drawImg,c2,c1,color,1); 189 | } 190 | } 191 | 192 | /** \brief Checks if a patch at a specific image location is still within the reference image. 193 | * 194 | * @param img - Reference Image. 195 | * @param c - Coordinates of the patch in the reference image. 196 | * @param withBorder - Check, using either the patch-patchSize of Patch::patch_ (withBorder = false) or the patch-patchSize 197 | * of the expanded patch Patch::patchWithBorder_ (withBorder = true). 198 | * @return true, if the patch is completely located within the reference image. 199 | */ 200 | static bool isPatchInFrame(const cv::Mat& img,const FeatureCoordinates& c,const bool withBorder = false){ 201 | if(c.isInFront() && c.com_warp_c()){ 202 | const int halfpatch_size = patchSize/2+(int)withBorder; 203 | if(c.isNearIdentityWarping()){ 204 | if(c.get_c().x < halfpatch_size || c.get_c().y < halfpatch_size || c.get_c().x > img.cols-halfpatch_size || c.get_c().y > img.rows-halfpatch_size){ 205 | return false; 206 | } else { 207 | return true; 208 | } 209 | } else { 210 | for(int y=0; y<2*halfpatch_size; y += 2*halfpatch_size-1){ 211 | for(int x=0; x<2*halfpatch_size; x += 2*halfpatch_size-1){ 212 | const float dx = x - halfpatch_size + 0.5; 213 | const float dy = y - halfpatch_size + 0.5; 214 | const float wdx = c.get_warp_c()(0,0)*dx + c.get_warp_c()(0,1)*dy; 215 | const float wdy = c.get_warp_c()(1,0)*dx + c.get_warp_c()(1,1)*dy; 216 | const float c_x = c.get_c().x+wdx - 0.5; 217 | const float c_y = c.get_c().y+wdy - 0.5; 218 | const int u_r = floor(c_x); 219 | const int v_r = floor(c_y); 220 | if(u_r < 0 || v_r < 0 || u_r >= img.cols-1 || v_r >= img.rows-1){ 221 | return false; 222 | } 223 | } 224 | } 225 | return true; 226 | } 227 | } else { 228 | return false; 229 | } 230 | } 231 | 232 | /** \brief Extracts a patch from an image. 233 | * 234 | * @param img - Reference Image. 235 | * @param c - Coordinates of the patch in the reference image (subpixel coordinates possible). 236 | * @param withBorder - If false, the patch object is only initialized with the patch data of the general patch (Patch::patch_). 237 | * If true, the patch object is initialized with both, the patch data of the general patch (Patch::patch_) 238 | * and the patch data of the expanded patch (Patch::patchWithBorder_). 239 | */ 240 | void extractPatchFromImage(const cv::Mat& img,const FeatureCoordinates& c,const bool withBorder = false){ 241 | assert(isPatchInFrame(img,c,withBorder)); 242 | const int halfpatch_size = patchSize/2+(int)withBorder; 243 | const int refStep = img.step.p[0]; 244 | 245 | // Get Pointers 246 | uint8_t* img_ptr; 247 | float* patch_ptr; 248 | if(withBorder){ 249 | patch_ptr = patchWithBorder_; 250 | } else { 251 | patch_ptr = patch_; 252 | } 253 | 254 | if(c.isNearIdentityWarping()){ 255 | const int u_r = floor(c.get_c().x); 256 | const int v_r = floor(c.get_c().y); 257 | 258 | // compute interpolation weights 259 | const float subpix_x = c.get_c().x-u_r; 260 | const float subpix_y = c.get_c().y-v_r; 261 | const float wTL = (1.0-subpix_x)*(1.0-subpix_y); 262 | const float wTR = subpix_x * (1.0-subpix_y); 263 | const float wBL = (1.0-subpix_x)*subpix_y; 264 | const float wBR = subpix_x * subpix_y; 265 | for(int y=0; y<2*halfpatch_size; ++y){ 266 | img_ptr = (uint8_t*) img.data + (v_r+y-halfpatch_size)*refStep + u_r-halfpatch_size; 267 | for(int x=0; x<2*halfpatch_size; ++x, ++img_ptr, ++patch_ptr) 268 | { 269 | *patch_ptr = wTL*img_ptr[0]; 270 | if(subpix_x > 0) *patch_ptr += wTR*img_ptr[1]; 271 | if(subpix_y > 0) *patch_ptr += wBL*img_ptr[refStep]; 272 | if(subpix_x > 0 && subpix_y > 0) *patch_ptr += wBR*img_ptr[refStep+1]; 273 | } 274 | } 275 | } else { 276 | for(int y=0; y<2*halfpatch_size; ++y){ 277 | for(int x=0; x<2*halfpatch_size; ++x, ++patch_ptr){ 278 | const float dx = x - halfpatch_size + 0.5; 279 | const float dy = y - halfpatch_size + 0.5; 280 | const float wdx = c.get_warp_c()(0,0)*dx + c.get_warp_c()(0,1)*dy; 281 | const float wdy = c.get_warp_c()(1,0)*dx + c.get_warp_c()(1,1)*dy; 282 | const float u_pixel = c.get_c().x+wdx - 0.5; 283 | const float v_pixel = c.get_c().y+wdy - 0.5; 284 | const int u_r = floor(u_pixel); 285 | const int v_r = floor(v_pixel); 286 | const float subpix_x = u_pixel-u_r; 287 | const float subpix_y = v_pixel-v_r; 288 | const float wTL = (1.0-subpix_x) * (1.0-subpix_y); 289 | const float wTR = subpix_x * (1.0-subpix_y); 290 | const float wBL = (1.0-subpix_x) * subpix_y; 291 | const float wBR = subpix_x * subpix_y; 292 | img_ptr = (uint8_t*) img.data + v_r*refStep + u_r; 293 | *patch_ptr = wTL*img_ptr[0]; 294 | if(subpix_x > 0) *patch_ptr += wTR*img_ptr[1]; 295 | if(subpix_y > 0) *patch_ptr += wBL*img_ptr[refStep]; 296 | if(subpix_x > 0 && subpix_y > 0) *patch_ptr += wBR*img_ptr[refStep+1]; 297 | } 298 | } 299 | } 300 | if(withBorder){ 301 | extractPatchFromPatchWithBorder(); 302 | } 303 | validGradientParameters_ = false; 304 | } 305 | }; 306 | 307 | } 308 | 309 | 310 | #endif /* ROVIO_PATCH_HPP_ */ 311 | -------------------------------------------------------------------------------- /include/rovio/RobocentricFeatureElement.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROBOCENTRICFEATUREELEMENT_HPP_ 30 | #define ROBOCENTRICFEATUREELEMENT_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "rovio/FeatureCoordinates.hpp" 34 | #include "rovio/FeatureDistance.hpp" 35 | 36 | namespace rovio{ 37 | 38 | class RobocentricFeatureElement: public LWF::ElementBase<RobocentricFeatureElement,RobocentricFeatureElement,3>{ 39 | public: 40 | typedef LWF::ElementBase<RobocentricFeatureElement,RobocentricFeatureElement,3> Base; 41 | using typename Base::mtDifVec; 42 | using typename Base::mtGet; 43 | using Base::name_; 44 | mutable LWF::NormalVectorElement::mtDifVec norDifTemp_; 45 | mutable MXD norCovMatTemp_; 46 | mutable LWF::NormalVectorElement norTemp_; 47 | FeatureCoordinates coordinates_; 48 | FeatureDistance distance_; 49 | RobocentricFeatureElement():distance_(FeatureDistance::REGULAR), norCovMatTemp_(3,3){} 50 | RobocentricFeatureElement(const Camera* mpCameras, const FeatureDistance::Type depthType):coordinates_(mpCameras),distance_(depthType), norCovMatTemp_(3,3){} 51 | RobocentricFeatureElement(const RobocentricFeatureElement& other):distance_(other.distance_.type_), norCovMatTemp_(3,3){ 52 | coordinates_ = other.coordinates_; 53 | distance_ = other.distance_; 54 | } 55 | 56 | /** \brief Destructor 57 | */ 58 | virtual ~RobocentricFeatureElement(){}; 59 | 60 | void boxPlus(const mtDifVec& vecIn, RobocentricFeatureElement& stateOut) const{ 61 | if(&stateOut != this){ 62 | stateOut.coordinates_ = coordinates_; 63 | stateOut.distance_ = distance_; 64 | } 65 | coordinates_.get_nor().boxPlus(vecIn.template block<2,1>(0,0),norTemp_); 66 | stateOut.coordinates_.set_nor(norTemp_,false); 67 | stateOut.distance_.p_ = distance_.p_ + vecIn(2); 68 | } 69 | void boxMinus(const RobocentricFeatureElement& stateIn, mtDifVec& vecOut) const{ 70 | coordinates_.get_nor().boxMinus(stateIn.coordinates_.get_nor(),norDifTemp_); 71 | vecOut.template block<2,1>(0,0) = norDifTemp_; 72 | vecOut(2) = distance_.p_-stateIn.distance_.p_; 73 | } 74 | void boxMinusJac(const RobocentricFeatureElement& stateIn, MXD& matOut) const{ 75 | matOut.setIdentity(); 76 | coordinates_.get_nor().boxMinusJac(stateIn.coordinates_.get_nor(),norCovMatTemp_); 77 | matOut.template block<2,2>(0,0) = norCovMatTemp_; 78 | } 79 | void print() const{ 80 | std::cout << "Bearing vector: " << coordinates_.get_nor().getVec().transpose() << " ,depth-parameter: " << distance_.p_ << std::endl; 81 | } 82 | void setIdentity(){ 83 | norTemp_.setIdentity(); 84 | coordinates_.set_nor(norTemp_); 85 | coordinates_.set_warp_identity(); 86 | distance_.p_ = 1.0; 87 | } 88 | void setRandom(unsigned int& s){ 89 | norTemp_.setRandom(s); 90 | coordinates_.set_nor(norTemp_); 91 | std::default_random_engine generator (s); 92 | std::normal_distribution<double> distribution (0.0,1.0); 93 | distance_.p_ = distribution(generator) + 1.0; 94 | s++; 95 | } 96 | void fix(){ 97 | norTemp_ = coordinates_.get_nor(); 98 | norTemp_.fix(); 99 | coordinates_.set_nor(norTemp_,false); 100 | } 101 | mtGet& get(unsigned int i = 0){ 102 | assert(i==0); 103 | return *this; 104 | } 105 | const mtGet& get(unsigned int i = 0) const{ 106 | assert(i==0); 107 | return *this; 108 | } 109 | void registerElementToPropertyHandler(LWF::PropertyHandler* mpPropertyHandler, const std::string& str){ 110 | coordinates_.nor_.registerElementToPropertyHandler(mpPropertyHandler,str + name_); // Does not work properly since when loading the info file the validity of nor_/c_ is not adapted 111 | mpPropertyHandler->doubleRegister_.registerScalar(str + name_ + "_d", distance_.p_); 112 | } 113 | }; 114 | 115 | } 116 | 117 | 118 | #endif /* ROBOCENTRICFEATUREELEMENT_HPP_ */ 119 | -------------------------------------------------------------------------------- /include/rovio/RovioFilter.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_ROVIO_FILTER_HPP_ 30 | #define ROVIO_ROVIO_FILTER_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "lightweight_filtering/FilterBase.hpp" 34 | #include "rovio/FilterStates.hpp" 35 | #include "rovio/ImgUpdate.hpp" 36 | #include "rovio/PoseUpdate.hpp" 37 | #include "rovio/VelocityUpdate.hpp" 38 | #include "rovio/ImuPrediction.hpp" 39 | #include "rovio/MultiCamera.hpp" 40 | 41 | namespace rovio { 42 | /** \brief Class, defining the Rovio Filter. 43 | * 44 | * @tparam FILTERSTATE - \ref rovio::FilterState 45 | */ 46 | template<typename FILTERSTATE> 47 | class RovioFilter:public LWF::FilterBase<ImuPrediction<FILTERSTATE>, 48 | ImgUpdate<FILTERSTATE>, 49 | PoseUpdate<FILTERSTATE,(int)(FILTERSTATE::mtState::nPose_>0)-1,(int)(FILTERSTATE::mtState::nPose_>1)*2-1>, 50 | VelocityUpdate<FILTERSTATE>>{ 51 | public: 52 | typedef LWF::FilterBase<ImuPrediction<FILTERSTATE>, 53 | ImgUpdate<FILTERSTATE>, 54 | PoseUpdate<FILTERSTATE,(int)(FILTERSTATE::mtState::nPose_>0)-1,(int)(FILTERSTATE::mtState::nPose_>1)*2-1>, 55 | VelocityUpdate<FILTERSTATE>> Base; 56 | using Base::init_; 57 | using Base::reset; 58 | using Base::predictionTimeline_; 59 | using Base::safe_; 60 | using Base::front_; 61 | using Base::readFromInfo; 62 | using Base::boolRegister_; 63 | using Base::intRegister_; 64 | using Base::doubleRegister_; 65 | using Base::mUpdates_; 66 | using Base::mPrediction_; 67 | using Base::stringRegister_; 68 | using Base::subHandlers_; 69 | using Base::updateToUpdateMeasOnly_; 70 | typedef typename Base::mtFilterState mtFilterState; 71 | typedef typename Base::mtPrediction mtPrediction; 72 | typedef typename Base::mtState mtState; 73 | rovio::MultiCamera<mtState::nCam_> multiCamera_; 74 | std::string cameraCalibrationFile_[mtState::nCam_]; 75 | int depthTypeInt_; 76 | 77 | /** \brief Constructor. Initializes the filter. 78 | */ 79 | RovioFilter(){ 80 | updateToUpdateMeasOnly_ = true; 81 | std::get<0>(mUpdates_).setCamera(&multiCamera_); 82 | init_.setCamera(&multiCamera_); 83 | depthTypeInt_ = 1; 84 | subHandlers_.erase("Update0"); 85 | subHandlers_["ImgUpdate"] = &std::get<0>(mUpdates_); 86 | subHandlers_.erase("Update1"); 87 | subHandlers_["PoseUpdate"] = &std::get<1>(mUpdates_); 88 | subHandlers_.erase("Update2"); 89 | subHandlers_["VelocityUpdate"] = &std::get<2>(mUpdates_); 90 | boolRegister_.registerScalar("Common.doVECalibration",init_.state_.aux().doVECalibration_); 91 | intRegister_.registerScalar("Common.depthType",depthTypeInt_); 92 | for(int camID=0;camID<mtState::nCam_;camID++){ 93 | cameraCalibrationFile_[camID] = ""; 94 | stringRegister_.registerScalar("Camera" + std::to_string(camID) + ".CalibrationFile",cameraCalibrationFile_[camID]); 95 | doubleRegister_.registerVector("Camera" + std::to_string(camID) + ".MrMC",init_.state_.aux().MrMC_[camID]); 96 | doubleRegister_.registerQuaternion("Camera" + std::to_string(camID) + ".qCM",init_.state_.aux().qCM_[camID]); 97 | doubleRegister_.removeScalarByVar(init_.state_.MrMC(camID)(0)); 98 | doubleRegister_.removeScalarByVar(init_.state_.MrMC(camID)(1)); 99 | doubleRegister_.removeScalarByVar(init_.state_.MrMC(camID)(2)); 100 | doubleRegister_.removeScalarByVar(init_.state_.qCM(camID).toImplementation().w()); 101 | doubleRegister_.removeScalarByVar(init_.state_.qCM(camID).toImplementation().x()); 102 | doubleRegister_.removeScalarByVar(init_.state_.qCM(camID).toImplementation().y()); 103 | doubleRegister_.removeScalarByVar(init_.state_.qCM(camID).toImplementation().z()); 104 | for(int j=0;j<3;j++){ 105 | doubleRegister_.removeScalarByVar(init_.cov_(mtState::template getId<mtState::_vep>(camID)+j,mtState::template getId<mtState::_vep>(camID)+j)); 106 | doubleRegister_.removeScalarByVar(init_.cov_(mtState::template getId<mtState::_vea>(camID)+j,mtState::template getId<mtState::_vea>(camID)+j)); 107 | doubleRegister_.registerScalar("Init.Covariance.vep",init_.cov_(mtState::template getId<mtState::_vep>(camID)+j,mtState::template getId<mtState::_vep>(camID)+j)); 108 | doubleRegister_.registerScalar("Init.Covariance.vea",init_.cov_(mtState::template getId<mtState::_vea>(camID)+j,mtState::template getId<mtState::_vea>(camID)+j)); 109 | } 110 | doubleRegister_.registerVector("Camera" + std::to_string(camID) + ".MrMC",init_.state_.MrMC(camID)); 111 | doubleRegister_.registerQuaternion("Camera" + std::to_string(camID) + ".qCM",init_.state_.qCM(camID)); 112 | } 113 | for(int i=0;i<mtState::nPose_;i++){ 114 | doubleRegister_.removeScalarByVar(init_.state_.poseLin(i)(0)); 115 | doubleRegister_.removeScalarByVar(init_.state_.poseLin(i)(1)); 116 | doubleRegister_.removeScalarByVar(init_.state_.poseLin(i)(2)); 117 | doubleRegister_.removeScalarByVar(init_.state_.poseRot(i).toImplementation().w()); 118 | doubleRegister_.removeScalarByVar(init_.state_.poseRot(i).toImplementation().x()); 119 | doubleRegister_.removeScalarByVar(init_.state_.poseRot(i).toImplementation().y()); 120 | doubleRegister_.removeScalarByVar(init_.state_.poseRot(i).toImplementation().z()); 121 | for(int j=0;j<3;j++){ 122 | doubleRegister_.removeScalarByVar(init_.cov_(mtState::template getId<mtState::_pop>(i)+j,mtState::template getId<mtState::_pop>(i)+j)); 123 | doubleRegister_.removeScalarByVar(init_.cov_(mtState::template getId<mtState::_poa>(i)+j,mtState::template getId<mtState::_poa>(i)+j)); 124 | } 125 | } 126 | if(std::get<1>(mUpdates_).inertialPoseIndex_>=0){ 127 | std::get<1>(mUpdates_).doubleRegister_.registerVector("IrIW",init_.state_.poseLin(std::get<1>(mUpdates_).inertialPoseIndex_)); 128 | std::get<1>(mUpdates_).doubleRegister_.registerQuaternion("qWI",init_.state_.poseRot(std::get<1>(mUpdates_).inertialPoseIndex_)); 129 | for(int j=0;j<3;j++){ 130 | std::get<1>(mUpdates_).doubleRegister_.registerScalar("init_cov_IrIW",init_.cov_(mtState::template getId<mtState::_pop>(std::get<1>(mUpdates_).inertialPoseIndex_)+j,mtState::template getId<mtState::_pop>(std::get<1>(mUpdates_).inertialPoseIndex_)+j)); 131 | std::get<1>(mUpdates_).doubleRegister_.registerScalar("init_cov_qWI",init_.cov_(mtState::template getId<mtState::_poa>(std::get<1>(mUpdates_).inertialPoseIndex_)+j,mtState::template getId<mtState::_poa>(std::get<1>(mUpdates_).inertialPoseIndex_)+j)); 132 | std::get<1>(mUpdates_).doubleRegister_.registerScalar("pre_cov_IrIW",mPrediction_.prenoiP_(mtPrediction::mtNoise::template getId<mtPrediction::mtNoise::_pop>(std::get<1>(mUpdates_).inertialPoseIndex_)+j,mtPrediction::mtNoise::template getId<mtPrediction::mtNoise::_pop>(std::get<1>(mUpdates_).inertialPoseIndex_)+j)); 133 | std::get<1>(mUpdates_).doubleRegister_.registerScalar("pre_cov_qWI",mPrediction_.prenoiP_(mtPrediction::mtNoise::template getId<mtPrediction::mtNoise::_poa>(std::get<1>(mUpdates_).inertialPoseIndex_)+j,mtPrediction::mtNoise::template getId<mtPrediction::mtNoise::_poa>(std::get<1>(mUpdates_).inertialPoseIndex_)+j)); 134 | } 135 | } 136 | if(std::get<1>(mUpdates_).bodyPoseIndex_>=0){ 137 | std::get<1>(mUpdates_).doubleRegister_.registerVector("MrMV",init_.state_.poseLin(std::get<1>(mUpdates_).bodyPoseIndex_)); 138 | std::get<1>(mUpdates_).doubleRegister_.registerQuaternion("qVM",init_.state_.poseRot(std::get<1>(mUpdates_).bodyPoseIndex_)); 139 | for(int j=0;j<3;j++){ 140 | std::get<1>(mUpdates_).doubleRegister_.registerScalar("init_cov_MrMV",init_.cov_(mtState::template getId<mtState::_pop>(std::get<1>(mUpdates_).bodyPoseIndex_)+j,mtState::template getId<mtState::_pop>(std::get<1>(mUpdates_).bodyPoseIndex_)+j)); 141 | std::get<1>(mUpdates_).doubleRegister_.registerScalar("init_cov_qVM",init_.cov_(mtState::template getId<mtState::_poa>(std::get<1>(mUpdates_).bodyPoseIndex_)+j,mtState::template getId<mtState::_poa>(std::get<1>(mUpdates_).bodyPoseIndex_)+j)); 142 | std::get<1>(mUpdates_).doubleRegister_.registerScalar("pre_cov_MrMV",mPrediction_.prenoiP_(mtPrediction::mtNoise::template getId<mtPrediction::mtNoise::_pop>(std::get<1>(mUpdates_).bodyPoseIndex_)+j,mtPrediction::mtNoise::template getId<mtPrediction::mtNoise::_pop>(std::get<1>(mUpdates_).bodyPoseIndex_)+j)); 143 | std::get<1>(mUpdates_).doubleRegister_.registerScalar("pre_cov_qVM",mPrediction_.prenoiP_(mtPrediction::mtNoise::template getId<mtPrediction::mtNoise::_poa>(std::get<1>(mUpdates_).bodyPoseIndex_)+j,mtPrediction::mtNoise::template getId<mtPrediction::mtNoise::_poa>(std::get<1>(mUpdates_).bodyPoseIndex_)+j)); 144 | } 145 | } 146 | int ind; 147 | for(int i=0;i<FILTERSTATE::mtState::nMax_;i++){ 148 | ind = mtState::template getId<mtState::_fea>(i); 149 | doubleRegister_.removeScalarByVar(init_.cov_(ind,ind)); 150 | doubleRegister_.removeScalarByVar(init_.cov_(ind+1,ind+1)); 151 | ind = mtState::template getId<mtState::_fea>(i)+2; 152 | doubleRegister_.removeScalarByVar(init_.cov_(ind,ind)); 153 | doubleRegister_.removeScalarByVar(init_.state_.dep(i).p_); 154 | doubleRegister_.removeScalarByVar(init_.state_.CfP(i).nor_.q_.toImplementation().w()); 155 | doubleRegister_.removeScalarByVar(init_.state_.CfP(i).nor_.q_.toImplementation().x()); 156 | doubleRegister_.removeScalarByVar(init_.state_.CfP(i).nor_.q_.toImplementation().y()); 157 | doubleRegister_.removeScalarByVar(init_.state_.CfP(i).nor_.q_.toImplementation().z()); 158 | std::get<0>(mUpdates_).intRegister_.registerScalar("statLocalQualityRange",init_.fsm_.features_[i].mpStatistics_->localQualityRange_); 159 | std::get<0>(mUpdates_).intRegister_.registerScalar("statLocalVisibilityRange",init_.fsm_.features_[i].mpStatistics_->localVisibilityRange_); 160 | std::get<0>(mUpdates_).intRegister_.registerScalar("statMinGlobalQualityRange",init_.fsm_.features_[i].mpStatistics_->minGlobalQualityRange_); 161 | std::get<0>(mUpdates_).boolRegister_.registerScalar("doPatchWarping",init_.state_.CfP(i).trackWarping_); 162 | } 163 | std::get<0>(mUpdates_).doubleRegister_.removeScalarByVar(std::get<0>(mUpdates_).outlierDetection_.getMahalTh(0)); 164 | std::get<0>(mUpdates_).doubleRegister_.registerScalar("MahalanobisTh",std::get<0>(mUpdates_).outlierDetection_.getMahalTh(0)); 165 | std::get<0>(mUpdates_).outlierDetection_.setEnabledAll(true); 166 | std::get<1>(mUpdates_).outlierDetection_.setEnabledAll(true); 167 | boolRegister_.registerScalar("Common.verbose",std::get<0>(mUpdates_).verbose_); 168 | mPrediction_.doubleRegister_.removeScalarByStr("alpha"); 169 | mPrediction_.doubleRegister_.removeScalarByStr("beta"); 170 | mPrediction_.doubleRegister_.removeScalarByStr("kappa"); 171 | boolRegister_.registerScalar("PoseUpdate.doVisualization",init_.plotPoseMeas_); 172 | reset(0.0); 173 | } 174 | 175 | /** \brief Reloads the camera calibration for all cameras and resets the depth map type. 176 | */ 177 | void refreshProperties(){ 178 | if(std::get<0>(mUpdates_).useDirectMethod_){ 179 | init_.mode_ = LWF::ModeIEKF; 180 | } else { 181 | init_.mode_ = LWF::ModeEKF; 182 | } 183 | for(int camID = 0;camID<mtState::nCam_;camID++){ 184 | if (!cameraCalibrationFile_[camID].empty()) { 185 | multiCamera_.cameras_[camID].load(cameraCalibrationFile_[camID]); 186 | } 187 | } 188 | for(int i=0;i<FILTERSTATE::mtState::nMax_;i++){ 189 | init_.state_.dep(i).setType(depthTypeInt_); 190 | } 191 | }; 192 | 193 | /** \brief Destructor 194 | */ 195 | virtual ~RovioFilter(){}; 196 | // void resetToImuPose(V3D WrWM, QPD qMW, double t = 0.0){ 197 | // init_.state_.initWithImuPose(WrWM,qMW); 198 | // reset(t); 199 | // } 200 | 201 | /** \brief Resets the filter with an accelerometer measurement. 202 | * 203 | * @param fMeasInit - Accelerometer measurement. 204 | * @param t - Current time. 205 | */ 206 | void resetWithAccelerometer(const V3D& fMeasInit, double t = 0.0){ 207 | init_.initWithAccelerometer(fMeasInit); 208 | reset(t); 209 | } 210 | 211 | /** \brief Resets the filter with an external pose. 212 | * 213 | * @param WrWM - Position Vector, pointing from the World-Frame to the IMU-Frame, expressed in World-Coordinates. 214 | * @param qMW - Quaternion, expressing World-Frame in IMU-Coordinates (World Coordinates->IMU Coordinates) 215 | * @param t - Current time. 216 | */ 217 | void resetWithPose(V3D WrWM, QPD qMW, double t = 0.0) { 218 | init_.initWithImuPose(WrWM, qMW); 219 | reset(t); 220 | } 221 | 222 | /** \brief Sets the transformation between IMU and Camera. 223 | * 224 | * @param R_VM - Rotation matrix, expressing the orientation of the IMU in Camera Cooridinates (IMU Coordinates -> Camera Coordinates). 225 | * @param VrVM - Vector, pointing from the camera frame to the IMU frame, expressed in IMU Coordinates. 226 | * @param camID - ID of the considered camera. 227 | */ 228 | void setExtrinsics(const Eigen::Matrix3d& R_CM, const Eigen::Vector3d& CrCM, const int camID = 0){ 229 | kindr::RotationMatrixD R(R_CM); 230 | init_.state_.aux().qCM_[camID] = QPD(R); 231 | init_.state_.aux().MrMC_[camID] = -init_.state_.aux().qCM_[camID].inverseRotate(CrCM); 232 | } 233 | }; 234 | 235 | } 236 | 237 | 238 | #endif /* ROVIO_ROVIO_FILTER_HPP_ */ 239 | -------------------------------------------------------------------------------- /include/rovio/RovioScene.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_ROVIOSCENE_HPP_ 30 | #define ROVIO_ROVIOSCENE_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "rovio/Scene.hpp" 34 | #include <memory> 35 | 36 | namespace rovio { 37 | 38 | template<typename FILTER> 39 | class RovioScene{ 40 | public: 41 | typedef typename FILTER::mtFilterState mtFilterState; 42 | typedef typename mtFilterState::mtState mtState; 43 | std::shared_ptr<FILTER> mpFilter_; 44 | 45 | rovio::Scene mScene; 46 | cv::Mat patch_; 47 | std::shared_ptr<SceneObject> mpSensor_[mtState::nCam_]; 48 | std::shared_ptr<SceneObject> mpGroundtruth_; 49 | std::shared_ptr<SceneObject> mpLines_[mtState::nCam_]; 50 | std::shared_ptr<SceneObject> mpDepthVar_[mtState::nCam_]; 51 | std::shared_ptr<SceneObject> mpPatches_[mtState::nMax_]; 52 | RovioScene(){ 53 | patch_ = cv::Mat::zeros(mtState::patchSize_*pow(2,mtState::nLevels_-1),mtState::patchSize_*pow(2,mtState::nLevels_-1),CV_8UC1); 54 | } 55 | virtual ~RovioScene(){}; 56 | void addKeyboardCB(unsigned char Key, std::function<void()> f){ 57 | mScene.addKeyboardCB(Key,f); 58 | } 59 | void addSpecialKeyboardCB(int Key, std::function<void()> f){ 60 | mScene.addSpecialKeyboardCB(Key,f); 61 | } 62 | void initScene(int argc, char** argv, const std::string& mVSFileName,const std::string& mFSFileName,std::shared_ptr<FILTER> mpFilter){ 63 | initGlut(argc,argv,mScene); 64 | mScene.init(argc, argv,mVSFileName,mFSFileName); 65 | mpFilter_ = mpFilter; 66 | 67 | std::shared_ptr<SceneObject> mpGroundplane1(mScene.addSceneObject()); 68 | mpGroundplane1->makeGroundPlaneMesh(0.25,40); 69 | mpGroundplane1->setColorFull(Eigen::Vector4f(0.6f,0.6f,0.6f,1.0f)); 70 | mpGroundplane1->lineWidth_ = 1.0f; 71 | mpGroundplane1->W_r_WB_(2) = -1.0f; 72 | std::shared_ptr<SceneObject> mpGroundplane2(mScene.addSceneObject()); 73 | mpGroundplane2->makeGroundPlaneMesh(1.0,10); 74 | mpGroundplane2->setColorFull(Eigen::Vector4f(0.8f,0.8f,0.8f,1.0f)); 75 | mpGroundplane2->lineWidth_ = 3.0f; 76 | mpGroundplane2->W_r_WB_(2) = -1.0f; 77 | for(int camID=0;camID<mtState::nCam_;camID++){ 78 | mpSensor_[camID] = mScene.addSceneObject(); 79 | mpSensor_[camID]->makeCoordinateFrame(1.0f); 80 | mpSensor_[camID]->lineWidth_ = 5.0f; 81 | 82 | mpLines_[camID] = mScene.addSceneObject(); 83 | mpLines_[camID]->makeLine(); 84 | mpLines_[camID]->lineWidth_ = 2.0f; 85 | mpLines_[camID]->mode_ = GL_LINES; 86 | 87 | mpDepthVar_[camID] = mScene.addSceneObject(); 88 | mpDepthVar_[camID]->makeLine(); 89 | mpDepthVar_[camID]->lineWidth_ = 3.0f; 90 | mpDepthVar_[camID]->mode_ = GL_LINES; 91 | } 92 | mpGroundtruth_ = mScene.addSceneObject(); 93 | mpGroundtruth_->makeCoordinateFrame(1.0f); 94 | mpGroundtruth_->lineWidth_ = 5.0f; 95 | Eigen::Vector4f color; 96 | for(int i=0;i<3;i++){ 97 | color = Eigen::Vector4f(0.0f,0.0f,0.0f,1.0f); 98 | color(i) = 0.6f; 99 | mpGroundtruth_->vertices_[i*2].color_.fromEigen(color); 100 | mpGroundtruth_->vertices_[i*2+1].color_.fromEigen(color); 101 | } 102 | mpGroundtruth_->allocateBuffer(); 103 | for(int i=0;i<mtState::nMax_;i++){ 104 | mpPatches_[i] = mScene.addSceneObject(); 105 | mpPatches_[i]->initTexture(mtState::patchSize_*pow(2,mtState::nLevels_-1),mtState::patchSize_*pow(2,mtState::nLevels_-1)); 106 | } 107 | 108 | mScene.setView(Eigen::Vector3f(-5.0f,-5.0f,5.0f),Eigen::Vector3f(0.0f,0.0f,0.0f)); 109 | mScene.setYDown(); 110 | } 111 | void setIdleFunction(void (*idleFunc)()){ 112 | mScene.setIdleFunction(idleFunc); 113 | } 114 | void drawScene(mtFilterState& filterState){ 115 | const mtState& state = filterState.state_; 116 | const MXD& cov = filterState.cov_; 117 | 118 | if(filterState.plotPoseMeas_){ 119 | mpGroundtruth_->q_BW_ = filterState.state_.qCW_ext(); 120 | mpGroundtruth_->W_r_WB_ = filterState.state_.WrWC_ext().template cast<float>(); 121 | mpGroundtruth_->draw_ = true; 122 | } else { 123 | mpGroundtruth_->draw_ = false; 124 | } 125 | 126 | for(unsigned int i=0;i<mtState::nMax_;i++){ 127 | mpPatches_[i]->draw_ = false; 128 | } 129 | 130 | for(unsigned int camID=0;camID<mtState::nCam_;camID++){ 131 | mpSensor_[camID]->W_r_WB_ = state.WrWC(camID).template cast<float>(); 132 | mpSensor_[camID]->q_BW_ = state.qCW(camID); 133 | 134 | std::vector<Eigen::Vector3f> points; 135 | std::vector<Eigen::Vector3f> lines; 136 | mpLines_[camID]->clear(); 137 | mpDepthVar_[camID]->clear(); 138 | FeatureDistance d; 139 | double d_far,d_near; 140 | const float s = pow(2.0,mtState::nLevels_-1)*0.5*mtState::patchSize_; 141 | for(unsigned int i=0;i<mtState::nMax_;i++){ 142 | if(filterState.fsm_.isValid_[i] && filterState.fsm_.features_[i].mpCoordinates_->camID_ == camID){ 143 | mpPatches_[i]->draw_ = true; 144 | d = state.dep(i); 145 | const double sigma = cov(mtState::template getId<mtState::_fea>(i)+2,mtState::template getId<mtState::_fea>(i)+2); 146 | d.p_ -= sigma; 147 | d_far = d.getDistance(); 148 | if(d.getType() == FeatureDistance::INVERSE && (d_far > 1000 || d_far <= 0.0)) d_far = 1000; 149 | d.p_ += 2*sigma; 150 | d_near = d.getDistance(); 151 | const LWF::NormalVectorElement middle = state.CfP(i).get_nor(); 152 | Eigen::Vector3d cornerVec[4]; 153 | const double s = mtState::patchSize_*std::pow(2.0,mtState::nLevels_-2); 154 | if(!filterState.fsm_.features_[i].mpCoordinates_->com_warp_nor()){ 155 | mpPatches_[i]->draw_ = false; 156 | continue; 157 | } 158 | for(int x=0;x<2;x++){ 159 | for(int y=0;y<2;y++){ 160 | cornerVec[y*2+x] = filterState.fsm_.features_[i].mpCoordinates_->get_patchCorner(s*(2*x-1),s*(2*y-1)).get_nor().getVec()*state.dep(i).getDistance(); 161 | } 162 | } 163 | const Eigen::Vector3d pos = middle.getVec()*state.dep(i).getDistance(); 164 | const Eigen::Vector3d pos_far = middle.getVec()*d_far; 165 | const Eigen::Vector3d pos_near = middle.getVec()*d_near; 166 | 167 | mpLines_[camID]->prolonge(cornerVec[0].cast<float>()); 168 | mpLines_[camID]->prolonge(cornerVec[1].cast<float>()); 169 | mpLines_[camID]->prolonge(cornerVec[1].cast<float>()); 170 | mpLines_[camID]->prolonge(cornerVec[3].cast<float>()); 171 | mpLines_[camID]->prolonge(cornerVec[3].cast<float>()); 172 | mpLines_[camID]->prolonge(cornerVec[2].cast<float>()); 173 | mpLines_[camID]->prolonge(cornerVec[2].cast<float>()); 174 | mpLines_[camID]->prolonge(cornerVec[0].cast<float>()); 175 | 176 | mpDepthVar_[camID]->prolonge(pos_far.cast<float>()); 177 | mpDepthVar_[camID]->prolonge(pos_near.cast<float>()); 178 | if(filterState.fsm_.features_[i].mpStatistics_->trackedInSomeFrame()){ 179 | std::next(mpDepthVar_[camID]->vertices_.rbegin())->color_.fromEigen(Eigen::Vector4f(0.0f,1.0f,0.0f,1.0f)); 180 | mpDepthVar_[camID]->vertices_.rbegin()->color_.fromEigen(Eigen::Vector4f(0.0f,1.0f,0.0f,1.0f)); 181 | for(int j=0;j<8;j++){ 182 | std::next(mpLines_[camID]->vertices_.rbegin(),j)->color_.fromEigen(Eigen::Vector4f(0.0f,1.0f,0.0f,1.0f)); 183 | } 184 | } else if(filterState.fsm_.features_[i].mpStatistics_->inSomeFrame()){ 185 | std::next( mpDepthVar_[camID]->vertices_.rbegin())->color_.fromEigen(Eigen::Vector4f(1.0f,0.0f,0.0f,1.0f)); 186 | mpDepthVar_[camID]->vertices_.rbegin()->color_.fromEigen(Eigen::Vector4f(1.0f,0.0f,0.0f,1.0f)); 187 | for(int j=0;j<8;j++){ 188 | std::next(mpLines_[camID]->vertices_.rbegin(),j)->color_.fromEigen(Eigen::Vector4f(1.0f,0.0f,0.0f,1.0f)); 189 | } 190 | } else { 191 | std::next( mpDepthVar_[camID]->vertices_.rbegin())->color_.fromEigen(Eigen::Vector4f(0.5f,0.5f,0.5f,1.0f)); 192 | mpDepthVar_[camID]->vertices_.rbegin()->color_.fromEigen(Eigen::Vector4f(0.5f,0.5f,0.5f,1.0f)); 193 | for(int j=0;j<8;j++){ 194 | std::next(mpLines_[camID]->vertices_.rbegin(),j)->color_.fromEigen(Eigen::Vector4f(0.5f,0.5f,0.5f,1.0f)); 195 | } 196 | } 197 | 198 | mpPatches_[i]->clear(); 199 | mpPatches_[i]->makeTexturedRectangle(1.0f,1.0f); 200 | filterState.fsm_.features_[i].mpMultilevelPatch_->drawMultilevelPatch(patch_,cv::Point2i(0,0),1,false); 201 | mpPatches_[i]->setTexture(patch_); 202 | for(int x=0;x<2;x++){ 203 | for(int y=0;y<2;y++){ 204 | mpPatches_[i]->vertices_[y*2+x].pos_.fromEigen(cornerVec[y*2+x].cast<float>()); 205 | } 206 | } 207 | mpPatches_[i]->allocateBuffer(); 208 | mpPatches_[i]->W_r_WB_ = mpSensor_[camID]->W_r_WB_; 209 | mpPatches_[i]->q_BW_ = mpSensor_[camID]->q_BW_; 210 | } 211 | mpLines_[camID]->W_r_WB_ = mpSensor_[camID]->W_r_WB_; 212 | mpLines_[camID]->q_BW_ = mpSensor_[camID]->q_BW_; 213 | mpLines_[camID]->allocateBuffer(); 214 | mpDepthVar_[camID]->W_r_WB_ = mpSensor_[camID]->W_r_WB_; 215 | mpDepthVar_[camID]->q_BW_ = mpSensor_[camID]->q_BW_; 216 | mpDepthVar_[camID]->allocateBuffer(); 217 | } 218 | } 219 | } 220 | }; 221 | 222 | } 223 | 224 | 225 | #endif /* ROVIO_ROVIOSCENE_HPP_ */ 226 | -------------------------------------------------------------------------------- /include/rovio/Scene.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_SCENE_HPP_ 30 | #define ROVIO_SCENE_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include <opencv2/features2d/features2d.hpp> 34 | #include "GL/glew.h" 35 | #include <GL/freeglut.h> 36 | #include <memory> 37 | #include <fstream> 38 | #include <functional> 39 | 40 | namespace rovio{ 41 | 42 | struct PersProjInfo{ 43 | float FOV_; 44 | float width_; 45 | float height_; 46 | float zNear_; 47 | float zFar_; 48 | }; 49 | 50 | struct DirectionalLight 51 | { 52 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW 53 | Eigen::Vector3f color_; 54 | float ambientIntensity_; 55 | Eigen::Vector3f direction_; 56 | float diffuseIntensity_; 57 | }; 58 | 59 | 60 | static bool ReadShaderFile(const char* pFileName, std::string& outFile){ 61 | std::ifstream f(pFileName); 62 | bool ret = false; 63 | if (f.is_open()) { 64 | std::string line; 65 | while (getline(f, line)) { 66 | outFile.append(line); 67 | outFile.append("\n"); 68 | } 69 | f.close(); 70 | ret = true; 71 | } 72 | return ret; 73 | } 74 | 75 | static Eigen::Matrix4f InitTransform(const Eigen::Vector3f& v,const kindr::RotationQuaternionPF& q){ 76 | Eigen::Matrix4f m = Eigen::Matrix4f::Identity(); 77 | m.block<3,3>(0,0) = kindr::RotationMatrixPF(q).matrix(); 78 | m.block<3,1>(0,3) = -q.rotate(v); 79 | return m; 80 | } 81 | 82 | static Eigen::Matrix4f InitInverseTransform(const Eigen::Vector3f& v,const kindr::RotationQuaternionPF& q){ 83 | Eigen::Matrix4f m = Eigen::Matrix4f::Identity(); 84 | m.block<3,3>(0,0) = kindr::RotationMatrixPF(q).inverted().matrix(); 85 | m.block<3,1>(0,3) = v; 86 | return m; 87 | } 88 | 89 | static Eigen::Matrix4f InitPersProjTransform(const PersProjInfo& p){ 90 | Eigen::Matrix4f m; 91 | const float ar = p.width_ / p.height_; 92 | const float zRange = p.zFar_ - p.zNear_; 93 | const float tanHalfFOV = tanf(p.FOV_ / 2.0f); 94 | 95 | m(0,0) = 1.0f/(tanHalfFOV * ar); m(0,1) = 0.0f; m(0,2) = 0.0f; m(0,3) = 0.0; 96 | m(1,0) = 0.0f; m(1,1) = 1.0f/tanHalfFOV; m(1,2) = 0.0f; m(1,3) = 0.0; 97 | m(2,0) = 0.0f; m(2,1) = 0.0f; m(2,2) = (-p.zNear_ - p.zFar_)/zRange ; m(2,3) = 2.0f*p.zFar_*p.zNear_/zRange; 98 | m(3,0) = 0.0f; m(3,1) = 0.0f; m(3,2) = -1.0f; m(3,3) = 0.0; 99 | return m; 100 | } 101 | 102 | template<int N> 103 | struct Arrayf{ 104 | Arrayf(){ 105 | for(int i=0;i<N;i++){ 106 | data_[i] = 0.0f; 107 | } 108 | } 109 | Arrayf(const Eigen::Matrix<float,N,1>& in){ 110 | fromEigen(in); 111 | } 112 | void fromEigen(const Eigen::Matrix<float,N,1>& in){ 113 | for(int i=0;i<N;i++){ 114 | data_[i] = in(i); 115 | } 116 | } 117 | Eigen::Matrix<float,N,1> toEigen(){ 118 | Eigen::Matrix<float,N,1> out; 119 | for(int i=0;i<N;i++){ 120 | out(i) = data_[i]; 121 | } 122 | return out; 123 | } 124 | float data_[N]; 125 | }; 126 | 127 | struct Vertex 128 | { 129 | Vertex(): 130 | pos_(Eigen::Vector3f(0.0f,0.0f,0.0f)), 131 | normal_(Eigen::Vector3f(0.0f,0.0f,1.0f)), 132 | color_(Eigen::Vector4f(1.0f,1.0f,1.0f,1.0f)){} 133 | Vertex(float x, float y, float z): 134 | pos_(Eigen::Vector3f(x,y,z)), 135 | normal_(Eigen::Vector3f(0.0f,0.0f,1.0f)), 136 | color_(Eigen::Vector4f(1.0f,1.0f,1.0f,1.0f)){} 137 | Vertex(const Eigen::Vector3f& vec): 138 | pos_(vec), 139 | normal_(Eigen::Vector3f(0.0f,0.0f,1.0f)), 140 | color_(Eigen::Vector4f(1.0f,1.0f,1.0f,1.0f)){} 141 | Arrayf<3> pos_; 142 | Arrayf<3> normal_; 143 | Arrayf<4> color_; 144 | }; 145 | 146 | class SceneObject{ 147 | public: 148 | EIGEN_MAKE_ALIGNED_OPERATOR_NEW 149 | SceneObject(); 150 | virtual ~SceneObject(); 151 | void initTexture(const int& cols, const int& rows); 152 | void setTexture(const int& cols, const int& rows, const float* ptr); 153 | void setTexture(const cv::Mat& img); 154 | void allocateBuffer(); 155 | void makeCubeFull(const float& l); 156 | void makeTetrahedron(const float& l); 157 | void makeCubeMesh(const float& l); 158 | void makeLine(); 159 | void makeLine(const std::vector<Eigen::Vector3f>& line); 160 | void makePoints(); 161 | void makePoints(const std::vector<Eigen::Vector3f>& points); 162 | void prolonge(const Eigen::Vector3f& point); 163 | void prolonge(const std::vector<Eigen::Vector3f>& points); 164 | void clear(); 165 | void makeCoordinateFrame(const float& l); 166 | void makeRectangle(const float& x,const float& y); 167 | void makeTexturedRectangle(const float& x,const float& y); 168 | void makeGroundPlane(const float& l,const int& N,const Eigen::Vector4f& color1,const Eigen::Vector4f& color2); 169 | void makeGroundPlaneMesh(const float& l,const int& N); 170 | void setColorFull(const Eigen::Vector4f& color); 171 | const Eigen::Matrix4f GetWorldTrans(); 172 | void CalcNormals(); 173 | void loadOptions(); 174 | Eigen::Vector3f W_r_WB_; 175 | kindr::RotationQuaternionPF q_BW_; 176 | std::vector<Vertex> vertices_; 177 | std::vector<unsigned int> indices_; 178 | GLuint VBO_; 179 | GLuint IBO_; 180 | GLuint textureID_; 181 | GLenum mode_; 182 | bool mbCullFace_; 183 | float lineWidth_; 184 | float pointSize_; 185 | bool useTexture_; 186 | bool draw_; 187 | }; 188 | 189 | class Scene{ 190 | public: 191 | std::map<unsigned char, std::function<void()>> keyboardCallbacks_; 192 | std::map<int, std::function<void()>> specialKeyboardCallbacks_; 193 | Scene(); 194 | virtual ~Scene(); 195 | int init(int argc, char** argv, const std::string& mVSFileName,const std::string& mFSFileName); 196 | std::shared_ptr<SceneObject> addSceneObject(); 197 | void makeTestScene(); 198 | void RenderSceneCB(); 199 | void setView(const Eigen::Vector3f& pos, const Eigen::Vector3f& target); 200 | void setYDown(float step = 0.1); 201 | void SpecialKeyboardCB(int Key, int x, int y); 202 | void addSpecialKeyboardCB(int Key, std::function<void()> f); 203 | void KeyboardCB(unsigned char Key, int x, int y); 204 | void addKeyboardCB(unsigned char Key, std::function<void()> f); 205 | void MotionCB(int x, int y); 206 | void MouseCB(int button, int state, int x, int y); 207 | void AddShader(GLuint ShaderProgram, const char* pShaderText, GLenum ShaderType); 208 | void CompileShaders(const std::string& mVSFileName,const std::string& mFSFileName); 209 | void setIdleFunction(void (*idleFunc)()); 210 | void (*mIdleFunc)(); 211 | private: 212 | float stepScale_; 213 | 214 | std::vector<std::shared_ptr<SceneObject>> mSceneObjects_; 215 | 216 | GLuint V_TF_B_location_; 217 | GLuint W_TF_B_location_; 218 | GLuint lightColor_location_; 219 | GLuint lightAmbientIntensity_location_; 220 | GLuint lightDiffuseIntensity_location_; 221 | GLuint lightDirection_location_; 222 | GLuint useTexture_location_; 223 | GLuint sampler_location_; 224 | 225 | PersProjInfo mPersProjInfo_; 226 | DirectionalLight mDirectionalLight_; 227 | 228 | Eigen::Vector3f W_r_WC_; 229 | kindr::RotationQuaternionPF q_CW_; 230 | 231 | Eigen::Matrix4f C_TF_W_; 232 | Eigen::Matrix4f V_TF_C_; 233 | Eigen::Matrix4f V_TF_B_; 234 | Eigen::Matrix4f W_TF_B_; 235 | 236 | Eigen::Vector2i mMousePos_; 237 | bool enableMouseMotion_; 238 | }; 239 | 240 | static Scene* mpScene = nullptr; 241 | 242 | static void initGlut(int argc, char** argv, Scene& scene){ 243 | glutInit(&argc, argv); 244 | glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGBA); 245 | glutInitWindowSize(1600, 900); 246 | glutInitWindowPosition(100, 100); 247 | glutCreateWindow("Scene"); 248 | 249 | mpScene = &scene; 250 | glutDisplayFunc([](){mpScene->RenderSceneCB();}); 251 | glutIdleFunc([](){ 252 | if(mpScene->mIdleFunc != nullptr){ 253 | mpScene->mIdleFunc(); 254 | } 255 | mpScene->RenderSceneCB(); 256 | }); 257 | glutSpecialFunc([](int Key, int x, int y){mpScene->SpecialKeyboardCB(Key,x,y);}); 258 | glutMotionFunc([](int x, int y){mpScene->MotionCB(x,y);}); 259 | glutMouseFunc([](int button, int state, int x, int y){mpScene->MouseCB(button,state,x,y);}); 260 | glutKeyboardFunc([](unsigned char Key, int x, int y){mpScene->KeyboardCB(Key,x,y);}); 261 | } 262 | 263 | } 264 | 265 | 266 | #endif /* ROVIO_SCENE_HPP_ */ 267 | -------------------------------------------------------------------------------- /include/rovio/VelocityUpdate.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_VELOCITYUPDATE_HPP_ 30 | #define ROVIO_VELOCITYUPDATE_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "lightweight_filtering/Update.hpp" 34 | #include "lightweight_filtering/State.hpp" 35 | #include "rovio/FilterStates.hpp" 36 | 37 | namespace rovio { 38 | 39 | /** \brief Class, defining the innovation. 40 | */ 41 | class VelocityInnovation: public LWF::State<LWF::VectorElement<3>>{ 42 | public: 43 | typedef LWF::State<LWF::VectorElement<3>> Base; 44 | using Base::E_; 45 | static constexpr unsigned int _vel = 0; 46 | VelocityInnovation(){ 47 | static_assert(_vel+1==E_,"Error with indices"); 48 | this->template getName<_vel>() = "vel"; 49 | }; 50 | virtual ~VelocityInnovation(){}; 51 | inline V3D& vel(){ 52 | return this->template get<_vel>(); 53 | } 54 | inline const V3D& vel() const{ 55 | return this->template get<_vel>(); 56 | } 57 | }; 58 | 59 | /** \brief Class, dummy auxillary class for Zero velocity update 60 | */ 61 | class VelocityUpdateMeasAuxiliary: public LWF::AuxiliaryBase<VelocityUpdateMeasAuxiliary>{ 62 | public: 63 | VelocityUpdateMeasAuxiliary(){ 64 | }; 65 | virtual ~VelocityUpdateMeasAuxiliary(){}; 66 | }; 67 | 68 | /** \brief Empty measurement 69 | */ 70 | class VelocityUpdateMeas: public LWF::State<LWF::VectorElement<3>,VelocityUpdateMeasAuxiliary>{ 71 | public: 72 | typedef LWF::State<LWF::VectorElement<3>,VelocityUpdateMeasAuxiliary> Base; 73 | using Base::E_; 74 | static constexpr unsigned int _vel = 0; 75 | static constexpr unsigned int _aux = _vel+1; 76 | VelocityUpdateMeas(){ 77 | static_assert(_aux+1==E_,"Error with indices"); 78 | this->template getName<_vel>() = "vel"; 79 | this->template getName<_aux>() = "aux"; 80 | }; 81 | virtual ~VelocityUpdateMeas(){}; 82 | inline V3D& vel(){ 83 | return this->template get<_vel>(); 84 | } 85 | inline const V3D& vel() const{ 86 | return this->template get<_vel>(); 87 | } 88 | }; 89 | 90 | /** \brief Class holding the update noise. 91 | */ 92 | class VelocityUpdateNoise: public LWF::State<LWF::VectorElement<3>>{ 93 | public: 94 | typedef LWF::State<LWF::VectorElement<3>> Base; 95 | using Base::E_; 96 | static constexpr unsigned int _vel = 0; 97 | VelocityUpdateNoise(){ 98 | static_assert(_vel+1==E_,"Error with indices"); 99 | this->template getName<_vel>() = "vel"; 100 | }; 101 | virtual ~VelocityUpdateNoise(){}; 102 | inline V3D& vel(){ 103 | return this->template get<_vel>(); 104 | } 105 | inline const V3D& vel() const{ 106 | return this->template get<_vel>(); 107 | } 108 | }; 109 | 110 | /** \brief Outlier Detection. 111 | * ODEntry<Start entry, dimension of detection> 112 | */ 113 | class VelocityOutlierDetection: public LWF::OutlierDetection<LWF::ODEntry<VelocityInnovation::template getId<VelocityInnovation::_vel>(),3>>{ 114 | public: 115 | virtual ~VelocityOutlierDetection(){}; 116 | }; 117 | 118 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 119 | 120 | /** \brief Class, holding the zero velocity update 121 | */ 122 | template<typename FILTERSTATE> 123 | class VelocityUpdate: public LWF::Update<VelocityInnovation,FILTERSTATE,VelocityUpdateMeas, 124 | VelocityUpdateNoise,VelocityOutlierDetection,false>{ 125 | public: 126 | typedef LWF::Update<VelocityInnovation,FILTERSTATE,VelocityUpdateMeas, 127 | VelocityUpdateNoise,VelocityOutlierDetection,false> Base; 128 | using Base::doubleRegister_; 129 | using Base::intRegister_; 130 | using Base::meas_; 131 | typedef typename Base::mtState mtState; 132 | typedef typename Base::mtFilterState mtFilterState; 133 | typedef typename Base::mtInnovation mtInnovation; 134 | typedef typename Base::mtMeas mtMeas; 135 | typedef typename Base::mtNoise mtNoise; 136 | typedef typename Base::mtOutlierDetection mtOutlierDetection; 137 | 138 | QPD qAM_; // Rotation between IMU (M) and coordinate frame where the velocity is expressed in (A) 139 | 140 | /** \brief Constructor. 141 | * 142 | * Loads and sets the needed parameters. 143 | */ 144 | VelocityUpdate(){ 145 | qAM_.setIdentity(); 146 | intRegister_.removeScalarByStr("maxNumIteration"); 147 | doubleRegister_.removeScalarByStr("alpha"); 148 | doubleRegister_.removeScalarByStr("beta"); 149 | doubleRegister_.removeScalarByStr("kappa"); 150 | doubleRegister_.removeScalarByStr("updateVecNormTermination"); 151 | doubleRegister_.registerQuaternion("qAM",qAM_); 152 | }; 153 | 154 | /** \brief Destructor 155 | */ 156 | virtual ~VelocityUpdate(){}; 157 | 158 | /** \brief Compute the inovvation term 159 | * 160 | * @param mtInnovation - Class, holding innovation data. 161 | * @param state - Filter %State. 162 | * @param meas - Not Used. 163 | * @param noise - Additive discrete Gaussian noise. 164 | * @param dt - Not used. 165 | */ 166 | void evalInnovation(mtInnovation& y, const mtState& state, const mtNoise& noise) const{ 167 | y.vel() = qAM_.rotate(state.MvM()) + meas_.vel() + noise.vel(); // Velocity of state has a minus sign 168 | } 169 | 170 | /** \brief Computes the Jacobian for the update step of the filter. 171 | * 172 | * @param F - Jacobian for the update step of the filter. 173 | * @param state - Filter state. 174 | * @param meas - Not used. 175 | * @param dt - Not used. 176 | */ 177 | void jacState(MXD& F, const mtState& state) const{ 178 | F.setZero(); 179 | F.template block<3,3>(mtInnovation::template getId<mtInnovation::_vel>(),mtState::template getId<mtState::_vel>()) = MPD(qAM_).matrix(); 180 | } 181 | 182 | /** \brief Computes the Jacobian for the update step of the filter w.r.t. to the noise variables 183 | * 184 | * @param G - Jacobian for the update step of the filter. 185 | * @param state - Filter state. 186 | * @param meas - Not used. 187 | * @param dt - Not used. 188 | */ 189 | void jacNoise(MXD& G, const mtState& state) const{ 190 | G.setZero(); 191 | G.template block<3,3>(mtInnovation::template getId<mtInnovation::_vel>(),mtNoise::template getId<mtNoise::_vel>()) = Eigen::Matrix3d::Identity(); 192 | } 193 | }; 194 | 195 | } 196 | 197 | 198 | #endif /* ROVIO_VELOCITYUPDATE_HPP_ */ 199 | -------------------------------------------------------------------------------- /include/rovio/ZeroVelocityUpdate.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_ZEROVELOCITYUPDATE_HPP_ 30 | #define ROVIO_ZEROVELOCITYUPDATE_HPP_ 31 | 32 | #include "lightweight_filtering/common.hpp" 33 | #include "lightweight_filtering/Update.hpp" 34 | #include "lightweight_filtering/State.hpp" 35 | #include "rovio/FilterStates.hpp" 36 | 37 | namespace rovio { 38 | 39 | /** \brief Class, defining the innovation. 40 | */ 41 | template<typename STATE> 42 | class ZeroVelocityInnovation: public LWF::State<LWF::VectorElement<3>>{ 43 | public: 44 | typedef LWF::State<LWF::VectorElement<3>> Base; 45 | using Base::E_; 46 | static constexpr unsigned int _vel = 0; 47 | ZeroVelocityInnovation(){ 48 | static_assert(_vel+1==E_,"Error with indices"); 49 | this->template getName<_vel>() = "vel"; 50 | }; 51 | virtual ~ZeroVelocityInnovation(){}; 52 | }; 53 | 54 | /** \brief Class, dummy auxillary class for Zero velocity update 55 | */ 56 | class ZeroVelocityUpdateMeasAuxiliary: public LWF::AuxiliaryBase<ZeroVelocityUpdateMeasAuxiliary>{ 57 | public: 58 | ZeroVelocityUpdateMeasAuxiliary(){ 59 | }; 60 | virtual ~ZeroVelocityUpdateMeasAuxiliary(){}; 61 | }; 62 | 63 | /** \brief Empty measurement 64 | */ 65 | template<typename STATE> 66 | class ZeroVelocityUpdateMeas: public LWF::State<ZeroVelocityUpdateMeasAuxiliary>{ 67 | public: 68 | typedef LWF::State<ZeroVelocityUpdateMeasAuxiliary> Base; 69 | using Base::E_; 70 | static constexpr unsigned int _aux = 0; 71 | ZeroVelocityUpdateMeas(){ 72 | static_assert(_aux+1==E_,"Error with indices"); 73 | this->template getName<_aux>() = "aux"; 74 | }; 75 | virtual ~ZeroVelocityUpdateMeas(){}; 76 | }; 77 | 78 | /** \brief Class holding the update noise. 79 | */ 80 | template<typename STATE> 81 | class ZeroVelocityUpdateNoise: public LWF::State<LWF::VectorElement<3>>{ 82 | public: 83 | typedef LWF::State<LWF::VectorElement<3>> Base; 84 | using Base::E_; 85 | static constexpr unsigned int _vel = 0; 86 | ZeroVelocityUpdateNoise(){ 87 | static_assert(_vel+1==E_,"Error with indices"); 88 | this->template getName<_vel>() = "vel"; 89 | }; 90 | virtual ~ZeroVelocityUpdateNoise(){}; 91 | }; 92 | 93 | /** \brief Outlier Detection. 94 | */ 95 | template<typename STATE> 96 | class ZeroVelocityOutlierDetection: public LWF::OutlierDetection<LWF::ODEntry<ZeroVelocityInnovation<STATE>::template getId<ZeroVelocityInnovation<STATE>::_vel>(),3>>{ 97 | public: 98 | virtual ~ZeroVelocityOutlierDetection(){}; 99 | }; 100 | 101 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 102 | 103 | /** \brief Class, holding the zero velocity update 104 | */ 105 | template<typename FILTERSTATE> 106 | class ZeroVelocityUpdate: public LWF::Update<ZeroVelocityInnovation<typename FILTERSTATE::mtState>,FILTERSTATE,ZeroVelocityUpdateMeas<typename FILTERSTATE::mtState>, 107 | ZeroVelocityUpdateNoise<typename FILTERSTATE::mtState>,ZeroVelocityOutlierDetection<typename FILTERSTATE::mtState>,false>{ 108 | public: 109 | typedef LWF::Update<ZeroVelocityInnovation<typename FILTERSTATE::mtState>,FILTERSTATE,ZeroVelocityUpdateMeas<typename FILTERSTATE::mtState>, 110 | ZeroVelocityUpdateNoise<typename FILTERSTATE::mtState>,ZeroVelocityOutlierDetection<typename FILTERSTATE::mtState>,false> Base; 111 | using Base::doubleRegister_; 112 | using Base::intRegister_; 113 | typedef typename Base::mtState mtState; 114 | typedef typename Base::mtFilterState mtFilterState; 115 | typedef typename Base::mtInnovation mtInnovation; 116 | typedef typename Base::mtMeas mtMeas; 117 | typedef typename Base::mtNoise mtNoise; 118 | typedef typename Base::mtOutlierDetection mtOutlierDetection; 119 | 120 | /** \brief Constructor. 121 | * 122 | * Loads and sets the needed parameters. 123 | */ 124 | ZeroVelocityUpdate(){ 125 | intRegister_.removeScalarByStr("maxNumIteration"); 126 | doubleRegister_.removeScalarByStr("alpha"); 127 | doubleRegister_.removeScalarByStr("beta"); 128 | doubleRegister_.removeScalarByStr("kappa"); 129 | doubleRegister_.removeScalarByStr("updateVecNormTermination"); 130 | }; 131 | 132 | /** \brief Destructor 133 | */ 134 | virtual ~ZeroVelocityUpdate(){}; 135 | 136 | /** \brief Compute the inovvation term 137 | * 138 | * @param mtInnovation - Class, holding innovation data. 139 | * @param state - Filter %State. 140 | * @param meas - Not Used. 141 | * @param noise - Additive discrete Gaussian noise. 142 | * @param dt - Not used. 143 | */ 144 | void evalInnovation(mtInnovation& y, const mtState& state, const mtNoise& noise) const{ 145 | y.template get<mtInnovation::_vel>() = state.MvM()+noise.template get<mtInnovation::_vel>(); 146 | } 147 | 148 | /** \brief Computes the Jacobian for the update step of the filter. 149 | * 150 | * @param F - Jacobian for the update step of the filter. 151 | * @param state - Filter state. 152 | * @param meas - Not used. 153 | * @param dt - Not used. 154 | */ 155 | void jacState(MXD& F, const mtState& state) const{ 156 | F.setZero(); 157 | F.template block<3,3>(mtInnovation::template getId<mtInnovation::_vel>(),mtState::template getId<mtState::_vel>()) = Eigen::Matrix3d::Identity(); 158 | } 159 | 160 | /** \brief Computes the Jacobian for the update step of the filter w.r.t. to the noise variables 161 | * 162 | * @param G - Jacobian for the update step of the filter. 163 | * @param state - Filter state. 164 | * @param meas - Not used. 165 | * @param dt - Not used. 166 | */ 167 | void jacNoise(MXD& G, const mtState& state) const{ 168 | G.setZero(); 169 | G.template block<3,3>(mtInnovation::template getId<mtInnovation::_vel>(),mtNoise::template getId<mtNoise::_vel>()) = Eigen::Matrix3d::Identity(); 170 | } 171 | }; 172 | 173 | } 174 | 175 | 176 | #endif /* ROVIO_ZEROVELOCITYUPDATE_HPP_ */ 177 | -------------------------------------------------------------------------------- /include/rovio/exceptions.hpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #ifndef ROVIO_EXCEPTION_HPP_ 30 | #define ROVIO_EXCEPTION_HPP_ 31 | 32 | #include <string> 33 | #include <iostream> 34 | #include <exception> 35 | #include <typeinfo> 36 | 37 | #define ROVIO_THROW(exceptionType) { \ 38 | throw exceptionType(__FUNCTION__,__FILE__,__LINE__); \ 39 | } 40 | 41 | namespace rovio { 42 | struct ExceptionBase : public std::exception 43 | { 44 | std::string message_; 45 | std::string function_; 46 | std::string file_; 47 | int line_; 48 | ExceptionBase(std::string message,std::string function, std::string file, int line){ 49 | message_ = message; 50 | function_ = function; 51 | file_ = file; 52 | line_ = line; 53 | } 54 | virtual ~ExceptionBase(){}; 55 | virtual const char * what () const throw () 56 | { 57 | return (file_ + ":" + std::to_string(line_) + ": " + function_ + "()" + " " + message_).c_str(); 58 | } 59 | }; 60 | 61 | struct CameraNullPtrException : public ExceptionBase 62 | { 63 | CameraNullPtrException(std::string function, std::string file, int line): ExceptionBase("Camera pointer is null!",function,file,line){} 64 | }; 65 | } 66 | 67 | /* Usage: 68 | * ROVIO_THROW(rovio::CameraNullPtrException); 69 | */ 70 | 71 | #endif /* ROVIO_EXCEPTION_HPP_ */ 72 | -------------------------------------------------------------------------------- /launch/rovio_node.launch: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <launch> 3 | <node pkg="rovio" type="rovio_node" name="rovio" output="screen"> 4 | <param name="filter_config" value="$(find rovio)/cfg/rovio.info"/> 5 | <param name="camera0_config" value="$(find rovio)/cfg/euroc_cam0.yaml"/> 6 | <param name="camera1_config" value="$(find rovio)/cfg/euroc_cam1.yaml"/> 7 | </node> 8 | </launch> 9 | -------------------------------------------------------------------------------- /launch/rovio_rosbag_node.launch: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <launch> 3 | <node pkg="rovio" type="rovio_rosbag_loader" name="rovio" output="screen"> 4 | <param name="filter_config" value="$(find rovio)/cfg/rovio.info"/> 5 | <param name="camera0_config" value="$(find rovio)/cfg/euroc_cam0.yaml"/> 6 | <param name="camera1_config" value="$(find rovio)/cfg/euroc_cam1.yaml"/> 7 | <param name="rosbag_filename" value="/home/michael/datasets/euroc/01_easy/dataset.bag"/> 8 | <param name="imu_topic_name" value="/imu0"/> 9 | <param name="cam0_topic_name" value="/cam0/image_raw"/> 10 | <param name="cam1_topic_name" value="/cam1/image_raw"/> 11 | </node> 12 | </launch> -------------------------------------------------------------------------------- /launch/valgrind_rovio.launch: -------------------------------------------------------------------------------- 1 | <?xml version="1.0" encoding="UTF-8"?> 2 | <launch> 3 | <node pkg="rovio" type="rovio_node" name="rovio" output="screen" launch-prefix="valgrind --leak-check=full"> 4 | </node> 5 | </launch> 6 | -------------------------------------------------------------------------------- /mainpage.dox: -------------------------------------------------------------------------------- 1 | /*! \mainpage Documentation 2 | * 3 | * \section intro_sec Introduction 4 | * ROVIO is a visual-inertial odometry framework which, by directly using pixel 5 | * intensity errors of image patches, achieves accurate tracking 6 | * performance while exhibiting a very high level of robustness. 7 | * 8 | * After detection, the tracking of the multilevel patch features is 9 | * closely coupled to the underlying extended Kalman filter (EKF) 10 | * by directly using the intensity errors as innovation term during 11 | * the update step. A purely robocentric approach is followed, 12 | * where the location of 3D landmarks are always estimated 13 | * with respect to the current camera pose. Furthermore, the landmark 14 | * positions are decomposed into a bearing vector and 15 | * a distance parametrization whereby a minimal 16 | * representation of differences on a corresponding σ-Algebra is employed 17 | * in order to achieve better consistency and to improve the 18 | * computational performance. 19 | * 20 | * Due to the robocentric, inverse- 21 | * distance (selectable) landmark parametrization, the framework does not 22 | * require any initialization procedure, leading to a truly power- 23 | * up-and-go state estimation system. 24 | * 25 | * 26 | * 27 | */ 28 | 29 | \cond ----------- Document the the rovio namespace. ------------ \endcond 30 | /*! \namespace rovio */ -------------------------------------------------------------------------------- /package.xml: -------------------------------------------------------------------------------- 1 | <?xml version="1.0"?> 2 | <package format="2"> 3 | <name>rovio</name> 4 | <version>0.0.0</version> 5 | <description> 6 | 7 | rovio 8 | 9 | </description> 10 | <url></url> 11 | <author>bloeschm</author> 12 | <maintainer email="bloeschm@ethz.ch">bloeschm</maintainer> 13 | <license>BSD License</license> 14 | <buildtool_depend>catkin</buildtool_depend> 15 | 16 | <depend>cmake_modules</depend> 17 | <depend>lightweight_filtering</depend> 18 | <depend>kindr</depend> 19 | <depend>roscpp</depend> 20 | <depend>roslib</depend> 21 | <depend>cv_bridge</depend> 22 | <depend>message_generation</depend> 23 | <depend>message_runtime</depend> 24 | <depend>geometry_msgs</depend> 25 | <depend>sensor_msgs</depend> 26 | <depend>std_msgs</depend> 27 | <depend>nav_msgs</depend> 28 | <depend>tf</depend> 29 | <depend>rosbag</depend> 30 | <depend>yaml_cpp_catkin</depend> 31 | </package> 32 | -------------------------------------------------------------------------------- /shaders/shader.fs: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | in vec4 Color0; 6 | in vec3 Normal0; 7 | in vec2 TexCoord0; 8 | 9 | out vec4 FragColor; 10 | 11 | struct DirectionalLight 12 | { 13 | vec3 Color; 14 | float AmbientIntensity; 15 | float DiffuseIntensity; 16 | vec3 Direction; 17 | }; 18 | 19 | uniform DirectionalLight gDirectionalLight; 20 | uniform sampler2D gSampler; 21 | uniform bool useTexture; 22 | 23 | void main() 24 | { 25 | vec4 AmbientColor = vec4(gDirectionalLight.Color, 1.0f) * gDirectionalLight.AmbientIntensity; 26 | 27 | float DiffuseFactor = dot(normalize(Normal0), -gDirectionalLight.Direction); 28 | 29 | vec4 DiffuseColor; 30 | 31 | if (DiffuseFactor > 0.0f) { 32 | DiffuseColor = vec4(gDirectionalLight.Color, 1.0f) * gDirectionalLight.DiffuseIntensity * DiffuseFactor; 33 | } 34 | else { 35 | DiffuseColor = vec4(0.0f, 0.0f, 0.0f, 0.0f); 36 | } 37 | 38 | if(!useTexture){ 39 | FragColor = Color0 * (AmbientColor + DiffuseColor); 40 | } 41 | else { 42 | FragColor = texture2D(gSampler, TexCoord0.st) * (AmbientColor + DiffuseColor); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /shaders/shader.vs: -------------------------------------------------------------------------------- 1 | #version 300 es 2 | 3 | precision highp float; 4 | 5 | layout (location = 0) in vec3 Position; 6 | layout (location = 1) in vec3 Normal; 7 | layout (location = 2) in vec4 Color; 8 | 9 | uniform mat4 V_TF_B; 10 | uniform mat4 W_TF_B; 11 | 12 | out vec4 Color0; 13 | out vec3 Normal0; 14 | out vec2 TexCoord0; 15 | 16 | void main() 17 | { 18 | gl_Position = V_TF_B * vec4(Position, 1.0f); 19 | Color0 = Color; 20 | Normal0 = (W_TF_B * vec4(Normal, 0.0)).xyz; 21 | TexCoord0 = Color.xy; 22 | } 23 | -------------------------------------------------------------------------------- /src/FeatureCoordinates.cpp: -------------------------------------------------------------------------------- 1 | #include "rovio/FeatureCoordinates.hpp" 2 | 3 | namespace rovio{ 4 | 5 | FeatureCoordinates::FeatureCoordinates(){ 6 | mpCamera_ = nullptr; 7 | trackWarping_ = false; 8 | resetCoordinates(); 9 | } 10 | 11 | FeatureCoordinates::FeatureCoordinates(const cv::Point2f& pixel){ 12 | mpCamera_ = nullptr; 13 | trackWarping_ = false; 14 | resetCoordinates(); 15 | c_ = pixel; 16 | valid_c_ = true; 17 | } 18 | 19 | FeatureCoordinates::FeatureCoordinates(const LWF::NormalVectorElement& nor){ 20 | mpCamera_ = nullptr; 21 | trackWarping_ = false; 22 | resetCoordinates(); 23 | nor_ = nor; 24 | valid_nor_ = true; 25 | } 26 | 27 | FeatureCoordinates::FeatureCoordinates(const Camera* mpCamera): mpCamera_(mpCamera){ 28 | trackWarping_ = false; 29 | resetCoordinates(); 30 | } 31 | 32 | FeatureCoordinates::~FeatureCoordinates(){}; 33 | 34 | void FeatureCoordinates::resetCoordinates(){ 35 | valid_c_ = false; 36 | valid_nor_ = false; 37 | set_warp_identity(); 38 | camID_ = -1; 39 | } 40 | 41 | bool FeatureCoordinates::com_c() const{ 42 | if(!valid_c_){ 43 | assert(mpCamera_ != nullptr); 44 | if(valid_nor_ && mpCamera_->bearingToPixel(nor_,c_)){ 45 | valid_c_ = true; 46 | } 47 | } 48 | return valid_c_; 49 | } 50 | 51 | const cv::Point2f& FeatureCoordinates::get_c() const{ 52 | if(!com_c()){ 53 | std::cout << " \033[31mERROR: No valid coordinate data!\033[0m" << std::endl; 54 | } 55 | return c_; 56 | } 57 | 58 | bool FeatureCoordinates::com_nor() const{ 59 | if(!valid_nor_){ 60 | assert(mpCamera_ != nullptr); 61 | if(valid_c_ && mpCamera_->pixelToBearing(c_,nor_)){ 62 | valid_nor_ = true; 63 | } 64 | } 65 | return valid_nor_; 66 | } 67 | 68 | const LWF::NormalVectorElement& FeatureCoordinates::get_nor() const{ 69 | if(!com_nor()){ 70 | std::cout << " \033[31mERROR: No valid coordinate data!\033[0m" << std::endl; 71 | } 72 | return nor_; 73 | } 74 | 75 | Eigen::Matrix<double,2,2> FeatureCoordinates::get_J() const{ 76 | assert(mpCamera_ != nullptr); 77 | if(!mpCamera_->bearingToPixel(get_nor(),c_,matrix2dTemp_)){ 78 | matrix2dTemp_.setZero(); 79 | std::cout << " \033[31mERROR: No valid coordinate data!\033[0m" << std::endl; 80 | } 81 | return matrix2dTemp_; 82 | } 83 | 84 | void FeatureCoordinates::set_c(const cv::Point2f& c, const bool resetWarp){ 85 | c_ = c; 86 | valid_c_ = true; 87 | valid_nor_ = false; 88 | if(trackWarping_ && resetWarp){ 89 | valid_warp_c_ = false; 90 | valid_warp_nor_ = false; 91 | } 92 | } 93 | 94 | void FeatureCoordinates::set_nor(const LWF::NormalVectorElement& nor, const bool resetWarp){ 95 | nor_ = nor; 96 | valid_nor_ = true; 97 | valid_c_ = false; 98 | if(trackWarping_ && resetWarp){ 99 | valid_warp_c_ = false; 100 | valid_warp_nor_ = false; 101 | } 102 | } 103 | 104 | bool FeatureCoordinates::com_warp_c() const{ 105 | if(!valid_warp_c_){ 106 | if(valid_warp_nor_ && com_c() && com_nor()){ 107 | matrix2dTemp_ = get_J(); 108 | warp_c_ = (matrix2dTemp_*warp_nor_).cast<float>(); 109 | valid_warp_c_ = true; 110 | } 111 | } 112 | return valid_warp_c_; 113 | } 114 | 115 | Eigen::Matrix2f& FeatureCoordinates::get_warp_c() const{ 116 | if(!com_warp_c()){ 117 | std::cout << " \033[31mERROR: No valid warping data in get_warp_c!\033[0m" << std::endl; 118 | } 119 | return warp_c_; 120 | } 121 | 122 | bool FeatureCoordinates::com_warp_nor() const{ 123 | if(!valid_warp_nor_){ 124 | if(valid_warp_c_ && com_c() && com_nor()){ 125 | matrix2dTemp_ = get_J(); 126 | fullPivLU2d_.compute(matrix2dTemp_); 127 | if(fullPivLU2d_.rank() == 2){ 128 | warp_nor_ = fullPivLU2d_.inverse()*warp_c_.cast<double>(); 129 | valid_warp_nor_ = true; 130 | } 131 | } 132 | } 133 | return valid_warp_nor_; 134 | } 135 | 136 | Eigen::Matrix2d& FeatureCoordinates::get_warp_nor() const{ 137 | if(!com_warp_nor()){ 138 | std::cout << " \033[31mERROR: No valid warping data in get_warp_nor!\033[0m" << std::endl; 139 | } 140 | return warp_nor_; 141 | } 142 | 143 | FeatureCoordinates FeatureCoordinates::get_patchCorner(const double x, const double y) const{ 144 | FeatureCoordinates temp; // TODO: avoid temp 145 | get_nor().boxPlus(get_warp_nor()*Eigen::Vector2d(x,y),norTemp_); 146 | temp.set_nor(norTemp_); 147 | temp.mpCamera_ = mpCamera_; 148 | temp.camID_ = camID_; 149 | return temp; 150 | } 151 | 152 | void FeatureCoordinates::set_warp_c(const Eigen::Matrix2f& warp_c){ 153 | warp_c_ = warp_c; 154 | valid_warp_c_ = true; 155 | valid_warp_nor_ = false; 156 | isWarpIdentity_ = false; 157 | } 158 | 159 | void FeatureCoordinates::set_warp_nor(const Eigen::Matrix2d& warp_nor){ 160 | warp_nor_ = warp_nor; 161 | valid_warp_nor_ = true; 162 | valid_warp_c_ = false; 163 | isWarpIdentity_ = false; 164 | } 165 | 166 | void FeatureCoordinates::set_warp_identity(){ 167 | warp_c_.setIdentity(); 168 | valid_warp_c_ = true; 169 | valid_warp_nor_ = false; 170 | isWarpIdentity_ = true; 171 | } 172 | 173 | bool FeatureCoordinates::isInFront() const{ 174 | return valid_c_ || (valid_nor_ && nor_.getVec()[2] > 0); 175 | } 176 | 177 | bool FeatureCoordinates::isNearIdentityWarping() const{ 178 | return isWarpIdentity_ || (com_warp_c() && (get_warp_c()-Eigen::Matrix2f::Identity()).norm() < 1e-6); 179 | } 180 | 181 | void FeatureCoordinates::setPixelCov(const Eigen::Matrix2d& cov){ 182 | pixelCov_ = cov; 183 | es_.compute(cov); 184 | sigmaAngle_ = std::atan2(es_.eigenvectors()(1,0).real(),es_.eigenvectors()(0,0).real()); 185 | sigma1_ = sqrt(es_.eigenvalues()(0).real()); 186 | sigma2_ = sqrt(es_.eigenvalues()(1).real()); 187 | if(sigma1_<sigma2_){ // Get larger axis on index 1 188 | const double temp = sigma1_; 189 | sigma1_ = sigma2_; 190 | sigma2_ = temp; 191 | sigmaAngle_ += 0.5*M_PI; 192 | eigenVector1_ = es_.eigenvectors().col(1).real(); 193 | eigenVector2_ = es_.eigenvectors().col(0).real(); 194 | } else { 195 | eigenVector1_ = es_.eigenvectors().col(0).real(); 196 | eigenVector2_ = es_.eigenvectors().col(1).real(); 197 | } 198 | } 199 | 200 | void FeatureCoordinates::drawPoint(cv::Mat& drawImg, const cv::Scalar& color, const float s) const{ 201 | cv::Size size(s,s); 202 | cv::ellipse(drawImg,get_c(),size,0,0,360,color,-1,8,0); 203 | } 204 | 205 | void FeatureCoordinates::drawEllipse(cv::Mat& drawImg, const cv::Scalar& color, double scaleFactor, const bool withCenterPoint) const{ 206 | if(withCenterPoint) drawPoint(drawImg,color); 207 | cv::ellipse(drawImg,get_c(),cv::Size(std::max(static_cast<int>(scaleFactor*sigma1_+0.5),1),std::max(static_cast<int>(scaleFactor*sigma2_+0.5),1)),sigmaAngle_*180/M_PI,0,360,color,1,8,0); 208 | } 209 | 210 | void FeatureCoordinates::drawLine(cv::Mat& drawImg, const FeatureCoordinates& other, const cv::Scalar& color, int thickness) const{ 211 | cv::line(drawImg,get_c(),other.get_c(),color,thickness); 212 | } 213 | 214 | void FeatureCoordinates::drawText(cv::Mat& drawImg, const std::string& s, const cv::Scalar& color) const{ 215 | cv::putText(drawImg,s,get_c(),cv::FONT_HERSHEY_SIMPLEX, 0.4, color); 216 | } 217 | 218 | bool FeatureCoordinates::getDepthFromTriangulation(const FeatureCoordinates& other, const V3D& C2rC2C1, const QPD& qC2C1, FeatureDistance& d, const double minDistance){ 219 | const V3D C2v1 = qC2C1.rotate(get_nor().getVec()); 220 | const V3D C2v2 = other.get_nor().getVec(); 221 | const double a = 1.0-pow(C2v1.dot(C2v2),2.0); 222 | if(a < 1e-6){ 223 | return false; 224 | } 225 | 226 | const double distance = -C2v1.dot((M3D::Identity()-C2v2*C2v2.transpose())*C2rC2C1) / a; 227 | if(distance < minDistance){ 228 | return false; 229 | } 230 | d.setParameter(distance); 231 | return true; 232 | 233 | // Possible alternative -> investigate 234 | // Eigen::Matrix<double,3,2> V; 235 | // V.col(0) = -C2v1; 236 | // V.col(1) = C2v2; 237 | // Eigen::JacobiSVD<Eigen::Matrix<double,3,2>> svd(V, Eigen::ComputeThinU | Eigen::ComputeThinV); 238 | // Eigen::Vector2d distances = svd.solve(C2rC2C1); 239 | } 240 | 241 | float FeatureCoordinates::getDepthUncertaintyTau(const V3D& C1rC1C2, const float d, const float px_error_angle){ 242 | const V3D C1fP = get_nor().getVec(); 243 | float t_0 = C1rC1C2(0); 244 | float t_1 = C1rC1C2(1); 245 | float t_2 = C1rC1C2(2); 246 | float a_0 = C1fP(0) * d - t_0; 247 | float a_1 = C1fP(1) * d - t_1; 248 | float a_2 = C1fP(2) * d - t_2; 249 | float t_norm = std::sqrt(t_0 * t_0 + t_1 * t_1 + t_2 * t_2); 250 | float a_norm = std::sqrt(a_0 * a_0 + a_1 * a_1 + a_2 * a_2); 251 | float alpha = std::acos((C1fP(0) * t_0 + C1fP(1) * t_1 + C1fP(2) * t_2) / t_norm); 252 | float beta = std::acos(( a_0 * (-t_0) + a_1 * (-t_1) + a_2 * (-t_2) ) / (t_norm * a_norm)); 253 | float beta_plus = beta + px_error_angle; 254 | float gamma_plus = M_PI - alpha - beta_plus; // Triangle angles sum to PI. 255 | float d_plus = t_norm * std::sin(beta_plus) / std::sin(gamma_plus); // Law of sines. 256 | return (d_plus - d); // Tau. 257 | } 258 | } 259 | -------------------------------------------------------------------------------- /src/FeatureDistance.cpp: -------------------------------------------------------------------------------- 1 | #include "rovio/FeatureDistance.hpp" 2 | #include <complex> 3 | #include <iostream> 4 | 5 | namespace rovio { 6 | 7 | FeatureDistance::FeatureDistance(const Type& type){ 8 | setType(type); 9 | p_ = 1.0; 10 | } 11 | 12 | FeatureDistance::~FeatureDistance(){}; 13 | 14 | void FeatureDistance::setType(const Type& type){ 15 | type_ = type; 16 | } 17 | 18 | FeatureDistance::Type FeatureDistance::getType(){ 19 | return type_; 20 | } 21 | 22 | void FeatureDistance::setType(const int& type){ 23 | switch(type){ 24 | case 0: 25 | type_ = REGULAR; 26 | break; 27 | case 1: 28 | type_ = INVERSE; 29 | break; 30 | case 2: 31 | type_ = LOG; 32 | break; 33 | case 3: 34 | type_ = HYPERBOLIC; 35 | break; 36 | default: 37 | std::cout << "Invalid type for distance parameterization: " << type << std::endl; 38 | type_ = REGULAR; 39 | break; 40 | } 41 | } 42 | 43 | void FeatureDistance::setParameter(const double& d){ 44 | switch(type_){ 45 | case REGULAR: 46 | setParameterRegular(d); 47 | break; 48 | case INVERSE: 49 | setParameterInverse(d); 50 | break; 51 | case LOG: 52 | setParameterLog(d); 53 | break; 54 | case HYPERBOLIC: 55 | setParameterHyperbolic(d); 56 | break; 57 | default: 58 | setParameterRegular(d); 59 | break; 60 | } 61 | } 62 | 63 | double FeatureDistance::getDistance() const{ 64 | switch(type_){ 65 | case REGULAR: 66 | return getDistanceRegular(); 67 | case INVERSE: 68 | return getDistanceInverse(); 69 | case LOG: 70 | return getDistanceLog(); 71 | case HYPERBOLIC: 72 | return getDistanceHyperbolic(); 73 | default: 74 | return getDistanceRegular(); 75 | } 76 | } 77 | 78 | double FeatureDistance::getDistanceDerivative() const{ 79 | switch(type_){ 80 | case REGULAR: 81 | return getDistanceDerivativeRegular(); 82 | case INVERSE: 83 | return getDistanceDerivativeInverse(); 84 | case LOG: 85 | return getDistanceDerivativeLog(); 86 | case HYPERBOLIC: 87 | return getDistanceDerivativeHyperbolic(); 88 | default: 89 | return getDistanceDerivativeRegular(); 90 | } 91 | } 92 | 93 | double FeatureDistance::getParameterDerivative() const{ 94 | switch(type_){ 95 | case REGULAR: 96 | return getParameterDerivativeRegular(); 97 | case INVERSE: 98 | return getParameterDerivativeInverse(); 99 | case LOG: 100 | return getParameterDerivativeLog(); 101 | case HYPERBOLIC: 102 | return getParameterDerivativeHyperbolic(); 103 | default: 104 | return getParameterDerivativeRegular(); 105 | } 106 | } 107 | 108 | double FeatureDistance::getParameterDerivativeCombined() const{ 109 | switch(type_){ 110 | case REGULAR: 111 | return getParameterDerivativeCombinedRegular(); 112 | case INVERSE: 113 | return getParameterDerivativeCombinedInverse(); 114 | case LOG: 115 | return getParameterDerivativeCombinedLog(); 116 | case HYPERBOLIC: 117 | return getParameterDerivativeCombinedHyperbolic(); 118 | default: 119 | return getParameterDerivativeCombinedRegular(); 120 | } 121 | } 122 | 123 | void FeatureDistance::getParameterDerivativeCombined(FeatureDistance other){ 124 | setParameter(other.getDistance()); 125 | } 126 | 127 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 128 | 129 | void FeatureDistance::setParameterRegular(const double& d){ 130 | p_ = d; 131 | } 132 | 133 | double FeatureDistance::getDistanceRegular() const{ 134 | return p_; 135 | } 136 | 137 | double FeatureDistance::getDistanceDerivativeRegular() const{ 138 | return 1.0; 139 | } 140 | 141 | double FeatureDistance::getParameterDerivativeRegular() const{ 142 | return 1.0; 143 | } 144 | 145 | double FeatureDistance::getParameterDerivativeCombinedRegular() const{ 146 | return 0.0; 147 | } 148 | 149 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 150 | 151 | double FeatureDistance::makeNonZero(const double& p) const{ 152 | if(p < 1e-6){ 153 | if(p >= 0){ 154 | return 1e-6; 155 | } else if (p > -1e-6){ 156 | return -1e-6; 157 | } 158 | } 159 | return p; 160 | } 161 | 162 | void FeatureDistance::setParameterInverse(const double& d){ 163 | p_ = 1/makeNonZero(d); 164 | } 165 | 166 | double FeatureDistance::getDistanceInverse() const{ 167 | const double p_temp = makeNonZero(p_); 168 | return 1/p_temp; 169 | } 170 | 171 | double FeatureDistance::getDistanceDerivativeInverse() const{ 172 | const double p_temp = makeNonZero(p_); 173 | return -1.0/(p_temp*p_temp); 174 | } 175 | 176 | double FeatureDistance::getParameterDerivativeInverse() const{ 177 | const double p_temp = makeNonZero(p_); 178 | return -p_temp*p_temp; 179 | } 180 | 181 | double FeatureDistance::getParameterDerivativeCombinedInverse() const{ 182 | const double p_temp = makeNonZero(p_); 183 | return -2*p_temp; 184 | } 185 | 186 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 187 | 188 | void FeatureDistance::setParameterLog(const double& d){ 189 | p_ = std::log(d); 190 | } 191 | 192 | double FeatureDistance::getDistanceLog() const{ 193 | return std::exp(p_); 194 | } 195 | 196 | double FeatureDistance::getDistanceDerivativeLog() const{ 197 | return std::exp(p_); 198 | } 199 | 200 | double FeatureDistance::getParameterDerivativeLog() const{ 201 | return std::exp(-p_); 202 | } 203 | 204 | double FeatureDistance::getParameterDerivativeCombinedLog() const{ 205 | return -std::exp(-p_); 206 | } 207 | 208 | //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 209 | 210 | void FeatureDistance::setParameterHyperbolic(const double& d){ 211 | p_ = std::asinh(d); 212 | } 213 | 214 | double FeatureDistance::getDistanceHyperbolic() const{ 215 | return std::sinh(p_); 216 | } 217 | 218 | double FeatureDistance::getDistanceDerivativeHyperbolic() const{ 219 | return std::cosh(p_); 220 | } 221 | 222 | double FeatureDistance::getParameterDerivativeHyperbolic() const{ 223 | return 1/std::sqrt(std::pow(std::sinh(p_),2)+1); // p = asinh(d) 224 | } 225 | 226 | double FeatureDistance::getParameterDerivativeCombinedHyperbolic() const{ 227 | return -std::sinh(p_)/std::pow(std::pow(std::sinh(p_),2)+1,1.5)*std::cosh(p_); 228 | } 229 | } 230 | -------------------------------------------------------------------------------- /src/feature_tracker_node.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #include "../include/rovio/featureTracker.hpp" 30 | 31 | int main(int argc, char** argv) { 32 | ros::init(argc, argv, "FeatureTrackerNode"); 33 | ros::NodeHandle nh; 34 | rovio::FeatureTrackerNode featureTrackerNode(nh); 35 | ros::spin(); 36 | return 0; 37 | } 38 | -------------------------------------------------------------------------------- /src/rovio_node.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | 30 | #include <memory> 31 | 32 | #include <Eigen/StdVector> 33 | 34 | #pragma GCC diagnostic push 35 | #pragma GCC diagnostic ignored "-Wunused-parameter" 36 | #include <ros/ros.h> 37 | #include <ros/package.h> 38 | #include <geometry_msgs/Pose.h> 39 | #pragma GCC diagnostic pop 40 | 41 | #include "rovio/RovioFilter.hpp" 42 | #include "rovio/RovioNode.hpp" 43 | #ifdef MAKE_SCENE 44 | #include "rovio/RovioScene.hpp" 45 | #endif 46 | 47 | #ifdef ROVIO_NMAXFEATURE 48 | static constexpr int nMax_ = ROVIO_NMAXFEATURE; 49 | #else 50 | static constexpr int nMax_ = 25; // Maximal number of considered features in the filter state. 51 | #endif 52 | 53 | #ifdef ROVIO_NLEVELS 54 | static constexpr int nLevels_ = ROVIO_NLEVELS; 55 | #else 56 | static constexpr int nLevels_ = 4; // // Total number of pyramid levels considered. 57 | #endif 58 | 59 | #ifdef ROVIO_PATCHSIZE 60 | static constexpr int patchSize_ = ROVIO_PATCHSIZE; 61 | #else 62 | static constexpr int patchSize_ = 6; // Edge length of the patches (in pixel). Must be a multiple of 2! 63 | #endif 64 | 65 | #ifdef ROVIO_NCAM 66 | static constexpr int nCam_ = ROVIO_NCAM; 67 | #else 68 | static constexpr int nCam_ = 1; // Used total number of cameras. 69 | #endif 70 | 71 | #ifdef ROVIO_NPOSE 72 | static constexpr int nPose_ = ROVIO_NPOSE; 73 | #else 74 | static constexpr int nPose_ = 0; // Additional pose states. 75 | #endif 76 | 77 | typedef rovio::RovioFilter<rovio::FilterState<nMax_,nLevels_,patchSize_,nCam_,nPose_>> mtFilter; 78 | 79 | #ifdef MAKE_SCENE 80 | static rovio::RovioScene<mtFilter> mRovioScene; 81 | 82 | void idleFunc(){ 83 | ros::spinOnce(); 84 | mRovioScene.drawScene(mRovioScene.mpFilter_->safe_); 85 | } 86 | #endif 87 | 88 | int main(int argc, char** argv){ 89 | ros::init(argc, argv, "rovio"); 90 | ros::NodeHandle nh; 91 | ros::NodeHandle nh_private("~"); 92 | 93 | std::string rootdir = ros::package::getPath("rovio"); // Leaks memory 94 | std::string filter_config = rootdir + "/cfg/rovio.info"; 95 | 96 | nh_private.param("filter_config", filter_config, filter_config); 97 | 98 | // Filter 99 | std::shared_ptr<mtFilter> mpFilter(new mtFilter); 100 | mpFilter->readFromInfo(filter_config); 101 | 102 | // Force the camera calibration paths to the ones from ROS parameters. 103 | for (unsigned int camID = 0; camID < nCam_; ++camID) { 104 | std::string camera_config; 105 | if (nh_private.getParam("camera" + std::to_string(camID) 106 | + "_config", camera_config)) { 107 | mpFilter->cameraCalibrationFile_[camID] = camera_config; 108 | } 109 | } 110 | mpFilter->refreshProperties(); 111 | 112 | // Node 113 | rovio::RovioNode<mtFilter> rovioNode(nh, nh_private, mpFilter); 114 | rovioNode.makeTest(); 115 | 116 | #ifdef MAKE_SCENE 117 | // Scene 118 | std::string mVSFileName = rootdir + "/shaders/shader.vs"; 119 | std::string mFSFileName = rootdir + "/shaders/shader.fs"; 120 | mRovioScene.initScene(argc,argv,mVSFileName,mFSFileName,mpFilter); 121 | mRovioScene.setIdleFunction(idleFunc); 122 | mRovioScene.addKeyboardCB('r',[&rovioNode]() mutable {rovioNode.requestReset();}); 123 | glutMainLoop(); 124 | #else 125 | ros::spin(); 126 | #endif 127 | return 0; 128 | } 129 | -------------------------------------------------------------------------------- /src/rovio_rosbag_loader.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014, Autonomous Systems Lab 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of the Autonomous Systems Lab, ETH Zurich nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 17 | * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 18 | * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | * 27 | */ 28 | 29 | #include <ros/package.h> 30 | #include <rosbag/bag.h> 31 | #include <rosbag/view.h> 32 | #include <memory> 33 | #include <iostream> 34 | #include <locale> 35 | #include <string> 36 | #include <Eigen/StdVector> 37 | #include "rovio/RovioFilter.hpp" 38 | #include "rovio/RovioNode.hpp" 39 | #include <boost/foreach.hpp> 40 | #include <boost/date_time/posix_time/posix_time.hpp> 41 | #include <boost/date_time/posix_time/posix_time_io.hpp> 42 | #define foreach BOOST_FOREACH 43 | 44 | #ifdef ROVIO_NMAXFEATURE 45 | static constexpr int nMax_ = ROVIO_NMAXFEATURE; 46 | #else 47 | static constexpr int nMax_ = 25; // Maximal number of considered features in the filter state. 48 | #endif 49 | 50 | #ifdef ROVIO_NLEVELS 51 | static constexpr int nLevels_ = ROVIO_NLEVELS; 52 | #else 53 | static constexpr int nLevels_ = 4; // // Total number of pyramid levels considered. 54 | #endif 55 | 56 | #ifdef ROVIO_PATCHSIZE 57 | static constexpr int patchSize_ = ROVIO_PATCHSIZE; 58 | #else 59 | static constexpr int patchSize_ = 8; // Edge length of the patches (in pixel). Must be a multiple of 2! 60 | #endif 61 | 62 | #ifdef ROVIO_NCAM 63 | static constexpr int nCam_ = ROVIO_NCAM; 64 | #else 65 | static constexpr int nCam_ = 1; // Used total number of cameras. 66 | #endif 67 | 68 | #ifdef ROVIO_NPOSE 69 | static constexpr int nPose_ = ROVIO_NPOSE; 70 | #else 71 | static constexpr int nPose_ = 0; // Additional pose states. 72 | #endif 73 | 74 | typedef rovio::RovioFilter<rovio::FilterState<nMax_,nLevels_,patchSize_,nCam_,nPose_>> mtFilter; 75 | 76 | int main(int argc, char** argv){ 77 | ros::init(argc, argv, "rovio"); 78 | ros::NodeHandle nh; 79 | ros::NodeHandle nh_private("~"); 80 | 81 | std::string rootdir = ros::package::getPath("rovio"); // Leaks memory 82 | std::string filter_config = rootdir + "/cfg/rovio.info"; 83 | 84 | nh_private.param("filter_config", filter_config, filter_config); 85 | 86 | // Filter 87 | std::shared_ptr<mtFilter> mpFilter(new mtFilter); 88 | mpFilter->readFromInfo(filter_config); 89 | 90 | // Force the camera calibration paths to the ones from ROS parameters. 91 | for (unsigned int camID = 0; camID < nCam_; ++camID) { 92 | std::string camera_config; 93 | if (nh_private.getParam("camera" + std::to_string(camID) 94 | + "_config", camera_config)) { 95 | mpFilter->cameraCalibrationFile_[camID] = camera_config; 96 | } 97 | } 98 | mpFilter->refreshProperties(); 99 | 100 | // Node 101 | rovio::RovioNode<mtFilter> rovioNode(nh, nh_private, mpFilter); 102 | rovioNode.makeTest(); 103 | double resetTrigger = 0.0; 104 | nh_private.param("record_odometry", rovioNode.forceOdometryPublishing_, rovioNode.forceOdometryPublishing_); 105 | nh_private.param("record_pose_with_covariance_stamped", rovioNode.forcePoseWithCovariancePublishing_, rovioNode.forcePoseWithCovariancePublishing_); 106 | nh_private.param("record_transform", rovioNode.forceTransformPublishing_, rovioNode.forceTransformPublishing_); 107 | nh_private.param("record_extrinsics", rovioNode.forceExtrinsicsPublishing_, rovioNode.forceExtrinsicsPublishing_); 108 | nh_private.param("record_imu_bias", rovioNode.forceImuBiasPublishing_, rovioNode.forceImuBiasPublishing_); 109 | nh_private.param("record_pcl", rovioNode.forcePclPublishing_, rovioNode.forcePclPublishing_); 110 | nh_private.param("record_markers", rovioNode.forceMarkersPublishing_, rovioNode.forceMarkersPublishing_); 111 | nh_private.param("record_patch", rovioNode.forcePatchPublishing_, rovioNode.forcePatchPublishing_); 112 | nh_private.param("reset_trigger", resetTrigger, resetTrigger); 113 | 114 | std::cout << "Recording"; 115 | if(rovioNode.forceOdometryPublishing_) std::cout << ", odometry"; 116 | if(rovioNode.forceTransformPublishing_) std::cout << ", transform"; 117 | if(rovioNode.forceExtrinsicsPublishing_) std::cout << ", extrinsics"; 118 | if(rovioNode.forceImuBiasPublishing_) std::cout << ", imu biases"; 119 | if(rovioNode.forcePclPublishing_) std::cout << ", point cloud"; 120 | if(rovioNode.forceMarkersPublishing_) std::cout << ", markers"; 121 | if(rovioNode.forcePatchPublishing_) std::cout << ", patch data"; 122 | std::cout << std::endl; 123 | 124 | rosbag::Bag bagIn; 125 | std::string rosbag_filename = "dataset.bag"; 126 | nh_private.param("rosbag_filename", rosbag_filename, rosbag_filename); 127 | bagIn.open(rosbag_filename, rosbag::bagmode::Read); 128 | 129 | rosbag::Bag bagOut; 130 | std::size_t found = rosbag_filename.find_last_of("/"); 131 | std::string file_path = rosbag_filename.substr(0,found); 132 | std::string file_name = rosbag_filename.substr(found+1); 133 | if(file_path==rosbag_filename){ 134 | file_path = "."; 135 | file_name = rosbag_filename; 136 | } 137 | 138 | std::stringstream stream; 139 | boost::posix_time::time_facet* facet = new boost::posix_time::time_facet(); 140 | facet->format("%Y-%m-%d-%H-%M-%S"); 141 | stream.imbue(std::locale(std::locale::classic(), facet)); 142 | stream << ros::Time::now().toBoost() << "_" << nMax_ << "_" << nLevels_ << "_" << patchSize_ << "_" << nCam_ << "_" << nPose_; 143 | std::string filename_out = file_path + "/rovio/" + stream.str(); 144 | nh_private.param("filename_out", filename_out, filename_out); 145 | std::string rosbag_filename_out = filename_out + ".bag"; 146 | std::string info_filename_out = filename_out + ".info"; 147 | std::cout << "Storing output to: " << rosbag_filename_out << std::endl; 148 | bagOut.open(rosbag_filename_out, rosbag::bagmode::Write); 149 | 150 | // Copy info 151 | std::ifstream src(filter_config, std::ios::binary); 152 | std::ofstream dst(info_filename_out, std::ios::binary); 153 | dst << src.rdbuf(); 154 | 155 | std::vector<std::string> topics; 156 | std::string imu_topic_name = "/imu0"; 157 | nh_private.param("imu_topic_name", imu_topic_name, imu_topic_name); 158 | std::string cam0_topic_name = "/cam0/image_raw"; 159 | nh_private.param("cam0_topic_name", cam0_topic_name, cam0_topic_name); 160 | std::string cam1_topic_name = "/cam1/image_raw"; 161 | nh_private.param("cam1_topic_name", cam1_topic_name, cam1_topic_name); 162 | std::string odometry_topic_name = rovioNode.pubOdometry_.getTopic(); 163 | std::string transform_topic_name = rovioNode.pubTransform_.getTopic(); 164 | std::string extrinsics_topic_name[mtFilter::mtState::nCam_]; 165 | for(int camID=0;camID<mtFilter::mtState::nCam_;camID++){ 166 | extrinsics_topic_name[camID] = rovioNode.pubExtrinsics_[camID].getTopic(); 167 | } 168 | std::string imu_bias_topic_name = rovioNode.pubImuBias_.getTopic(); 169 | std::string pcl_topic_name = rovioNode.pubPcl_.getTopic(); 170 | std::string u_rays_topic_name = rovioNode.pubMarkers_.getTopic(); 171 | std::string patch_topic_name = rovioNode.pubPatch_.getTopic(); 172 | 173 | topics.push_back(std::string(imu_topic_name)); 174 | topics.push_back(std::string(cam0_topic_name)); 175 | topics.push_back(std::string(cam1_topic_name)); 176 | rosbag::View view(bagIn, rosbag::TopicQuery(topics)); 177 | 178 | 179 | bool isTriggerInitialized = false; 180 | double lastTriggerTime = 0.0; 181 | for(rosbag::View::iterator it = view.begin();it != view.end() && ros::ok();it++){ 182 | if(it->getTopic() == imu_topic_name){ 183 | sensor_msgs::Imu::ConstPtr imuMsg = it->instantiate<sensor_msgs::Imu>(); 184 | if (imuMsg != NULL) rovioNode.imuCallback(imuMsg); 185 | } 186 | if(it->getTopic() == cam0_topic_name){ 187 | sensor_msgs::ImageConstPtr imgMsg = it->instantiate<sensor_msgs::Image>(); 188 | if (imgMsg != NULL) rovioNode.imgCallback0(imgMsg); 189 | } 190 | if(it->getTopic() == cam1_topic_name){ 191 | sensor_msgs::ImageConstPtr imgMsg = it->instantiate<sensor_msgs::Image>(); 192 | if (imgMsg != NULL) rovioNode.imgCallback1(imgMsg); 193 | } 194 | ros::spinOnce(); 195 | 196 | if(rovioNode.gotFirstMessages_){ 197 | static double lastSafeTime = rovioNode.mpFilter_->safe_.t_; 198 | if(rovioNode.mpFilter_->safe_.t_ > lastSafeTime){ 199 | if(rovioNode.forceOdometryPublishing_) bagOut.write(odometry_topic_name,ros::Time::now(),rovioNode.odometryMsg_); 200 | if(rovioNode.forceTransformPublishing_) bagOut.write(transform_topic_name,ros::Time::now(),rovioNode.transformMsg_); 201 | for(int camID=0;camID<mtFilter::mtState::nCam_;camID++){ 202 | if(rovioNode.forceExtrinsicsPublishing_) bagOut.write(extrinsics_topic_name[camID],ros::Time::now(),rovioNode.extrinsicsMsg_[camID]); 203 | } 204 | if(rovioNode.forceImuBiasPublishing_) bagOut.write(imu_bias_topic_name,ros::Time::now(),rovioNode.imuBiasMsg_); 205 | if(rovioNode.forcePclPublishing_) bagOut.write(pcl_topic_name,ros::Time::now(),rovioNode.pclMsg_); 206 | if(rovioNode.forceMarkersPublishing_) bagOut.write(u_rays_topic_name,ros::Time::now(),rovioNode.markerMsg_); 207 | if(rovioNode.forcePatchPublishing_) bagOut.write(patch_topic_name,ros::Time::now(),rovioNode.patchMsg_); 208 | lastSafeTime = rovioNode.mpFilter_->safe_.t_; 209 | } 210 | if(!isTriggerInitialized){ 211 | lastTriggerTime = lastSafeTime; 212 | isTriggerInitialized = true; 213 | } 214 | if(resetTrigger>0.0 && lastSafeTime - lastTriggerTime > resetTrigger){ 215 | rovioNode.requestReset(); 216 | rovioNode.mpFilter_->init_.state_.WrWM() = rovioNode.mpFilter_->safe_.state_.WrWM(); 217 | rovioNode.mpFilter_->init_.state_.qWM() = rovioNode.mpFilter_->safe_.state_.qWM(); 218 | lastTriggerTime = lastSafeTime; 219 | } 220 | } 221 | } 222 | 223 | bagOut.close(); 224 | bagIn.close(); 225 | 226 | 227 | return 0; 228 | } 229 | -------------------------------------------------------------------------------- /src/test_patch.cpp: -------------------------------------------------------------------------------- 1 | #include "gtest/gtest.h" 2 | #include <assert.h> 3 | 4 | #include "rovio/Patch.hpp" 5 | 6 | using namespace rovio; 7 | 8 | class PatchTesting : public virtual ::testing::Test { 9 | protected: 10 | static const int patchSize_ = 2; 11 | static const int imgSize_ = patchSize_+4; 12 | static const int nMax_ = 20; 13 | static const int dx_ = 2; 14 | static const int dy_ = 3; 15 | cv::Mat img1_; 16 | cv::Mat img2_; 17 | Patch<patchSize_> p_; 18 | FeatureCoordinates c_; 19 | PatchTesting(){ 20 | img1_ = cv::Mat::zeros(imgSize_,imgSize_,CV_8UC1); 21 | uint8_t* img_ptr = (uint8_t*) img1_.data; 22 | for(int i=0;i<imgSize_;i++){ 23 | for(int j=0;j<imgSize_;j++, ++img_ptr){ 24 | *img_ptr = i*dy_+j*dx_; 25 | } 26 | } 27 | img2_ = cv::Mat::zeros(imgSize_,imgSize_,CV_8UC1); 28 | img_ptr = (uint8_t*) img2_.data; 29 | for(int i=0;i<imgSize_;i++){ 30 | for(int j=0;j<imgSize_;j++, ++img_ptr){ 31 | if(j<imgSize_/2 & i<imgSize_/2){ 32 | *img_ptr = 0; 33 | } else { 34 | *img_ptr = 255; 35 | } 36 | } 37 | } 38 | } 39 | virtual ~PatchTesting() {} 40 | }; 41 | 42 | // Test constructors 43 | TEST_F(PatchTesting, constructors) { 44 | Patch<(this->patchSize_)> p; 45 | ASSERT_EQ(p.validGradientParameters_,false); 46 | ASSERT_EQ(p.s_,0.0); 47 | } 48 | 49 | // Test isPatchInFrame 50 | TEST_F(PatchTesting, isPatchInFrame) { 51 | c_.set_c(cv::Point2f(0,0)); 52 | c_.set_warp_identity(); 53 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 54 | c_.set_c(cv::Point2f(patchSize_/2-0.1,patchSize_/2-0.1)); 55 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 56 | c_.set_c(cv::Point2f(patchSize_/2,patchSize_/2)); 57 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),true); 58 | c_.set_c(cv::Point2f(patchSize_/2+0.1,patchSize_/2+0.1)); 59 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),true); 60 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2-0.1,imgSize_-patchSize_/2-0.1)); 61 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),true); 62 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2,imgSize_-patchSize_/2)); 63 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),true); 64 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2+0.1,imgSize_-patchSize_/2+0.1)); 65 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 66 | c_.set_c(cv::Point2f(imgSize_,imgSize_)); 67 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 68 | c_.set_c(cv::Point2f(0,0)); 69 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); 70 | c_.set_c(cv::Point2f(patchSize_/2+1-0.1,patchSize_/2+1-0.1)); 71 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); 72 | c_.set_c(cv::Point2f(patchSize_/2+1,patchSize_/2+1)); 73 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),true); 74 | c_.set_c(cv::Point2f(patchSize_/2+1+0.1,patchSize_/2+1+0.1)); 75 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),true); 76 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2-1-0.1,imgSize_-patchSize_/2-1-0.1)); 77 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),true); 78 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2-1,imgSize_-patchSize_/2-1)); 79 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),true); 80 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2-1+0.1,imgSize_-patchSize_/2-1+0.1)); 81 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); 82 | c_.set_c(cv::Point2f(imgSize_,imgSize_)); 83 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); 84 | } 85 | 86 | // Test isPatchInFrame 87 | TEST_F(PatchTesting, isPatchInFrameWithWarping) { 88 | Eigen::Matrix2f aff; 89 | aff.setIdentity(); 90 | c_.set_warp_identity(); 91 | c_.set_c(cv::Point2f(0,0)); 92 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 93 | c_.set_c(cv::Point2f(patchSize_/2-0.1,patchSize_/2-0.1)); 94 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 95 | c_.set_c(cv::Point2f(patchSize_/2,patchSize_/2)); 96 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),true); 97 | c_.set_c(cv::Point2f(patchSize_/2+0.1,patchSize_/2+0.1)); 98 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),true); 99 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2-0.1,imgSize_-patchSize_/2-0.1)); 100 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),true); 101 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2,imgSize_-patchSize_/2)); 102 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),true); 103 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2+0.1,imgSize_-patchSize_/2+0.1)); 104 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 105 | c_.set_c(cv::Point2f(imgSize_,imgSize_)); 106 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 107 | c_.set_c(cv::Point2f(0,0)); 108 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); 109 | c_.set_c(cv::Point2f(patchSize_/2+1-0.1,patchSize_/2+1-0.1)); 110 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); 111 | c_.set_c(cv::Point2f(patchSize_/2+1,patchSize_/2+1)); 112 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),true); 113 | c_.set_c(cv::Point2f(patchSize_/2+1+0.1,patchSize_/2+1+0.1)); 114 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),true); 115 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2-1-0.1,imgSize_-patchSize_/2-1-0.1)); 116 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),true); 117 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2-1,imgSize_-patchSize_/2-1)); 118 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),true); 119 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2-1+0.1,imgSize_-patchSize_/2-1+0.1)); 120 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); 121 | c_.set_c(cv::Point2f(imgSize_,imgSize_)); 122 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); 123 | aff << 0, -1, 1, 0; 124 | c_.set_warp_c(aff); 125 | c_.set_c(cv::Point2f(0,0)); 126 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 127 | c_.set_c(cv::Point2f(patchSize_/2-0.1,patchSize_/2-0.1)); 128 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 129 | c_.set_c(cv::Point2f(patchSize_/2,patchSize_/2)); 130 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),true); 131 | c_.set_c(cv::Point2f(patchSize_/2+0.1,patchSize_/2+0.1)); 132 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),true); 133 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2-0.1,imgSize_-patchSize_/2-0.1)); 134 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),true); 135 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2,imgSize_-patchSize_/2)); 136 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); // should be true, but the implementation is just simpler like this (more reliable) 137 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2+0.1,imgSize_-patchSize_/2+0.1)); 138 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 139 | c_.set_c(cv::Point2f(imgSize_,imgSize_)); 140 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 141 | c_.set_c(cv::Point2f(0,0)); 142 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); 143 | c_.set_c(cv::Point2f(patchSize_/2+1-0.1,patchSize_/2+1-0.1)); 144 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); 145 | c_.set_c(cv::Point2f(patchSize_/2+1,patchSize_/2+1)); 146 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),true); 147 | c_.set_c(cv::Point2f(patchSize_/2+1+0.1,patchSize_/2+1+0.1)); 148 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),true); 149 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2-1-0.1,imgSize_-patchSize_/2-1-0.1)); 150 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),true); 151 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2-1,imgSize_-patchSize_/2-1)); 152 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); // should be true, but the implementation is just simpler like this (more reliable) 153 | c_.set_c(cv::Point2f(imgSize_-patchSize_/2-1+0.1,imgSize_-patchSize_/2-1+0.1)); 154 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); 155 | c_.set_c(cv::Point2f(imgSize_,imgSize_)); 156 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_,true),false); 157 | aff << cos(M_PI/6.0), -sin(M_PI/6.0), sin(M_PI/6.0), cos(M_PI/6.0); 158 | c_.set_warp_c(aff); 159 | c_.set_c(cv::Point2f((sin(M_PI/6.0)+cos(M_PI/6.0))*(patchSize_/2-0.5)+0.5+1e-6,(sin(M_PI/6.0)+cos(M_PI/6.0))*(patchSize_/2-0.5)+0.5+1e-6)); 160 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),true); 161 | c_.set_c(cv::Point2f((sin(M_PI/6.0)+cos(M_PI/6.0))*(patchSize_/2-0.5)+0.5+1e-6,(sin(M_PI/6.0)+cos(M_PI/6.0))*(patchSize_/2-0.5)+0.5-1e-6)); 162 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 163 | c_.set_c(cv::Point2f((sin(M_PI/6.0)+cos(M_PI/6.0))*(patchSize_/2-0.5)+0.5-1e-6,(sin(M_PI/6.0)+cos(M_PI/6.0))*(patchSize_/2-0.5)+0.5+1e-6)); 164 | ASSERT_EQ(p_.isPatchInFrame(img1_,c_),false); 165 | } 166 | 167 | // Test extractPatchFromImage 168 | TEST_F(PatchTesting, extractPatchFromImage) { 169 | const int N = 6; 170 | cv::Point2f patchOrigins[N] = {cv::Point2f(0,0), 171 | cv::Point2f(0.5,0), 172 | cv::Point2f(0,0.5), 173 | cv::Point2f(0.5,0.5), 174 | cv::Point2f(1.5544,0.5234), 175 | cv::Point2f(imgSize_-patchSize_-2,imgSize_-patchSize_-2)}; 176 | for(unsigned int n=0;n<N;n++){ 177 | c_.set_c(cv::Point2f(patchSize_/2+1,patchSize_/2+1)+patchOrigins[n]); 178 | c_.set_warp_identity(); 179 | p_.extractPatchFromImage(img1_,c_,true); 180 | float* patch_ptr = p_.patchWithBorder_; 181 | for(int i=0;i<patchSize_+2;i++){ 182 | for(int j=0;j<patchSize_+2;j++, ++patch_ptr){ 183 | ASSERT_NEAR(*patch_ptr,(float)((i+patchOrigins[n].y)*dy_+(j+patchOrigins[n].x)*dx_),1e-6); 184 | } 185 | } 186 | } 187 | } 188 | 189 | // Test extractWarpedPatchFromImage 190 | TEST_F(PatchTesting, extractWarpedPatchFromImage) { 191 | Eigen::Matrix2f aff; 192 | aff << cos(M_PI/6.0), -sin(M_PI/6.0), sin(M_PI/6.0), cos(M_PI/6.0); 193 | c_.set_warp_c(aff); 194 | c_.set_c(cv::Point2f(imgSize_/2,imgSize_/2)); 195 | p_.extractPatchFromImage(img1_,c_,true); 196 | float* patch_ptr = p_.patchWithBorder_; 197 | for(int i=0;i<patchSize_+2;i++){ 198 | for(int j=0;j<patchSize_+2;j++, ++patch_ptr){ 199 | ASSERT_NEAR(*patch_ptr,((cos(M_PI/6.0)*(i-patchSize_/2-0.5)+sin(M_PI/6.0)*(j-patchSize_/2-0.5)+0.5*imgSize_-0.5)*dy_ 200 | +(-sin(M_PI/6.0)*(i-patchSize_/2-0.5)+cos(M_PI/6.0)*(j-patchSize_/2-0.5)+0.5*imgSize_-0.5)*dx_),1e-4); 201 | } 202 | } 203 | } 204 | 205 | // Test extractPatchFromPatchWithBorder 206 | TEST_F(PatchTesting, extractPatchFromPatchWithBorder) { 207 | c_.set_c(cv::Point2f(patchSize_/2+1,patchSize_/2+1)); 208 | c_.set_warp_identity(); 209 | p_.extractPatchFromImage(img1_,c_,true); 210 | p_.extractPatchFromPatchWithBorder(); 211 | float* patch_ptr = p_.patch_; 212 | for(int i=0;i<patchSize_;i++){ 213 | for(int j=0;j<patchSize_;j++, ++patch_ptr){ 214 | ASSERT_EQ(*patch_ptr,(float)((i+1)*dy_+(j+1)*dx_)); 215 | } 216 | } 217 | } 218 | 219 | // Test computeGradientParameters 220 | TEST_F(PatchTesting, computeGradientParameters) { 221 | c_.set_c(cv::Point2f(patchSize_/2+1,patchSize_/2+1+0.5)); 222 | c_.set_warp_identity(); 223 | p_.extractPatchFromImage(img1_,c_,true); 224 | p_.computeGradientParameters(); 225 | float* it_dx = p_.dx_; 226 | float* it_dy = p_.dy_; 227 | for(int i=0;i<patchSize_;i++){ 228 | for(int j=0;j<patchSize_;j++, ++it_dx, ++it_dy){ 229 | ASSERT_EQ(*it_dx,float(dx_)); 230 | ASSERT_EQ(*it_dy,float(dy_)); 231 | } 232 | } 233 | ASSERT_EQ(p_.H_(0,0),dx_*dx_*patchSize_*patchSize_); 234 | ASSERT_EQ(p_.H_(0,1),dx_*dy_*patchSize_*patchSize_); 235 | ASSERT_EQ(p_.H_(0,2),dx_*patchSize_*patchSize_); 236 | ASSERT_EQ(p_.H_(1,0),dx_*dy_*patchSize_*patchSize_); 237 | ASSERT_EQ(p_.H_(1,1),dy_*dy_*patchSize_*patchSize_); 238 | ASSERT_EQ(p_.H_(1,2),dy_*patchSize_*patchSize_); 239 | ASSERT_EQ(p_.H_(2,0),dx_*patchSize_*patchSize_); 240 | ASSERT_EQ(p_.H_(2,1),dy_*patchSize_*patchSize_); 241 | ASSERT_EQ(p_.H_(2,2),patchSize_*patchSize_); 242 | 243 | c_.set_c(cv::Point2f(imgSize_/2,imgSize_/2)); 244 | c_.set_warp_identity(); 245 | p_.extractPatchFromImage(img2_,c_,true); 246 | p_.computeGradientParameters(); 247 | double s = 0.5 * (patchSize_ + patchSize_ - sqrtf((patchSize_ + patchSize_) * (patchSize_ + patchSize_) - 4 * (patchSize_ * patchSize_ - 1 * 1))) 248 | + 0.5 * (patchSize_ + patchSize_ + sqrtf((patchSize_ + patchSize_) * (patchSize_ + patchSize_) - 4 * (patchSize_ * patchSize_ - 1 * 1))); 249 | s = s*(255*0.5)*(255*0.5)/(patchSize_*patchSize_); 250 | ASSERT_EQ(p_.s_,s); 251 | } 252 | 253 | int main(int argc, char **argv) { 254 | ::testing::InitGoogleTest(&argc, argv); 255 | return RUN_ALL_TESTS(); 256 | } 257 | -------------------------------------------------------------------------------- /srv/SrvResetToPose.srv: -------------------------------------------------------------------------------- 1 | # Initial IMU pose after reset. 2 | # T_WM transforms points from IMU frame (M) to World frame (W) 3 | # Conventions: W_p = T_WM * M_p 4 | # Check wiki page "Coordinate Frames and Notation" for more information about frames 5 | geometry_msgs/Pose T_WM 6 | --- 7 | std_msgs/Empty nothing --------------------------------------------------------------------------------