Compare commits

...

269 Commits

Author SHA1 Message Date
matlabbe
75854fc026 OccupancyGrid: updated parameters check 2017-08-04 11:41:50 -04:00
matlabbe
d8a6ed4ba6 DbViewer: fixed voxelize assert when voxel size is set and there are no laser scans in database 2017-08-04 10:47:25 -04:00
matlabbe
459bbda60c increased package version to 0.13.2 2017-08-03 16:42:46 -04:00
matlabbe
2a9508b4e3 Fixed build for Lunar 2017-08-03 16:40:12 -04:00
matlabbe
c0c288e0d9 Tango: removed seekbar for FOV(use pinch zoom instead), show UI on single tap instead of swipe down 2017-08-03 11:52:18 -04:00
matlabbe
82fd5b36a8 util3d::cloud[RGB]FromSensorData(): supporting roi ratios for stereo images 2017-08-02 15:14:03 -04:00
matlabbe
dd3c7d8fa4 CameraStereoZed: fixed build for ZED sdk 2.1 (https://github.com/introlab/rtabmap_ros/issues/192) 2017-07-31 15:12:05 -04:00
matlabbe
b63f073d90 CameraStereoZed: handling initialization failures 2017-07-31 14:11:32 -04:00
matlabbe
0491125e92 fixed voxelize assertion with c++ rgbd mapping example 2017-07-26 16:00:02 -04:00
matlabbe
3443c3b8ea RegistrationVis: fixed assert covariance in bundle adjustement when transform is perfect (covariance is null) by setting an epsilon to generated covariance is null or very close to 0 2017-07-26 15:27:54 -04:00
matlabbe
be720be74a 💄 2017-07-26 11:46:59 -04:00
matlabbe
f3e491f15b Added KAZE feature detector (OpenCV3) 2017-07-25 16:20:05 -04:00
matlabbe
5855198b5f Tango: swipe down to show hud, added notification sound after saving or exporting, added polygon cluster filtering export option, action and status bars are transparent 2017-07-24 20:24:16 -04:00
matlabbe
62de6fcdae util3d::denseMeshPostProcessing(): coloredOutput param not used anymore 2017-07-24 19:21:22 -04:00
matlabbe
57dc0cd53e DepthCalibration: support depth images smaller than RGB images 2017-07-24 13:06:30 -04:00
matlabbe
0a1694dd78 MainWindow: Detect more loop closures: uncompress images when reextract features on loop closure is enabled 2017-07-24 12:18:19 -04:00
matlabbe
edc690973a DbViewer: added warning when reextract feature is false and signatures have no features 2017-07-24 11:48:49 -04:00
matlabbe
48148a9e26 DbViewer: fixed voxel assert 2017-07-23 22:33:26 -04:00
matlabbe
62b9911176 docker: fixed tango build with res tool prebuild 2017-07-13 14:33:52 -04:00
matlabbe
fb69a37445 docker missing g++ 2017-07-13 14:18:58 -04:00
matlabbe
81ae1eae51 docker update 2017-07-13 14:14:51 -04:00
matlabbe
517c70d855 CMake: added ANDROID_PREBUILD option 2017-07-13 13:36:34 -04:00
matlabbe
85f7c1e73c OccupancyGrid/voxelize: if organized cloud, indices should not be null 2017-07-13 12:23:03 -04:00
matlabbe
b4cfa0e844 RtabmapThread: use largest covariance instead of summation 2017-07-13 11:36:55 -04:00
matlabbe
3c758ab2f6 Update .travis.yml 2017-07-13 11:32:14 -04:00
matlabbe
1ed01b8d3d Memory: fixed cov->inf conversion error 2017-07-13 11:07:00 -04:00
matlabbe
19abbe0dbd DBViewer: fixing previous commit for very large databases (where we don't want to regenerate map if we don't show it) 2017-07-12 21:39:51 -04:00
matlabbe
c833af1ae6 DBViewer: fixed disabled show/hide map option while map is available 2017-07-12 21:26:14 -04:00
matlabbe
78bdd4a087 Added check if covariance is invertible, if not an error is thrown 2017-07-12 16:41:47 -04:00
matlabbe
dc77bb4332 OdometryViso2: updated for dynamic local transform 2017-07-10 17:34:37 -04:00
matlabbe
9e011d6ad9 Fixed changing local transform not handled correctly when changing for third party odometries 2017-07-07 19:41:11 -04:00
matlabbe
f9ed36ed54 Parameters: renamed Rtabmap/VhStrategy to VhEp/Enabled 2017-07-05 13:38:27 -04:00
matlabbe
495681770e Tango: updated About copyright year 2017-07-03 18:48:02 -04:00
matlabbe
eb1f0e0a8a Tango: aligned share sketchfab button to top (over pause) 2017-07-03 16:52:22 -04:00
matlabbe
23ae5caa3c Tango: bump apk version 2017-07-03 14:48:04 -04:00
matlabbe
4b7d558026 Tango: moved export to file button under share to sketchfab (fixing overlap of button on opengl status text), fixed export empty poses after resuming without relocalizing (append mode) 2017-07-03 14:42:48 -04:00
matlabbe
44969a7fdf Docker: added zesty 2017-06-29 14:32:12 -04:00
matlabbe
5f5c74f260 RGBDMapping example: fixed -lvtkproj4 not found error on Xenial 2017-06-29 16:59:15 +00:00
matlabbe
5646751f88 RTABMapConfig.cmake: Set WITH_GUI default true if no components are specified 2017-06-29 15:31:05 -04:00
matlabbe
b6d3e785df Tango: fixed export failing after saving the database 2017-06-29 10:31:59 -04:00
matlabbe
ebada30984 Tango: updated UI 2017-06-28 13:59:20 -04:00
matlabbe
64fc9f203e Tango: fixed build for Ikariotikos release 2017-06-27 11:45:51 -04:00
matlabbe
653d4fef4b Fixed Windows+PCL1.8 build (std::vector/Eigen error) 2017-06-26 15:45:30 -04:00
matlabbe
5cc04b58a4 Tango: updated sdk to Ikariotikos 2017-06-26 15:45:04 -04:00
matlabbe
f628da7a91 Merge branch 'master' of https://github.com/introlab/rtabmap into devel 2017-06-26 13:04:20 -04:00
matlabbe
a8853bdee6 ExportCloudsDialog: fixed scan output frame 2017-06-26 12:02:48 -04:00
matlabbe
5f8ffa7afc Fixed compilation warning 2017-06-22 11:49:02 -04:00
matlabbe
d74f4f64f7 Tango: Open: use small launcher image for old databases without preview image 2017-06-21 22:11:09 -04:00
matlabbe
3e7929bed6 Tango: Fullscreen mode 2017-06-21 20:54:16 -04:00
matlabbe
7a2d1c29f0 Tango: fixed saveOnDevice and shareSketchfab actions when visualizing optimized mesh of a just opened database 2017-06-21 17:14:40 -04:00
matlabbe
0a841f17a4 fixed desktop app with new util3d::mergeTextures() return value 2017-06-20 17:57:32 -04:00
matlabbe
ee8d48a915 Database: added "opt_****" fields in Admin table. Tango: optimized mesh saved in database for quick open, open menu shows preview images. util3d::mergeTextures() return all textures in same cv::Mat. 2017-06-20 17:29:06 -04:00
matlabbe
539d500528 Tango: bump version 2017-06-16 22:14:57 +00:00
matlabbe
3d1de43ff1 Tango: Hidden Presets chromium webview 2017-06-16 21:57:57 +00:00
matlabbe
e7998acf66 Update build.bash 2017-06-16 17:38:24 -04:00
matlabbe
e0640418e4 ExportCloudsDialog: fixed compilation warning 2017-06-16 16:59:55 -04:00
matlabbe
52a6cc5bad Tango: fixed sketchfab export ply error, exported objs are now rotated -90deg x-axis by default for sketchfab 2017-06-16 16:24:38 -04:00
matlabbe
8787ecceb8 Tango: refactored mesh creation 2017-06-16 14:44:48 -04:00
matlabbe
a1f2f95d1b fixed build 2017-06-15 19:39:22 -04:00
matlabbe
c3aeae5ed7 Moved clean texture mesh stuff from ExportCloudsDialog to util3d::cleanTextureMesh() 2017-06-15 14:10:08 -04:00
matlabbe
29ff2c5d0a RTABMapConfig.cmake: added components support 2017-06-15 15:59:52 -04:00
matlabbe
a7880dc3b0 RTABMapConfig.cmake: fixed dependencies path error when path has a space (LINK : fatal error LNK1181: cannot open input file 'C:\Program.obj') 2017-06-14 19:55:23 -04:00
matlabbe
ba4437edee Tango: replaced RTABMapApp::mergeTextures() by util3d::mergeTextures() 2017-06-14 10:33:26 -04:00
matlabbe
811afa1171 Moved ExportCloudsDialog::mergeTextures() method in util3d_surface module 2017-06-13 19:20:09 -04:00
matlabbe
29a48aba66 Tango: added wireframe button (#191) 2017-06-12 19:08:51 -04:00
matlabbe
c00119989e Tango: Added Ortho mode (#193) 2017-06-12 15:36:33 -04:00
matlabbe
bbaac8b2b1 Grid: support negative ground/obstacle height thresholds 2017-06-12 11:48:13 -04:00
matlabbe
9554597948 Tango: added multi-texturing support (#189) 2017-06-10 21:45:51 -04:00
matlabbe
774afe9fdd Tango: added presets (#190) 2017-06-10 12:29:57 -04:00
matlabbe
fa2199c3ea Merged master to devel 2017-06-10 10:34:52 -04:00
matlabbe
e321e1bb2c fixed output textures count 2017-06-09 17:51:13 -04:00
matlabbe
dfc425a7c5 Update Parameters.h 2017-06-09 14:58:23 -04:00
matlabbe
4ac422314d fixed some compilation warnings 2017-06-09 13:44:09 -04:00
matlabbe
ff6e42fa6d DbViewer: added more info about size of all tables in database 2017-06-06 18:22:19 -04:00
matlabbe
7a0a82bcb4 Texturing: using depth image to filter wrongly projected textures 2017-06-06 11:42:42 -04:00
matlabbe
fa95ede3e9 Fixed build 2017-06-05 19:35:03 -04:00
matlabbe
26147c97cf PArameters: don't show usage with ORBSLAM2 parameters if not built with it. 2017-06-05 19:10:04 -04:00
matlabbe
c4ca6a0bac Integrated ORB_SLAM2 as an odometry approach Odom/Strategy=5. 2017-06-05 19:04:23 -04:00
matlabbe
8de694b2d7 Tango: Hide buttons after 5 seconds not touching the screen 2017-06-03 20:06:45 -04:00
matlabbe
de797b644e Export: added rgb/gray gain compensation option, added maximum outout textures option (can be useful for #189). 2017-06-03 18:24:56 -04:00
matlabbe
c8357be4d0 cloudRGBFromSensorData(): just return empty cloud if inputs are not valid (don't assert) 2017-06-01 13:09:34 -04:00
matlabbe
657f0314e4 Updated warning when stereo is used with DVO odometry 2017-05-31 20:59:35 -04:00
matlabbe
4f26e34717 Integrated DVO odometry approach 2017-05-31 20:57:24 -04:00
matlabbe
133ed68152 Parameters --params: don't show those related to dependencies not built in RTAB-Map 2017-05-31 11:33:51 -04:00
matlabbe
e2c5b87a7e Parameters.h: normalized indendation 2017-05-31 11:09:06 -04:00
matlabbe
21e716b08a Updated default Vis/EstimationType=1 (PnP). Added all fovis and viso2 parameters. 2017-05-30 18:29:49 -04:00
matlabbe
f6e21bd6c8 Integration of viso2 odometry approach. 2017-05-30 14:03:46 -04:00
matlabbe
4ffbc0fb58 Integrated Fovis (Odom/Strategy=2) 2017-05-30 09:27:31 -04:00
matlabbe
6d6c5e2e17 Updated Create Calibration dialog 2017-05-26 11:46:02 -04:00
matlabbe
d795bea543 fixed #201 2017-05-25 14:48:39 -04:00
matlabbe
10c23e60b7 OptimizerG2O: removed fixed frame if a posePrior link is detected 2017-05-24 15:03:27 -04:00
matlabbe
6f9ac4b88b fixed some compilation warnings 2017-05-23 17:30:23 -04:00
matlabbe
f92025e120 docker: finally using OpenCV3 built from source with opencv_contrib (arm64-v8a is not in 2.4.13 android binaries) 2017-05-23 16:24:38 -04:00
matlabbe
392ae832b8 Docker: added opencv2 android, tango now linking on opencv2 (fixing gftt/brief not available) 2017-05-23 14:20:32 -04:00
matlabbe
87a5f69335 MainWindow: fixed localization pose reset to latest pose in map when lost (localization mode) 2017-05-23 12:00:33 -04:00
matlabbe
c8e1060ea4 Merge branch 'dronecrew-g2o_prior' into devel 2017-05-22 21:14:02 -04:00
matlabbe
e361abcecd Reg: normalize covariance angle /10 2017-05-22 21:11:36 -04:00
matlabbe
e8af8f7792 Added SensorData's globalPose and globalPoseCovariance field. Link: added new type PosePrior. g2o: adding edge prior for self-refering edges. Memory: adding self-refering link when SensorData's globalPose is set. 2017-05-22 21:05:34 -04:00
matlabbe
2e906f9b8a Merge branch 'g2o_prior' of https://github.com/dronecrew/rtabmap into dronecrew-g2o_prior 2017-05-22 11:59:16 -04:00
matlabbe
385b7e3389 Parameters: Added "Reg/VarianceNormalized". Registration: Transforms are now only normalized in Registration. Added rgbd_dataset tool. MainWindow: odom inliers-only shown option. ExportCloudsDialog: ignoring intermediate nodes for texturing (if they don't have data). DatabaseViewer: "optimized" checkbox enabled in Constraints view for non-neighbor links too. 2017-05-22 11:48:01 -04:00
matlabbe
48ba55d02c Fixed #197 (handling zed pose confidence == -1) 2017-05-18 17:32:00 -04:00
matlabbe
5223629ab1 Windows: fixe build error (discrete_depth_distortion_model.h) 2017-05-18 16:23:39 -04:00
James Goppert
a2a8638f28 Add edge prior to g2o. 2017-05-17 22:58:26 -04:00
matlabbe
58e6424bf7 Export Clouds: export scans integrated in the same dialog (remove export scans dialog) 2017-05-11 15:02:18 -04:00
matlabbe
d2255adc4e fixed unknown character 2017-05-11 15:02:18 -04:00
matlabbe
7f8ca64f64 DbViewer: added frame selection when exporting poses. DBDriver: added getLaserScanInfo(). 2017-05-11 15:02:18 -04:00
matlabbe
104c1e6945 0.13.0 Database: Added velocity field to Node table, renamed Map_Node_Word table to Feature, added information_matrix field to Link table (replacing rot_variance and trans_variance). Added graph::calcKittiSequenceErrors().Added "Mem/IntermediateNodeDataKept" parameter (default false). Updated all interfaces using rotVariance and transVariance values with covariance matrix instead. g2o SBA: always use covariance in links. kitti-dataset tool: added --disp option and kitti statistics are shown at the end. StatsToolBox: units can have "/". 2017-05-11 15:02:18 -04:00
matlabbe
414e3555a5 DepthCalibrationDialog: added distortion model parameters 2017-05-11 14:44:15 -04:00
matlabbe
c63b45dbf3 Merge pull request #194 from T0ny0/fix_Kinect2_depth_calibration
Depth calibration: using appropriate bin_width and bin_height for all cameras
2017-05-11 13:22:38 -04:00
Anton Onishchenko
197bb2179f Depth calibration: move GetBinSize to clams namespace 2017-05-11 11:38:42 +03:00
matlabbe
62fdb8d0af DbViewer: fixed not reextracted features when reextract features is on 2017-05-10 18:00:30 -04:00
matlabbe
98184c31de Export clouds/poses: frame reference can be selected when clouds are not assembled 2017-05-10 15:53:02 -04:00
matlabbe
ee04ad500a Fixed build when opencv2 gpu module is not here 2017-05-10 10:26:37 -04:00
Anton Onishchenko
df40b0b8d3 Depth calibration: using appropriate bin_width and bin_height for all cameras 2017-05-10 13:54:11 +03:00
matlabbe
8eab31c469 Docker: android-deps build with API19 2017-05-09 17:06:27 -04:00
matlabbe
474011033b CameraStereoZed: fixed parameters not used with svo input 2017-05-09 15:46:47 -04:00
matlabbe
5893e42a8d Docker: backward compatibility for yellowstone API=19 2017-05-09 11:55:08 -04:00
matlabbe
9d18f7b15f Update CameraStereo.cpp
fixed #192
2017-05-09 09:02:02 -04:00
matlabbe
b0c22e7a3a Docker: fixed armeabi-v7a copy to arm64-v8a 2017-05-08 13:23:38 -04:00
matlabbe
9ab78acf09 Docker: fixed android-deps api 21 2017-05-08 12:30:15 -04:00
matlabbe
aa6499e7e4 Docker: fixed final tango workdir 2017-05-08 11:58:17 -04:00
matlabbe
fffd3592d3 Tango: increased min API to 21 2017-05-08 11:51:51 -04:00
matlabbe
842da98e61 Docker: updated android files to build for arm64_v8a 2017-05-08 11:49:25 -04:00
matlabbe
eadeb3841b Export: CPU-TSDF mesh reconstruction integration 2017-05-05 21:44:06 -04:00
matlabbe
b25379c243 Odometry: Don't assert if dt is negative, just show error if guess from motion / kalman filter is used (https://github.com/introlab/rtabmap_ros/issues/169) 2017-05-05 16:25:03 -04:00
matlabbe
4d025568dc updated FindRealSense.cmake 2017-05-05 16:10:09 -04:00
matlabbe
c3ec7fbbe4 💄 2017-05-01 15:40:30 -04:00
matlabbe
14baca125d cloudFromDisparity(): adjusting decimation if not valid with current image size. Standalone: ask user to set other parameters to default if some were set on command line. 2017-04-28 11:43:27 -04:00
matlabbe
1ea94c0356 DbViewer: refining cancelable, statistics labels selectable and x-axis can be time or IDs 2017-04-27 16:13:27 -04:00
matlabbe
57dbece417 DbViewer: Updated doubleSpinBox decimals/singleStep for ParametersToolbox 2017-04-27 14:42:58 -04:00
matlabbe
f023adff4b Export: supporting texturing with multi-camera 2017-04-26 18:39:57 -04:00
matlabbe
6a2fe47b22 Preferences: updated RGBD/ProximityPathMaxNeighbors description and default value (now 0=disabled) 2017-04-26 14:06:42 -04:00
matlabbe
461d167547 DbViewer: update loop closure slider after detecting more loop closures 2017-04-25 16:50:57 -04:00
matlabbe
13425e1ad4 3D Rendering: Added floor/ceiling filtering and normal estimation for scans 2017-04-24 19:12:53 -04:00
matlabbe
c7deb5ed33 StereoBM: Fixed speckle window size parameter not set correctly (creating a lot of noise in generated disparity images) 2017-04-24 17:14:57 -04:00
matlabbe
27313bc3d6 DBViewer: added "Restore default GUI settings" menu action 2017-04-24 16:20:41 -04:00
matlabbe
6e1dbbcf4f Reverted change of cloudFromStereoImages() decimation, should be done after StereoBM to avoid backward compatibility problems 2017-04-24 15:26:12 -04:00
matlabbe
4e3216a75d SourceRGB: added rectify option for all types (including usb camera) 2017-04-24 14:11:38 -04:00
matlabbe
51c353e504 DatabaseViewer: Added ground truth statistics 2017-04-24 13:04:31 -04:00
matlabbe
1b71a96a3d Added rtabmap-kitti_dataset tool 2017-04-24 12:17:18 -04:00
matlabbe
a0a7237c01 Occupancy grid graph changed detection: Quiet warning when map is empty 2017-04-22 19:29:13 -04:00
matlabbe
af576ea0c4 Force full global occupancy grid udpate when the graph has changed (e.g., localizing in other map not connected to current one in database) 2017-04-22 18:43:22 -04:00
matlabbe
183c6abc98 Fixed stereo optical flow crash when no keypoints are extracted 2017-04-22 16:56:38 -04:00
matlabbe
559e65a4e1 disabled label realsense odometry when not built with realsense slam 2017-04-21 22:35:45 -04:00
matlabbe
b93ca148a8 fixed build realsense on Windows 2017-04-21 21:59:53 -04:00
matlabbe
07d6763e69 Fixed build without realsense 2017-04-21 21:58:38 -04:00
matlabbe
bc2da10713 RealSense driver: added odometry option (ZR300) 2017-04-21 21:24:23 -04:00
matlabbe
2e515f5fc7 Export: texture roiRatios default "0.0 0.0 0.0 0.0" 2017-04-20 12:01:20 -04:00
matlabbe
a274f3cf01 Export Added RoiRatios parameter to texturing (#171) 2017-04-20 11:51:23 -04:00
matlabbe
c068c3c33a MainWindow: added ZR300 menu 2017-04-19 15:24:42 -04:00
matlabbe
e258a7cf64 Update build.bash 2017-04-19 11:13:53 -04:00
matlabbe
5814724600 Fixed cloud -1 not found on export, fixed cloud visibility doing nothing to cloud -1 2017-04-18 23:08:28 -04:00
matlabbe
220a454859 fixed compile error 2017-04-18 20:22:05 -04:00
matlabbe
42fb02c36f zed 2.0: fixed sensing mode order, fixed conversion from zed pose to transform (when zed odometry is enabled) 2017-04-18 20:16:04 -04:00
matlabbe
732223e832 Tango: refactored shaders (to remove most "if" in them), added "Auto" to reconstruction depth option 2017-04-18 17:30:14 -04:00
matlabbe
286ab7a600 Merge pull request #184 from akirayou/zed20
change for zed sdk 2.0
2017-04-18 08:37:14 -04:00
akria_you
b402ce1564 change for zed sdk 2.0 2017-04-18 15:03:10 +09:00
matlabbe
0ccba3281e Tango: added online blending option, background color option, double tap, fixed meshes jiggering on touch, removed raw mesh option 2017-04-17 21:42:01 -04:00
matlabbe
6f148c47e2 0.12.15 Parameters: added "GridGlobal" parameter group, fixed https://github.com/introlab/rtabmap_ros/issues/162 2017-04-10 16:59:48 -04:00
matlabbe
98a96a897b Tango: improved optimized texture colors 2017-04-09 20:00:23 -04:00
matlabbe
f1d96a30a4 Export: Added blending option, gain compensation performance increased when exporting with textures 2017-04-09 19:16:50 -04:00
matlabbe
2509a842f0 DBViewer: fixed Export dialog parameters not loaded correctly 2017-04-08 16:46:06 -04:00
matlabbe
b7dbf27931 Parameters: added Grid/FullUpdate (default true). Updated how occupancy grid is updated after loop closure. OctoMap: added tree depth argument when creating 2d map, added full update argument on constructor (default false). MainWindow: using OccupancyGrid object instead of keeping in cache local grids (we can have actual time to update the global grid). 2017-04-07 18:31:11 -04:00
matlabbe
6bfce63060 fixed compilation warning 2017-04-06 14:39:46 -04:00
matlabbe
6ca3b8246a fixed some compilation warnings 2017-04-06 12:41:16 -04:00
matlabbe
1d8952867d MainWindow: added timing stats on global map creation. Updated util3d::occupancy2DFromLaserScan() and util3d::create2DMap() interfaces (hit/noHit scans in opencv matrix format). Parameter default: Grid/ProjRayTracing=true, Grid/NormalK=true 2017-04-06 12:27:12 -04:00
matlabbe
e415dd8504 Fixed inf loop when all signatures are loaded in WM and if a signature has a -1 word 2017-04-04 12:26:06 -04:00
matlabbe
aa37ac6038 Increased version to 0.12.4, Tango: gain compensation on each channel, added min depth parameter, fixed exporting failing when doing export just after opening a database 2017-04-01 14:14:36 -04:00
matlabbe
d68eeada0e Export: Disabled exposure fusion when built with Opencv < 3 2017-03-31 18:56:52 -04:00
matlabbe
accbe5a423 Export: Added exposure fusion option 2017-03-31 18:56:52 -04:00
matlabbe
f33b838204 DBViewer: updated more loop closures dialog default size 2017-03-31 18:56:52 -04:00
matlabbe
767b29d5a3 Updated detect more loop closures with optimization check to accept (like in dbviewer). DBViewer: added Depth image edition dialog. GainCompensator: now doing it on 3 channels separatly. Export: removed gain's alpha option, added max polygons option, added brightness/contrast auto balance option 2017-03-31 18:56:52 -04:00
matlabbe
a928a0b404 Moved create occupancy grid parameter to Ocupancy Grid panel 2017-03-31 18:56:52 -04:00
matlabbe
2574f3a8ee DatabaseViewer: Added ExportCloudsDialog, added Occupancy Grid View 2017-03-31 18:56:52 -04:00
matlabbe
622352b411 Freenect2: fixed noisy rectification of depth image on IR+Depth mode. 2017-03-31 18:28:19 -04:00
matlabbe
900de0a5c9 SimpleCalibrationDialog: width and height are now mandatory to save 2017-03-31 15:07:24 -04:00
matlabbe
def90355a9 Tango: fixed "Waiting creating clouds..." dialog not closing 2017-03-26 13:40:25 -04:00
matlabbe
a3f1e04a4d Update README.md 2017-03-22 22:24:57 -04:00
matlabbe
39286deb19 Dockerfile: updated tags 2017-03-22 21:48:01 -04:00
matlabbe
504bffa57a Update README.md 2017-03-22 21:23:10 -04:00
matlabbe
d89c43befa Dockerfile: fixed aapt error 2017-03-22 21:09:21 -04:00
matlabbe
d95818f1b2 update dockerfile (pcl ply headers not found) 2017-03-22 13:54:09 -04:00
matlabbe
9b0faaac34 updated dockerfiles 2017-03-21 19:52:18 -04:00
matlabbe
eaafe91ade Docker: added Dockerfile for android 2017-03-21 10:35:46 -04:00
matlabbe
f84bfd8384 Tango: Updated some files for docker 2017-03-20 15:45:24 +00:00
matlabbe
79709f3f06 Update util3d_surface.cpp
Added PCL_ONLY_CORE_POINT_TYPES check
2017-03-20 11:09:15 -04:00
matlabbe
ce6edf893a Update util3d_surface.cpp
Removed NormalEstimationOMP instantiate with PointXYZRGB/Normal for PCL > 1.8.0
2017-03-19 23:42:16 -04:00
matlabbe
5d5d602f1d Updated Dockfile for xenial 2017-03-17 21:03:14 -04:00
matlabbe
ad3aa30471 Added Docker file for xenial 2017-03-16 16:24:25 -04:00
matlabbe
69d174309d Tango: fixed bundle adjustment poses not used for export 2017-03-16 11:47:04 -04:00
matlabbe
5b08a69607 Tango: added comptible fisheye cloud density level 2017-03-15 17:05:19 -04:00
matlabbe
1bd9d41164 Tango: updated default export max polygons, added more values to color radius parameter 2017-03-14 10:54:23 -04:00
matlabbe
ef7bf87187 Tango: added fisheye option 2017-03-13 20:51:59 -04:00
matlabbe
d21ae76fff 0.12.3: Increased Tango rendering performance, modified all handleEvent() with new interface (now returning bool) 2017-03-12 21:21:09 -04:00
matlabbe
c12980ee91 Tango: Fixed scan local transform 2017-03-08 12:55:21 -05:00
matlabbe
719416741f Fixed "Export octomap..." not enabled on first load of the OctoMap 2017-03-08 08:33:43 -05:00
matlabbe
1b14263bb8 fixed #174 2017-03-07 20:58:38 -05:00
matlabbe
5c8da20eea Tango: Fixed color gain bug on pointcloud and mesh (without texture) 2017-03-07 10:53:29 -05:00
matlabbe
560fcdc541 Grid: Adjusting viewpoint when projecting into map frame 2017-03-06 13:32:48 -05:00
matlabbe
d1e9525052 Added viewpoint to laser scan 2D ray tracing 2017-03-06 12:07:59 -05:00
matlabbe
9f65ef199b Tango: Added Level of detail rendering depending on the distance from the camera 2017-03-05 21:48:18 -05:00
matlabbe
fed9d4ef3b Tango: zipping obj files, exporting in Export sub directory 2017-03-05 13:05:26 -05:00
matlabbe
867e8727c1 GraphViewer: Fixed scale of saved PNG/SVG 2017-03-05 11:55:22 -05:00
matlabbe
d927b82020 Tango: added min texture cluster size option 2017-03-04 19:34:40 -05:00
matlabbe
e003fb8d35 Texturing: Added min polygon cluster size parameter 2017-03-04 18:20:26 -05:00
matlabbe
4db957f437 Increased polygon texturing step speed 2017-03-04 02:53:11 -05:00
matlabbe
46ec0b8f70 Fixed Freenect2 calibration default rgb/depth/switched config not working 2017-03-03 18:12:55 -05:00
matlabbe
d1aa8bf5ae changed a warning to debug (about loop ratio) 2017-03-03 16:22:22 -05:00
matlabbe
3cf8ea63d8 Fixed a bug where camera facing polygons were not textured 2017-03-03 15:22:20 -05:00
matlabbe
fd55828c42 0.12.2: ros package sync 2017-03-03 11:36:07 -05:00
matlabbe
1ce4db5604 Fixed backward compatibility for exporting texture mesh with old databases 2017-03-03 00:19:46 -05:00
matlabbe
300e37124c GTSAM: added optimizer approach option #172 2017-03-02 16:46:15 -05:00
matlabbe
9b3b7b09a0 Projection ray tracing, keep empty cells from projection 2017-03-01 17:34:28 -05:00
matlabbe
17121d5861 Added parameter "Grid/ProjRayTracing" and renamed "Grid/3DGroundIsObstacle" to "Grid/GroundIsObstacle" 2017-03-01 14:06:21 -05:00
matlabbe
c9f6dabfc6 Tango: added progression bar when exporting, averaging colors in color radius when exporting without texture 2017-02-28 21:50:50 -05:00
matlabbe
b76952f016 Export: using color transfer radius to limit texturing far polygons from the orignal cloud 2017-02-27 17:31:02 -05:00
matlabbe
6c9572714f Tango: added sketchfab links, Color Radius is used when texturing optimized mesh 2017-02-27 16:53:05 -05:00
matlabbe
2565239a1b Export dialog: hiding not used options, exporting can be now canceled on texturing phase 2017-02-26 18:17:00 -05:00
matlabbe
8ab609471a CLAMS: added isFinite conditions in coneFit (before reproject) http://official-rtab-map-forum.67519.x6.nabble.com/Depth-calibration-fatal-error-td2682.html 2017-02-25 16:14:18 -05:00
matlabbe
3cf21a7e7f fixed laserScanFromDepthImage order (counterclockwise) 2017-02-24 15:26:42 -05:00
matlabbe
b0170d1f6f OdometryF2M: generating custom ids for bundle adjustement https://github.com/introlab/rtabmap_ros/issues/151 2017-02-24 11:50:29 -05:00
matlabbe
45ca3500c6 Removed assert when data.id = 0 (only requirement for odom is that id >=0) 2017-02-23 15:57:50 -05:00
matlabbe
526fdb495b Loop closure view: Added legend "gray" color for features not quantized in vocabulary (-1) 2017-02-23 11:49:33 -05:00
matlabbe
8de6cb1ca0 Added util3d::projectCloudToCamera() with PCLPointcloud2 interface, update util2d::fillDeptHoles() to support CV_32FC1 2017-02-23 00:15:43 -05:00
matlabbe
a1c036a7e2 removed warning when setting user data to SensorData if compressed user data is already here 2017-02-22 14:38:42 -05:00
matlabbe
a9b03bb39e Tango: 0.12.0 (performance optimization, time and memory) 2017-02-22 09:48:45 -05:00
matlabbe
595ac49552 0.12.0: database update: added missing octave field, added preview_image field 2017-02-17 14:37:41 -05:00
matlabbe
af1cdadabd Tango: updated export workflow, added sketchfab activity, added graph optimization parameters, fixed raw images kept in memory (disabled reexctract words on loop closure while updating memory to be able to create more features for transform estimation than needed in vocabulary), portrait/landscape orientation, updated to Eisa TangoSDK. DBReader: fixed high variance when node has no links (if not the first in the current map id). MainWindow: remove frustums not in the current graph. 2017-02-15 19:07:10 -05:00
matlabbe
1be0d52051 Fixed compilation error with PCL < 1.7.2 (disabled graph frustums option) 2017-02-09 19:25:35 -05:00
matlabbe
0d0577a886 3D Rendering: Added option to show graph's frustums, added option to filter floor and/or ceiling. 2017-02-09 18:32:44 -05:00
matlabbe
e4629cc740 Tango: file name using 0-24 hours format 2017-02-07 19:00:52 -05:00
matlabbe
1c555f321b Fixed Tango odometry variance 2017-02-07 15:57:52 -05:00
matlabbe
5e9c4fde95 Tango: added Privacy Policy link 2017-02-07 00:37:37 -05:00
matlabbe
6aecebcf2c ExportDialog: fixed minClusterSize signal/slot error 2017-02-06 21:07:27 -05:00
matlabbe
9a2c9f607f DBViewer: compute normals when showing clouds 2017-02-06 17:05:53 -05:00
matlabbe
3a9b725c0c Tango: doing mesh decimation only when texturing 2017-02-05 18:04:22 -05:00
matlabbe
f7616f6e94 Tango: update to 0.11.14 2017-02-05 17:24:45 -05:00
matlabbe
ce8bd9ac40 Export: for min polygon cluster size, added option -1 to just keep the largest cluster 2017-02-04 18:28:43 -05:00
matlabbe
5c44082c42 updated log commment in memory when changing feature type 2017-02-04 09:27:35 -05:00
matlabbe
585f0c54bf Adjusted min polygon cluster size for applying texture 2017-02-03 17:40:55 -05:00
matlabbe
31453d187d Updated how texturing is done (occlusion+distance) 2017-02-03 17:27:54 -05:00
matlabbe
53ff5b56e6 fixed texture not exported with single image scan 2017-02-01 12:53:05 -05:00
matlabbe
a1ceff8ce8 Texturing: ignore polygons not facing the camera 2017-02-01 00:29:13 -05:00
matlabbe
bfb9feaf07 TextureMapping: added maximum camera distance 2017-01-31 23:26:35 -05:00
matlabbe
8e0e04eae9 CloudViewer: added point picker on doubleclick 2017-01-30 19:51:06 -05:00
matlabbe
0f96bf7709 Added FREAK detector/descriptor option with OpenCV3 2017-01-30 22:24:51 -05:00
matlabbe
f61569622a CloudViewer: no need to save texture on disk before rendering TextureMesh (opencv image to vtk texture directly) 2017-01-30 21:23:56 -05:00
matlabbe
31d8ae08c8 Fixed a compilation warning... 2017-01-30 13:35:16 -05:00
matlabbe
4e324e34d8 About dialog: Added VTK version and updated copyright year 2017-01-30 13:17:03 -05:00
matlabbe
7b5761106d Tango: updated how RGB and depth images are synchronized (to minimize the dt between them). Added time offset to get stamps in epoch time. Trajectory Mode: fixed top button not selected. 2017-01-30 12:29:34 -05:00
matlabbe
819db9538f Ask to set detection rate to 0 when selecting a source database. DBReader: set 9999 covariance for the first odom pose of a database. 2017-01-29 18:24:10 -05:00
matlabbe
e3b3a08f5f DbViewer: fixed features not added in right image when adding loop closure 2017-01-28 15:49:29 -05:00
matlabbe
e3d9ad005e Tango default feature set to BRIEF 2017-01-28 01:17:32 -05:00
matlabbe
bcacf2fe74 Export: darker background to see grid lines 2017-01-27 16:55:01 -05:00
matlabbe
b3a6650a6f Updated error msg when database cannot be written on disk (write permission issue) 2017-01-27 14:31:44 -05:00
matlabbe
534efcb987 updated version to 0.11.14 2017-01-27 12:19:39 -05:00
matlabbe
79a211ad02 RtabmapThread: changed state stack for a queue to process events in FIFO order (instead of FILO). Tango: Added detector type parameter (FREAK is now the default with 400 features). 2017-01-27 11:47:57 -05:00
matlabbe
b4a0fe54cd Tango: added gain radius and min cluster size parameters 2017-01-26 17:34:15 -05:00
matlabbe
3a73414972 Tango: Added Settings/Optimized Mesh/Sketchfab Upload 2017-01-26 16:46:24 -05:00
matlabbe
66ee792e8c Export: fixed white squares in exported texture (shifting next tex coords to wrong sub texture). Transfer color radius option use nearest point when =0. Fixed a crash on export dense with texture when last materials are not used (they have no polygons associated). 2017-01-26 09:42:52 -05:00
matlabbe
496319a2b0 Export: Added merging textures option (default true) 2017-01-19 11:20:48 -05:00
matlabbe
0a98df922e Export: added texture format option (jpg, png) 2017-01-17 14:57:50 -05:00
matlabbe
4c7d46c8a0 createTextureCameras: using CameraModel's localTransform instead of hard coded optical rotation 2017-01-17 12:44:30 -05:00
matlabbe
a011a6af64 Refactored texture projection (avoid saving image on disk at this step) 2017-01-16 18:29:14 -05:00
matlabbe
2b8f40e505 fixed compilation warnings 2017-01-16 11:21:40 -05:00
matlabbe
8f797e81ae Export: added option to remove not textured/colored polygons. Cloud generation: Black pixels can be projected. Added RoiRatios options to 3D Rendering and Export. Added fill depth holes option to Export. 2017-01-16 01:32:53 -05:00
matlabbe
f8ec338fa3 Added Poisson surface reconstruction in export options 2017-01-15 19:09:37 -05:00
matlabbe
ea5f0fadb8 Tango: added more Map Update Rate options 2017-01-12 16:49:02 -05:00
matlabbe
bf01a1d138 consoleApp: fixed redefined i 2017-01-07 15:04:36 -05:00
236 changed files with 38479 additions and 11192 deletions

2
.gitignore vendored
View File

@@ -1,6 +1,8 @@
/lib
.DS_Store
.settings/language.settings.xml
.idea/
cmake-build-debug/
app/android/.classpath
app/android/.project
app/android/AndroidManifest.xml

View File

@@ -1,6 +1,7 @@
sudo: true
dist: trusty
language: cpp
group: deprecated-2017Q3
compiler:
- gcc

View File

@@ -20,8 +20,8 @@ SET(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake_modules")
# VERSION
#######################
SET(RTABMAP_MAJOR_VERSION 0)
SET(RTABMAP_MINOR_VERSION 11)
SET(RTABMAP_PATCH_VERSION 13)
SET(RTABMAP_MINOR_VERSION 13)
SET(RTABMAP_PATCH_VERSION 2)
SET(RTABMAP_VERSION
${RTABMAP_MAJOR_VERSION}.${RTABMAP_MINOR_VERSION}.${RTABMAP_PATCH_VERSION})
@@ -46,25 +46,25 @@ IF(NOT ANDROID)
ENDIF(NOT ANDROID)
IF(WIN32 AND NOT MINGW)
ADD_DEFINITIONS("-DNOMINMAX")
ADD_DEFINITIONS("-DNOMINMAX")
ADD_DEFINITIONS("-wd4100 -wd4127 -wd4150 -wd4191 -wd4242 -wd4244 -wd4251 -wd4305 -wd4365 -wd4512 -wd4514 -wd4548 -wd4571 -wd4619 -wd4625 -wd4626 -wd4628 -wd4668 -wd4710 -wd4711 -wd4738 -wd4820 -wd4946 -wd4986")
ELSE ()
ADD_DEFINITIONS( "-Wall" )
ADD_DEFINITIONS("-Wno-unknown-pragmas")
ADD_DEFINITIONS( "-Wall" )
ADD_DEFINITIONS("-Wno-unknown-pragmas")
ENDIF()
if(POLICY CMP0020)
cmake_policy(SET CMP0020 OLD)
cmake_policy(SET CMP0020 OLD)
endif()
if(POLICY CMP0043)
cmake_policy(SET CMP0043 OLD)
cmake_policy(SET CMP0043 OLD)
endif()
IF(MINGW)
# Hide the --enable-auto-import warning
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--enable-auto-import")
SET(CMAKE_MODULE_LINKER_FLAGS "-Wl,--enable-auto-import")
SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--enable-auto-import")
SET(CMAKE_EXE_LINKER_FLAGS "-Wl,--enable-auto-import")
SET(CMAKE_MODULE_LINKER_FLAGS "-Wl,--enable-auto-import")
SET(CMAKE_SHARED_LINKER_FLAGS "-Wl,--enable-auto-import")
ENDIF(MINGW)
# GCC 4 required
@@ -124,8 +124,17 @@ set(INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH
"Installation directory for CMake files")
####### BUILD OPTIONS #######
# ANDROID_PREBUILD (early exit if true)
OPTION( ANDROID_PREBUILD "Set to ON to build rtabmap resource build tool (required for android build)" OFF )
IF(ANDROID_PREBUILD)
MESSAGE("Option ANDROID_PREBUILD is set, only rtabmap resource tool will be built. You can use android toolchain after that.")
ADD_SUBDIRECTORY( utilite )
return()
ENDIF(ANDROID_PREBUILD)
IF(APPLE)
OPTION(BUILD_AS_BUNDLE "Set to ON to build as bundle (DragNDrop)" OFF)
OPTION(BUILD_AS_BUNDLE "Set to ON to build as bundle (DragNDrop)" OFF)
ENDIF(APPLE)
OPTION(BUILD_APP "Build main application" ON)
OPTION(BUILD_TOOLS "Build tools" ON)
@@ -149,16 +158,24 @@ option(WITH_CVSBA "Include cvsba support" ON)
option(WITH_FLYCAPTURE2 "Include FlyCapture2/Triclops support" ON)
option(WITH_ZED "Include ZED sdk support" ON)
option(WITH_REALSENSE "Include RealSense support" ON)
option(WITH_REALSENSE_SLAM "Include RealSenseSlam support" ON)
option(WITH_OCTOMAP "Include Octomap support" ON)
option(WITH_CPUTSDF "Include CPUTSDF support" ON)
option(WITH_FOVIS "Include FOVIS support" ON)
option(WITH_VISO2 "Include VISO2 support" ON)
option(WITH_DVO "Include DVO support" ON)
option(WITH_ORB_SLAM2 "Include ORB_SLAM2 support" ON)
option(PCL_OMP "With PCL OMP implementations" ON)
FIND_PACKAGE(OpenCV REQUIRED QUIET)
FIND_PACKAGE(PCL 1.7 REQUIRED QUIET)
FIND_PACKAGE(ZLIB REQUIRED QUIET)
# fix libproj.so not found on Xenial
if(NOT "${PCL_LIBRARIES}" STREQUAL "")
# fix libproj.so not found on Xenial
list(REMOVE_ITEM PCL_LIBRARIES "vtkproj4")
# fix libmpi.so not found on Zesty
list(REMOVE_ITEM PCL_LIBRARIES "/usr/lib/libmpi.so")
endif()
# OpenMP ("-fopenmp" should be added for flann included in PCL)
@@ -199,12 +216,12 @@ IF(WITH_QT)
IF("${VTK_MAJOR_VERSION}" GREATER 5)
FIND_PACKAGE(Qt5 COMPONENTS Widgets Core Gui QUIET)
IF(Qt5_FOUND)
FIND_PACKAGE(Qt5 COMPONENTS Widgets Core Gui Svg)
FIND_PACKAGE(Qt5 COMPONENTS Widgets Core Gui OPTIONAL_COMPONENTS Svg)
ENDIF(Qt5_FOUND)
ENDIF("${VTK_MAJOR_VERSION}" GREATER 5)
IF(NOT Qt5_FOUND)
FIND_PACKAGE(Qt4 COMPONENTS QtCore QtGui QtSvg)
FIND_PACKAGE(Qt4 COMPONENTS QtCore QtGui OPTIONAL_COMPONENTS QtSvg)
ENDIF(NOT Qt5_FOUND)
IF(QT4_FOUND OR Qt5_FOUND)
@@ -230,18 +247,18 @@ ENDIF(WITH_FREENECT)
IF(WITH_FREENECT2)
FIND_PACKAGE(freenect2 QUIET)
IF(freenect2_FOUND)
IF(NOT freenect2_INCLUDE_DIRS)
SET(freenect2_INCLUDE_DIRS ${freenect2_INCLUDE_DIR})
ENDIF(NOT freenect2_INCLUDE_DIRS)
IF(NOT freenect2_INCLUDE_DIRS)
SET(freenect2_INCLUDE_DIRS ${freenect2_INCLUDE_DIR})
ENDIF(NOT freenect2_INCLUDE_DIRS)
MESSAGE(STATUS "Found freenect2: ${freenect2_INCLUDE_DIRS}")
# Explicitly link to OpenCL (in case of CUDA installed)
FIND_PACKAGE(OpenCL QUIET)
IF(OpenCL_FOUND)
SET(freenect2_LIBRARIES
${OpenCL_LIBRARIES}
${freenect2_LIBRARIES}
)
ENDIF(OpenCL_FOUND)
FIND_PACKAGE(OpenCL QUIET)
IF(OpenCL_FOUND)
SET(freenect2_LIBRARIES
${OpenCL_LIBRARIES}
${freenect2_LIBRARIES}
)
ENDIF(OpenCL_FOUND)
ENDIF(freenect2_FOUND)
ENDIF(WITH_FREENECT2)
@@ -279,70 +296,122 @@ IF(WITH_FLYCAPTURE2)
ENDIF(WITH_FLYCAPTURE2)
IF(WITH_CVSBA)
FIND_PACKAGE(cvsba QUIET)
FIND_PACKAGE(cvsba QUIET)
IF(cvsba_FOUND)
MESSAGE(STATUS "Found cvsba: ${cvsba_INCLUDE_DIRS}")
ENDIF(cvsba_FOUND)
ENDIF(WITH_CVSBA)
IF(WITH_ZED)
IF(WIN32) # Windows
SET(ZED_INCLUDE_DIRS $ENV{ZED_INCLUDE_DIRS})
if (CMAKE_CL_64) # 64 bits
SET(ZED_LIBRARIES $ENV{ZED_LIBRARIES_64})
else(CMAKE_CL_64) # 32 bits
message("32bits compilation is no more available with CUDA7.0")
endif(CMAKE_CL_64)
SET(ZED_LIBRARY_DIR $ENV{ZED_LIBRARY_DIR})
IF(ZED_LIBRARIES AND ZED_INCLUDE_DIRS)
SET(ZED_FOUND TRUE)
LINK_DIRECTORIES( ${LINK_DIRECTORIES} ${ZED_LIBRARY_DIR})
ENDIF(ZED_LIBRARIES AND ZED_INCLUDE_DIRS)
ELSE() # Linux
find_package(ZED 1 QUIET)
ENDIF(WIN32)
IF(ZED_FOUND)
IF(WIN32) # Windows
SET(ZED_INCLUDE_DIRS $ENV{ZED_INCLUDE_DIRS})
if (CMAKE_CL_64) # 64 bits
SET(ZED_LIBRARIES $ENV{ZED_LIBRARIES_64})
else(CMAKE_CL_64) # 32 bits
message("32bits compilation is no more available with CUDA7.0")
endif(CMAKE_CL_64)
SET(ZED_LIBRARY_DIR $ENV{ZED_LIBRARY_DIR})
IF(ZED_LIBRARIES AND ZED_INCLUDE_DIRS)
SET(ZED_FOUND TRUE)
LINK_DIRECTORIES( ${LINK_DIRECTORIES} ${ZED_LIBRARY_DIR})
ENDIF(ZED_LIBRARIES AND ZED_INCLUDE_DIRS)
ELSE() # Linux
find_package(ZED 1 QUIET)
ENDIF(WIN32)
IF(ZED_FOUND)
MESSAGE(STATUS "Found ZED sdk: ${ZED_INCLUDE_DIRS}")
## look for CUDA
find_package(CUDA)
IF(CUDA_FOUND)
MESSAGE(STATUS "Found CUDA: ${CUDA_INCLUDE_DIRS}")
ELSE()
MESSAGE(FATAL_ERROR "CUDA is required to build with Zed sdk! Set -DWITH_ZED=OFF if you don't have CUDA.")
ENDIF()
## look for CUDA
find_package(CUDA)
IF(CUDA_FOUND)
MESSAGE(STATUS "Found CUDA: ${CUDA_INCLUDE_DIRS}")
ELSE()
MESSAGE(FATAL_ERROR "CUDA is required to build with Zed sdk! Set -DWITH_ZED=OFF if you don't have CUDA.")
ENDIF()
ENDIF(ZED_FOUND)
ENDIF(WITH_ZED)
IF(WITH_REALSENSE)
FIND_PACKAGE(RealSense QUIET)
IF(WITH_REALSENSE_SLAM)
FIND_PACKAGE(RealSense QUIET COMPONENTS slam)
ELSE()
FIND_PACKAGE(RealSense QUIET)
ENDIF()
IF(RealSense_FOUND)
MESSAGE(STATUS "Found RealSense: ${RealSense_INCLUDE_DIRS}")
ENDIF(RealSense_FOUND)
IF(RealSenseSlam_FOUND)
MESSAGE(STATUS "Found RealSenseSlam: ${RealSense_INCLUDE_DIRS}")
ENDIF(RealSenseSlam_FOUND)
ENDIF(WITH_REALSENSE)
IF(WITH_OCTOMAP)
FIND_PACKAGE(OCTOMAP QUIET)
FIND_PACKAGE(OCTOMAP QUIET)
IF(OCTOMAP_FOUND)
MESSAGE(STATUS "Found octomap: ${OCTOMAP_INCLUDE_DIRS}")
ENDIF(OCTOMAP_FOUND)
ENDIF(WITH_OCTOMAP)
IF(G2O_FOUND OR GTSAM_FOUND OR ZED_FOUND OR ANDROID OR RealSense_FOUND)
IF(WITH_CPUTSDF)
FIND_PACKAGE(CPUTSDF QUIET)
IF(CPUTSDF_FOUND)
MESSAGE(STATUS "Found CPUTSDF: ${CPUTSDF_INCLUDE_DIRS}")
ENDIF(CPUTSDF_FOUND)
ENDIF(WITH_CPUTSDF)
IF(WITH_FOVIS)
FIND_PACKAGE(libfovis QUIET)
IF(libfovis_FOUND)
MESSAGE(STATUS "Found libfovis: ${libfovis_INCLUDE_DIRS}")
ENDIF(libfovis_FOUND)
ENDIF(WITH_FOVIS)
IF(WITH_VISO2)
FIND_PACKAGE(libviso2 QUIET)
IF(libviso2_FOUND)
MESSAGE(STATUS "Found libviso2: ${libviso2_INCLUDE_DIRS}")
ENDIF(libviso2_FOUND)
ENDIF(WITH_VISO2)
IF(WITH_DVO)
FIND_PACKAGE(dvo_core QUIET)
IF(dvo_core_FOUND)
MESSAGE(STATUS "Found dvo_core: ${dvo_core_INCLUDE_DIRS}")
ENDIF(dvo_core_FOUND)
ENDIF(WITH_DVO)
IF(WITH_ORB_SLAM2 AND NOT G2O_FOUND)
FIND_PACKAGE(ORB_SLAM2 QUIET)
IF(ORB_SLAM2_FOUND)
MESSAGE(STATUS "Found ORB_SLAM2: ${ORB_SLAM2_INCLUDE_DIRS}")
FIND_PACKAGE(Pangolin QUIET)
IF(NOT Pangolin_FOUND)
SET(ORB_SLAM2_FOUND FALSE)
MESSAGE(STATUS "Found ORB_SLAM2 but not Pangolin, disabling ORB_SLAM2.")
ELSE()
MESSAGE(STATUS "Found Pangolin: ${Pangolin_INCLUDE_DIRS}")
SET(ORB_SLAM2_INCLUDE_DIRS ${ORB_SLAM2_INCLUDE_DIRS} ${Pangolin_INCLUDE_DIRS})
SET(ORB_SLAM2_LIBRARIES ${ORB_SLAM2_LIBRARIES} ${Pangolin_LIBRARIES})
MESSAGE(WARNING "Don't forget to build ORB_SLAM2 (and included g2o) without \"-march=native\" to avoid crash when ORB_SLAM2 starts.")
ENDIF()
ENDIF(ORB_SLAM2_FOUND)
ENDIF(WITH_ORB_SLAM2 AND NOT G2O_FOUND)
IF(G2O_FOUND OR GTSAM_FOUND OR ZED_FOUND OR ANDROID OR RealSense_FOUND OR ORB_SLAM2_FOUND)
#Newest versions require std11
IF(NOT MSVC)
include(CheckCXXCompilerFlag)
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
IF(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
ELSEIF(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
ELSE()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler if you want to use g2o or gtsam (set \"-DWITH_G2O=OFF -DWITH_GTSAM=OFF\" to build without g2o and gtsam).")
ENDIF()
CHECK_CXX_COMPILER_FLAG("-std=c++11" COMPILER_SUPPORTS_CXX11)
CHECK_CXX_COMPILER_FLAG("-std=c++0x" COMPILER_SUPPORTS_CXX0X)
IF(COMPILER_SUPPORTS_CXX11)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
ELSEIF(COMPILER_SUPPORTS_CXX0X)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++0x")
ELSE()
message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++11 support. Please use a different C++ compiler if you want to use g2o or gtsam (set \"-DWITH_G2O=OFF -DWITH_GTSAM=OFF\" to build without g2o and gtsam).")
ENDIF()
ENDIF()
ENDIF(G2O_FOUND OR GTSAM_FOUND OR ZED_FOUND OR ANDROID OR RealSense_FOUND)
ENDIF(G2O_FOUND OR GTSAM_FOUND OR ZED_FOUND OR ANDROID OR RealSense_FOUND OR ORB_SLAM2_FOUND)
####### OSX BUNDLE CMAKE_INSTALL_PREFIX #######
IF(APPLE AND BUILD_AS_BUNDLE)
@@ -376,7 +445,7 @@ ENDIF(APPLE AND BUILD_AS_BUNDLE)
# CONF_DEPENDENCIES contains only dependencies not required by the headers
SET(CONF_DEPENDENCIES
${ZLIB_LIBRARIES}
${ZLIB_LIBRARIES}
)
IF(NOT (OPENCV_NONFREE_FOUND OR OPENCV_XFEATURES2D_FOUND))
SET(NONFREE "//")
@@ -437,11 +506,39 @@ IF(NOT RealSense_FOUND)
ELSE()
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${RealSense_LIBRARIES})
ENDIF()
IF(NOT RealSenseSlam_FOUND)
SET(REALSENSESLAM "//")
ENDIF(NOT RealSenseSlam_FOUND)
IF(NOT OCTOMAP_FOUND)
SET(OCTOMAP "//")
ELSE()
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${OCTOMAP_LIBRARIES})
ENDIF()
IF(NOT CPUTSDF_FOUND)
SET(CPUTSDF "//")
ELSE()
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${CPUTSDF_LIBRARIES})
ENDIF()
IF(NOT libfovis_FOUND)
SET(FOVIS "//")
ELSE()
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${libfovis_LIBRARIES})
ENDIF()
IF(NOT libviso2_FOUND)
SET(VISO2 "//")
ELSE()
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${libviso2_LIBRARIES})
ENDIF()
IF(NOT dvo_core_FOUND)
SET(DVO "//")
ELSE()
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${dvo_core_LIBRARIES})
ENDIF()
IF(NOT ORB_SLAM2_FOUND)
SET(ORB_SLAM2 "//")
ELSE()
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} ${ORB_SLAM2_LIBRARIES})
ENDIF()
IF(ADD_VTK_GUI_SUPPORT_QT_TO_CONF)
SET(CONF_VTK_QT true)
SET(CONF_DEPENDENCIES ${CONF_DEPENDENCIES} vtkGUISupportQt)
@@ -496,8 +593,8 @@ file(RELATIVE_PATH REL_LIB_DIR "${CMAKE_INSTALL_PREFIX}/${INSTALL_CMAKE_DIR}" "$
# ... for the build tree
set(CONF_INCLUDE_DIRS "${PROJECT_SOURCE_DIR}/corelib/include"
"${PROJECT_SOURCE_DIR}/guilib/include"
"${PROJECT_SOURCE_DIR}/utilite/include")
"${PROJECT_SOURCE_DIR}/guilib/include"
"${PROJECT_SOURCE_DIR}/utilite/include")
set(CONF_LIB_DIR "${CMAKE_ARCHIVE_OUTPUT_DIRECTORY} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
IF(QT4_FOUND OR Qt5_FOUND)
set(CONF_WITH_GUI ON)
@@ -622,8 +719,8 @@ MESSAGE(STATUS " BUILD_APP = ${BUILD_APP}")
MESSAGE(STATUS " BUILD_TOOLS = ${BUILD_TOOLS}")
MESSAGE(STATUS " BUILD_EXAMPLES = ${BUILD_EXAMPLES}")
IF(NOT WIN32)
# see comment above for the BUILD_SHARED_LIBS option on Windows
MESSAGE(STATUS " BUILD_SHARED_LIBS = ${BUILD_SHARED_LIBS}")
# see comment above for the BUILD_SHARED_LIBS option on Windows
MESSAGE(STATUS " BUILD_SHARED_LIBS = ${BUILD_SHARED_LIBS}")
ENDIF(NOT WIN32)
IF(APPLE)
MESSAGE(STATUS " BUILD_AS_BUNDLE = ${BUILD_AS_BUNDLE}")
@@ -708,11 +805,15 @@ ELSE()
MESSAGE(STATUS " With GTSAM = NO (GTSAM not found)")
ENDIF()
IF(G2O_FOUND OR GTSAM_FOUND)
IF(WITH_VERTIGO)
MESSAGE(STATUS " With VERTIGO = YES (License: GPLv3)")
ELSE()
MESSAGE(STATUS " With VERTIGO = NO (WITH_VERTIGO=OFF)")
ENDIF()
ELSE()
MESSAGE(STATUS " With VERTIGO = NO (GTSAM or g2o required)")
ENDIF()
IF(cvsba_FOUND)
MESSAGE(STATUS " With cvsba = YES (License: GPLv2)")
@@ -736,6 +837,13 @@ ENDIF()
IF(RealSense_FOUND)
MESSAGE(STATUS " With RealSense = YES (License: Apache-2)")
IF(RealSenseSlam_FOUND)
MESSAGE(STATUS " With RealSenseSlam = YES")
ELSEIF(NOT WITH_REALSENSE)
MESSAGE(STATUS " With RealSenseSlam = NO (librealsense_slam not found)")
ELSE()
MESSAGE(STATUS " With RealSenseSlam = NO (WITH_REALSENSE_SLAM=OFF)")
ENDIF()
ELSEIF(NOT WITH_REALSENSE)
MESSAGE(STATUS " With RealSense = NO (WITH_REALSENSE=OFF)")
ELSE()
@@ -750,6 +858,48 @@ ELSE()
MESSAGE(STATUS " With OCTOMAP = NO (octomap not found)")
ENDIF()
IF(CPUTSDF_FOUND)
MESSAGE(STATUS " With CPUTSDF = YES (License: BSD)")
ELSEIF(NOT WITH_CPUTSDF)
MESSAGE(STATUS " With CPUTSDF = NO (WITH_CPUTSDF=OFF)")
ELSE()
MESSAGE(STATUS " With CPUTSDF = NO (CPUTSDF not found)")
ENDIF()
IF(libfovis_FOUND)
MESSAGE(STATUS " With libfovis = YES (License: GPLv2)")
ELSEIF(NOT WITH_FOVIS)
MESSAGE(STATUS " With libfovis = NO (WITH_FOVIS=OFF)")
ELSE()
MESSAGE(STATUS " With libfovis = NO (libfovis not found)")
ENDIF()
IF(libviso2_FOUND)
MESSAGE(STATUS " With libviso2 = YES (License: GPLv3)")
ELSEIF(NOT WITH_VISO2)
MESSAGE(STATUS " With libviso2 = NO (WITH_VISO2=OFF)")
ELSE()
MESSAGE(STATUS " With libviso2 = NO (libviso2 not found)")
ENDIF()
IF(dvo_core_FOUND)
MESSAGE(STATUS " With dvo_core = YES (License: GPLv3)")
ELSEIF(NOT WITH_DVO)
MESSAGE(STATUS " With dvo_core = NO (WITH_DVO=OFF)")
ELSE()
MESSAGE(STATUS " With dvo_core = NO (dvo_core not found)")
ENDIF()
IF(ORB_SLAM2_FOUND)
MESSAGE(STATUS " With ORB_SLAM2 = YES (License: GPLv3)")
ELSEIF(NOT WITH_ORB_SLAM2)
MESSAGE(STATUS " With ORB_SLAM2 = NO (WITH_ORB_SLAM2=OFF)")
ELSEIF(G2O_FOUND)
MESSAGE(STATUS " With ORB_SLAM2 = NO (WITH_G2O should be OFF as ORB_SLAM2 uses its own g2o version)")
ELSE()
MESSAGE(STATUS " With ORB_SLAM2 = NO (ORB_SLAM2 not found, make sure environment variable ORB_SLAM2_ROOT_DIR is set)")
ENDIF()
IF(QT4_FOUND)
MESSAGE(STATUS " With Qt4 = YES (License: Open Source or Commercial)")
ELSEIF(Qt5_FOUND)
@@ -768,3 +918,5 @@ MESSAGE(SEND_ERROR "No graph optimizer found! You should have at least one of th
GTSAM (https://collab.cc.gatech.edu/borg/gtsam)
set -DWITH_TORO=ON")
ENDIF(NOT GTSAM_FOUND AND NOT G2O_FOUND AND NOT WITH_TORO)
# vim: set et ft=cmake fenc=utf-8 ff=unix sts=0 sw=2 ts=2 :

View File

@@ -6,5 +6,3 @@ RTAB-Map library and standalone application.
For more information, visit the [RTAB-Map's home page](http://introlab.github.io/rtabmap) or the [RTAB-Map's wiki](https://github.com/introlab/rtabmap/wiki).
To use RTAB-Map under ROS, visit the [rtabmap](http://wiki.ros.org/rtabmap) page on the ROS wiki.

View File

@@ -1,4 +1,8 @@
# - Config file for the RTABMap package
# Components:
# core (required)
# gui (optional)
# utilite (required)
# It defines the following variables
# RTABMap_INCLUDE_DIRS - include directories for RTABMap
# RTABMap_LIBRARIES - libraries to link against
@@ -42,8 +46,18 @@ ENDIF()
set(RTABMap_LIBRARIES ${RTABMap_CORE} ${RTABMap_UTILITE})
list(LENGTH RTABMap_FIND_COMPONENTS RTABMap_FIND_COMPONENTS_LENGTH)
set(WITH_GUI ON)
if(${RTABMap_FIND_COMPONENTS_LENGTH} GREATER 0)
list (FIND RTABMap_FIND_COMPONENTS "gui" _index)
if (${_index} EQUAL -1)
set(WITH_GUI OFF)
endif()
endif(${RTABMap_FIND_COMPONENTS_LENGTH} GREATER 0)
#gui lib (OFF if RTAB-Map is not built with Qt)
if(@CONF_WITH_GUI@)
if(@CONF_WITH_GUI@ AND ${WITH_GUI})
find_library(RTABMap_GUI_RELEASE NAMES rtabmap_gui NO_DEFAULT_PATH HINTS @CONF_LIB_DIR@)
find_library(RTABMap_GUI_DEBUG NAMES rtabmap_guid NO_DEFAULT_PATH HINTS @CONF_LIB_DIR@)
@@ -59,13 +73,15 @@ if(@CONF_WITH_GUI@)
ENDIF()
set(RTABMap_LIBRARIES ${RTABMap_LIBRARIES} ${RTABMap_GUI})
endif(@CONF_WITH_GUI@)
elseif(${WITH_GUI})
MESSAGE(ERROR "Asked for \"gui\" module but RTABMap hasn't been built with gui support.")
endif()
# Dependencies
if(@CONF_VTK_QT@)
if(@CONF_VTK_QT@ AND ${WITH_GUI})
find_package(VTK COMPONENTS vtkGUISupportQt NO_MODULE) # to define vtkGUISupportQt target
endif(@CONF_VTK_QT@)
set(RTABMap_LIBRARIES ${RTABMap_LIBRARIES} @CONF_DEPENDENCIES@)
endif(@CONF_VTK_QT@ AND ${WITH_GUI})
SET(RTABMap_LIBRARIES ${RTABMap_LIBRARIES} "@CONF_DEPENDENCIES@")
#backward compatibilities
set(RTABMAP_CORE ${RTABMap_CORE})
@@ -74,3 +90,7 @@ if(RTABMap_GUI)
set(RTABMAP_GUI ${RTABMap_GUI})
set(RTABMAP_QT_VERSION @CONF_QT_VERSION@)
endif(RTABMap_GUI)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(RTABMap DEFAULT_MSG RTABMap_LIBRARIES RTABMap_INCLUDE_DIRS)
mark_as_advanced(RTABMap_LIBRARIES RTABMap_INCLUDE_DIRS RTABMap_LIBRARY_DIRS)

View File

@@ -51,7 +51,13 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@FLYCAPTURE2@#define RTABMAP_FLYCAPTURE2
@ZED@#define RTABMAP_ZED
@REALSENSE@#define RTABMAP_REALSENSE
@REALSENSESLAM@#define RTABMAP_REALSENSE_SLAM
@OCTOMAP@#define RTABMAP_OCTOMAP
@CPUTSDF@#define RTABMAP_CPUTSDF
@FOVIS@#define RTABMAP_FOVIS
@VISO2@#define RTABMAP_VISO2
@DVO@#define RTABMAP_DVO
@ORB_SLAM2@#define RTABMAP_ORB_SLAM2
#endif /* VERSION_H_ */

1
app/android/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
/bin/

View File

@@ -2,7 +2,7 @@
<!-- BEGIN_INCLUDE(manifest) -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.introlab.rtabmap"
android:versionCode="29"
android:versionCode="55"
android:versionName="@RTABMAP_VERSION@">
<uses-permission android:name="android.permission.CAMERA" />
@@ -10,15 +10,18 @@
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
<uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-feature android:glEsVersion="0x00020000" />
<!-- This is the platform API where NativeActivity was introduced. -->
<uses-sdk android:minSdkVersion="17" />
<uses-sdk android:minSdkVersion="19" />
<!-- This .apk has no Java code itself, so set hasCode to false. -->
<application
android:label="@string/app_name"
android:icon="@drawable/ic_launcher">
android:icon="@drawable/ic_launcher"
android:debuggable="@ANDROID_DEBUGGABLE@">
<uses-library android:name="com.projecttango.libtango_device2" android:required="true" />
@@ -27,7 +30,9 @@
<activity android:name="RTABMapActivity"
android:label="@string/app_name"
android:launchMode="singleTask"
android:screenOrientation="landscape">
android:screenOrientation="fullSensor"
android:configChanges="orientation|screenSize|keyboardHidden"
android:theme="@style/ThemeApp">
<!-- Tell NativeActivity the name of our .so -->
<meta-data android:name="android.app.lib_name"
android:value="NativeRTABMap" />
@@ -36,6 +41,9 @@
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="SettingsActivity" android:label="@string/settings" android:screenOrientation="fullSensor"/>
<activity android:name="SketchfabActivity" android:label="@string/sketchfab" android:screenOrientation="fullSensor"/>
</application>
</manifest>

View File

@@ -1,4 +1,17 @@
option(DISABLE_LOG "Disable Android logging (should be true in release)" ON)
IF(DISABLE_LOG)
ADD_DEFINITIONS(-DDISABLE_LOG)
ENDIF(DISABLE_LOG)
MESSAGE(STATUS "DISABLE_LOG = ${DISABLE_LOG}")
IF(DISABLE_LOG)
SET(ANDROID_DEBUGGABLE false)
ELSE()
SET(ANDROID_DEBUGGABLE true)
ENDIF()
add_subdirectory(jni)
@@ -32,6 +45,11 @@ configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/ant.properties.in"
"${CMAKE_CURRENT_BINARY_DIR}/ant.properties"
@ONLY)
configure_file(
"${CMAKE_CURRENT_SOURCE_DIR}/custom_rules.xml"
"${CMAKE_CURRENT_BINARY_DIR}/custom_rules.xml"
COPYONLY)
add_custom_target(NativeRTABMap-ant-configure ALL
COMMAND "${ANDROID_EXECUTABLE}"

View File

@@ -1,5 +1,6 @@
builddir=@CMAKE_CURRENT_BINARY_DIR@
srcdir=@CMAKE_CURRENT_SOURCE_DIR@
android.abi=@ANDROID_ABI@
source.dir=${srcdir}/src
gen.dir=${builddir}/gen

View File

@@ -0,0 +1,13 @@
<project>
<target name="-pre-build">
<copy todir="${jar.libs.dir}">
<fileset dir="${srcdir}/libs" includes="**/*.jar" excludes="**/*sources.jar, **/*javadoc.jar" />
</copy>
<copy todir="${native.libs.dir}/${android.abi}">
<fileset dir="${srcdir}/jni/third-party/lib" includes="*.so"/>
</copy>
<copy todir="${native.libs.dir}">
<fileset dir="${srcdir}/jni/third-party/lib" includes="${android.abi}/*.so"/>
</copy>
</target>
</project>

View File

@@ -1,8 +1,7 @@
<h3>Real-Time Appearance-Based Mapping</h3>
Version @RTABMAP_VERSION@<br>
Author: Mathieu Labb&eacute;<br>
Copyright 2016<br>
Copyright 2016-2017<br>
IntRoLab - Universit&eacute; de Sherbrooke<br>
<b>http://introlab.github.io/rtabmap</b><br><br>

View File

@@ -40,13 +40,16 @@ namespace rtabmap {
const int kVersionStringLength = 128;
const int holeSize = 5;
const float maxDepthError = 0.10;
const int scanDownsampling = 10;
const int scanDownsampling = 1;
// Callbacks
void onPointCloudAvailableRouter(void* context, const TangoPointCloud* point_cloud)
{
CameraTango* app = static_cast<CameraTango*>(context);
app->cloudReceived(cv::Mat(1, point_cloud->num_points, CV_32FC4, point_cloud->points[0]), point_cloud->timestamp);
if(point_cloud->num_points>0)
{
app->cloudReceived(cv::Mat(1, point_cloud->num_points, CV_32FC4, point_cloud->points[0]), point_cloud->timestamp);
}
}
void onFrameAvailableRouter(void* context, TangoCameraId id, const TangoImageBuffer* color)
@@ -65,6 +68,10 @@ void onFrameAvailableRouter(void* context, TangoCameraId id, const TangoImageBuf
{
tangoImage = cv::Mat(color->height+color->height/2, color->width, CV_8UC1, color->data);
}
else if(color->format == 35)
{
tangoImage = cv::Mat(color->height+color->height/2, color->width, CV_8UC1, color->data);
}
else
{
LOGE("Not supported color format : %d.", color->format);
@@ -94,15 +101,22 @@ void onTangoEventAvailableRouter(void* context, const TangoEvent* event)
//////////////////////////////
// CameraTango
//////////////////////////////
CameraTango::CameraTango(int decimation, bool autoExposure) :
const float CameraTango::bilateralFilteringSigmaS = 2.0f;
const float CameraTango::bilateralFilteringSigmaR = 0.075f;
CameraTango::CameraTango(bool colorCamera, int decimation, bool publishRawScan, bool smoothing) :
Camera(0),
tango_config_(0),
firstFrame_(true),
previousStamp_(0.0),
stampEpochOffset_(0.0),
colorCamera_(colorCamera),
decimation_(decimation),
autoExposure_(autoExposure),
rawScanPublished_(publishRawScan),
smoothing_(smoothing),
cloudStamp_(0),
tangoColorType_(0),
tangoColorStamp_(0)
tangoColorStamp_(0),
colorCameraToDisplayRotation_(ROTATION_0)
{
UASSERT(decimation >= 1);
}
@@ -112,11 +126,70 @@ CameraTango::~CameraTango() {
close();
}
// Compute fisheye distorted coordinates from undistorted coordinates.
// The distortion model used by the Tango fisheye camera is called FOV and is
// described in 'Straight lines have to be straight' by Frederic Devernay and
// Olivier Faugeras. See https://hal.inria.fr/inria-00267247/document.
// Tango ROS Streamer: https://github.com/Intermodalics/tango_ros/blob/master/tango_ros_common/tango_ros_native/src/tango_ros_node.cpp
void applyFovModel(
double xu, double yu, double w, double w_inverse, double two_tan_w_div_two,
double* xd, double* yd) {
double ru = sqrt(xu * xu + yu * yu);
constexpr double epsilon = 1e-7;
if (w < epsilon || ru < epsilon) {
*xd = xu;
*yd = yu ;
} else {
double rd_div_ru = std::atan(ru * two_tan_w_div_two) * w_inverse / ru;
*xd = xu * rd_div_ru;
*yd = yu * rd_div_ru;
}
}
// Compute the warp maps to undistort the Tango fisheye image using the FOV
// model. See OpenCV documentation for more information on warp maps:
// http://docs.opencv.org/2.4/modules/imgproc/doc/geometric_transformations.html
// Tango ROS Streamer: https://github.com/Intermodalics/tango_ros/blob/master/tango_ros_common/tango_ros_native/src/tango_ros_node.cpp
// @param fisheyeModel the fisheye camera intrinsics.
// @param mapX the output map for the x direction.
// @param mapY the output map for the y direction.
void initFisheyeRectificationMap(
const CameraModel& fisheyeModel,
cv::Mat & mapX, cv::Mat & mapY) {
const double & fx = fisheyeModel.K().at<double>(0,0);
const double & fy = fisheyeModel.K().at<double>(1,1);
const double & cx = fisheyeModel.K().at<double>(0,2);
const double & cy = fisheyeModel.K().at<double>(1,2);
const double & w = fisheyeModel.D().at<double>(0,0);
mapX.create(fisheyeModel.imageSize(), CV_32FC1);
mapY.create(fisheyeModel.imageSize(), CV_32FC1);
LOGD("initFisheyeRectificationMap: fx=%f fy=%f, cx=%f, cy=%f, w=%f", fx, fy, cx, cy, w);
// Pre-computed variables for more efficiency.
const double fy_inverse = 1.0 / fy;
const double fx_inverse = 1.0 / fx;
const double w_inverse = 1 / w;
const double two_tan_w_div_two = 2.0 * std::tan(w * 0.5);
// Compute warp maps in x and y directions.
// OpenCV expects maps from dest to src, i.e. from undistorted to distorted
// pixel coordinates.
for(int iu = 0; iu < fisheyeModel.imageHeight(); ++iu) {
for (int ju = 0; ju < fisheyeModel.imageWidth(); ++ju) {
double xu = (ju - cx) * fx_inverse;
double yu = (iu - cy) * fy_inverse;
double xd, yd;
applyFovModel(xu, yu, w, w_inverse, two_tan_w_div_two, &xd, &yd);
double jd = cx + xd * fx;
double id = cy + yd * fy;
mapX.at<float>(iu, ju) = jd;
mapY.at<float>(iu, ju) = id;
}
}
}
bool CameraTango::init(const std::string & calibrationFolder, const std::string & cameraName)
{
close();
TangoSupport_initializeLibrary();
TangoSupport_initialize(TangoService_getPoseAtTime, TangoService_getCameraIntrinsics);
// Connect to Tango
LOGI("NativeRTABMap: Setup tango config");
@@ -136,38 +209,15 @@ bool CameraTango::init(const std::string & calibrationFolder, const std::string
return false;
}
// Enable color.
ret = TangoConfig_setBool(tango_config_, "config_enable_color_camera", true);
if (ret != TANGO_SUCCESS)
if(colorCamera_)
{
LOGE("NativeRTABMap: config_enable_color_camera() failed with error code: %d", ret);
return false;
}
// disable auto exposure (disabled, seems broken on latest Tango releases)
ret = TangoConfig_setBool(tango_config_, "config_color_mode_auto", autoExposure_);
if (ret != TANGO_SUCCESS)
{
LOGE("NativeRTABMap: config_color_mode_auto() failed with error code: %d", ret);
//return false;
}
else
{
if(!autoExposure_)
// Enable color.
ret = TangoConfig_setBool(tango_config_, "config_enable_color_camera", true);
if (ret != TANGO_SUCCESS)
{
ret = TangoConfig_setInt32(tango_config_, "config_color_iso", 800);
if (ret != TANGO_SUCCESS)
{
LOGE("NativeRTABMap: config_color_iso() failed with error code: %d", ret);
return false;
}
LOGE("NativeRTABMap: config_enable_color_camera() failed with error code: %d", ret);
return false;
}
bool verifyAutoExposureState;
int32_t verifyIso, verifyExp;
TangoConfig_getBool( tango_config_, "config_color_mode_auto", &verifyAutoExposureState );
TangoConfig_getInt32( tango_config_, "config_color_iso", &verifyIso );
TangoConfig_getInt32( tango_config_, "config_color_exp", &verifyExp );
LOGI( "NativeRTABMap: config_color autoExposure=%s %d %d", verifyAutoExposureState?"On" : "Off", verifyIso, verifyExp );
}
// Enable depth.
@@ -232,7 +282,7 @@ bool CameraTango::init(const std::string & calibrationFolder, const std::string
return false;
}
ret = TangoService_connectOnFrameAvailable(TANGO_CAMERA_COLOR, this, onFrameAvailableRouter);
ret = TangoService_connectOnFrameAvailable(colorCamera_?TANGO_CAMERA_COLOR:TANGO_CAMERA_FISHEYE, this, onFrameAvailableRouter);
if (ret != TANGO_SUCCESS)
{
LOGE("NativeRTABMap: Failed to connect to color callback with error code: %d", ret);
@@ -281,7 +331,7 @@ bool CameraTango::init(const std::string & calibrationFolder, const std::string
//
// Get color camera with respect to device transformation matrix.
frame_pair.base = TANGO_COORDINATE_FRAME_DEVICE;
frame_pair.target = TANGO_COORDINATE_FRAME_CAMERA_COLOR;
frame_pair.target = colorCamera_?TANGO_COORDINATE_FRAME_CAMERA_COLOR:TANGO_COORDINATE_FRAME_CAMERA_FISHEYE;
ret = TangoService_getPoseAtTime(0.0, frame_pair, &pose_data);
if (ret != TANGO_SUCCESS)
{
@@ -299,22 +349,67 @@ bool CameraTango::init(const std::string & calibrationFolder, const std::string
// camera intrinsic
TangoCameraIntrinsics color_camera_intrinsics;
ret = TangoService_getCameraIntrinsics(TANGO_CAMERA_COLOR, &color_camera_intrinsics);
ret = TangoService_getCameraIntrinsics(colorCamera_?TANGO_CAMERA_COLOR:TANGO_CAMERA_FISHEYE, &color_camera_intrinsics);
if (ret != TANGO_SUCCESS)
{
LOGE("NativeRTABMap: Failed to get the intrinsics for the color camera with error code: %d.", ret);
return false;
}
model_ = CameraModel(
LOGD("Calibration: fx=%f fy=%f cx=%f cy=%f width=%d height=%d",
color_camera_intrinsics.fx,
color_camera_intrinsics.fy,
color_camera_intrinsics.cx,
color_camera_intrinsics.cy,
this->getLocalTransform());
model_.setImageSize(cv::Size(color_camera_intrinsics.width, color_camera_intrinsics.height));
color_camera_intrinsics.width,
color_camera_intrinsics.height);
// device to camera optical rotation in rtabmap frame
model_.setLocalTransform(tango_device_T_rtabmap_device.inverse()*deviceTColorCamera_);
cv::Mat K = cv::Mat::eye(3, 3, CV_64FC1);
K.at<double>(0,0) = color_camera_intrinsics.fx;
K.at<double>(1,1) = color_camera_intrinsics.fy;
K.at<double>(0,2) = color_camera_intrinsics.cx;
K.at<double>(1,2) = color_camera_intrinsics.cy;
cv::Mat D = cv::Mat::zeros(1, 5, CV_64FC1);
LOGD("Calibration type = %d", color_camera_intrinsics.calibration_type);
if(color_camera_intrinsics.calibration_type == TANGO_CALIBRATION_POLYNOMIAL_5_PARAMETERS ||
color_camera_intrinsics.calibration_type == TANGO_CALIBRATION_EQUIDISTANT)
{
D.at<double>(0,0) = color_camera_intrinsics.distortion[0];
D.at<double>(0,1) = color_camera_intrinsics.distortion[1];
D.at<double>(0,2) = color_camera_intrinsics.distortion[2];
D.at<double>(0,3) = color_camera_intrinsics.distortion[3];
D.at<double>(0,4) = color_camera_intrinsics.distortion[4];
}
else if(color_camera_intrinsics.calibration_type == TANGO_CALIBRATION_POLYNOMIAL_3_PARAMETERS)
{
D.at<double>(0,0) = color_camera_intrinsics.distortion[0];
D.at<double>(0,1) = color_camera_intrinsics.distortion[1];
D.at<double>(0,2) = 0.;
D.at<double>(0,3) = 0.;
D.at<double>(0,4) = color_camera_intrinsics.distortion[2];
}
else if(color_camera_intrinsics.calibration_type == TANGO_CALIBRATION_POLYNOMIAL_2_PARAMETERS)
{
D.at<double>(0,0) = color_camera_intrinsics.distortion[0];
D.at<double>(0,1) = color_camera_intrinsics.distortion[1];
D.at<double>(0,2) = 0.;
D.at<double>(0,3) = 0.;
D.at<double>(0,4) = 0.;
}
cv::Mat R = cv::Mat::eye(3, 3, CV_64FC1);
cv::Mat P;
LOGD("Distortion params: %f, %f, %f, %f, %f", D.at<double>(0,0), D.at<double>(0,1), D.at<double>(0,2), D.at<double>(0,3), D.at<double>(0,4));
model_ = CameraModel(colorCamera_?"color":"fisheye",
cv::Size(color_camera_intrinsics.width, color_camera_intrinsics.height),
K, D, R, P,
tango_device_T_rtabmap_device.inverse()*deviceTColorCamera_); // device to camera optical rotation in rtabmap frame
if(!colorCamera_)
{
initFisheyeRectificationMap(model_, fisheyeRectifyMapX_, fisheyeRectifyMapY_);
}
LOGI("deviceTColorCameraTango =%s", deviceTColorCamera_.prettyPrint().c_str());
LOGI("deviceTColorCameraRtabmap=%s", (tango_device_T_rtabmap_device.inverse()*deviceTColorCamera_).prettyPrint().c_str());
@@ -332,46 +427,43 @@ void CameraTango::close()
tango_config_ = nullptr;
TangoService_disconnect();
}
firstFrame_ = true;
previousPose_.setNull();
previousStamp_ = 0.0;
fisheyeRectifyMapX_ = cv::Mat();
fisheyeRectifyMapY_ = cv::Mat();
}
void CameraTango::cloudReceived(const cv::Mat & cloud, double timestamp)
{
if(this->isRunning())
if(this->isRunning() && !cloud.empty())
{
//LOGD("Depth received! %fs (%d points)", timestamp, cloud.cols);
UASSERT(cloud.type() == CV_32FC4);
boost::mutex::scoped_lock lock(dataMutex_);
bool notify = cloud_.empty();
cloud_ = cloud.clone();
cloudStamp_ = timestamp;
LOGD("Depth received! (%d points)", cloud.cols);
if(!tangoColor_.empty() && notify)
// From post: http://stackoverflow.com/questions/29236110/timing-issues-with-tango-image-frames
// "In the current version of Project Tango Tablet RGB IR camera
// is used for both depth and color images and it can only do one
// or the other for each frame. So in the stream we get 4 RGB frames
// followed by 1 Depth frame resulting in the pattern you observed. This
// is more of a hardware limitation."
//
// So, synchronize with the last RGB frame before the Depth is acquired
if(!tangoColor_.empty())
{
LOGD("Cloud: Release semaphore");
dataReady_.release();
}
}
}
double dt = fabs(timestamp - tangoColorStamp_);
void CameraTango::rgbReceived(const cv::Mat & tangoImage, int type, double timestamp)
{
if(this->isRunning())
{
boost::mutex::scoped_lock lock(dataMutex_);
//LOGD("Depth: %f vs %f = %f", tangoColorStamp_, timestamp, dt);
if(!cloud_.empty())
{
if(!tangoImage.empty())
if(dt >= 0.0 && dt < 0.5)
{
bool notify = tangoColor_.empty();
tangoColor_ = tangoImage.clone();
tangoColorStamp_ = timestamp;
tangoColorType_ = type;
LOGD("RGB received!");
if(!cloud_.empty() && notify)
bool notify = cloud_.empty();
cloud_ = cloud.clone();
cloudStamp_ = timestamp;
if(notify)
{
LOGD("RGB: Release semaphore");
//LOGD("Cloud: Release semaphore");
dataReady_.release();
}
}
@@ -379,7 +471,21 @@ void CameraTango::rgbReceived(const cv::Mat & tangoImage, int type, double times
}
}
static rtabmap::Transform opticalRotationTango(
void CameraTango::rgbReceived(const cv::Mat & tangoImage, int type, double timestamp)
{
if(this->isRunning() && !tangoImage.empty())
{
//LOGD("RGB received! %fs", timestamp);
boost::mutex::scoped_lock lock(dataMutex_);
tangoColor_ = tangoImage.clone();
tangoColorStamp_ = timestamp;
tangoColorType_ = type;
}
}
static rtabmap::Transform opticalRotation(
1.0f, 0.0f, 0.0f, 0.0f,
0.0f, -1.0f, 0.0f, 0.0f,
0.0f, 0.0f, -1.0f, 0.0f);
@@ -388,7 +494,7 @@ void CameraTango::poseReceived(const Transform & pose)
if(!pose.isNull() && pose.getNormSquared() < 100000)
{
// send pose of the camera (without optical rotation), not the device
this->post(new PoseEvent(pose*deviceTColorCamera_*opticalRotationTango));
this->post(new PoseEvent(pose*deviceTColorCamera_*opticalRotation));
}
}
@@ -458,7 +564,7 @@ rtabmap::Transform CameraTango::getPoseAtTimestamp(double timestamp)
SensorData CameraTango::captureImage(CameraInfo * info)
{
LOGI("Capturing image...");
//LOGI("Capturing image...");
SensorData data;
if(!dataReady_.acquire(1, 2000))
@@ -503,6 +609,7 @@ SensorData CameraTango::captureImage(CameraInfo * info)
tangoColorType_ = 0;
}
LOGD("tangoColorType=%d", tangoColorType);
if(tangoColorType == TANGO_HAL_PIXEL_FORMAT_RGBA_8888)
{
cv::cvtColor(tangoImage, rgb, CV_RGBA2BGR);
@@ -515,6 +622,10 @@ SensorData CameraTango::captureImage(CameraInfo * info)
{
cv::cvtColor(tangoImage, rgb, CV_YUV2BGR_NV21);
}
else if(tangoColorType == 35)
{
cv::cvtColor(tangoImage, rgb, cv::COLOR_YUV420sp2GRAY);
}
else
{
LOGE("Not supported color format : %d.", tangoColorType);
@@ -527,10 +638,22 @@ SensorData CameraTango::captureImage(CameraInfo * info)
//}
CameraModel model = model_;
if(decimation_ > 1)
if(colorCamera_)
{
rgb = util2d::decimate(rgb, decimation_);
model = model.scaled(1.0/double(decimation_));
if(decimation_ > 1)
{
rgb = util2d::decimate(rgb, decimation_);
model = model.scaled(1.0/double(decimation_));
}
}
else
{
//UTimer t;
cv::Mat rgbRect;
cv::remap(rgb, rgbRect, fisheyeRectifyMapX_, fisheyeRectifyMapY_, cv::INTER_LINEAR, cv::BORDER_CONSTANT, 0);
rgb = rgbRect;
//LOGD("Rectification time=%fs", t.ticks());
}
// Querying the depth image's frame transformation based on the depth image's
@@ -543,7 +666,7 @@ SensorData CameraTango::captureImage(CameraInfo * info)
Transform colorToDepth;
TangoPoseData pose_color_image_t1_T_depth_image_t0;
if (TangoSupport_calculateRelativePose(
rgbStamp, TANGO_COORDINATE_FRAME_CAMERA_COLOR, cloudStamp,
rgbStamp, colorCamera_?TANGO_COORDINATE_FRAME_CAMERA_COLOR:TANGO_COORDINATE_FRAME_CAMERA_FISHEYE, cloudStamp,
TANGO_COORDINATE_FRAME_CAMERA_DEPTH,
&pose_color_image_t1_T_depth_image_t0) == TANGO_SUCCESS)
{
@@ -567,47 +690,67 @@ SensorData CameraTango::captureImage(CameraInfo * info)
{
// The Color Camera frame at timestamp t0 with respect to Depth
// Camera frame at timestamp t1.
LOGI("colorToDepth=%s", colorToDepth.prettyPrint().c_str());
//LOGD("colorToDepth=%s", colorToDepth.prettyPrint().c_str());
LOGD("rgb=%dx%d cloud size=%d", rgb.cols, rgb.rows, (int)cloud.total());
int pixelsSet = 0;
depth = cv::Mat::zeros(model_.imageHeight()/8, model_.imageWidth()/8, CV_16UC1); // mm
CameraModel depthModel = model_.scaled(1.0f/8.0f);
std::vector<cv::Point3f> scanData(cloud.total());
int depthSizeDec = colorCamera_?8:1;
depth = cv::Mat::zeros(model_.imageHeight()/depthSizeDec, model_.imageWidth()/depthSizeDec, CV_16UC1); // mm
CameraModel depthModel = model_.scaled(1.0f/float(depthSizeDec));
std::vector<cv::Point3f> scanData(rawScanPublished_?cloud.total():0);
int oi=0;
for(unsigned int i=0; i<cloud.total(); ++i)
{
float * p = cloud.ptr<float>(0,i);
cv::Point3f pt = util3d::transformPoint(cv::Point3f(p[0], p[1], p[2]), colorToDepth);
if(pt.z > 0.0f && i%scanDownsampling == 0)
if(pt.z > 0.0f && i%scanDownsampling == 0 && rawScanPublished_)
{
scanData.at(oi++) = pt;
}
int pixel_x, pixel_y;
int pixel_x_l, pixel_y_l, pixel_x_h, pixel_y_h;
// get the coordinate on image plane.
pixel_x = static_cast<int>((depthModel.fx()) * (pt.x / pt.z) + depthModel.cx());
pixel_y = static_cast<int>((depthModel.fy()) * (pt.y / pt.z) + depthModel.cy());
pixel_x_l = static_cast<int>((depthModel.fx()) * (pt.x / pt.z) + depthModel.cx());
pixel_y_l = static_cast<int>((depthModel.fy()) * (pt.y / pt.z) + depthModel.cy());
pixel_x_h = static_cast<int>((depthModel.fx()) * (pt.x / pt.z) + depthModel.cx() + 0.5f);
pixel_y_h = static_cast<int>((depthModel.fy()) * (pt.y / pt.z) + depthModel.cy() + 0.5f);
unsigned short depth_value(pt.z * 1000.0f);
if(pixel_x>=0 && pixel_x<depth.cols &&
pixel_y>0 && pixel_y<depth.rows &&
bool pixelSet = false;
if(pixel_x_l>=0 && pixel_x_l<depth.cols &&
pixel_y_l>0 && pixel_y_l<depth.rows && // ignore first line
depth_value)
{
unsigned short & depthPixel = depth.at<unsigned short>(pixel_y, pixel_x);
unsigned short & depthPixel = depth.at<unsigned short>(pixel_y_l, pixel_x_l);
if(depthPixel == 0 || depthPixel > depth_value)
{
depthPixel = depth_value;
pixelsSet += 1;
pixelSet = true;
}
}
if(pixel_x_h>=0 && pixel_x_h<depth.cols &&
pixel_y_h>0 && pixel_y_h<depth.rows && // ignore first line
depth_value)
{
unsigned short & depthPixel = depth.at<unsigned short>(pixel_y_h, pixel_x_h);
if(depthPixel == 0 || depthPixel > depth_value)
{
depthPixel = depth_value;
pixelSet = true;
}
}
if(pixelSet)
{
pixelsSet += 1;
}
}
if(oi)
{
scan = cv::Mat(1, oi, CV_32FC3, scanData.data()).clone();
}
LOGI("pixels depth set= %d", pixelsSet);
//LOGD("pixels depth set= %d", pixelsSet);
}
else
{
@@ -620,17 +763,79 @@ SensorData CameraTango::captureImage(CameraInfo * info)
Transform poseDevice = getPoseAtTimestamp(rgbStamp);
LOGD("Local = %s", model.localTransform().prettyPrint().c_str());
LOGD("tango = %s", poseDevice.prettyPrint().c_str());
LOGD("opengl(t)= %s", (opengl_world_T_tango_world * poseDevice).prettyPrint().c_str());
//LOGD("Local = %s", model.localTransform().prettyPrint().c_str());
//LOGD("tango = %s", poseDevice.prettyPrint().c_str());
//LOGD("opengl(t)= %s", (opengl_world_T_tango_world * poseDevice).prettyPrint().c_str());
//Rotate in RTAB-Map's coordinate
Transform odom = rtabmap_world_T_tango_world * poseDevice * tango_device_T_rtabmap_device;
LOGD("rtabmap = %s", odom.prettyPrint().c_str());
LOGD("opengl(r)= %s", (opengl_world_T_rtabmap_world * odom * rtabmap_device_T_opengl_device).prettyPrint().c_str());
//LOGD("rtabmap = %s", odom.prettyPrint().c_str());
//LOGD("opengl(r)= %s", (opengl_world_T_rtabmap_world * odom * rtabmap_device_T_opengl_device).prettyPrint().c_str());
data = SensorData(scan, LaserScanInfo(cloud.total()/scanDownsampling, 0, model.localTransform()), rgb, depth, model, this->getNextSeqID(), rgbStamp);
Transform scanLocalTransform = model.localTransform();
// Rotate image depending on the camera orientation
if(colorCameraToDisplayRotation_ == ROTATION_90)
{
cv::Mat rgbt(rgb.cols, rgb.rows, rgb.type());
cv::flip(rgb,rgb,1);
cv::transpose(rgb,rgbt);
rgb = rgbt;
cv::Mat deptht(depth.cols, depth.rows, depth.type());
cv::flip(depth,depth,1);
cv::transpose(depth,deptht);
depth = deptht;
cv::Size sizet(model.imageHeight(), model.imageWidth());
model = CameraModel(model.fy(), model.fx(), model.cy(), model.cx()>0?model.imageWidth()-model.cx():0, model.localTransform()*rtabmap::Transform(0,0,0,0,0,1.57079632679489661923132169163975144));
model.setImageSize(sizet);
}
else if(colorCameraToDisplayRotation_ == ROTATION_180)
{
cv::flip(rgb,rgb,1);
cv::flip(rgb,rgb,0);
cv::flip(depth,depth,1);
cv::flip(depth,depth,0);
cv::Size sizet(model.imageWidth(), model.imageHeight());
model = CameraModel(
model.fx(),
model.fy(),
model.cx()>0?model.imageWidth()-model.cx():0,
model.cy()>0?model.imageHeight()-model.cy():0,
model.localTransform()*rtabmap::Transform(0,0,0,0,0,1.57079632679489661923132169163975144*2.0));
model.setImageSize(sizet);
}
else if(colorCameraToDisplayRotation_ == ROTATION_270)
{
cv::Mat rgbt(rgb.cols, rgb.rows, rgb.type());
cv::transpose(rgb,rgbt);
cv::flip(rgbt,rgbt,1);
rgb = rgbt;
cv::Mat deptht(depth.cols, depth.rows, depth.type());
cv::transpose(depth,deptht);
cv::flip(deptht,deptht,1);
depth = deptht;
cv::Size sizet(model.imageHeight(), model.imageWidth());
model = CameraModel(model.fy(), model.fx(), model.cy()>0?model.imageHeight()-model.cy():0, model.cx(), model.localTransform()*rtabmap::Transform(0,0,0,0,0,-1.57079632679489661923132169163975144));
model.setImageSize(sizet);
}
if(smoothing_)
{
//UTimer t;
depth = rtabmap::util2d::fastBilateralFiltering(depth, bilateralFilteringSigmaS, bilateralFilteringSigmaR);
data.setDepthOrRightRaw(depth);
//LOGD("Bilateral filtering, time=%fs", t.ticks());
}
if(rawScanPublished_)
{
data = SensorData(scan, LaserScanInfo(cloud.total()/scanDownsampling, 0, scanLocalTransform), rgb, depth, model, this->getNextSeqID(), rgbStamp);
}
else
{
data = SensorData(rgb, depth, model, this->getNextSeqID(), rgbStamp);
}
data.setGroundTruth(odom);
}
else
@@ -661,9 +866,24 @@ void CameraTango::mainLoop()
{
rtabmap::Transform pose = data.groundTruth();
data.setGroundTruth(Transform());
LOGI("Publish odometry message (variance=%f)", firstFrame_?9999:0.0001);
this->post(new OdometryEvent(data, pose, firstFrame_?9999:0.0001, firstFrame_?9999:0.0001));
firstFrame_ = false;
// convert stamp to epoch
bool firstFrame = previousPose_.isNull();
if(firstFrame)
{
stampEpochOffset_ = UTimer::now()-data.stamp();
}
data.setStamp(stampEpochOffset_ + data.stamp());
OdometryInfo info;
if(!firstFrame)
{
info.interval = data.stamp()-previousStamp_;
info.transform = previousPose_.inverse() * pose;
}
info.covariance = cv::Mat::eye(6,6,CV_64FC1) * (firstFrame?9999.0:0.000001);
LOGI("Publish odometry message (variance=%f)", firstFrame?9999:0.000001);
this->post(new OdometryEvent(data, pose, info));
previousPose_ = pose;
previousStamp_ = data.stamp();
}
else if(!this->isKilled())
{

View File

@@ -36,6 +36,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <rtabmap/utilite/UEvent.h>
#include <rtabmap/utilite/UTimer.h>
#include <boost/thread/mutex.hpp>
#include <tango_support_api.h>
class TangoPoseData;
@@ -70,7 +71,11 @@ private:
class CameraTango : public Camera, public UThread, public UEventsSender {
public:
CameraTango(int decimation, bool autoExposure);
static const float bilateralFilteringSigmaS;
static const float bilateralFilteringSigmaR;
public:
CameraTango(bool colorCamera, int decimation, bool publishRawScan, bool smoothing);
virtual ~CameraTango();
virtual bool init(const std::string & calibrationFolder = ".", const std::string & cameraName = "");
@@ -79,8 +84,11 @@ public:
virtual std::string getSerial() const;
const CameraModel & getCameraModel() const {return model_;}
rtabmap::Transform tangoPoseToTransform(const TangoPoseData * tangoPose) const;
void setColorCamera(bool enabled) {if(!this->isRunning()) colorCamera_ = enabled;}
void setDecimation(int value) {decimation_ = value;}
void setAutoExposure(bool enabled) {autoExposure_ = enabled;}
void setSmoothing(bool enabled) {smoothing_ = enabled;}
void setRawScanPublished(bool enabled) {rawScanPublished_ = enabled;}
void setScreenRotation(TangoSupportRotation colorCameraToDisplayRotation) {colorCameraToDisplayRotation_ = colorCameraToDisplayRotation;}
void cloudReceived(const cv::Mat & cloud, double timestamp);
void rgbReceived(const cv::Mat & tangoImage, int type, double timestamp);
@@ -98,10 +106,14 @@ private:
private:
void * tango_config_;
bool firstFrame_;
Transform previousPose_;
double previousStamp_;
UTimer cameraStartedTime_;
double stampEpochOffset_;
bool colorCamera_;
int decimation_;
bool autoExposure_;
bool rawScanPublished_;
bool smoothing_;
cv::Mat cloud_;
double cloudStamp_;
cv::Mat tangoColor_;
@@ -111,6 +123,9 @@ private:
USemaphore dataReady_;
CameraModel model_;
Transform deviceTColorCamera_;
TangoSupportRotation colorCameraToDisplayRotation_;
cv::Mat fisheyeRectifyMapX_;
cv::Mat fisheyeRectifyMapY_;
};
} /* namespace rtabmap */

View File

@@ -0,0 +1,124 @@
/*
* ProgressionStatus.h
*
* Created on: Feb 28, 2017
* Author: mathieu
*/
#ifndef APP_ANDROID_JNI_PROGRESSIONSTATUS_H_
#define APP_ANDROID_JNI_PROGRESSIONSTATUS_H_
#include <rtabmap/core/ProgressState.h>
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UEventsManager.h>
#include <jni.h>
namespace rtabmap {
class ProgressEvent : public UEvent
{
public:
ProgressEvent(int count = 1) : count_(count){}
virtual std::string getClassName() const {return "ProgressEvent";}
int count_;
};
class ProgressionStatus: public ProgressState, public UEventsHandler
{
public:
ProgressionStatus() : count_(0), max_(100), jvm_(0), rtabmap_(0)
{
registerToEventsManager();
}
void setJavaObjects(JavaVM * jvm, jobject rtabmap)
{
jvm_ = jvm;
rtabmap_ = rtabmap;
}
void reset(int max)
{
count_=-1;
max_ = max;
setCanceled(false);
increment();
}
void setMax(int max)
{
max_ = max;
}
int getMax() const {return max_;}
void increment(int count = 1) const
{
UEventsManager::post(new ProgressEvent(count));
}
void finish()
{
}
virtual bool callback(const std::string & msg) const
{
if(!isCanceled())
{
increment();
}
return ProgressState::callback(msg);
}
virtual ~ProgressionStatus(){}
protected:
virtual bool handleEvent(UEvent * event)
{
if(event->getClassName().compare("ProgressEvent") == 0)
{
count_ += ((ProgressEvent*)event)->count_;
// Call JAVA callback
bool success = false;
if(jvm_ && rtabmap_)
{
JNIEnv *env = 0;
jint rs = jvm_->AttachCurrentThread(&env, NULL);
if(rs == JNI_OK && env)
{
jclass clazz = env->GetObjectClass(rtabmap_);
if(clazz)
{
jmethodID methodID = env->GetMethodID(clazz, "updateProgressionCallback", "(II)V" );
if(methodID)
{
env->CallVoidMethod(rtabmap_, methodID,
count_,
max_);
success = true;
}
}
}
jvm_->DetachCurrentThread();
}
if(!success)
{
UERROR("Failed to call rtabmap::updateProgressionCallback");
}
}
return false;
}
private:
int count_;
int max_;
JavaVM *jvm_;
jobject rtabmap_;
};
}
#endif /* APP_ANDROID_JNI_PROGRESSIONSTATUS_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -34,14 +34,16 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <tango_client_api.h> // NOLINT
#include <tango-gl/util.h>
#include <scene.h>
#include <CameraTango.h>
#include <util.h>
#include "scene.h"
#include "CameraTango.h"
#include "util.h"
#include "ProgressionStatus.h"
#include <rtabmap/core/RtabmapThread.h>
#include <rtabmap/utilite/UEventsHandler.h>
#include <boost/thread/mutex.hpp>
#include <pcl/pcl_base.h>
#include <pcl/TextureMesh.h>
// RTABMapApp handles the application lifecycle and resources.
class RTABMapApp : public UEventsHandler {
@@ -52,7 +54,9 @@ class RTABMapApp : public UEventsHandler {
void onCreate(JNIEnv* env, jobject caller_activity);
void openDatabase(const std::string & databasePath = "");
void setScreenRotation(int displayRotation, int cameraRotation);
int openDatabase(const std::string & databasePath, bool databaseInMemory, bool optimize, const std::string & databaseSource=std::string());
bool onTangoServiceConnected(JNIEnv* env, jobject iBinder);
@@ -110,37 +114,73 @@ class RTABMapApp : public UEventsHandler {
float x0, float y0, float x1, float y1);
void setPausedMapping(bool paused);
void setOnlineBlending(bool enabled);
void setMapCloudShown(bool shown);
void setOdomCloudShown(bool shown);
void setMeshRendering(bool enabled, bool withTexture);
void setPointSize(float value);
void setFOV(float angle);
void setOrthoCropFactor(float value);
void setGridRotation(float value);
void setLighting(bool enabled);
void setBackfaceCulling(bool enabled);
void setWireframe(bool enabled);
void setLocalizationMode(bool enabled);
void setTrajectoryMode(bool enabled);
void setGraphOptimization(bool enabled);
void setNodesFiltering(bool enabled);
void setDriftCorrection(bool enabled);
void setGraphVisible(bool visible);
void setGridVisible(bool visible);
void setAutoExposure(bool enabled);
void setRawScanSaved(bool enabled);
void setCameraColor(bool enabled);
void setFullResolution(bool enabled);
void setSmoothing(bool enabled);
void setAppendMode(bool enabled);
void setDataRecorderMode(bool enabled);
void setMaxCloudDepth(float value);
void setMeshDecimation(int value);
void setMinCloudDepth(float value);
void setCloudDensityLevel(int value);
void setMeshAngleTolerance(float value);
void setMeshTriangleSize(int value);
void setClusterRatio(float value);
void setMaxGainRadius(float value);
void setRenderingTextureDecimation(int value);
void setBackgroundColor(float gray);
int setMappingParameter(const std::string & key, const std::string & value);
void resetMapping();
void save(const std::string & databasePath);
bool exportMesh(const std::string & filePath);
void cancelProcessing();
bool exportMesh(
float cloudVoxelSize,
bool regenerateCloud,
bool meshing,
int textureSize,
int textureCount,
int normalK,
bool optimized,
float optimizedVoxelSize,
int optimizedDepth,
int optimizedMaxPolygons,
float optimizedColorRadius,
bool optimizedCleanWhitePolygons,
int optimizedMinClusterSize,
float optimizedMaxTextureDistance,
int optimizedMinTextureClusterSize,
bool blockRendering);
bool postExportation(bool visualize);
bool writeExportedMesh(const std::string & directory, const std::string & name);
int postProcessing(int approach);
protected:
virtual void handleEvent(UEvent * event);
virtual bool handleEvent(UEvent * event);
private:
rtabmap::ParametersMap getRtabmapParameters();
bool smoothMesh(int id, Mesh & mesh);
void gainCompensation(bool full = false);
std::vector<pcl::Vertices> filterOrganizedPolygons(const std::vector<pcl::Vertices> & polygons, int cloudSize) const;
std::vector<pcl::Vertices> filterPolygons(const std::vector<pcl::Vertices> & polygons, int cloudSize) const;
private:
rtabmap::CameraTango * camera_;
@@ -151,49 +191,75 @@ class RTABMapApp : public UEventsHandler {
bool odomCloudShown_;
bool graphOptimization_;
bool nodesFiltering_;
bool driftCorrection_;
bool localizationMode_;
bool trajectoryMode_;
bool autoExposure_;
bool rawScanSaved_;
bool smoothing_;
bool cameraColor_;
bool fullResolution_;
bool appendMode_;
float maxCloudDepth_;
int meshDecimation_;
float minCloudDepth_;
int cloudDensityLevel_;
int meshTrianglePix_;
float meshAngleToleranceDeg_;
float clusterRatio_;
float maxGainRadius_;
int renderingTextureDecimation_;
float backgroundColor_;
rtabmap::ParametersMap mappingParameters_;
bool paused_;
bool dataRecorderMode_;
bool clearSceneOnNextRender_;
bool openingDatabase_;
bool exporting_;
bool postProcessing_;
bool filterPolygonsOnNextRender_;
int gainCompensationOnNextRender_;
bool bilateralFilteringOnNextRender_;
bool takeScreenshotOnNextRender_;
bool cameraJustInitialized_;
int meshDecimation_;
int totalPoints_;
int totalPolygons_;
int lastDrawnCloudsCount_;
float renderingTime_;
double lastPostRenderEventTime_;
long processMemoryUsedBytes;
long processGPUMemoryUsedBytes;
std::map<std::string, float> bufferedStatsData_;
bool visualizingMesh_;
bool exportedMeshUpdated_;
pcl::TextureMesh::Ptr optMesh_;
cv::Mat optTexture_;
// main_scene_ includes all drawable object for visualizing Tango device's
// movement and point cloud.
Scene main_scene_;
std::list<rtabmap::Statistics> rtabmapEvents_;
std::list<rtabmap::RtabmapEvent*> rtabmapEvents_;
std::list<rtabmap::OdometryEvent> odomEvents_;
std::list<rtabmap::Transform> poseEvents_;
rtabmap::Transform mapToOdom_;
boost::mutex rtabmapMutex_;
boost::mutex meshesMutex_;
boost::mutex odomMutex_;
boost::mutex poseMutex_;
boost::mutex renderingMutex_;
USemaphore screenshotReady_;
std::map<int, Mesh> createdMeshes_;
std::map<int, rtabmap::Transform> rawPoses_;
std::pair<rtabmap::RtabmapEventInit::Status, std::string> status_;
rtabmap::ProgressionStatus progressionStatus_;
};
#endif // TANGO_POINT_CLOUD_POINT_CLOUD_APP_H_

View File

@@ -0,0 +1,131 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef BOUNDING_BOX_DRAWABLE_H_
#define BOUNDING_BOX_DRAWABLE_H_
#include "tango-gl/line.h"
class BoundingBoxDrawable : public tango_gl::Line
{
public:
BoundingBoxDrawable() :
Line(3.0f, GL_LINES)
{
vec_vertices_.resize(24);
}
void updateVertices(const pcl::PointXYZ & min, const pcl::PointXYZ & max)
{
int index = 0;
vec_vertices_[index].x = min.x;
vec_vertices_[index].y = min.y;
vec_vertices_[index++].z = min.z;
vec_vertices_[index].x = min.x;
vec_vertices_[index].y = max.y;
vec_vertices_[index++].z = min.z;
vec_vertices_[index].x = min.x;
vec_vertices_[index].y = min.y;
vec_vertices_[index++].z = min.z;
vec_vertices_[index].x = max.x;
vec_vertices_[index].y = min.y;
vec_vertices_[index++].z = min.z;
vec_vertices_[index].x = min.x;
vec_vertices_[index].y = min.y;
vec_vertices_[index++].z = min.z;
vec_vertices_[index].x = min.x;
vec_vertices_[index].y = min.y;
vec_vertices_[index++].z = max.z;
vec_vertices_[index].x = max.x;
vec_vertices_[index].y = max.y;
vec_vertices_[index++].z = max.z;
vec_vertices_[index].x = max.x;
vec_vertices_[index].y = min.y;
vec_vertices_[index++].z = max.z;
vec_vertices_[index].x = max.x;
vec_vertices_[index].y = max.y;
vec_vertices_[index++].z = max.z;
vec_vertices_[index].x = min.x;
vec_vertices_[index].y = max.y;
vec_vertices_[index++].z = max.z;
vec_vertices_[index].x = max.x;
vec_vertices_[index].y = max.y;
vec_vertices_[index++].z = max.z;
vec_vertices_[index].x = max.x;
vec_vertices_[index].y = max.y;
vec_vertices_[index++].z = min.z;
vec_vertices_[index].x = max.x;
vec_vertices_[index].y = min.y;
vec_vertices_[index++].z = min.z;
vec_vertices_[index].x = max.x;
vec_vertices_[index].y = min.y;
vec_vertices_[index++].z = max.z;
vec_vertices_[index].x = max.x;
vec_vertices_[index].y = min.y;
vec_vertices_[index++].z = min.z;
vec_vertices_[index].x = max.x;
vec_vertices_[index].y = max.y;
vec_vertices_[index++].z = min.z;
vec_vertices_[index].x = min.x;
vec_vertices_[index].y = max.y;
vec_vertices_[index++].z = min.z;
vec_vertices_[index].x = max.x;
vec_vertices_[index].y = max.y;
vec_vertices_[index++].z = min.z;
vec_vertices_[index].x = min.x;
vec_vertices_[index].y = max.y;
vec_vertices_[index++].z = min.z;
vec_vertices_[index].x = min.x;
vec_vertices_[index].y = max.y;
vec_vertices_[index++].z = max.z;
vec_vertices_[index].x = min.x;
vec_vertices_[index].y = min.y;
vec_vertices_[index++].z = max.z;
vec_vertices_[index].x = max.x;
vec_vertices_[index].y = min.y;
vec_vertices_[index++].z = max.z;
vec_vertices_[index].x = min.x;
vec_vertices_[index].y = min.y;
vec_vertices_[index++].z = max.z;
vec_vertices_[index].x = min.x;
vec_vertices_[index].y = max.y;
vec_vertices_[index++].z = max.z;
}
};
#endif // TANGO_GL_LINE_H_

View File

@@ -56,19 +56,30 @@ Java_com_introlab_rtabmap_RTABMapLib_onCreate(
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_openEmptyDatabase(
JNIEnv* env, jobject)
Java_com_introlab_rtabmap_RTABMapLib_setScreenRotation(
JNIEnv* env, jobject, int displayRotation, int cameraRotation)
{
return app.openDatabase();
return app.setScreenRotation(displayRotation, cameraRotation);
}
JNIEXPORT void JNICALL
JNIEXPORT int JNICALL
Java_com_introlab_rtabmap_RTABMapLib_openDatabase(
JNIEnv* env, jobject, jstring databasePath)
JNIEnv* env, jobject, jstring databasePath, bool databaseInMemory, bool optimize)
{
std::string databasePathC;
GetJStringContent(env,databasePath,databasePathC);
return app.openDatabase(databasePathC);
return app.openDatabase(databasePathC, databaseInMemory, optimize);
}
JNIEXPORT int JNICALL
Java_com_introlab_rtabmap_RTABMapLib_openDatabase2(
JNIEnv* env, jobject, jstring databaseSource, jstring databasePath, bool databaseInMemory, bool optimize)
{
std::string databasePathC;
GetJStringContent(env,databasePath,databasePathC);
std::string databaseSourceC;
GetJStringContent(env,databaseSource,databaseSourceC);
return app.openDatabase(databasePathC, databaseInMemory, optimize, databaseSourceC);
}
JNIEXPORT bool JNICALL
@@ -127,6 +138,12 @@ Java_com_introlab_rtabmap_RTABMapLib_setPausedMapping(
return app.setPausedMapping(paused);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setOnlineBlending(
JNIEnv*, jobject, bool enabled)
{
return app.setOnlineBlending(enabled);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setMapCloudShown(
JNIEnv*, jobject, bool shown)
{
@@ -145,6 +162,48 @@ Java_com_introlab_rtabmap_RTABMapLib_setMeshRendering(
return app.setMeshRendering(enabled, withTexture);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setPointSize(
JNIEnv*, jobject, float value)
{
return app.setPointSize(value);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setFOV(
JNIEnv*, jobject, float fov)
{
return app.setFOV(fov);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setOrthoCropFactor(
JNIEnv*, jobject, float value)
{
return app.setOrthoCropFactor(value);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setGridRotation(
JNIEnv*, jobject, float value)
{
return app.setGridRotation(value);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setLighting(
JNIEnv*, jobject, bool enabled)
{
return app.setLighting(enabled);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setBackfaceCulling(
JNIEnv*, jobject, bool enabled)
{
return app.setBackfaceCulling(enabled);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setWireframe(
JNIEnv*, jobject, bool enabled)
{
return app.setWireframe(enabled);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setLocalizationMode(
JNIEnv*, jobject, bool enabled)
{
@@ -169,12 +228,6 @@ Java_com_introlab_rtabmap_RTABMapLib_setNodesFiltering(
return app.setNodesFiltering(enabled);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setDriftCorrection(
JNIEnv*, jobject, bool enabled)
{
return app.setDriftCorrection(enabled);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setGraphVisible(
JNIEnv*, jobject, bool visible)
{
@@ -187,10 +240,10 @@ Java_com_introlab_rtabmap_RTABMapLib_setGridVisible(
return app.setGridVisible(visible);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setAutoExposure(
Java_com_introlab_rtabmap_RTABMapLib_setRawScanSaved(
JNIEnv*, jobject, bool enabled)
{
return app.setAutoExposure(enabled);
return app.setRawScanSaved(enabled);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setFullResolution(
@@ -199,6 +252,18 @@ Java_com_introlab_rtabmap_RTABMapLib_setFullResolution(
return app.setFullResolution(enabled);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setSmoothing(
JNIEnv*, jobject, bool enabled)
{
return app.setSmoothing(enabled);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setCameraColor(
JNIEnv*, jobject, bool enabled)
{
return app.setCameraColor(enabled);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setAppendMode(
JNIEnv*, jobject, bool enabled)
{
@@ -217,10 +282,16 @@ Java_com_introlab_rtabmap_RTABMapLib_setMaxCloudDepth(
return app.setMaxCloudDepth(value);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setMeshDecimation(
Java_com_introlab_rtabmap_RTABMapLib_setMinCloudDepth(
JNIEnv*, jobject, float value)
{
return app.setMinCloudDepth(value);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setCloudDensityLevel(
JNIEnv*, jobject, int value)
{
return app.setMeshDecimation(value);
return app.setCloudDensityLevel(value);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setMeshAngleTolerance(
@@ -234,6 +305,30 @@ Java_com_introlab_rtabmap_RTABMapLib_setMeshTriangleSize(
{
return app.setMeshTriangleSize(value);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setClusterRatio(
JNIEnv*, jobject, float value)
{
return app.setClusterRatio(value);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setMaxGainRadius(
JNIEnv*, jobject, float value)
{
return app.setMaxGainRadius(value);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setRenderingTextureDecimation(
JNIEnv*, jobject, int value)
{
return app.setRenderingTextureDecimation(value);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setBackgroundColor(
JNIEnv*, jobject, float value)
{
return app.setBackgroundColor(value);
}
JNIEXPORT jint JNICALL
Java_com_introlab_rtabmap_RTABMapLib_setMappingParameter(
JNIEnv* env, jobject, jstring key, jstring value)
@@ -260,15 +355,71 @@ Java_com_introlab_rtabmap_RTABMapLib_save(
return app.save(databasePathC);
}
JNIEXPORT void JNICALL
Java_com_introlab_rtabmap_RTABMapLib_cancelProcessing(
JNIEnv* env, jobject)
{
return app.cancelProcessing();
}
JNIEXPORT bool JNICALL
Java_com_introlab_rtabmap_RTABMapLib_exportMesh(
JNIEnv* env, jobject, jstring filePath)
JNIEnv* env, jobject,
float cloudVoxelSize,
bool regenerateCloud,
bool meshing,
int textureSize,
int textureCount,
int normalK,
bool optimized,
float optimizedVoxelSize,
int optimizedDepth,
int optimizedMaxPolygons,
float optimizedColorRadius,
bool optimizedCleanWhitePolygons,
int optimizedMinClusterSize,
float optimizedMaxTextureDistance,
int optimizedMinTextureClusterSize,
bool blockRendering)
{
std::string filePathC;
GetJStringContent(env,filePath,filePathC);
return app.exportMesh(filePathC);
return app.exportMesh(
cloudVoxelSize,
regenerateCloud,
meshing,
textureSize,
textureCount,
normalK,
optimized,
optimizedVoxelSize,
optimizedDepth,
optimizedMaxPolygons,
optimizedColorRadius,
optimizedCleanWhitePolygons,
optimizedMinClusterSize,
optimizedMaxTextureDistance,
optimizedMinTextureClusterSize,
blockRendering);
}
JNIEXPORT bool JNICALL
Java_com_introlab_rtabmap_RTABMapLib_postExportation(
JNIEnv* env, jobject, bool visualize)
{
return app.postExportation(visualize);
}
JNIEXPORT bool JNICALL
Java_com_introlab_rtabmap_RTABMapLib_writeExportedMesh(
JNIEnv* env, jobject, jstring directory, jstring name)
{
std::string directoryC;
GetJStringContent(env,directory,directoryC);
std::string nameC;
GetJStringContent(env,name,nameC);
return app.writeExportedMesh(directoryC, nameC);
}
JNIEXPORT int JNICALL
Java_com_introlab_rtabmap_RTABMapLib_postProcessing(
JNIEnv* env, jobject, int approach)

File diff suppressed because it is too large Load Diff

View File

@@ -40,28 +40,41 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
// PointCloudDrawable is responsible for the point cloud rendering.
class PointCloudDrawable {
public:
static void createShaderPrograms();
static void releaseShaderPrograms();
private:
static std::vector<GLuint> shaderPrograms_;
public:
PointCloudDrawable(
GLuint cloudShaderProgram,
GLuint textureShaderProgram,
const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
const pcl::IndicesPtr & indices,
float gain);
float gainR = 1.0f,
float gainG = 1.0f,
float gainB = 1.0f);
PointCloudDrawable(
GLuint cloudShaderProgram,
GLuint textureShaderProgram,
const Mesh & mesh,
const cv::Mat & texture);
bool createWireframe = false);
virtual ~PointCloudDrawable();
void updatePolygons(const std::vector<pcl::Vertices> & polygons);
void updateCloud(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud, const pcl::IndicesPtr & indices, float gain);
void updateMesh(const Mesh & mesh, const cv::Mat & texture);
void updatePolygons(const std::vector<pcl::Vertices> & polygons, const std::vector<pcl::Vertices> & polygonsLowRes = std::vector<pcl::Vertices>(), bool createWireframe = false);
void updateCloud(const pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud, const pcl::IndicesPtr & indices);
void updateMesh(const Mesh & mesh, bool createWireframe = false);
void setPose(const rtabmap::Transform & pose);
void setVisible(bool visible) {visible_=visible;}
rtabmap::Transform getPose() const {return glmToTransform(pose_);}
void setGains(float gainR, float gainG, float gainB) {gainR_ = gainR; gainG_ = gainG; gainB_ = gainB;}
rtabmap::Transform getPose() const {return pose_;}
const glm::mat4 & getPoseGl() const {return poseGl_;}
bool isVisible() const {return visible_;}
bool hasMesh() const {return polygons_.size()!=0;}
bool hasTexture() const {return textures_ != 0;}
float getMinHeight() const {return minHeight_;}
const pcl::PointXYZ & aabbMinModel() const {return aabbMinModel_;}
const pcl::PointXYZ & aabbMaxModel() const {return aabbMaxModel_;}
const pcl::PointXYZ & aabbMinWorld() const {return aabbMinWorld_;}
const pcl::PointXYZ & aabbMaxWorld() const {return aabbMaxWorld_;}
// Update current point cloud data.
//
@@ -69,22 +82,61 @@ class PointCloudDrawable {
// @param view_mat: view matrix from current render camera.
// @param model_mat: model matrix for this point cloud frame.
// @param vertices: all vertices in this point cloud frame.
void Render(const glm::mat4 & projectionMatrix, const glm::mat4 & viewMatrix, bool meshRendering = true, float pointSize = 3.0f, bool textureRendering = false);
void Render(
const glm::mat4 & projectionMatrix,
const glm::mat4 & viewMatrix,
bool meshRendering = true,
float pointSize = 3.0f,
bool textureRendering = false,
bool lighting = true,
float distanceToCamSqr = 0.0f,
const GLuint & depthTexture = 0,
int screenWidth = 0, // nonnull if depthTexture>0
int screenHeight = 0, // nonnull if depthTexture>0
float nearClipPlane = 0, // nonnull if depthTexture>0
float farClipPlane = 0, // nonnull if depthTexture>0
bool packDepthToColorChannel = false,
bool wireFrame = false) const;
private:
template<class PointT>
void updateAABBMinMax(const PointT & pt, pcl::PointXYZ & min, pcl::PointXYZ & max)
{
if(pt.x<min.x) min.x = pt.x;
if(pt.y<min.y) min.y = pt.y;
if(pt.z<min.z) min.z = pt.z;
if(pt.x>max.x) max.x = pt.x;
if(pt.y>max.y) max.y = pt.y;
if(pt.z>max.z) max.z = pt.z;
}
void updateAABBWorld(const rtabmap::Transform & pose);
private:
// Vertex buffer of the point cloud geometry.
GLuint vertex_buffers_;
GLuint textures_;
std::vector<GLushort> polygons_;
std::vector<GLuint> polygons_;
std::vector<GLuint> polygonsLowRes_;
std::vector<GLuint> polygonLines_;
std::vector<GLuint> polygonLinesLowRes_;
std::vector<GLuint> verticesLowRes_;
std::vector<GLuint> verticesLowLowRes_;
int nPoints_;
glm::mat4 pose_;
rtabmap::Transform pose_;
glm::mat4 poseGl_;
bool visible_;
std::vector<int> organizedToDenseIndices_;
bool hasNormals_;
std::vector<unsigned int> organizedToDenseIndices_;
float minHeight_; // odom frame
GLuint cloud_shader_program_;
GLuint texture_shader_program_;
float gainR_;
float gainG_;
float gainB_;
float gain_;
pcl::PointXYZ aabbMinModel_;
pcl::PointXYZ aabbMaxModel_;
pcl::PointXYZ aabbMinWorld_;
pcl::PointXYZ aabbMaxWorld_;
};
#endif // TANGO_POINT_CLOUD_POINT_CLOUD_DRAWABLE_H_

View File

@@ -16,10 +16,18 @@
#include <tango-gl/conversions.h>
#include <tango-gl/gesture_camera.h>
#include <tango-gl/util.h>
#include <rtabmap/utilite/ULogger.h>
#include <rtabmap/utilite/UStl.h>
#include <rtabmap/utilite/UTimer.h>
#include <rtabmap/core/util3d_filtering.h>
#include <rtabmap/core/util3d_transforms.h>
#include <rtabmap/core/util3d_surface.h>
#include <pcl/common/transforms.h>
#include <pcl/common/common.h>
#include <glm/gtx/transform.hpp>
#include "scene.h"
#include "util.h"
@@ -28,7 +36,7 @@
// add an offset in z to our origin. We'll set this offset to 1.3 meters based
// on the average height of a human standing with a Tango device. This allows us
// to place a grid roughly on the ground for most users.
const glm::vec3 kHeightOffset = glm::vec3(0.0f, 1.3f, 0.0f);
const glm::vec3 kHeightOffset = glm::vec3(0.0f, -1.3f, 0.0f);
// Color of the motion tracking trajectory.
const tango_gl::Color kTraceColor(0.66f, 0.66f, 0.66f);
@@ -39,52 +47,6 @@ const tango_gl::Color kGridColor(0.85f, 0.85f, 0.85f);
// Frustum scale.
const glm::vec3 kFrustumScale = glm::vec3(0.4f, 0.3f, 0.5f);
const std::string kPointCloudVertexShader =
"precision mediump float;\n"
"precision mediump int;\n"
"attribute vec3 vertex;\n"
"attribute vec3 color;\n"
"uniform mat4 mvp;\n"
"uniform float point_size;\n"
"varying vec3 v_color;\n"
"void main() {\n"
" gl_Position = mvp*vec4(vertex.x, vertex.y, vertex.z, 1.0);\n"
" gl_PointSize = point_size;\n"
" v_color = color;\n"
"}\n";
const std::string kPointCloudFragmentShader =
"precision mediump float;\n"
"precision mediump int;\n"
"uniform float u_gain;\n"
"varying vec3 v_color;\n"
"void main() {\n"
" gl_FragColor = vec4(v_color.z*u_gain, v_color.y*u_gain, v_color.x*u_gain, 1.0);\n"
"}\n";
const std::string kTextureMeshVertexShader =
"precision mediump float;\n"
"precision mediump int;\n"
"attribute vec3 vertex;\n"
"attribute vec2 a_TexCoordinate;\n"
"uniform mat4 mvp;\n"
"varying vec2 v_TexCoordinate;\n"
"void main() {\n"
" gl_Position = mvp*vec4(vertex.x, vertex.y, vertex.z, 1.0);\n"
" v_TexCoordinate = a_TexCoordinate;\n"
"}\n";
const std::string kTextureMeshFragmentShader =
"precision mediump float;\n"
"precision mediump int;\n"
"uniform sampler2D u_Texture;\n"
"uniform float u_gain;\n"
"varying vec2 v_TexCoordinate;\n"
"void main() {\n"
" gl_FragColor = texture2D(u_Texture, v_TexCoordinate);\n"
" gl_FragColor.x *= u_gain;\n"
" gl_FragColor.y *= u_gain;\n"
" gl_FragColor.z *= u_gain;\n"
"}\n";
const std::string kGraphVertexShader =
"precision mediump float;\n"
"precision mediump int;\n"
@@ -111,93 +73,109 @@ Scene::Scene() :
axis_(0),
frustum_(0),
grid_(0),
box_(0),
trace_(0),
graph_(0),
graphVisible_(true),
gridVisible_(true),
traceVisible_(true),
color_camera_to_display_rotation_(ROTATION_0),
currentPose_(0),
cloud_shader_program_(0),
texture_mesh_shader_program_(0),
graph_shader_program_(0),
blending_(true),
mapRendering_(true),
meshRendering_(true),
meshRenderingTexture_(true),
pointSize_(3.0f) {}
pointSize_(5.0f),
boundingBoxRendering_(false),
lighting_(false),
backfaceCulling_(true),
wireFrame_(false),
r_(0.0f),
g_(0.0f),
b_(0.0f),
fboId_(0),
depthTexture_(0),
screenWidth_(0),
screenHeight_(0),
doubleTapOn_(false)
{
gesture_camera_ = new tango_gl::GestureCamera();
gesture_camera_->SetCameraType(
tango_gl::GestureCamera::kFirstPerson);
}
Scene::~Scene() {DeleteResources();}
Scene::~Scene() {
DeleteResources();
delete gesture_camera_;
}
//Should only be called in OpenGL thread!
void Scene::InitGLContent()
{
if(gesture_camera_ != 0)
if(axis_ != 0)
{
DeleteResources();
}
UASSERT(gesture_camera_ == 0);
gesture_camera_ = new tango_gl::GestureCamera();
axis_ = new tango_gl::Axis();
frustum_ = new tango_gl::Frustum();
trace_ = new tango_gl::Trace();
grid_ = new tango_gl::Grid();
currentPose_ = new rtabmap::Transform();
UASSERT(axis_ == 0);
axis_->SetScale(glm::vec3(0.5f,0.5f,0.5f));
frustum_->SetColor(kTraceColor);
trace_->ClearVertexArray();
trace_->SetColor(kTraceColor);
grid_->SetColor(kGridColor);
grid_->SetPosition(-kHeightOffset);
gesture_camera_->SetCameraType(
tango_gl::GestureCamera::kFirstPerson);
axis_ = new tango_gl::Axis();
frustum_ = new tango_gl::Frustum();
trace_ = new tango_gl::Trace();
grid_ = new tango_gl::Grid();
box_ = new BoundingBoxDrawable();
currentPose_ = new rtabmap::Transform();
if(cloud_shader_program_ == 0)
{
cloud_shader_program_ = tango_gl::util::CreateProgram(kPointCloudVertexShader.c_str(), kPointCloudFragmentShader.c_str());
UASSERT(cloud_shader_program_ != 0);
}
if(texture_mesh_shader_program_ == 0)
{
texture_mesh_shader_program_ = tango_gl::util::CreateProgram(kTextureMeshVertexShader.c_str(), kTextureMeshFragmentShader.c_str());
UASSERT(texture_mesh_shader_program_ != 0);
}
if(graph_shader_program_ == 0)
{
graph_shader_program_ = tango_gl::util::CreateProgram(kGraphVertexShader.c_str(), kGraphFragmentShader.c_str());
UASSERT(graph_shader_program_ != 0);
}
axis_->SetScale(glm::vec3(0.5f,0.5f,0.5f));
frustum_->SetColor(kTraceColor);
trace_->ClearVertexArray();
trace_->SetColor(kTraceColor);
grid_->SetColor(kGridColor);
grid_->SetPosition(kHeightOffset);
box_->SetShader();
box_->SetColor(1,0,0);
PointCloudDrawable::createShaderPrograms();
if(graph_shader_program_ == 0)
{
graph_shader_program_ = tango_gl::util::CreateProgram(kGraphVertexShader.c_str(), kGraphFragmentShader.c_str());
UASSERT(graph_shader_program_ != 0);
}
}
//Should only be called in OpenGL thread!
void Scene::DeleteResources() {
LOGI("Scene::DeleteResources()");
if(gesture_camera_)
if(axis_)
{
delete gesture_camera_;
delete axis_;
delete frustum_;
delete trace_;
delete grid_;
delete currentPose_;
gesture_camera_ = 0;
delete axis_;
axis_ = 0;
delete frustum_;
delete trace_;
delete grid_;
delete currentPose_;
delete box_;
}
if (cloud_shader_program_) {
glDeleteShader(cloud_shader_program_);
cloud_shader_program_ = 0;
}
if (texture_mesh_shader_program_) {
glDeleteShader(texture_mesh_shader_program_);
texture_mesh_shader_program_ = 0;
}
PointCloudDrawable::releaseShaderPrograms();
if (graph_shader_program_) {
glDeleteShader(graph_shader_program_);
graph_shader_program_ = 0;
}
}
if(fboId_>0)
{
glDeleteFramebuffers(1, &fboId_);
fboId_ = 0;
glDeleteTextures(1, &depthTexture_);
depthTexture_ = 0;
}
clear();
}
@@ -220,144 +198,360 @@ void Scene::clear()
graph_ = 0;
}
pointClouds_.clear();
if(grid_)
{
grid_->SetPosition(kHeightOffset);
}
}
//Should only be called in OpenGL thread!
void Scene::SetupViewPort(int w, int h) {
if (h == 0) {
LOGE("Setup graphic height not valid");
if (h == 0) {
LOGE("Setup graphic height not valid");
}
UASSERT(gesture_camera_ != 0);
gesture_camera_->SetWindowSize(static_cast<float>(w), static_cast<float>(h));
glViewport(0, 0, w, h);
if(screenWidth_ != w || fboId_ == 0)
{
if(fboId_>0)
{
glDeleteFramebuffers(1, &fboId_);
fboId_ = 0;
glDeleteTextures(1, &depthTexture_);
depthTexture_ = 0;
}
// Create depth texture
glGenTextures(1, &depthTexture_);
glBindTexture(GL_TEXTURE_2D, depthTexture_);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, w, h, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
glBindTexture(GL_TEXTURE_2D, 0);
// regenerate fbo texture
// create a framebuffer object, you need to delete them when program exits.
glGenFramebuffers(1, &fboId_);
glBindFramebuffer(GL_FRAMEBUFFER, fboId_);
// Set the texture to be at the depth attachment point of the FBO
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depthTexture_, 0);
GLuint status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if ( status != GL_FRAMEBUFFER_COMPLETE)
{
LOGE("Frame buffer cannot be generated! Status: %in", status);
}
glBindFramebuffer(GL_FRAMEBUFFER,0);
}
screenWidth_ = w;
screenHeight_ = h;
}
std::vector<glm::vec4> computeFrustumPlanes(const glm::mat4 & mat, bool normalize = true)
{
// http://www.txutxi.com/?p=444
std::vector<glm::vec4> planes(6);
// Left Plane
// col4 + col1
planes[0].x = mat[0][3] + mat[0][0];
planes[0].y = mat[1][3] + mat[1][0];
planes[0].z = mat[2][3] + mat[2][0];
planes[0].w = mat[3][3] + mat[3][0];
// Right Plane
// col4 - col1
planes[1].x = mat[0][3] - mat[0][0];
planes[1].y = mat[1][3] - mat[1][0];
planes[1].z = mat[2][3] - mat[2][0];
planes[1].w = mat[3][3] - mat[3][0];
// Bottom Plane
// col4 + col2
planes[2].x = mat[0][3] + mat[0][1];
planes[2].y = mat[1][3] + mat[1][1];
planes[2].z = mat[2][3] + mat[2][1];
planes[2].w = mat[3][3] + mat[3][1];
// Top Plane
// col4 - col2
planes[3].x = mat[0][3] - mat[0][1];
planes[3].y = mat[1][3] - mat[1][1];
planes[3].z = mat[2][3] - mat[2][1];
planes[3].w = mat[3][3] - mat[3][1];
// Near Plane
// col4 + col3
planes[4].x = mat[0][3] + mat[0][2];
planes[4].y = mat[1][3] + mat[1][2];
planes[4].z = mat[2][3] + mat[2][2];
planes[4].w = mat[3][3] + mat[3][2];
// Far Plane
// col4 - col3
planes[5].x = mat[0][3] - mat[0][2];
planes[5].y = mat[1][3] - mat[1][2];
planes[5].z = mat[2][3] - mat[2][2];
planes[5].w = mat[3][3] - mat[3][2];
//if(normalize)
{
for(unsigned int i=0;i<planes.size(); ++i)
{
if(normalize)
{
float d = std::sqrt(planes[i].x * planes[i].x + planes[i].y * planes[i].y + planes[i].z * planes[i].z); // for normalizing the coordinates
planes[i].x/=d;
planes[i].y/=d;
planes[i].z/=d;
planes[i].w/=d;
}
}
}
return planes;
}
/**
* Tells whether or not b is intersecting f.
* http://www.txutxi.com/?p=584
* @param f Viewing frustum.
* @param b An axis aligned bounding box.
* @return True if b intersects f, false otherwise.
*/
bool intersectFrustumAABB(
const std::vector<glm::vec4> &planes,
const pcl::PointXYZ &boxMin,
const pcl::PointXYZ &boxMax)
{
// Indexed for the 'index trick' later
const pcl::PointXYZ * box[] = {&boxMin, &boxMax};
// We only need to do 6 point-plane tests
for (unsigned int i = 0; i < planes.size(); ++i)
{
// This is the current plane
const glm::vec4 &p = planes[i];
// p-vertex selection (with the index trick)
// According to the plane normal we can know the
// indices of the positive vertex
const int px = p.x > 0.0f?1:0;
const int py = p.y > 0.0f?1:0;
const int pz = p.z > 0.0f?1:0;
// Dot product
// project p-vertex on plane normal
// (How far is p-vertex from the origin)
const float dp =
(p.x*box[px]->x) +
(p.y*box[py]->y) +
(p.z*box[pz]->z) + p.w;
// Doesn't intersect if it is behind the plane
if (dp < 0) {return false; }
}
UASSERT(gesture_camera_ != 0);
gesture_camera_->SetAspectRatio(static_cast<float>(w) /
static_cast<float>(h));
glViewport(0, 0, w, h);
return true;
}
//Should only be called in OpenGL thread!
int Scene::Render() {
UASSERT(gesture_camera_ != 0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
if(!currentPose_->isNull())
{
glm::vec3 position(currentPose_->x(), currentPose_->y(), currentPose_->z());
Eigen::Quaternionf quat = currentPose_->getQuaternionf();
glm::quat rotation(quat.w(), quat.x(), quat.y(), quat.z());
if (gesture_camera_->GetCameraType() == tango_gl::GestureCamera::kFirstPerson)
{
// In first person mode, we directly control camera's motion.
gesture_camera_->SetPosition(position);
gesture_camera_->SetRotation(rotation);
}
else
{
// In third person or top down mode, we follow the camera movement.
gesture_camera_->SetAnchorPosition(position, rotation);
frustum_->SetPosition(position);
frustum_->SetRotation(rotation);
// Set the frustum scale to 4:3, this doesn't necessarily match the physical
// camera's aspect ratio, this is just for visualization purposes.
frustum_->SetScale(kFrustumScale);
frustum_->Render(gesture_camera_->GetProjectionMatrix(),
gesture_camera_->GetViewMatrix());
axis_->SetPosition(position);
axis_->SetRotation(rotation);
axis_->Render(gesture_camera_->GetProjectionMatrix(),
gesture_camera_->GetViewMatrix());
}
trace_->UpdateVertexArray(position);
if(traceVisible_)
{
trace_->Render(gesture_camera_->GetProjectionMatrix(),
gesture_camera_->GetViewMatrix());
}
}
if(gridVisible_)
{
grid_->Render(gesture_camera_->GetProjectionMatrix(),
gesture_camera_->GetViewMatrix());
}
bool frustumCulling = true;
int cloudDrawn=0;
if(mapRendering_ && frustumCulling)
glm::vec3 position(currentPose_->x(), currentPose_->y(), currentPose_->z());
Eigen::Quaternionf quat = currentPose_->getQuaternionf();
glm::quat rotation(quat.w(), quat.x(), quat.y(), quat.z());
glm::mat4 rotateM;
if(!currentPose_->isNull())
{
//Use camera frustum to cull nodes that don't need to be drawn
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
std::vector<int> ids(pointClouds_.size());
rotateM = glm::rotate<float>(float(color_camera_to_display_rotation_)*-1.57079632679489661923132169163975144, glm::vec3(0.0f, 0.0f, 1.0f));
cloud->resize(pointClouds_.size());
ids.resize(pointClouds_.size());
int oi=0;
for(std::map<int, PointCloudDrawable*>::const_iterator iter=pointClouds_.begin(); iter!=pointClouds_.end(); ++iter)
if (gesture_camera_->GetCameraType() == tango_gl::GestureCamera::kFirstPerson)
{
if(!iter->second->getPose().isNull() && iter->second->isVisible())
{
(*cloud)[oi] = pcl::PointXYZ(iter->second->getPose().x(), iter->second->getPose().y(), iter->second->getPose().z());
ids[oi++] = iter->first;
}
// In first person mode, we directly control camera's motion.
gesture_camera_->SetPosition(position);
gesture_camera_->SetRotation(rotation*glm::quat(rotateM));
}
cloud->resize(oi);
ids.resize(oi);
if(oi)
else
{
float fov = 45.0f;
rtabmap::Transform openglCamera = GetOpenGLCameraPose(&fov)*rtabmap::Transform(0.0f, 0.0f, 3.0f, 0.0f, 0.0f, 0.0f);
// transform in same coordinate as frustum filtering
openglCamera *= rtabmap::Transform(
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f);
pcl::IndicesPtr indices = rtabmap::util3d::frustumFiltering(
cloud,
pcl::IndicesPtr(new std::vector<int>),
openglCamera,
fov*2.0f,
fov*2.0f,
0.1f,
100.0f);
// In third person or top down mode, we follow the camera movement.
gesture_camera_->SetAnchorPosition(position, rotation*glm::quat(rotateM));
}
}
//LOGI("Frustum poses filtered = %d (showing %d/%d)",
// (int)(pointClouds_.size()-indices->size()),
// (int)indices->size(),
// (int)pointClouds_.size());
glm::mat4 projectionMatrix = gesture_camera_->GetProjectionMatrix();
glm::mat4 viewMatrix = gesture_camera_->GetViewMatrix();
for(unsigned int i=0; i<indices->size(); ++i)
rtabmap::Transform openglCamera = GetOpenGLCameraPose();//*rtabmap::Transform(0.0f, 0.0f, 3.0f, 0.0f, 0.0f, 0.0f);
// transform in same coordinate as frustum filtering
openglCamera *= rtabmap::Transform(
0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
-1.0f, 0.0f, 0.0f, 0.0f);
//Culling
std::vector<glm::vec4> planes = computeFrustumPlanes(projectionMatrix*viewMatrix, true);
std::vector<PointCloudDrawable*> cloudsToDraw(pointClouds_.size());
int oi=0;
for(std::map<int, PointCloudDrawable*>::const_iterator iter=pointClouds_.begin(); iter!=pointClouds_.end(); ++iter)
{
if(!mapRendering_ && iter->first > 0)
{
break;
}
if(iter->second->isVisible())
{
if(intersectFrustumAABB(planes,
iter->second->aabbMinWorld(),
iter->second->aabbMaxWorld()))
{
++cloudDrawn;
pointClouds_.find(ids[indices->at(i)])->second->Render(gesture_camera_->GetProjectionMatrix(), gesture_camera_->GetViewMatrix(), meshRendering_, pointSize_, meshRenderingTexture_);
cloudsToDraw[oi++] = iter->second;
}
}
}
cloudsToDraw.resize(oi);
// First rendering to get depth texture
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LESS);
glDepthMask(GL_TRUE);
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
glDisable (GL_BLEND);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
if(backfaceCulling_)
{
glEnable(GL_CULL_FACE);
}
else
{
for(std::map<int, PointCloudDrawable*>::const_iterator iter=pointClouds_.begin(); iter!=pointClouds_.end(); ++iter)
glDisable(GL_CULL_FACE);
}
UTimer timer;
bool onlineBlending = blending_ && gesture_camera_->GetCameraType()!=tango_gl::GestureCamera::kTopOrtho && mapRendering_ && meshRendering_ && cloudsToDraw.size()>1;
if(onlineBlending && fboId_)
{
// set the rendering destination to FBO
glBindFramebuffer(GL_FRAMEBUFFER, fboId_);
glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
glClearColor(1, 1, 1, 1);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
// Draw scene
for(std::vector<PointCloudDrawable*>::const_iterator iter=cloudsToDraw.begin(); iter!=cloudsToDraw.end(); ++iter)
{
if((mapRendering_ || iter->first < 0) && iter->second->isVisible())
{
++cloudDrawn;
iter->second->Render(gesture_camera_->GetProjectionMatrix(), gesture_camera_->GetViewMatrix(), meshRendering_, pointSize_, meshRenderingTexture_);
}
// set large distance to cam to use low res polygons for fast processing
(*iter)->Render(projectionMatrix, viewMatrix, meshRendering_, pointSize_, false, false, 999.0f);
}
// back to normal window-system-provided framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0); // unbind
glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
if(doubleTapOn_ && gesture_camera_->GetCameraType() != tango_gl::GestureCamera::kFirstPerson)
{
glClearColor(0, 0, 0, 0);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
for(std::vector<PointCloudDrawable*>::const_iterator iter=cloudsToDraw.begin(); iter!=cloudsToDraw.end(); ++iter)
{
// set large distance to cam to use low res polygons for fast processing
(*iter)->Render(projectionMatrix, viewMatrix, meshRendering_, pointSize_*10.0f, false, false, 999.0f, 0, 0, 0, 0, 0, true);
}
GLubyte zValue[4];
glReadPixels(doubleTapPos_.x*screenWidth_, screenHeight_-doubleTapPos_.y*screenHeight_, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, zValue);
float fromFixed = 256.0f/255.0f;
float zValueF = float(zValue[0]/255.0f)*fromFixed + float(zValue[1]/255.0f)*fromFixed/255.0f + float(zValue[2]/255.0f)*fromFixed/65025.0f + float(zValue[3]/255.0f)*fromFixed/160581375.0f;
if(zValueF != 0.0f)
{
zValueF = zValueF*2.0-1.0;//NDC
glm::vec4 point = glm::inverse(projectionMatrix*viewMatrix)*glm::vec4(doubleTapPos_.x*2.0f-1.0f, (1.0f-doubleTapPos_.y)*2.0f-1.0f, zValueF, 1.0f);
point /= point.w;
gesture_camera_->SetAnchorOffset(glm::vec3(point.x, point.y, point.z) - position);
}
}
doubleTapOn_ = false;
glClearColor(r_, g_, b_, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
if(!currentPose_->isNull())
{
if (gesture_camera_->GetCameraType() != tango_gl::GestureCamera::kFirstPerson)
{
frustum_->SetPosition(position);
frustum_->SetRotation(rotation);
// Set the frustum scale to 4:3, this doesn't necessarily match the physical
// camera's aspect ratio, this is just for visualization purposes.
frustum_->SetScale(kFrustumScale);
frustum_->Render(projectionMatrix, viewMatrix);
axis_->SetPosition(position);
axis_->SetRotation(rotation);
axis_->Render(projectionMatrix, viewMatrix);
}
trace_->UpdateVertexArray(position);
if(traceVisible_)
{
trace_->Render(projectionMatrix, viewMatrix);
}
if(gridVisible_)
{
grid_->Render(projectionMatrix, viewMatrix);
}
}
if(graphVisible_ && graph_)
{
graph_->Render(gesture_camera_->GetProjectionMatrix(), gesture_camera_->GetViewMatrix());
graph_->Render(projectionMatrix, viewMatrix);
}
return cloudDrawn;
if(onlineBlending)
{
glEnable (GL_BLEND);
glDepthMask(GL_FALSE);
}
for(std::vector<PointCloudDrawable*>::const_iterator iter=cloudsToDraw.begin(); iter!=cloudsToDraw.end(); ++iter)
{
PointCloudDrawable * cloud = *iter;
if(boundingBoxRendering_)
{
box_->updateVertices(cloud->aabbMinWorld(), cloud->aabbMaxWorld());
box_->Render(projectionMatrix, viewMatrix);
}
Eigen::Vector3f cloudToCamera(
cloud->getPose().x() - openglCamera.x(),
cloud->getPose().y() - openglCamera.y(),
cloud->getPose().z() - openglCamera.z());
float distanceToCameraSqr = cloudToCamera[0]*cloudToCamera[0] + cloudToCamera[1]*cloudToCamera[1] + cloudToCamera[2]*cloudToCamera[2];
cloud->Render(projectionMatrix, viewMatrix, meshRendering_, pointSize_, meshRenderingTexture_, lighting_, distanceToCameraSqr, onlineBlending?depthTexture_:0, screenWidth_, screenHeight_, gesture_camera_->getNearClipPlane(), gesture_camera_->getFarClipPlane(), false, wireFrame_);
}
if(onlineBlending)
{
glDisable (GL_BLEND);
glDepthMask(GL_TRUE);
}
return (int)cloudsToDraw.size();
}
void Scene::SetCameraType(tango_gl::GestureCamera::CameraType camera_type) {
@@ -371,6 +565,24 @@ void Scene::SetCameraPose(const rtabmap::Transform & pose)
*currentPose_ = pose;
}
void Scene::setFOV(float angle)
{
gesture_camera_->SetFieldOfView(angle);
}
void Scene::setOrthoCropFactor(float value)
{
gesture_camera_->SetOrthoCropFactor(value);
}
void Scene::setGridRotation(float angleDeg)
{
float angleRad = angleDeg * DEGREE_2_RADIANS;
if(grid_)
{
glm::quat rot = glm::rotate(glm::quat(1,0,0,0), angleRad, glm::vec3(0, 1, 0));
grid_->SetRotation(rot);
}
}
rtabmap::Transform Scene::GetOpenGLCameraPose(float * fov) const
{
if(fov)
@@ -378,14 +590,27 @@ rtabmap::Transform Scene::GetOpenGLCameraPose(float * fov) const
*fov = gesture_camera_->getFOV();
}
return glmToTransform(gesture_camera_->GetTransformationMatrix());
}
void Scene::OnTouchEvent(int touch_count,
tango_gl::GestureCamera::TouchEvent event, float x0,
float y0, float x1, float y1) {
UASSERT(gesture_camera_ != 0);
gesture_camera_->OnTouchEvent(touch_count, event, x0, y0, x1, y1);
if(touch_count == 3)
{
//doubletap
if(!doubleTapOn_)
{
doubleTapPos_.x = x0;
doubleTapPos_.y = y0;
doubleTapOn_ = true;
}
}
else
{
// rotate/translate/zoom
gesture_camera_->OnTouchEvent(touch_count, event, x0, y0, x1, y1);
}
}
void Scene::updateGraph(
@@ -400,8 +625,11 @@ void Scene::updateGraph(
}
//create
UASSERT(graph_shader_program_ != 0);
graph_ = new GraphDrawable(graph_shader_program_, poses, links);
if(graphVisible_)
{
UASSERT(graph_shader_program_ != 0);
graph_ = new GraphDrawable(graph_shader_program_, poses, links);
}
}
void Scene::setGraphVisible(bool visible)
@@ -426,7 +654,7 @@ void Scene::addCloud(
const pcl::IndicesPtr & indices,
const rtabmap::Transform & pose)
{
LOGI("add cloud %d", id);
LOGI("add cloud %d (%d points %d indices)", id, (int)cloud->size(), indices.get()?(int)indices->size():0);
std::map<int, PointCloudDrawable*>::iterator iter=pointClouds_.find(id);
if(iter != pointClouds_.end())
{
@@ -435,13 +663,7 @@ void Scene::addCloud(
}
//create
UASSERT(cloud_shader_program_ != 0 && texture_mesh_shader_program_!=0);
PointCloudDrawable * drawable = new PointCloudDrawable(
cloud_shader_program_,
texture_mesh_shader_program_,
cloud,
indices,
1.0f);
PointCloudDrawable * drawable = new PointCloudDrawable(cloud, indices);
drawable->setPose(pose);
pointClouds_.insert(std::make_pair(id, drawable));
}
@@ -449,8 +671,8 @@ void Scene::addCloud(
void Scene::addMesh(
int id,
const Mesh & mesh,
const cv::Mat & texture,
const rtabmap::Transform & pose)
const rtabmap::Transform & pose,
bool createWireframe)
{
LOGI("add mesh %d", id);
std::map<int, PointCloudDrawable*>::iterator iter=pointClouds_.find(id);
@@ -461,14 +683,61 @@ void Scene::addMesh(
}
//create
UASSERT(cloud_shader_program_ != 0 && texture_mesh_shader_program_!=0);
PointCloudDrawable * drawable = new PointCloudDrawable(
cloud_shader_program_,
texture_mesh_shader_program_,
mesh,
texture);
PointCloudDrawable * drawable = new PointCloudDrawable(mesh, createWireframe);
drawable->setPose(pose);
pointClouds_.insert(std::make_pair(id, drawable));
if(!mesh.pose.isNull() && mesh.cloud->size() && (!mesh.cloud->isOrganized() || mesh.indices->size()))
{
UTimer time;
float height = 0.0f;
Eigen::Affine3f affinePose = mesh.pose.toEigen3f();
if(mesh.polygons.size())
{
for(unsigned int i=0; i<mesh.polygons.size(); ++i)
{
for(unsigned int j=0; j<mesh.polygons[i].vertices.size(); ++j)
{
pcl::PointXYZRGB pt = pcl::transformPoint(mesh.cloud->at(mesh.polygons[i].vertices[j]), affinePose);
if(pt.z < height)
{
height = pt.z;
}
}
}
}
else
{
if(mesh.cloud->isOrganized())
{
for(unsigned int i=0; i<mesh.indices->size(); ++i)
{
pcl::PointXYZRGB pt = pcl::transformPoint(mesh.cloud->at(mesh.indices->at(i)), affinePose);
if(pt.z < height)
{
height = pt.z;
}
}
}
else
{
for(unsigned int i=0; i<mesh.cloud->size(); ++i)
{
pcl::PointXYZRGB pt = pcl::transformPoint(mesh.cloud->at(i), affinePose);
if(pt.z < height)
{
height = pt.z;
}
}
}
}
if(grid_->GetPosition().y == kHeightOffset.y || grid_->GetPosition().y > height)
{
grid_->SetPosition(glm::vec3(0,height,0));
}
LOGD("compute min height %f s", time.ticks());
}
}
@@ -496,6 +765,11 @@ bool Scene::hasCloud(int id) const
return pointClouds_.find(id) != pointClouds_.end();
}
bool Scene::hasMesh(int id) const
{
return pointClouds_.find(id) != pointClouds_.end() && pointClouds_.at(id)->hasMesh();
}
bool Scene::hasTexture(int id) const
{
return pointClouds_.find(id) != pointClouds_.end() && pointClouds_.at(id)->hasTexture();
@@ -515,11 +789,28 @@ void Scene::updateCloudPolygons(int id, const std::vector<pcl::Vertices> & polyg
}
}
void Scene::updateMesh(int id, const Mesh & mesh, const cv::Mat & texture)
void Scene::updateMesh(int id, const Mesh & mesh)
{
std::map<int, PointCloudDrawable*>::iterator iter=pointClouds_.find(id);
if(iter != pointClouds_.end())
{
iter->second->updateMesh(mesh, texture);
iter->second->updateMesh(mesh);
}
}
void Scene::updateGains(int id, float gainR, float gainG, float gainB)
{
std::map<int, PointCloudDrawable*>::iterator iter=pointClouds_.find(id);
if(iter != pointClouds_.end())
{
iter->second->setGains(gainR, gainG, gainB);
}
}
void Scene::setGridColor(float r, float g, float b)
{
if(grid_)
{
grid_->SetColor(r, g, b);
}
}

View File

@@ -37,6 +37,7 @@
#include <point_cloud_drawable.h>
#include <graph_drawable.h>
#include <bounding_box_drawable.h>
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
@@ -56,6 +57,10 @@ class Scene {
// Setup GL view port.
void SetupViewPort(int w, int h);
int getViewPortWidth() const {return screenWidth_;}
int getViewPortHeight() const {return screenHeight_;}
void setScreenRotation(TangoSupportRotation colorCameraToDisplayRotation) {color_camera_to_display_rotation_ = colorCameraToDisplayRotation;}
void clear(); // removed all point clouds
@@ -75,7 +80,7 @@ class Scene {
void SetCameraPose(const rtabmap::Transform & pose);
rtabmap::Transform GetCameraPose() const {return currentPose_!=0?*currentPose_:rtabmap::Transform();}
rtabmap::Transform GetOpenGLCameraPose(float * fov) const;
rtabmap::Transform GetOpenGLCameraPose(float * fov = 0) const;
// Touch event passed from android activity. This function only support two
// touches.
@@ -105,23 +110,39 @@ class Scene {
void addMesh(
int id,
const Mesh & mesh,
const cv::Mat & texture,
const rtabmap::Transform & pose);
const rtabmap::Transform & pose,
bool createWireframe = false);
void setCloudPose(int id, const rtabmap::Transform & pose);
void setCloudVisible(int id, bool visible);
bool hasCloud(int id) const;
bool hasMesh(int id) const;
bool hasTexture(int id) const;
std::set<int> getAddedClouds() const;
void updateCloudPolygons(int id, const std::vector<pcl::Vertices> & polygons);
void updateMesh(int id, const Mesh & mesh, const cv::Mat & texture);
void updateMesh(int id, const Mesh & mesh);
void updateGains(int id, float gainR, float gainG, float gainB);
void setBlending(bool enabled) {blending_ = enabled;}
void setMapRendering(bool enabled) {mapRendering_ = enabled;}
void setMeshRendering(bool enabled, bool withTexture) {meshRendering_ = enabled; meshRenderingTexture_ = withTexture;}
void setPointSize(float size) {pointSize_ = size;}
void setFOV(float angle);
void setOrthoCropFactor(float value);
void setGridRotation(float angleDeg);
void setLighting(bool enabled) {lighting_ = enabled;}
void setBackfaceCulling(bool enabled) {backfaceCulling_ = enabled;}
void setWireframe(bool enabled) {wireFrame_ = enabled;}
void setBackgroundColor(float r, float g, float b) {r_=r; g_=g; b_=b;} // 0.0f <> 1.0f
void setGridColor(float r, float g, float b);
bool isBlending() const {return blending_;}
bool isMapRendering() const {return mapRendering_;}
bool isMeshRendering() const {return meshRendering_;}
bool isMeshTexturing() const {return meshRendering_ && meshRenderingTexture_;}
float getPointSize() const {return pointSize_;}
bool isLighting() const {return lighting_;}
bool isBackfaceCulling() const {return backfaceCulling_;}
private:
// Camera object that allows user to use touch input to interact with.
@@ -136,6 +157,9 @@ class Scene {
// Ground grid.
tango_gl::Grid* grid_;
// Bounding box
BoundingBoxDrawable * box_;
// Trace of pose data.
tango_gl::Trace* trace_;
GraphDrawable * graph_;
@@ -143,19 +167,33 @@ class Scene {
bool gridVisible_;
bool traceVisible_;
TangoSupportRotation color_camera_to_display_rotation_;
std::map<int, PointCloudDrawable*> pointClouds_;
rtabmap::Transform * currentPose_;
// Shader to display point cloud.
GLuint cloud_shader_program_;
GLuint texture_mesh_shader_program_;
GLuint graph_shader_program_;
bool blending_;
bool mapRendering_;
bool meshRendering_;
bool meshRenderingTexture_;
float pointSize_;
bool boundingBoxRendering_;
bool lighting_;
bool backfaceCulling_;
bool wireFrame_;
float r_;
float g_;
float b_;
GLuint fboId_;
GLuint depthTexture_;
GLsizei screenWidth_;
GLsizei screenHeight_;
bool doubleTapOn_;
cv::Point2f doubleTapPos_;
};
#endif // TANGO_POINT_CLOUD_SCENE_H_

View File

@@ -22,8 +22,13 @@ namespace tango_gl {
Camera::Camera() {
field_of_view_ = 45.0f * DEGREE_2_RADIANS;
aspect_ratio_ = 4.0f / 3.0f;
near_clip_plane_ = 0.1f;
far_clip_plane_ = 100.0f;
width_ = 800.0f;
height_ = 600.0f;
near_clip_plane_ = 0.2f;
far_clip_plane_ = 1000.0f;
ortho_ = false;
orthoScale_ = 2.0f;
orthoCropFactor_ = -1.0f;
}
glm::mat4 Camera::GetViewMatrix() {
@@ -31,18 +36,29 @@ glm::mat4 Camera::GetViewMatrix() {
}
glm::mat4 Camera::GetProjectionMatrix() {
return glm::perspective(field_of_view_, aspect_ratio_,
near_clip_plane_, far_clip_plane_);
if(ortho_)
{
return glm::ortho(-orthoScale_*aspect_ratio_, orthoScale_*aspect_ratio_, -orthoScale_, orthoScale_, orthoScale_ + orthoCropFactor_, far_clip_plane_);
}
return glm::perspective(field_of_view_, aspect_ratio_, near_clip_plane_, far_clip_plane_);
}
void Camera::SetAspectRatio(float aspect_ratio) {
aspect_ratio_ = aspect_ratio;
void Camera::SetWindowSize(float width, float height) {
width_ = width;
height_ = height;
aspect_ratio_ = width/height;
}
void Camera::SetFieldOfView(float fov) {
field_of_view_ = fov * DEGREE_2_RADIANS;
}
void Camera::SetNearFarClipPlanes(const float near, const float far)
{
near_clip_plane_ = near;
far_clip_plane_ = far;
}
Camera::~Camera() {
}

View File

@@ -62,68 +62,83 @@ GestureCamera::GestureCamera() :
GestureCamera::~GestureCamera() { delete cam_parent_transform_; }
void GestureCamera::OnTouchEvent(int touch_count, TouchEvent event, float x0,
float y0, float x1, float y1) {
if (camera_type_ == kFirstPerson) {
return;
}
float y0, float x1, float y1) {
if (touch_count == 1) {
switch (event) {
case kTouch0Down: {
cam_start_angle_ = cam_cur_angle_;
if (camera_type_!=kFirstPerson && touch_count == 1) {
switch (event) {
case kTouch0Down: {
cam_start_angle_ = cam_cur_angle_;
touch0_start_position_.x = x0;
touch0_start_position_.y = y0;
break;
}
case kTouchMove: {
float rotation_x = (touch0_start_position_.y - y0) * kRotationSpeed;
float rotation_y = (touch0_start_position_.x - x0) * kRotationSpeed;
touch0_start_position_.x = x0;
touch0_start_position_.y = y0;
break;
}
case kTouchMove: {
glm::vec2 offset;
cam_cur_angle_.x = cam_start_angle_.x + rotation_x;
cam_cur_angle_.y = cam_start_angle_.y + rotation_y;
StartCameraToCurrentTransform();
break;
}
default: { break; }
}
}
if (touch_count == 2) {
switch (event) {
case kTouch1Down: {
float abs_x = x0 - x1;
float abs_y = y0 - y1;
start_touch_dist_ = std::sqrt(abs_x * abs_x + abs_y * abs_y);
cam_start_dist_ = GetPosition().z;
float rotation_x = (touch0_start_position_.y - y0) * kRotationSpeed;
float rotation_y = (touch0_start_position_.x - x0) * kRotationSpeed;
// center touch
touch0_start_position_.x = (x0+x1)/2.0f;
touch0_start_position_.y = (y0+y1)/2.0f;
break;
}
case kTouchMove: {
float abs_x = x0 - x1;
float abs_y = y0 - y1;
float dist = start_touch_dist_ - std::sqrt(abs_x * abs_x + abs_y * abs_y);
if(camera_type_!=kTopOrtho)
cam_cur_angle_.x = cam_start_angle_.x + rotation_x;
cam_cur_angle_.y = cam_start_angle_.y + rotation_y;
cam_cur_dist_ = tango_gl::util::Clamp(cam_start_dist_ + dist * kZoomSpeed,
kCamViewMinDist, kCamViewMaxDist);
StartCameraToCurrentTransform();
glm::vec2 touch_center_position((x0+x1)/2.0f, (y0+y1)/2.0f);
glm::vec2 offset;
offset.x = (touch_center_position.x - touch0_start_position_.x) * kMoveSpeed;
offset.y = (touch_center_position.y - touch0_start_position_.y) * kMoveSpeed;
touch0_start_position_ = touch_center_position;
break;
}
default: { break; }
}
}
if (touch_count == 2) {
switch (event) {
case kTouch1Down: {
float abs_x = x0 - x1;
float abs_y = y0 - y1;
start_touch_dist_ = std::sqrt(abs_x * abs_x + abs_y * abs_y);
cam_start_dist_ = GetPosition().z;
cam_start_fov_ = this->getFOV();
StartCameraToCurrentTransform();
// center touch
touch0_start_position_.x = (x0+x1)/2.0f;
touch0_start_position_.y = (y0+y1)/2.0f;
break;
}
case kTouchMove: {
float abs_x = x0 - x1;
float abs_y = y0 - y1;
float dist = start_touch_dist_ - std::sqrt(abs_x * abs_x + abs_y * abs_y);
anchor_offset_ += glm::rotate(cam_parent_transform_->GetRotation(), glm::vec3(-offset.x, offset.y, 0));
if(camera_type_ == kFirstPerson)
{
this->SetFieldOfView(tango_gl::util::Clamp(cam_start_fov_ + dist * kZoomSpeed*10.0f, 45, 90));
}
else
{
cam_cur_dist_ = tango_gl::util::Clamp(cam_start_dist_ + dist * kZoomSpeed,
kCamViewMinDist, kCamViewMaxDist);
break;
}
default: { break; }
}
}
this->SetOrthoMode(camera_type_ == kTopOrtho);
if(camera_type_ == kTopOrtho)
{
this->SetOrthoScale(cam_cur_dist_);
}
glm::vec2 touch_center_position((x0+x1)/2.0f, (y0+y1)/2.0f);
glm::vec2 offset;
offset.x = (touch_center_position.x - touch0_start_position_.x) * kMoveSpeed;
offset.y = (touch_center_position.y - touch0_start_position_.y) * kMoveSpeed;
touch0_start_position_ = touch_center_position;
StartCameraToCurrentTransform();
anchor_offset_ += glm::rotate(cam_parent_transform_->GetRotation(), glm::vec3(-offset.x, offset.y, 0));
}
break;
}
default: { break; }
}
}
}
Segment GestureCamera::GetSegmentFromTouch(float normalized_x,
@@ -164,6 +179,7 @@ void GestureCamera::SetCameraType(CameraType camera_index) {
camera_type_ = camera_index;
switch (camera_index) {
case kFirstPerson:
SetOrthoMode(false);
SetFieldOfView(kLowFov);
SetPosition(glm::vec3(0.0f, 0.0f, 0.0f));
SetRotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f));
@@ -177,20 +193,22 @@ void GestureCamera::SetCameraType(CameraType camera_index) {
break;
case kThirdPerson:
case kThirdPersonFollow:
SetFieldOfView(kHighFov);
SetOrthoMode(false);
SetFieldOfView(kHighFov);
SetPosition(glm::vec3(0.0f, 0.0f, 0.0f));
SetRotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f));
cam_cur_dist_ = kThirdPersonFollow?kThirdPersonFollowCameraDist:kThirdPersonCameraDist;
anchor_offset_ = glm::vec3(0.0f,0.0f,0.0f);
cam_cur_angle_.x = -M_PI / 4.0f;
cam_cur_angle_.x = -M_PI / 6.0f;
cam_cur_angle_.y = kThirdPersonFollow?0:M_PI / 4.0f;
cam_cur_target_rot_ = glm::quat(1,0,0,0);
StartCameraToCurrentTransform();
break;
case kTopDown:
SetFieldOfView(kHighFov);
SetPosition(glm::vec3(0.0f, 0.0f, 0.0f));
SetRotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f));
SetOrthoMode(false);
SetFieldOfView(kHighFov);
cam_cur_dist_ = kTopDownCameraDist;
anchor_offset_ = glm::vec3(0.0f,0.0f,0.0f);
cam_cur_angle_.x = -M_PI / 2.0f;
@@ -198,6 +216,19 @@ void GestureCamera::SetCameraType(CameraType camera_index) {
cam_cur_target_rot_ = glm::quat(1,0,0,0);
StartCameraToCurrentTransform();
break;
case kTopOrtho:
SetPosition(glm::vec3(0.0f, 0.0f, 0.0f));
SetRotation(glm::quat(1.0f, 0.0f, 0.0f, 0.0f));
SetOrthoMode(true);
SetOrthoScale(kTopDownCameraDist);
SetOrthoCropFactor(-1.0f);
cam_cur_dist_ = kTopDownCameraDist;
anchor_offset_ = glm::vec3(0.0f,0.0f,0.0f);
cam_cur_angle_.x = -M_PI / 2.0f;
cam_cur_angle_.y = 0.0f;
cam_cur_target_rot_ = glm::quat(1,0,0,0);
StartCameraToCurrentTransform();
break;
default:
break;
}

View File

@@ -27,11 +27,17 @@ class Camera : public Transform {
Camera& operator=(const Camera&) = delete;
~Camera();
void SetAspectRatio(const float aspect_ratio);
void SetWindowSize(const float width, const float height);
void SetFieldOfView(const float fov);
void SetOrthoMode(bool enabled) {ortho_ = enabled;}
void SetOrthoScale(float scale) {orthoScale_ = scale;}
void SetOrthoCropFactor(float value) {orthoCropFactor_ = value;}
void SetNearFarClipPlanes(const float near, const float far);
glm::mat4 GetViewMatrix();
glm::mat4 GetProjectionMatrix();
float getNearClipPlane() const {return near_clip_plane_;}
float getFarClipPlane() const {return far_clip_plane_;}
/**
* Create an OpenGL perspective matrix from window size, camera intrinsics, and clip settings.
@@ -52,7 +58,12 @@ class Camera : public Transform {
protected:
float field_of_view_;
float aspect_ratio_;
float width_;
float height_;
float near_clip_plane_, far_clip_plane_;
bool ortho_;
float orthoScale_;
float orthoCropFactor_;
};
} // namespace tango_gl
#endif // TANGO_GL_CAMERA_H_

View File

@@ -29,7 +29,8 @@ class GestureCamera : public Camera {
kFirstPerson = 0,
kThirdPersonFollow = 1,
kTopDown = 2,
kThirdPerson = 3
kTopOrtho = 3,
kThirdPerson = 4
};
enum TouchEvent {
@@ -55,6 +56,11 @@ class GestureCamera : public Camera {
float touch_range);
void SetAnchorPosition(const glm::vec3& pos, const glm::quat & rotation);
void SetAnchorOffset(const glm::vec3& pos) {anchor_offset_ = pos;}
const glm::vec3& GetAnchorOffset() const {return anchor_offset_;}
void SetCameraDistance(float cameraDistance) {cam_cur_dist_ = cameraDistance;}
float GetCameraDistance() const {return cam_cur_dist_;}
// Set camera type, set render camera's parent position and rotation.
void SetCameraType(CameraType camera_index);
@@ -75,6 +81,7 @@ class GestureCamera : public Camera {
glm::quat cam_cur_target_rot_;
float cam_start_dist_;
float cam_start_fov_;
float cam_cur_dist_;
glm::vec3 anchor_offset_;

View File

@@ -25,6 +25,7 @@
#include <android/log.h>
#include <GLES2/gl2.h>
#include <GLES2/gl2ext.h>
#include <tango_support_api.h>
#include "glm/glm.hpp"
#include "glm/gtc/matrix_transform.hpp"
@@ -33,9 +34,15 @@
#include "glm/gtx/matrix_decompose.hpp"
#define LOG_TAG "rtabmap"
#ifdef DISABLE_LOG
#define LOGD(...) ;
#define LOGI(...) ;
#define LOGW(...) ;
#else
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG,LOG_TAG,__VA_ARGS__)
#define LOGI(...) __android_log_print(ANDROID_LOG_INFO,LOG_TAG,__VA_ARGS__)
#define LOGW(...) __android_log_print(ANDROID_LOG_WARN,LOG_TAG,__VA_ARGS__)
#endif
#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR,LOG_TAG,__VA_ARGS__)
#ifndef M_PI
@@ -76,6 +83,33 @@ namespace util {
const glm::vec3& start, const glm::vec3& end);
glm::vec3 ApplyTransform(const glm::mat4& mat, const glm::vec3& vec);
// Get the Android rotation integer value from color camera to display.
// This function is used to compute the orientation difference to handle
// the portrait and landscape mode for color camera display.
//
// @param display: integer value of display orientation, values available
// are 0, 1, 2 ,3. Followed by Android display orientation standard:
// https://developer.android.com/reference/android/view/Display.html#getRotation()
// @param color_camera: integer value of color camera oreintation, values
// available are 0, 90, 180, 270. Followed by Android camera orientation
// standard:
// https://developer.android.com/reference/android/hardware/Camera.CameraInfo.html#orientation
TangoSupportRotation GetAndroidRotationFromColorCameraToDisplay(
int display_rotation, int color_camera_rotation);
// Get the Android rotation integer value from color camera to display.
// This function is used to compute the orientation difference to handle
// the portrait and landscape mode for color camera display.
//
// @param display: the device display orientation.
// @param color_camera: integer value of color camera oreintation, values
// available are 0, 90, 180, 270. Followed by Android camera orientation
// standard:
// https://developer.android.com/reference/android/hardware/Camera.CameraInfo.html#orientation
TangoSupportRotation GetAndroidRotationFromColorCameraToDisplay(
TangoSupportRotation display_rotation, int color_camera_rotation);
} // namespace util
} // namespace tango_gl
#endif // TANGO_GL_RENDERER_GL_UTIL

View File

@@ -19,6 +19,27 @@
namespace tango_gl {
namespace {
int NormalizedColorCameraRotation(int camera_rotation) {
int camera_n = 0;
switch (camera_rotation) {
case 90:
camera_n = 1;
break;
case 180:
camera_n = 2;
break;
case 270:
camera_n = 3;
break;
default:
camera_n = 0;
break;
}
return camera_n;
}
} // annonymous namespace
void util::CheckGlError(const char* operation) {
for (GLint error = glGetError(); error; error = glGetError()) {
LOGE("after %s() glError (0x%x)\n", operation, error);
@@ -217,4 +238,23 @@ glm::vec3 util::ApplyTransform(const glm::mat4& mat, const glm::vec3& vec) {
return glm::vec3(mat * glm::vec4(vec, 1.0f));
}
TangoSupportRotation util::GetAndroidRotationFromColorCameraToDisplay(
int display_rotation, int color_camera_rotation) {
TangoSupportRotation r =
static_cast<TangoSupportRotation>(display_rotation);
return util::GetAndroidRotationFromColorCameraToDisplay(
r, color_camera_rotation);
}
TangoSupportRotation util::GetAndroidRotationFromColorCameraToDisplay(
TangoSupportRotation display_rotation, int color_camera_rotation) {
int color_camera_n = NormalizedColorCameraRotation(color_camera_rotation);
int ret = static_cast<int>(display_rotation) - color_camera_n;
if (ret < 0) {
ret += 4;
}
return static_cast<TangoSupportRotation>(ret % 4);
}
} // namespace tango_gl

View File

@@ -0,0 +1 @@

View File

@@ -44,14 +44,14 @@ class LogHandler : public UEventsHandler
public:
LogHandler()
{
ULogger::setLevel(ULogger::kWarning);
ULogger::setEventLevel(ULogger::kWarning);
ULogger::setLevel(ULogger::kDebug);
ULogger::setEventLevel(ULogger::kDebug);
ULogger::setPrintThreadId(true);
registerToEventsManager();
}
protected:
virtual void handleEvent(UEvent * event)
virtual bool handleEvent(UEvent * event)
{
if(event->getClassName().compare("ULogEvent") == 0)
{
@@ -74,6 +74,7 @@ protected:
}
}
return false;
}
};
@@ -143,15 +144,33 @@ inline rtabmap::Transform glmToTransform(const glm::mat4 & mat)
return transform;
}
struct Mesh
class Mesh
{
public:
Mesh() :
cloud(new pcl::PointCloud<pcl::PointXYZRGB>),
normals(new pcl::PointCloud<pcl::Normal>),
indices(new std::vector<int>),
visible(true)
{
gains[0] = gains[1] = gains[2] = 1.0f;
}
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud; // organized cloud
pcl::PointCloud<pcl::Normal>::Ptr normals;
pcl::IndicesPtr indices;
std::vector<pcl::Vertices> polygons;
std::vector<pcl::Vertices> polygonsLowRes;
rtabmap::Transform pose; // in rtabmap coordinates
bool visible;
rtabmap::CameraModel cameraModel;
float gain;
double gains[3]; // RGB gains
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > texCoords;
#else
std::vector<Eigen::Vector2f> texCoords;
#endif
cv::Mat texture;
};
#endif /* UTIL_H_ */

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android" >
<item>
<shape>
<gradient
android:endColor="#00ffffff"
android:startColor="#ff686868"
android:useLevel="false" />
</shape>
</item>
</layer-list>

View File

@@ -15,259 +15,130 @@
-->
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
android:layout_height="wrap_content">
<android.opengl.GLSurfaceView
android:id="@+id/gl_surface_view"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:layout_gravity="top" />
<LinearLayout
android:id="@+id/debug_layout"
android:layout_gravity="top"/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:orientation="vertical"
android:paddingLeft="5dp" >
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/status" />
<TextView
android:id="@+id/status"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/nodes" />
<TextView
android:id="@+id/nodes"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/words" />
<TextView
android:id="@+id/words"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/memory" />
<TextView
android:id="@+id/memory"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/db_size" />
<TextView
android:id="@+id/db_size"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/points" />
<TextView
android:id="@+id/points"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/polygons" />
<TextView
android:id="@+id/polygons"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/update_time" />
<TextView
android:id="@+id/update_time"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/features" />
<TextView
android:id="@+id/features"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/total_loop" />
<TextView
android:id="@+id/total_loop"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/inliers" />
<TextView
android:id="@+id/inliers"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hypothesis" />
<TextView
android:id="@+id/hypothesis"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/fps" />
<TextView
android:id="@+id/fps"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
<Button
android:id="@+id/first_person_button"
android:layout_height="match_parent"
android:fitsSystemWindows="true">
<ToggleButton
android:id="@+id/wireframe_button"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_above="@+id/third_person_button"
android:layout_alignLeft="@+id/third_person_button"
android:layout_above="@+id/light_button"
android:layout_alignLeft="@+id/light_button"
android:layout_alignParentRight="true"
android:layout_marginBottom="5dp"
android:layout_marginRight="5dp"
android:paddingRight="5dp"
android:text="@string/first_person" />
<Button
android:id="@+id/top_down_button"
android:textOff="@string/wireframe"
android:textOn="@string/wireframe" />
<ToggleButton
android:id="@+id/light_button"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_above="@+id/backface_button"
android:layout_alignLeft="@+id/backface_button"
android:layout_alignParentRight="true"
android:layout_marginBottom="5dp"
android:layout_marginRight="5dp"
android:paddingRight="5dp"
android:textOff="@string/light_off"
android:textOn="@string/light_on" />
<ToggleButton
android:id="@+id/backface_button"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_above="@+id/camera_button"
android:layout_alignRight="@+id/camera_button"
android:layout_alignParentRight="true"
android:layout_marginBottom="15dp"
android:layout_marginRight="5dp"
android:paddingRight="5dp"
android:textOff="@string/backface_off"
android:textOn="@string/backface_on" />
<com.introlab.rtabmap.NDSpinner
android:id="@+id/camera_button"
android:layout_width="140dp"
android:layout_height="40dp"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginRight="5dp"
android:layout_marginBottom="10dp"
android:paddingRight="5dp"
android:text="@string/top_down" />
android:paddingBottom="10dp"
android:text="@string/camera_button"
android:spinnerMode="dropdown"/>
<Button
android:id="@+id/third_person_button"
<ToggleButton
android:id="@+id/pause_button"
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_above="@+id/top_down_button"
android:layout_marginRight="5dp"
android:layout_alignParentTop="true"
android:layout_marginTop="10dp"
android:layout_alignParentRight="true"
android:layout_marginBottom="5dp"
android:layout_marginRight="5dp"
android:paddingRight="5dp"
android:text="@string/third_person" />
android:textOff="@string/pause"
android:textOn="@string/resume" />
<Button
android:id="@+id/button_shareToSketchfab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginRight="5dp"
android:layout_alignParentTop="true"
android:layout_marginTop="10dp"
android:layout_alignParentRight="true"
android:text="@string/share_to_sketchfab" />
<Button
android:id="@+id/button_saveOnDevice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignRight="@+id/button_shareToSketchfab"
android:layout_below="@+id/button_shareToSketchfab"
android:text="@string/save_to_file" />
<Button
android:id="@+id/close_visualization_button"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_above="@+id/camera_button"
android:layout_centerHorizontal="true"
android:text="@string/close_visualization" />
<SeekBar
android:id="@+id/seekBar_ortho_cut"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:rotation="270"
android:layout_above="@+id/light_button"
android:layout_alignParentLeft="true"
android:layout_gravity="center"
android:layout_marginLeft="-50dp"
android:progressDrawable="@drawable/custom_seekbar" />
<SeekBar
android:id="@+id/seekBar_grid"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignBottom="@+id/camera_button"
android:layout_marginLeft="35dp"
android:paddingBottom="10dp"
android:progressDrawable="@drawable/custom_seekbar" />
</RelativeLayout>
</RelativeLayout>

View File

@@ -0,0 +1,336 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/pref_title_rendering">
<ListPreference
android:key="@string/pref_key_density"
android:title="@string/pref_title_density"
android:summary="@string/pref_summary_density"
android:entries="@array/pref_density_keys"
android:entryValues="@array/pref_density_values"
android:defaultValue="@string/pref_default_density"/>
<ListPreference
android:key="@string/pref_key_depth"
android:title="@string/pref_title_depth"
android:summary="@string/pref_summary_depth"
android:entries="@array/pref_depth_keys"
android:entryValues="@array/pref_depth_values"
android:defaultValue="@string/pref_default_depth"/>
<ListPreference
android:key="@string/pref_key_min_depth"
android:title="@string/pref_title_min_depth"
android:summary="@string/pref_summary_min_depth"
android:entries="@array/pref_min_depth_keys"
android:entryValues="@array/pref_min_depth_values"
android:defaultValue="@string/pref_default_min_depth"/>
<ListPreference
android:key="@string/pref_key_point_size"
android:title="@string/pref_title_point_size"
android:summary="@string/pref_summary_point_size"
android:entries="@array/pref_point_size_values"
android:entryValues="@array/pref_point_size_values"
android:defaultValue="@string/pref_default_point_size"/>
<ListPreference
android:key="@string/pref_key_angle"
android:title="@string/pref_title_angle"
android:summary="@string/pref_summary_angle"
android:entries="@array/pref_angle_keys"
android:entryValues="@array/pref_angle_values"
android:defaultValue="@string/pref_default_angle"/>
<ListPreference
android:key="@string/pref_key_triangle"
android:title="@string/pref_title_triangle"
android:summary="@string/pref_summary_triangle"
android:entries="@array/pref_triangle_keys"
android:entryValues="@array/pref_triangle_values"
android:defaultValue="@string/pref_default_triangle"/>
<ListPreference
android:key="@string/pref_key_rendering_texture_decimation"
android:title="@string/pref_title_rendering_texture_decimation"
android:summary="@string/pref_summary_rendering_texture_decimation"
android:entries="@array/pref_rendering_texture_decimation_keys"
android:entryValues="@array/pref_rendering_texture_decimation_values"
android:defaultValue="@string/pref_default_rendering_texture_decimation"/>
<ListPreference
android:key="@string/pref_key_background_color"
android:title="@string/pref_title_background_color"
android:summary="@string/pref_summary_background_color"
android:entries="@array/pref_background_color_keys"
android:entryValues="@array/pref_background_color_values"
android:defaultValue="@string/pref_default_background_color"/>
<SwitchPreference
android:key="@string/pref_key_blending"
android:title="@string/pref_title_blending"
android:summary="@string/pref_summary_blending"
android:defaultValue="@string/pref_default_blending"/>
<SwitchPreference
android:key="@string/pref_key_nodes_filtering"
android:title="@string/pref_title_nodes_filtering"
android:summary="@string/pref_summary_nodes_filtering"
android:defaultValue="@string/pref_default_nodes_filtering"/>
</PreferenceCategory>
<PreferenceCategory
android:title="@string/pref_title_general">
<PreferenceScreen
android:key="pref_button_mapping"
android:title="@string/pref_title_mapping_sub"
android:summary="@string/pref_summary_mapping"
android:persistent="false">
<SwitchPreference
android:key="@string/pref_key_append"
android:title="@string/pref_title_append"
android:summary="@string/pref_summary_append"
android:defaultValue="@string/pref_default_append"/>
<SwitchPreference
android:key="@string/pref_key_resolution"
android:title="@string/pref_title_resolution"
android:summary="@string/pref_summary_resolution"
android:defaultValue="@string/pref_default_resolution"/>
<SwitchPreference
android:key="@string/pref_key_smoothing"
android:title="@string/pref_title_smoothing"
android:summary="@string/pref_summary_smoothing"
android:defaultValue="@string/pref_default_smoothing"/>
<SwitchPreference
android:key="@string/pref_key_fisheye"
android:title="@string/pref_title_fisheye"
android:summary="@string/pref_summary_fisheye"
android:defaultValue="@string/pref_default_fisheye"/>
<PreferenceCategory
android:title="@string/pref_title_mapping_core">
<ListPreference
android:key="@string/pref_key_update_rate"
android:title="@string/pref_title_update_rate"
android:summary="@string/pref_summary_update_rate"
android:entries="@array/pref_update_rate_keys"
android:entryValues="@array/pref_update_rate_values"
android:defaultValue="@string/pref_default_update_rate"/>
<ListPreference
android:key="@string/pref_key_time_thr"
android:title="@string/pref_title_time_thr"
android:summary="@string/pref_summary_time_thr"
android:entries="@array/pref_time_thr_keys"
android:entryValues="@array/pref_time_thr_values"
android:defaultValue="@string/pref_default_time_thr"/>
<ListPreference
android:key="@string/pref_key_mem_thr"
android:title="@string/pref_title_mem_thr"
android:summary="@string/pref_summary_mem_thr"
android:entries="@array/pref_mem_thr_keys"
android:entryValues="@array/pref_mem_thr_values"
android:defaultValue="@string/pref_default_mem_thr"/>
<ListPreference
android:key="@string/pref_key_loop_thr"
android:title="@string/pref_title_loop_thr"
android:summary="@string/pref_summary_loop_thr"
android:entries="@array/pref_loop_thr_keys"
android:entryValues="@array/pref_loop_thr_values"
android:defaultValue="@string/pref_default_loop_thr"/>
<ListPreference
android:key="@string/pref_key_sim_thr"
android:title="@string/pref_title_sim_thr"
android:summary="@string/pref_summary_sim_thr"
android:entries="@array/pref_sim_thr_keys"
android:entryValues="@array/pref_sim_thr_values"
android:defaultValue="@string/pref_default_sim_thr"/>
<ListPreference
android:key="@string/pref_key_min_inliers"
android:title="@string/pref_title_min_inliers"
android:summary="@string/pref_summary_min_inliers"
android:entries="@array/pref_min_inliers_keys"
android:entryValues="@array/pref_min_inliers_values"
android:defaultValue="@string/pref_default_min_inliers"/>
<ListPreference
android:key="@string/pref_key_opt_error"
android:title="@string/pref_title_opt_error"
android:summary="@string/pref_summary_opt_error"
android:entries="@array/pref_opt_error_keys"
android:entryValues="@array/pref_opt_error_values"
android:defaultValue="@string/pref_default_opt_error"/>
<ListPreference
android:key="@string/pref_key_features_voc"
android:title="@string/pref_title_features_voc"
android:summary="@string/pref_summary_features_voc"
android:entries="@array/pref_features_voc_keys"
android:entryValues="@array/pref_features_voc_values"
android:defaultValue="@string/pref_default_features_voc"/>
<ListPreference
android:key="@string/pref_key_features"
android:title="@string/pref_title_features"
android:summary="@string/pref_summary_features"
android:entries="@array/pref_features_keys"
android:entryValues="@array/pref_features_values"
android:defaultValue="@string/pref_default_features"/>
<ListPreference
android:key="@string/pref_key_features_type"
android:title="@string/pref_title_features_type"
android:summary="@string/pref_summary_features_type"
android:entries="@array/pref_features_type_keys"
android:entryValues="@array/pref_features_type_values"
android:defaultValue="@string/pref_default_features_type"/>
<ListPreference
android:key="@string/pref_key_optimizer"
android:title="@string/pref_title_optimizer"
android:summary="@string/pref_summary_optimizer"
android:entries="@array/pref_optimizer_keys"
android:entryValues="@array/pref_optimizer_values"
android:defaultValue="@string/pref_default_optimizer"/>
<SwitchPreference
android:key="@string/pref_key_optimize_end"
android:title="@string/pref_title_optimize_end"
android:summary="@string/pref_summary_optimize_end"
android:defaultValue="@string/pref_default_optimize_end"/>
</PreferenceCategory>
<PreferenceCategory
android:title="@string/pref_title_mapping_database">
<SwitchPreference
android:key="@string/pref_key_keep_all_db"
android:title="@string/pref_title_keep_all_db"
android:summary="@string/pref_summary_keep_all_db"
android:defaultValue="@string/pref_default_keep_all_db"/>
<SwitchPreference
android:key="@string/pref_key_raw_scan_saved"
android:title="@string/pref_title_raw_scan_saved"
android:summary="@string/pref_summary_raw_scan_saved"
android:defaultValue="@string/pref_default_raw_scan_saved"/>
<SwitchPreference
android:key="@string/pref_key_db_in_memory"
android:title="@string/pref_title_db_in_memory"
android:summary="@string/pref_summary_db_in_memory"
android:defaultValue="@string/pref_default_db_in_memory"/>
</PreferenceCategory>
</PreferenceScreen>
<PreferenceScreen
android:key="pref_button_export"
android:title="@string/pref_title_export_sub"
android:summary="@string/pref_summary_export"
android:persistent="false">
<ListPreference
android:key="@string/pref_key_cloud_voxel"
android:title="@string/pref_title_cloud_voxel"
android:summary="@string/pref_summary_cloud_voxel"
android:entries="@array/pref_cloud_voxel_keys"
android:entryValues="@array/pref_cloud_voxel_values"
android:defaultValue="@string/pref_default_cloud_voxel"/>
<ListPreference
android:key="@string/pref_key_texture_size"
android:title="@string/pref_title_texture_size"
android:summary="@string/pref_summary_texture_size"
android:entries="@array/pref_texture_size_keys"
android:entryValues="@array/pref_texture_size_values"
android:defaultValue="@string/pref_default_texture_size"/>
<ListPreference
android:key="@string/pref_key_texture_count"
android:title="@string/pref_title_texture_count"
android:summary="@string/pref_summary_texture_count"
android:entries="@array/pref_texture_count_keys"
android:entryValues="@array/pref_texture_count_values"
android:defaultValue="@string/pref_default_texture_count"/>
<ListPreference
android:key="@string/pref_key_normal_k"
android:title="@string/pref_title_normal_k"
android:summary="@string/pref_summary_normal_k"
android:entries="@array/pref_normal_k_values"
android:entryValues="@array/pref_normal_k_values"
android:defaultValue="@string/pref_default_normal_k"/>
<ListPreference
android:key="@string/pref_key_max_texture_distance"
android:title="@string/pref_title_max_texture_distance"
android:summary="@string/pref_summary_max_texture_distance"
android:entries="@array/pref_max_texture_distance_keys"
android:entryValues="@array/pref_max_texture_distance_values"
android:defaultValue="@string/pref_default_max_texture_distance"/>
<ListPreference
android:key="@string/pref_key_min_texture_cluster_size"
android:title="@string/pref_title_min_texture_cluster_size"
android:summary="@string/pref_summary_min_texture_cluster_size"
android:entries="@array/pref_min_texture_cluster_size_keys"
android:entryValues="@array/pref_min_texture_cluster_size_values"
android:defaultValue="@string/pref_default_min_texture_cluster_size"/>
<SwitchPreference
android:key="@string/pref_key_block_render"
android:title="@string/pref_title_block_render"
android:summary="@string/pref_summary_block_render"
android:defaultValue="@string/pref_default_block_render"/>
<PreferenceCategory
android:title="@string/pref_title_optimized">
<ListPreference
android:key="@string/pref_key_opt_depth"
android:title="@string/pref_title_opt_depth"
android:summary="@string/pref_summary_opt_depth"
android:entries="@array/pref_opt_depth_keys"
android:entryValues="@array/pref_opt_depth_values"
android:defaultValue="@string/pref_default_opt_depth"/>
<ListPreference
android:key="@string/pref_key_opt_color_radius"
android:title="@string/pref_title_opt_color_radius"
android:summary="@string/pref_summary_opt_color_radius"
android:entries="@array/pref_opt_color_radius_keys"
android:entryValues="@array/pref_opt_color_radius_values"
android:defaultValue="@string/pref_default_opt_color_radius"/>
<SwitchPreference
android:key="@string/pref_key_opt_clean_white"
android:title="@string/pref_title_opt_clean_white"
android:summary="@string/pref_summary_opt_clean_white"
android:defaultValue="@string/pref_default_opt_clean_white"/>
<ListPreference
android:key="@string/pref_key_opt_min_cluster_size"
android:title="@string/pref_title_opt_min_cluster_size"
android:summary="@string/pref_summary_opt_min_cluster_size"
android:entries="@array/pref_opt_min_cluster_size_keys"
android:entryValues="@array/pref_opt_min_cluster_size_values"
android:defaultValue="@string/pref_default_opt_min_cluster_size"/>
</PreferenceCategory>
</PreferenceScreen>
<ListPreference
android:key="@string/pref_key_gain_max_radius"
android:title="@string/pref_title_gain_max_radius"
android:summary="@string/pref_summary_gain_max_radius"
android:entries="@array/pref_gain_max_radius_keys"
android:entryValues="@array/pref_gain_max_radius_values"
android:defaultValue="@string/pref_default_gain_max_radius"/>
<ListPreference
android:key="@string/pref_key_cluster_ratio"
android:title="@string/pref_title_cluster_ratio"
android:summary="@string/pref_summary_cluster_ratio"
android:entries="@array/pref_cluster_ratio_keys"
android:entryValues="@array/pref_cluster_ratio_values"
android:defaultValue="@string/pref_default_cluster_ratio"/>
<SwitchPreference
android:key="@string/pref_key_notification_sound"
android:title="@string/pref_title_notification_sound"
android:summary="@string/pref_summary_notification_sound"
android:defaultValue="@string/pref_default_notification_sound"/>
</PreferenceCategory>
<PreferenceCategory
android:title="@string/pref_title_presets">
<Preference android:title="@string/pref_title_open_button"
android:key="@string/pref_key_open_button"/>
<Preference android:title="@string/pref_title_save_button"
android:key="@string/pref_key_save_button"/>
<Preference android:title="@string/pref_title_remove_button"
android:key="@string/pref_key_remove_button"/>
<Preference android:title="@string/pref_title_reset_button"
android:key="@string/pref_key_reset_button"/>
</PreferenceCategory>
</PreferenceScreen>

View File

@@ -0,0 +1,81 @@
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:focusableInTouchMode="true" >
<TextView android:id="@+id/text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Model Name*:" />
<EditText
android:id="@+id/editText_filename"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="flagNoExtractUi"
android:ems="10" />
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Description:" />
<EditText
android:id="@+id/editText_description"
android:ems="10"
android:lines="4"
android:minLines="2"
android:gravity="top|left"
android:maxLines="8"
android:layout_weight="1"
android:layout_height="wrap_content"
android:layout_width="fill_parent"
android:scrollbars="vertical"
android:imeOptions="flagNoExtractUi"
android:inputType="textMultiLine" >
<requestFocus />
</EditText>
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tags:" />
<EditText
android:id="@+id/editText_tags"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:imeOptions="flagNoExtractUi"
android:ems="10" />
<CheckBox
android:id="@+id/checkBox_draft"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:checked="true"
android:text="Draft Mode" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dip"
android:layout_weight="1"
android:gravity="right|bottom"
android:orientation="horizontal" >
<Button
android:id="@+id/button_ok"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="0.06"
android:text="Upload" />
</LinearLayout>
</LinearLayout>
</ScrollView>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<WebView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/webv"/>
</LinearLayout>

View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#fff">
<ImageView
android:id="@+id/imageView"
android:layout_width="@dimen/image_width"
android:layout_height="@dimen/image_width"
android:layout_marginLeft="10dp"
android:padding="5dp"
android:src="@drawable/ic_launcher" />
<TextView
android:id="@+id/textView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Demo"
android:textColor="#000" />
</LinearLayout>

View File

@@ -1,19 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<group android:id="@+id/group_pause" android:checkableBehavior="all">
<item android:id="@+id/pause" android:checked="false" android:title="Pause"/>
</group>
<group android:id="@+id/group_actions">
<item android:id="@+id/post_processing" android:title="Post-Processing...">
<group android:checkableBehavior="single">
<item android:id="@+id/point_cloud" android:title="Point Cloud" />
<item android:id="@+id/mesh" android:title="Mesh" />
<item android:id="@+id/texture_mesh" android:checked="true" android:title="Texture Mesh" />
</group>
<item android:id="@+id/save" android:title="Save" android:showAsAction="ifRoom"/>
<item android:id="@+id/export" android:showAsAction="ifRoom" android:title="Export">
<menu>
<item android:id="@+id/export_point_cloud_menu" android:title="Point Cloud">
<menu>
<item android:id="@+id/export_point_cloud" android:title="Current Density" />
<item android:id="@+id/export_point_cloud_highrez" android:title="Max Density" />
</menu>
</item>
<item android:id="@+id/export_optimized_mesh_menu" android:title="Optimized Mesh..." >
<menu>
<item android:id="@+id/export_optimized_mesh" android:title="Colored Mesh" />
<item android:id="@+id/export_optimized_mesh_texture" android:title="Textured Mesh" />
</menu>
</item>
</menu>
</item>
<item android:id="@+id/post_processing" android:title="Optimize" android:showAsAction="ifRoom">
<menu>
<item android:id="@+id/post_processing_standard" android:title="Standard Optimization" />
<item android:id="@+id/post_processing_advanced" android:title="Advanced..." >
<menu>
<item android:id="@+id/global_graph_optimization" android:title="Global Graph Optimization" />
<item android:id="@+id/detect_more_loop_closures" android:title="Detect More Loop Closures" />
<item android:id="@+id/icp_refining" android:title="ICP Refining" />
<item android:id="@+id/gain_compensation_fast" android:title="Adjust Colors (Fast)" />
<item android:id="@+id/gain_compensation_full" android:title="Adjust Colors (Full)" />
<item android:id="@+id/bilateral_filtering" android:title="Mesh Smoothing" />
@@ -23,35 +42,14 @@
</item>
</menu>
</item>
<item android:id="@+id/open" android:title="Open"/>
<item android:id="@+id/export" android:title="Export...">
<menu>
<group android:id="@+id/group_export">
<item android:id="@+id/export_ply" android:title="Mesh (.ply)" />
<item android:id="@+id/export_obj" android:title="Mesh with texture (*.obj)" />
</group>
</menu>
</item>
<item android:id="@+id/save" android:title="Save"/>
<item android:id="@+id/reset" android:title="Reset"/>
<item android:id="@+id/menu_rendering_settings" android:title="Rendering Options...">
<item android:id="@+id/open" android:title="Open" android:showAsAction="ifRoom"/>
<item android:id="@+id/menu_rendering_settings" android:title="Visibility...">
<menu >
<group android:id="@+id/group_rendering_visibility" android:checkableBehavior="all">
<item android:id="@+id/status" android:checked="true" android:title="Status" />
<item android:id="@+id/debug" android:checked="false" android:title="Debug" />
<item android:id="@+id/menu_rendering" android:checkable="false" android:title="Mesh Rendering..." >
<menu>
<group android:checkableBehavior="single">
<item android:id="@+id/point_cloud" android:title="Point Cloud" />
<item android:id="@+id/mesh" android:title="Mesh" />
<item android:id="@+id/texture_mesh" android:checked="true" android:title="Texture Mesh" />
</group>
<item android:id="@+id/mesh_decimation" android:checkable="false" android:title="Mesh Decimation..." />
<item android:id="@+id/mesh_angle_tolerance" android:checkable="false" android:title="Mesh Angle Tolerance..." />
<item android:id="@+id/mesh_triangle_size" android:checkable="false" android:title="Mesh Triangle Size..." />
<item android:id="@+id/max_depth" android:checkable="false" android:title="Max Depth..." />
</menu>
</item>
<item android:id="@+id/map_shown" android:checked="true" android:title="Map Visible" />
<item android:id="@+id/odom_shown" android:checked="true" android:title="Odom Visible" />
<item android:id="@+id/graph_visible" android:checked="true" android:title="Graph Visible" />
@@ -60,30 +58,17 @@
</group>
</menu>
</item>
<item android:id="@+id/menu_mapping_settings" android:title="Mapping Options...">
<item android:id="@+id/modes" android:title="Modes...">
<menu >
<group android:id="@+id/group_mapping_visibility" android:checkableBehavior="all">
<item android:id="@+id/localization_mode" android:checked="false" android:title="Localization Mode" />
<item android:id="@+id/trajectory_mode" android:checked="false" android:title="Trajectory Mode" />
<item android:id="@+id/append" android:checked="true" android:title="Append Mode" />
<item android:id="@+id/nodes_filtering" android:checked="false" android:title="Nodes Filtering" />
<item android:id="@+id/drift_correction" android:checked="false" android:title="Drift Correction" />
<item android:id="@+id/auto_exposure" android:checked="true" android:title="Auto Exposure" />
<item android:id="@+id/resolution" android:checked="false" android:title="HD Mode" />
<item android:id="@+id/data_recorder" android:checked="false" android:title="Data Recorder Mode" />
<item android:id="@+id/menu_param_settings" android:checkable="false" android:title="Parameters...">
<menu >
<item android:id="@+id/update_rate" android:title="Map Update Rate..." />
<item android:id="@+id/time_threshold" android:title="Time Threshold..." />
<item android:id="@+id/loop_threshold" android:title="Loop Closure Threshold..." />
<item android:id="@+id/optimize_error" android:title="Max Optimization Error..." />
<item android:id="@+id/features" android:title="Max Features Extracted..." />
</menu>
</item>
</group>
</menu>
</item>
<item android:id="@+id/settings" android:title="Settings"/>
<item android:id="@+id/reset" android:title="Reset"/>
<item android:id="@+id/about" android:title="About"/>
</group>
</menu>

View File

@@ -0,0 +1,9 @@
<resources>
<string-array name="camera_view_array">
<item>First View</item>
<item>Third-P. View</item>
<item>Top View</item>
<item>Ortho View</item>
</string-array>
</resources>

View File

@@ -0,0 +1,4 @@
<resources>
<dimen name="image_width">150dp</dimen>
</resources>

View File

@@ -1,25 +1,817 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">RTAB-Map</string>
<string name="sys_name">RTAB-Map</string>
<string name="menu_name">Real-Time Appearance-Based Mapping</string>
<string name="menu_name">RTAB-Map</string>
<string name="settings">Settings</string>
<string name="sketchfab">Upload to Sketchfab&#8230;</string>
<string name="status">"Status: "</string>
<string name="words">"Words: "</string>
<string name="first_person">First</string>
<string name="third_person">Third</string>
<string name="top_down">Top</string>
<string name="camera_button">First View</string>
<string name="pause">Pause</string>
<string name="resume">Resume</string>
<string name="backface_on">Backface</string>
<string name="backface_off">Backface</string>
<string name="light_on">Lighting</string>
<string name="light_off">Lighting</string>
<string name="wireframe">Wireframe</string>
<string name="close_visualization">Close Visualization</string>
<string name="save_to_file">Export to File&#8230;</string>
<string name="share_to_sketchfab">Share to Sketchfab&#8230;</string>
<string name="start">Start</string>
<string name="nodes">"Nodes (WM): "</string>
<string name="points">"Number of points: "</string>
<string name="update_time">"Update time (ms): "</string>
<string name="loop_closure">"Loop closure ID: "</string>
<string name="db_size">"Database (MB): "</string>
<string name="free_memory">"Free Memory (MB): "</string>
<string name="database_size">"Database (MB): "</string>
<string name="total_loop">"Loop closures: "</string>
<string name="inliers">"Inliers: "</string>
<string name="features">"Features: "</string>
<string name="rehearsal">"Rehearsal (%): "</string>
<string name="polygons">"Polygons: "</string>
<string name="memory">"Memory (MB): "</string>
<string name="hypothesis">"Hypothesis: "</string>
<string name="memory">"Used Memory (MB): "</string>
<string name="hypothesis">"Hypothesis (%): "</string>
<string name="fps">"FPS (rendering): "</string>
<!-- Preference keys: BEGIN -->
<string name="pref_key_tags">pref_key_tags</string>
<string name="pref_default_tags">rtabmap 3dscan tango</string>
<string name="pref_key_rendering">pref_key_rendering</string>
<string name="pref_default_rendering">2</string>
<string name="pref_key_open_button">pref_key_open_button</string>
<string name="pref_key_save_button">pref_key_save_button</string>
<string name="pref_key_remove_button">pref_key_remove_button</string>
<string name="pref_key_reset_button">pref_key_reset_button</string>
<string name="pref_key_density">pref_key_density</string>
<string name="pref_default_density">1</string>
<string name="pref_key_min_depth">pref_key_min_depth</string>
<string name="pref_default_min_depth">0</string>
<string name="pref_key_depth">pref_key_depth</string>
<string name="pref_default_depth">2.5</string>
<string name="pref_key_point_size">pref_key_point_size</string>
<string name="pref_default_point_size">5</string>
<string name="pref_key_angle">pref_key_angle</string>
<string name="pref_default_angle">20</string>
<string name="pref_key_triangle">pref_key_triangle</string>
<string name="pref_default_triangle">2</string>
<string name="pref_key_rendering_texture_decimation">pref_key_rendering_texture_decimation</string>
<string name="pref_default_rendering_texture_decimation">4</string>
<string name="pref_key_blending">pref_key_blending</string>
<string name="pref_default_blending">true</string>
<string name="pref_key_background_color">pref_key_background_color</string>
<string name="pref_default_background_color">0.2</string>
<string name="pref_key_nodes_filtering">pref_key_nodes_filtering</string>
<string name="pref_default_nodes_filtering">false</string>
<string name="pref_key_append">pref_key_append</string>
<string name="pref_default_append">true</string>
<string name="pref_key_resolution">pref_key_resolution</string>
<string name="pref_default_resolution">false</string>
<string name="pref_key_smoothing">pref_key_smoothing</string>
<string name="pref_default_smoothing">true</string>
<string name="pref_key_fisheye">pref_key_fisheye</string>
<string name="pref_default_fisheye">false</string>
<string name="pref_key_update_rate">pref_key_update_rate</string>
<string name="pref_default_update_rate">1</string>
<string name="pref_key_time_thr">pref_key_time_thr</string>
<string name="pref_default_time_thr">1000</string>
<string name="pref_key_mem_thr">pref_key_mem_thr</string>
<string name="pref_default_mem_thr">0</string>
<string name="pref_key_loop_thr">pref_key_loop_thr</string>
<string name="pref_default_loop_thr">0.11</string>
<string name="pref_key_sim_thr">pref_key_sim_thr</string>
<string name="pref_default_sim_thr">0.3</string>
<string name="pref_key_min_inliers">pref_key_min_inliers</string>
<string name="pref_default_min_inliers">25</string>
<string name="pref_key_opt_error">pref_key_opt_error</string>
<string name="pref_default_opt_error">0.1</string>
<string name="pref_key_features_voc">pref_key_features_voc</string>
<string name="pref_default_features_voc">200</string>
<string name="pref_key_features">pref_key_features</string>
<string name="pref_default_features">400</string>
<string name="pref_key_features_type">pref_key_features_type</string>
<string name="pref_default_features_type">6</string>
<string name="pref_key_optimizer">pref_key_optimizer</string>
<string name="pref_default_optimizer">2</string>
<string name="pref_key_optimize_end">pref_key_optimize_end</string>
<string name="pref_default_optimize_end">true</string>
<string name="pref_key_keep_all_db">pref_key_keep_all_db</string>
<string name="pref_default_keep_all_db">true</string>
<string name="pref_key_raw_scan_saved">pref_key_raw_scan_saved</string>
<string name="pref_default_raw_scan_saved">false</string>
<string name="pref_key_db_in_memory">pref_key_db_in_memory</string>
<string name="pref_default_db_in_memory">true</string>
<string name="pref_key_cloud_voxel">pref_key_cloud_voxel</string>
<string name="pref_default_cloud_voxel">0.01</string>
<string name="pref_key_texture_size">pref_key_texture_size</string>
<string name="pref_default_texture_size">4096</string>
<string name="pref_key_texture_count">pref_key_texture_count</string>
<string name="pref_default_texture_count">1</string>
<string name="pref_key_normal_k">pref_key_normal_k</string>
<string name="pref_default_normal_k">18</string>
<string name="pref_key_max_texture_distance">pref_key_max_texture_distance</string>
<string name="pref_default_max_texture_distance">3</string>
<string name="pref_key_min_texture_cluster_size">pref_key_min_texture_cluster_size</string>
<string name="pref_default_min_texture_cluster_size">50</string>
<string name="pref_key_block_render">pref_key_block_render</string>
<string name="pref_default_block_render">false</string>
<string name="pref_key_opt_depth">pref_key_opt_depth</string>
<string name="pref_default_opt_depth">0</string>
<string name="pref_key_opt_color_radius">pref_key_opt_color_radius</string>
<string name="pref_default_opt_color_radius">0.05</string>
<string name="pref_key_opt_clean_white">pref_key_opt_clean_white</string>
<string name="pref_default_opt_clean_white">true</string>
<string name="pref_key_opt_min_cluster_size">pref_key_opt_min_cluster_size</string>
<string name="pref_default_opt_min_cluster_size">0</string>
<string name="pref_key_gain_max_radius">pref_key_gain_max_radius</string>
<string name="pref_default_gain_max_radius">0.02</string>
<string name="pref_key_cluster_ratio">pref_key_cluster_ratio</string>
<string name="pref_default_cluster_ratio">0.05</string>
<string name="pref_key_notification_sound">pref_key_notification_sound</string>
<string name="pref_default_notification_sound">true</string>
<!-- Preference keys: END -->
<string name="pref_title_rendering">Rendering</string>
<string name="pref_title_density">Point Cloud Density</string>
<string name="pref_summary_density">Decrease density to reduce rendering time and memory. Tip: To apply a different density to current map: save the map, change density and re-open the same map to regenerate the point clouds at this density.</string>
<string name="pref_title_angle">Mesh Angle Tolerance</string>
<string name="pref_summary_angle">Minimum polygon angle. Increase to force scanning perpendicular to surfaces.</string>
<string name="pref_title_triangle">Mesh Triangle Size</string>
<string name="pref_summary_triangle">Size in pixels of the polygons created from the depth image.</string>
<string name="pref_title_rendering_texture_decimation">Texture Resolution</string>
<string name="pref_summary_rendering_texture_decimation">Resolution of the texture for online rendering. This doesn\'t affect Export results.</string>
<string name="pref_title_min_depth">Min Depth</string>
<string name="pref_summary_min_depth">Points under the minimum depth are not rendered.</string>
<string name="pref_title_depth">Max Depth</string>
<string name="pref_summary_depth">Points over the maximum depth are not rendered.</string>
<string name="pref_title_point_size">Point Size</string>
<string name="pref_summary_point_size">Size of the points when rendering only the point cloud.</string>
<string name="pref_title_blending">Blending</string>
<string name="pref_summary_blending">Blend close surfaces together to get more smooth colors on overlapping surfaces. May decrease rendering frame rate.</string>
<string name="pref_title_background_color">Background Color</string>
<string name="pref_summary_background_color"></string>
<string name="pref_title_nodes_filtering">Nodes Filtering</string>
<string name="pref_summary_nodes_filtering">Render only the newest point cloud of a loop closure.</string>
<string-array name="pref_density_keys">
<item>"Maximum"</item>
<item>"High"</item>
<item>"Low"</item>
<item>"Very Low"</item>
</string-array>
<string-array name="pref_density_values">
<item>"0"</item>
<item>"1"</item>
<item>"2"</item>
<item>"3"</item>
</string-array>
<string-array name="pref_min_depth_keys">
<item>"0 m"</item>
<item>"0.3 m"</item>
<item>"0.5 m"</item>
<item>"0.75 m"</item>
<item>"1 m"</item>
<item>"1.5 m"</item>
<item>"2 m"</item>
<item>"2.5 m"</item>
<item>"3 m"</item>
</string-array>
<string-array name="pref_min_depth_values">
<item>"0"</item>
<item>"0.3"</item>
<item>"0.5"</item>
<item>"0.75"</item>
<item>"1"</item>
<item>"1.5"</item>
<item>"2"</item>
<item>"2.5"</item>
<item>"3"</item>
</string-array>
<string-array name="pref_depth_keys">
<item>"No Limit"</item>
<item>"5 m"</item>
<item>"4.5 m"</item>
<item>"4 m"</item>
<item>"3.5 m"</item>
<item>"3 m"</item>
<item>"2.5 m"</item>
<item>"2 m"</item>
<item>"1.5 m"</item>
<item>"1 m"</item>
</string-array>
<string-array name="pref_depth_values">
<item>"0"</item>
<item>"5"</item>
<item>"4.5"</item>
<item>"4"</item>
<item>"3.5"</item>
<item>"3"</item>
<item>"2.5"</item>
<item>"2"</item>
<item>"1.5"</item>
<item>"1"</item>
</string-array>
<string-array name="pref_point_size_values">
<item>"50"</item>
<item>"30"</item>
<item>"25"</item>
<item>"15"</item>
<item>"10"</item>
<item>"5"</item>
<item>"1"</item>
</string-array>
<string-array name="pref_angle_keys">
<item>"60 deg"</item>
<item>"45 deg"</item>
<item>"35 deg"</item>
<item>"30 deg"</item>
<item>"25 deg"</item>
<item>"20 deg"</item>
<item>"15 deg"</item>
<item>"10 deg"</item>
<item>"5 deg"</item>
</string-array>
<string-array name="pref_angle_values">
<item>"60"</item>
<item>"45"</item>
<item>"35"</item>
<item>"30"</item>
<item>"25"</item>
<item>"20"</item>
<item>"15"</item>
<item>"10"</item>
<item>"5"</item>
</string-array>
<string-array name="pref_triangle_keys">
<item>"6 pix"</item>
<item>"5 pix"</item>
<item>"4 pix"</item>
<item>"3 pix"</item>
<item>"2 pix"</item>
</string-array>
<string-array name="pref_triangle_values">
<item>"6"</item>
<item>"5"</item>
<item>"4"</item>
<item>"3"</item>
<item>"2"</item>
</string-array>
<string-array name="pref_rendering_texture_decimation_keys">
<item>"Maximum"</item>
<item>"High"</item>
<item>"Low"</item>
<item>"Very Low"</item>
</string-array>
<string-array name="pref_rendering_texture_decimation_values">
<item>"1"</item>
<item>"2"</item>
<item>"4"</item>
<item>"8"</item>
</string-array>
<string-array name="pref_background_color_keys">
<item>"White"</item>
<item>"0.9"</item>
<item>"Light Gray"</item>
<item>"0.7"</item>
<item>"0.6"</item>
<item>"Gray"</item>
<item>"0.4"</item>
<item>"0.3"</item>
<item>"Dark Gray"</item>
<item>"0.1"</item>
<item>"Black"</item>
</string-array>
<string-array name="pref_background_color_values">
<item>"1.0"</item>
<item>"0.9"</item>
<item>"0.8"</item>
<item>"0.7"</item>
<item>"0.6"</item>
<item>"0.5"</item>
<item>"0.4"</item>
<item>"0.3"</item>
<item>"0.2"</item>
<item>"0.1"</item>
<item>"0.0"</item>
</string-array>
<string name="pref_title_mapping_sub">Mapping&#8230;</string>
<string name="pref_title_mapping">Mapping</string>
<string name="pref_summary_mapping">Advanced mapping parameters for fine tuning.</string>
<string name="pref_title_mapping_core">Core</string>
<string name="pref_title_mapping_database">Database</string>
<string name="pref_title_append">Append Mode</string>
<string name="pref_summary_append">When resuming mapping, wait for a relocalization on the current map before starting a new map.</string>
<string name="pref_title_resolution">HD Mode</string>
<string name="pref_summary_resolution">Save HD images of the color camera if you want very detailed textures. More memory will be required.</string>
<string name="pref_title_smoothing">Smoothing</string>
<string name="pref_summary_smoothing">Smooth the point clouds.</string>
<string name="pref_title_fisheye">Fish Eye Camera</string>
<string name="pref_summary_fisheye">Use fish eye camera instead of the color camera. May not work on some devices.</string>
<string name="pref_title_update_rate">Update Rate</string>
<string name="pref_summary_update_rate">Rate at which a new node is added to map.</string>
<string name="pref_title_time_thr">Time Limit</string>
<string name="pref_summary_time_thr">Maximum time allowed for map updates. If time to add a new node is above this theshold, some old parts of the map are temporarly forgotten to reduce time of next updates.</string>
<string name="pref_title_mem_thr">Memory Limit</string>
<string name="pref_summary_mem_thr">Maximum nodes kept in working memory.</string>
<string name="pref_title_loop_thr">Loop Closure Threshold</string>
<string name="pref_summary_loop_thr">Threshold at which loop closure hypotheses are accepted. Higher means more robust to false loop closures while rejecting more good loop closures.</string>
<string name="pref_title_sim_thr">Similarity Threshold</string>
<string name="pref_summary_sim_thr">Threshold at which consecutive images are considered the same, so the corresponding node\'s weight is increased. The background turns dark blue when this happens.</string>
<string name="pref_title_min_inliers">Min Inliers</string>
<string name="pref_summary_min_inliers">Minimum visual inliers to accept a loop closure.</string>
<string name="pref_title_opt_error">Max Optimization Error</string>
<string name="pref_summary_opt_error">Reject any loop closures causing error corrections in the map higher than this threshold.</string>
<string name="pref_title_features_voc">Max Features Extracted (Vocabulary)</string>
<string name="pref_summary_features_voc">Extracting more features per image would result in better loop closure hypotheses but more processing time is required.</string>
<string name="pref_title_features">Max Features Extracted (Loop Closure)</string>
<string name="pref_summary_features">Extracting more features per image would result in better loop closure transforms but more processing time is required.</string>
<string name="pref_title_features_type">Feature Type</string>
<string name="pref_summary_features_type">BRIEF features are fast to compute but are not rotation invariant like FREAK. Warning: Changing feature type will automatically reset the map!</string>
<string name="pref_title_optimizer">Graph Optimizer</string>
<string name="pref_summary_optimizer">Graph optimization approach.</string>
<string name="pref_title_optimize_end">Optimization from Graph End</string>
<string name="pref_summary_optimize_end">The map\'s graph is optimized from the last node. The map is moved when a loop closure happens instead of jumping the current pose back to localized area. </string>
<string name="pref_title_keep_all_db">Save All Frames in Database</string>
<string name="pref_summary_keep_all_db">Discarded frames while not moving are still saved in database. Useful to replay exactly the scanning on RTAB-Map Desktop.</string>
<string name="pref_title_raw_scan_saved">Save Raw Scan</string>
<string name="pref_summary_raw_scan_saved">Save raw point clouds in database.</string>
<string name="pref_title_db_in_memory">Database In Memory</string>
<string name="pref_summary_db_in_memory">The database is kept in RAM for fast access. Set to false to reduce RAM used at the cost of slower access. This parameter is applied on reset or when a database is opened.</string>
<string-array name="pref_update_rate_keys">
<item>"Max"</item>
<item>"5 Hz"</item>
<item>"4 Hz"</item>
<item>"3 Hz"</item>
<item>"2 Hz"</item>
<item>"1 Hz"</item>
<item>"0.5 Hz"</item>
</string-array>
<string-array name="pref_update_rate_values">
<item>"0"</item>
<item>"5"</item>
<item>"4"</item>
<item>"3"</item>
<item>"2"</item>
<item>"1"</item>
<item>"0.5"</item>
</string-array>
<string-array name="pref_time_thr_keys">
<item>"No Limit"</item>
<item>"1500 ms"</item>
<item>"1400 ms"</item>
<item>"1300 ms"</item>
<item>"1200 ms"</item>
<item>"1100 ms"</item>
<item>"1000 ms"</item>
<item>"900 ms"</item>
<item>"800 ms"</item>
<item>"700 ms"</item>
<item>"600 ms"</item>
<item>"500 ms"</item>
<item>"400"</item>
</string-array>
<string-array name="pref_time_thr_values">
<item>"0"</item>
<item>"1500"</item>
<item>"1400"</item>
<item>"1300"</item>
<item>"1200"</item>
<item>"1100"</item>
<item>"1000"</item>
<item>"900"</item>
<item>"800"</item>
<item>"700"</item>
<item>"600"</item>
<item>"500"</item>
<item>"400"</item>
</string-array>
<string-array name="pref_mem_thr_keys">
<item>"No Limit"</item>
<item>"500 nodes"</item>
<item>"400 nodes"</item>
<item>"300 nodes"</item>
<item>"200 nodes"</item>
<item>"100 nodes"</item>
<item>"50 nodes"</item>
</string-array>
<string-array name="pref_mem_thr_values">
<item>"0"</item>
<item>"500"</item>
<item>"400"</item>
<item>"300"</item>
<item>"200"</item>
<item>"100"</item>
<item>"50"</item>
</string-array>
<string-array name="pref_loop_thr_keys">
<item>"0.90"</item>
<item>"0.80"</item>
<item>"0.70"</item>
<item>"0.60"</item>
<item>"0.50"</item>
<item>"0.40"</item>
<item>"0.30"</item>
<item>"0.20"</item>
<item>"0.15"</item>
<item>"0.11"</item>
<item>"0.10"</item>
</string-array>
<string-array name="pref_loop_thr_values">
<item>"0.90"</item>
<item>"0.80"</item>
<item>"0.70"</item>
<item>"0.60"</item>
<item>"0.50"</item>
<item>"0.40"</item>
<item>"0.30"</item>
<item>"0.20"</item>
<item>"0.15"</item>
<item>"0.11"</item>
<item>"0.10"</item>
</string-array>
<string-array name="pref_sim_thr_keys">
<item>"Disabled"</item>
<item>"0.60"</item>
<item>"0.50"</item>
<item>"0.40"</item>
<item>"0.30"</item>
<item>"0.20"</item>
<item>"0.10"</item>
</string-array>
<string-array name="pref_sim_thr_values">
<item>"0"</item>
<item>"0.6"</item>
<item>"0.5"</item>
<item>"0.4"</item>
<item>"0.3"</item>
<item>"0.2"</item>
<item>"0.1"</item>
</string-array>
<string-array name="pref_min_inliers_keys">
<item>"35"</item>
<item>"30"</item>
<item>"25"</item>
<item>"20"</item>
<item>"15"</item>
<item>"10"</item>
</string-array>
<string-array name="pref_min_inliers_values">
<item>"35"</item>
<item>"30"</item>
<item>"25"</item>
<item>"20"</item>
<item>"15"</item>
<item>"10"</item>
</string-array>
<string-array name="pref_opt_error_keys">
<item>"1.0 m"</item>
<item>"0.5 m"</item>
<item>"0.35 m"</item>
<item>"0.2 m"</item>
<item>"0.1 m"</item>
<item>"0.05 m"</item>
<item>"0.025 m"</item>
<item>"0.01 m"</item>
<item>"Disabled"</item>
</string-array>
<string-array name="pref_opt_error_values">
<item>"1.0"</item>
<item>"0.5"</item>
<item>"0.35"</item>
<item>"0.2"</item>
<item>"0.1"</item>
<item>"0.05"</item>
<item>"0.025"</item>
<item>"0.01"</item>
<item>"0"</item>
</string-array>
<string-array name="pref_features_voc_keys">
<item>"No Limit"</item>
<item>"1000"</item>
<item>"900"</item>
<item>"800"</item>
<item>"700"</item>
<item>"600"</item>
<item>"500"</item>
<item>"400"</item>
<item>"300"</item>
<item>"200"</item>
<item>"100"</item>
<item>"Disabled"</item>
</string-array>
<string-array name="pref_features_voc_values">
<item>"0"</item>
<item>"1000"</item>
<item>"900"</item>
<item>"800"</item>
<item>"700"</item>
<item>"600"</item>
<item>"500"</item>
<item>"400"</item>
<item>"300"</item>
<item>"200"</item>
<item>"100"</item>
<item>"-1"</item>
</string-array>
<string-array name="pref_features_keys">
<item>"No Limit"</item>
<item>"1000"</item>
<item>"900"</item>
<item>"800"</item>
<item>"700"</item>
<item>"600"</item>
<item>"500"</item>
<item>"400"</item>
<item>"300"</item>
<item>"200"</item>
<item>"100"</item>
</string-array>
<string-array name="pref_features_values">
<item>"0"</item>
<item>"1000"</item>
<item>"900"</item>
<item>"800"</item>
<item>"700"</item>
<item>"600"</item>
<item>"500"</item>
<item>"400"</item>
<item>"300"</item>
<item>"200"</item>
<item>"100"</item>
</string-array>
<string-array name="pref_features_type_keys">
<item>"BRIEF"</item>
<item>"FREAK"</item>
</string-array>
<string-array name="pref_features_type_values">
<item>"6"</item>
<item>"5"</item>
</string-array>
<string-array name="pref_optimizer_keys">
<item>"GTSAM"</item>
<item>"g2o"</item>
<item>"TORO"</item>
</string-array>
<string-array name="pref_optimizer_values">
<item>"2"</item>
<item>"1"</item>
<item>"0"</item>
</string-array>
<string name="pref_title_export_sub">Exporting&#8230;</string>
<string name="pref_title_export">Exporting</string>
<string name="pref_summary_export">Advanced parameters used when exporting the map.</string>
<string name="pref_title_cloud_voxel">Voxel Size</string>
<string name="pref_summary_cloud_voxel">If you don\'t need a very precise point cloud, you can set this to reduce the output point cloud size. This is also used for optimized mesh.</string>
<string name="pref_title_texture_size">Texture Size</string>
<string name="pref_summary_texture_size">If the map is large, you may want to increase this to maximize the texture resolution.</string>
<string name="pref_title_texture_count">Maximum Output Textures</string>
<string name="pref_summary_texture_count">Note that all textures are still merged into one for visualization, but exported in multiple files.</string>
<string name="pref_title_normal_k">Normal K</string>
<string name="pref_summary_normal_k">K-nearest neighbors used for normal computation when a mesh is created.</string>
<string name="pref_title_max_texture_distance">Max Texture Distance</string>
<string name="pref_summary_max_texture_distance">Maximum distance from a camera for polygons to be textured by this camera.</string>
<string name="pref_title_min_texture_cluster_size">Min Texture Cluster Size</string>
<string name="pref_summary_min_texture_cluster_size">Minimum polygon cluster size to be textured by a camera. This helps to filter sparse textured polygons.</string>
<string name="pref_title_block_render">Block Rendering Thread While Exporting</string>
<string name="pref_summary_block_render">This decreases exporting time, but freezes rendering while exporting. This also clears temporary the rendered clouds/meshes from memory during exporting, this can be useful to avoid out of memory errors.</string>
<string-array name="pref_cloud_voxel_keys">
<item>"0.2 m"</item>
<item>"0.1 m"</item>
<item>"0.05 m"</item>
<item>"0.02 m"</item>
<item>"0.01 m"</item>
<item>"0.005 m"</item>
<item>"Disabled"</item>
</string-array>
<string-array name="pref_cloud_voxel_values">
<item>"0.2"</item>
<item>"0.1"</item>
<item>"0.05"</item>
<item>"0.02"</item>
<item>"0.01"</item>
<item>"0.005"</item>
<item>"0"</item>
</string-array>
<string-array name="pref_texture_size_keys">
<item>"16384x16384"</item>
<item>"8192x8192"</item>
<item>"4096x4096"</item>
<item>"2048x2048"</item>
<item>"1024x1024"</item>
</string-array>
<string-array name="pref_texture_size_values">
<item>"16384"</item>
<item>"8192"</item>
<item>"4096"</item>
<item>"2048"</item>
<item>"1024"</item>
</string-array>
<string-array name="pref_texture_count_keys">
<item>"8"</item>
<item>"7"</item>
<item>"6"</item>
<item>"5"</item>
<item>"4"</item>
<item>"3"</item>
<item>"2"</item>
<item>"1"</item>
</string-array>
<string-array name="pref_texture_count_values">
<item>"8"</item>
<item>"7"</item>
<item>"6"</item>
<item>"5"</item>
<item>"4"</item>
<item>"3"</item>
<item>"2"</item>
<item>"1"</item>
</string-array>
<string-array name="pref_normal_k_values">
<item>"30"</item>
<item>"24"</item>
<item>"18"</item>
<item>"12"</item>
<item>"6"</item>
</string-array>
<string-array name="pref_max_texture_distance_keys">
<item>"No Limit"</item>
<item>"5 m"</item>
<item>"4.5 m"</item>
<item>"4 m"</item>
<item>"3.5 m"</item>
<item>"3 m"</item>
<item>"2.5 m"</item>
<item>"2 m"</item>
</string-array>
<string-array name="pref_max_texture_distance_values">
<item>"0"</item>
<item>"5"</item>
<item>"4.5"</item>
<item>"4"</item>
<item>"3.5"</item>
<item>"3"</item>
<item>"2.5"</item>
<item>"2"</item>
</string-array>
<string-array name="pref_min_texture_cluster_size_keys">
<item>"1000"</item>
<item>"500"</item>
<item>"200"</item>
<item>"100"</item>
<item>"50"</item>
<item>"10"</item>
<item>"Disabled"</item>
</string-array>
<string-array name="pref_min_texture_cluster_size_values">
<item>"1000"</item>
<item>"500"</item>
<item>"200"</item>
<item>"100"</item>
<item>"50"</item>
<item>"10"</item>
<item>"0"</item>
</string-array>
<string name="pref_title_optimized">Optimized</string>
<string name="pref_title_opt_voxel">Voxel Size</string>
<string name="pref_summary_opt_voxel">Increasing this can reduce reconstruction time at the cost of less geometry precision.</string>
<string name="pref_title_opt_depth">Reconstruction Depth</string>
<string name="pref_summary_opt_depth">Lowering this parameter decreases reconstruction time, but geometry precision is lower. Minimum polygon size: map length / 2^depth). \"Auto\" means that depth is chosen so that polygon size is just under 3 cm.</string>
<string name="pref_title_opt_color_radius">Color Radius</string>
<string name="pref_summary_opt_color_radius">Radius used to transfer nearest color from the point cloud to reconstructed mesh. When exporting with texture, if Clean Mesh is also enabled, this will limit the number of polygons textured in holes.</string>
<string name="pref_title_opt_clean_white">Clean Mesh</string>
<string name="pref_summary_opt_clean_white">Clean mesh from textureless or colorless reconstructed polygons.</string>
<string name="pref_summary_opt_min_cluster_size">This can be used to filter polygons before texturing.</string>
<string name="pref_title_opt_min_cluster_size">Polygon Filtering</string>
<string-array name="pref_opt_depth_keys">
<item>"Auto"</item>
<item>"12"</item>
<item>"11"</item>
<item>"10"</item>
<item>"9"</item>
<item>"8"</item>
<item>"7"</item>
<item>"6"</item>
</string-array>
<string-array name="pref_opt_depth_values">
<item>"0"</item>
<item>"12"</item>
<item>"11"</item>
<item>"10"</item>
<item>"9"</item>
<item>"8"</item>
<item>"7"</item>
<item>"6"</item>
</string-array>
<string-array name="pref_opt_color_radius_keys">
<item>"Nearest"</item>
<item>"2 m"</item>
<item>"1 m"</item>
<item>"0.5 m"</item>
<item>"0.2 m"</item>
<item>"0.1 m"</item>
<item>"0.05 m"</item>
<item>"0.025"</item>
<item>"0.02"</item>
<item>"0.015"</item>
<item>"0.01"</item>
<item>"Disabled"</item>
</string-array>
<string-array name="pref_opt_color_radius_values">
<item>"0"</item>
<item>"2"</item>
<item>"1"</item>
<item>"0.5"</item>
<item>"0.2"</item>
<item>"0.1"</item>
<item>"0.05"</item>
<item>"0.025"</item>
<item>"0.02"</item>
<item>"0.015"</item>
<item>"0.01"</item>
<item>"-1"</item>
</string-array>
<string-array name="pref_opt_min_cluster_size_keys">
<item>"Only biggest cluster kept"</item>
<item>"Keep all polygons"</item>
</string-array>
<string-array name="pref_opt_min_cluster_size_values">
<item>"-1"</item>
<item>"0"</item>
</string-array>
<string name="pref_title_general">General</string>
<string name="pref_title_gain_max_radius">Color Correction Radius</string>
<string name="pref_summary_gain_max_radius">Radius used to find pixel correspondences for Adjust Colors optimization.</string>
<string name="pref_title_cluster_ratio">Noise Filtering Ratio</string>
<string name="pref_summary_cluster_ratio">Polygon clusters with size smaller than this ratio of the largest cluster are removed by the Noise Filtering optimization.</string>
<string name="pref_title_notification_sound">Notification Sound</string>
<string name="pref_summary_notification_sound">After saving database or preparing data to export, a notification sound is played.</string>
<string-array name="pref_gain_max_radius_keys">
<item>"0.3 m"</item>
<item>"0.2 m"</item>
<item>"0.1 m"</item>
<item>"0.05 m"</item>
<item>"0.025 m"</item>
<item>"0.02 m"</item>
<item>"0.015 m"</item>
<item>"0.01 m"</item>
</string-array>
<string-array name="pref_gain_max_radius_values">
<item>"0.3"</item>
<item>"0.2"</item>
<item>"0.1"</item>
<item>"0.05"</item>
<item>"0.025"</item>
<item>"0.02"</item>
<item>"0.015"</item>
<item>"0.01"</item>
</string-array>
<string-array name="pref_cluster_ratio_keys">
<item>"Keep Largest Only"</item>
<item>"0.9"</item>
<item>"0.8"</item>
<item>"0.7"</item>
<item>"0.6"</item>
<item>"0.5"</item>
<item>"0.4"</item>
<item>"0.3"</item>
<item>"0.2"</item>
<item>"0.1"</item>
<item>"0.05"</item>
<item>"0.01"</item>
</string-array>
<string-array name="pref_cluster_ratio_values">
<item>"1.0"</item>
<item>"0.9"</item>
<item>"0.8"</item>
<item>"0.7"</item>
<item>"0.6"</item>
<item>"0.5"</item>
<item>"0.4"</item>
<item>"0.3"</item>
<item>"0.2"</item>
<item>"0.1"</item>
<item>"0.05"</item>
<item>"0.01"</item>
</string-array>
<string name="pref_title_presets">Presets</string>
<string name="pref_title_open_button">Open</string>
<string name="pref_title_save_button">Save</string>
<string name="pref_title_remove_button">Remove</string>
<string name="pref_title_reset_button">Restore All Default Settings</string>
<string name="title_activity_sketchfab">SketchfabActivity</string>
<string name="hello_world">Hello world!</string>
<string name="action_settings">Settings</string>
</resources>

View File

@@ -0,0 +1,10 @@
<resources>
<style name="ThemeActionBar" parent="@android:style/Widget.DeviceDefault.ActionBar.Solid">
<item name="android:background">#20000000</item>
</style>
<style name="ThemeApp" parent="@android:style/Theme.DeviceDefault">
<item name="android:actionBarStyle">@style/ThemeActionBar</item>
<item name="android:windowActionBarOverlay">true</item>
</style>
</resources>

View File

@@ -8,11 +8,13 @@ import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import android.app.Dialog;
import android.content.Context;
import android.graphics.Color;
import android.os.Bundle;
import android.text.Html;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.widget.TextView;
@@ -33,8 +35,10 @@ public class AboutDialog extends Dialog{
setContentView(R.layout.about);
TextView tv = (TextView)findViewById(R.id.info_text);
tv.setText(Html.fromHtml(readRawTextFile(R.raw.info)));
tv.setMovementMethod(LinkMovementMethod.getInstance());
tv.setLinkTextColor(Color.WHITE);
Linkify.addLinks(tv, Linkify.ALL);
tv.append(Html.fromHtml("<b><a href=http://introlab.github.io/rtabmap/index.html#privacy-policy>Privacy Policy</a></b>"));
}
public static String readRawTextFile(int id) {

View File

@@ -0,0 +1,102 @@
package com.introlab.rtabmap;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Drawable;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.SimpleAdapter;
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
public class DatabaseListArrayAdapter extends SimpleAdapter {
LayoutInflater inflater;
Context context;
ArrayList<HashMap<String, String>> arrayList;
int imageWidth;
public DatabaseListArrayAdapter(Context context, ArrayList<HashMap<String, String>> data, int resource, String[] from, int[] to) {
super(context, data, resource, from, to);
this.context = context;
this.arrayList = data;
this.imageWidth = (int)context.getResources().getDimension(R.dimen.image_width);
inflater.from(context);
}
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
View view = super.getView(position, convertView, parent);
ImageView imageView = (ImageView) view.findViewById(R.id.imageView);
boolean imageSet = false;
String path = this.arrayList.get(position).get("path");
if(!path.isEmpty())
{
SQLiteDatabase db = null;
try {
db = SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READONLY);
// get version
Cursor c1 = db.rawQuery("SELECT version FROM Admin", null);
if(c1.moveToFirst()) {
String version = c1.getString(c1.getColumnIndex("version"));
Log.i(RTABMapActivity.TAG, "Version="+version);
if(Util.versionCompare(version, "0.12.0") >= 0) {
Cursor c2 = db.rawQuery("SELECT preview_image FROM Admin WHERE preview_image is not null", null);
if(c2.moveToFirst()) {
Log.i(RTABMapActivity.TAG, "Found image preview for db " + path);
byte[] bytes = c2.getBlob(c2.getColumnIndex("preview_image"));
ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
Bitmap bitmap = BitmapFactory.decodeStream(inputStream);
imageView.setImageBitmap(bitmap);
imageSet = true;
}
else {
Log.i(RTABMapActivity.TAG, "Not found image preview for db " + path);
}
}
else {
Log.i(RTABMapActivity.TAG, "Too old database for preview image, path = " + path);
}
}
else {
Log.e(RTABMapActivity.TAG, "Failed getting version from database");
}
} catch (Exception e) {
Log.e(RTABMapActivity.TAG, e.getMessage());
}
finally {
if(db != null && db.isOpen()) {
db.close();
}
}
}
else
{
Log.e(RTABMapActivity.TAG, "Database path empty for item " + position);
}
if(!imageSet)
{
Drawable myDrawable = context.getResources().getDrawable(R.drawable.ic_launcher);
imageView.setImageDrawable(myDrawable);
}
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(imageWidth,imageWidth/(!imageSet?2:1));
imageView.setLayoutParams(layoutParams);
return view;
}
}

View File

@@ -0,0 +1,148 @@
package com.introlab.rtabmap;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.List;
/**
* This utility class provides an abstraction layer for sending multipart HTTP
* POST requests to a web server.
* @author www.codejava.net
* http://www.codejava.net/java-se/networking/upload-files-by-sending-multipart-request-programmatically
*
*/
public class MultipartUtility {
private final String boundary;
private static final String LINE_FEED = "\r\n";
private HttpURLConnection httpConn;
private String charset;
private OutputStream outputStream;
private PrintWriter writer;
/**
* This constructor initializes a new HTTP POST request with content type
* is set to multipart/form-data
* @param requestURL
* @param charset
* @throws IOException
*/
public MultipartUtility(String requestURL, String token, String charset)
throws IOException {
this.charset = charset;
// creates a unique boundary based on time stamp
boundary = "===" + System.currentTimeMillis() + "===";
URL url = new URL(requestURL);
httpConn = (HttpURLConnection) url.openConnection();
httpConn.setUseCaches(false);
httpConn.setDoOutput(true); // indicates POST method
httpConn.setDoInput(true);
httpConn.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundary);
httpConn.setRequestProperty("Authorization", "Bearer " + token);
outputStream = httpConn.getOutputStream();
writer = new PrintWriter(new OutputStreamWriter(outputStream, charset),
true);
}
/**
* Adds a form field to the request
* @param name field name
* @param value field value
*/
public void addFormField(String name, String value) {
writer.append("--" + boundary).append(LINE_FEED);
writer.append("Content-Disposition: form-data; name=\"" + name + "\"").append(LINE_FEED);
writer.append("Content-Type: text/plain; charset=" + charset).append(LINE_FEED);
writer.append(LINE_FEED);
writer.append(value).append(LINE_FEED);
writer.flush();
}
/**
* Adds a upload file section to the request
* @param fieldName name attribute in <input type="file" name="..." />
* @param uploadFile a File to be uploaded
* @throws IOException
*/
public void addFilePart(String fieldName, File uploadFile)
throws IOException {
String fileName = uploadFile.getName();
writer.append("--" + boundary).append(LINE_FEED);
writer.append(
"Content-Disposition: form-data; name=\"" + fieldName
+ "\"; filename=\"" + fileName + "\"")
.append(LINE_FEED);
writer.append(
"Content-Type: "
+ URLConnection.guessContentTypeFromName(fileName))
.append(LINE_FEED);
writer.append("Content-Transfer-Encoding: binary").append(LINE_FEED);
writer.append(LINE_FEED);
writer.flush();
FileInputStream inputStream = new FileInputStream(uploadFile);
byte[] buffer = new byte[4096];
int bytesRead = -1;
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
outputStream.flush();
inputStream.close();
writer.append(LINE_FEED);
writer.flush();
}
/**
* Adds a header field to the request.
* @param name - name of the header field
* @param value - value of the header field
*/
public void addHeaderField(String name, String value) {
writer.append(name + ": " + value).append(LINE_FEED);
writer.flush();
}
/**
* Completes the request and receives response from the server.
* @return a list of Strings as response in case the server returned
* status OK, otherwise an exception is thrown.
* @throws IOException
*/
public List<String> finish() throws IOException {
List<String> response = new ArrayList<String>();
writer.append(LINE_FEED).flush();
writer.append("--" + boundary + "--").append(LINE_FEED);
writer.close();
// checks server's status code first
int status = httpConn.getResponseCode();
if (status == 201) {
BufferedReader reader = new BufferedReader(new InputStreamReader(
httpConn.getInputStream()));
String line = null;
while ((line = reader.readLine()) != null) {
response.add(line);
}
reader.close();
httpConn.disconnect();
} else {
throw new IOException("Server returned non-OK status: " + status + ", msg: " + httpConn.getResponseMessage());
}
return response;
}
}

View File

@@ -0,0 +1,43 @@
package com.introlab.rtabmap;
import android.content.Context;
import android.util.AttributeSet;
import android.widget.Spinner;
/** Spinner extension that calls onItemSelected even when the selection is the same as its previous value
Author: Mattia Ruggiero
https://stackoverflow.com/questions/5335306/how-can-i-get-an-event-in-android-spinner-when-the-current-selected-item-is-sele
*/
public class NDSpinner extends Spinner {
public NDSpinner(Context context)
{ super(context); }
public NDSpinner(Context context, AttributeSet attrs)
{ super(context, attrs); }
public NDSpinner(Context context, AttributeSet attrs, int defStyle)
{ super(context, attrs, defStyle); }
@Override
public void setSelection(int position, boolean animate) {
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position, animate);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
//getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
@Override
public void setSelection(int position) {
boolean sameSelected = position == getSelectedItemPosition();
super.setSelection(position);
if (sameSelected) {
// Spinner does not call the OnItemSelectedListener if the same item is selected, so do it manually now
getOnItemSelectedListener().onItemSelected(this, getSelectedView(), position, getSelectedItemId());
}
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -25,8 +25,10 @@ public class RTABMapLib
// The activity object is used for checking if the API version is outdated.
public static native void onCreate(RTABMapActivity activity);
public static native void openEmptyDatabase();
public static native void openDatabase(String databasePath);
public static native void setScreenRotation(int displayRotation, int cameraRotation);
public static native int openDatabase(String databasePath, boolean databaseInMemory, boolean optimize);
public static native int openDatabase2(String databaseSource, String databasePath, boolean databaseInMemory, boolean optimize);
/*
* Called when the Tango service is connected.
@@ -57,6 +59,7 @@ public class RTABMapLib
public static native void setPausedMapping(boolean paused);
public static native void setOnlineBlending(boolean enabled);
public static native void setMapCloudShown(boolean shown);
public static native void setOdomCloudShown(boolean shown);
public static native void setMeshRendering(boolean enabled, boolean withTexture);
@@ -64,22 +67,54 @@ public class RTABMapLib
public static native void setTrajectoryMode(boolean enabled);
public static native void setGraphOptimization(boolean enabled);
public static native void setNodesFiltering(boolean enabled);
public static native void setDriftCorrection(boolean enabled);
public static native void setGraphVisible(boolean visible);
public static native void setGridVisible(boolean visible);
public static native void setAutoExposure(boolean enabled);
public static native void setRawScanSaved(boolean enabled);
public static native void setFullResolution(boolean enabled);
public static native void setSmoothing(boolean enabled);
public static native void setCameraColor(boolean enabled);
public static native void setAppendMode(boolean enabled);
public static native void setDataRecorderMode(boolean enabled);
public static native void setMaxCloudDepth(float value);
public static native void setMeshDecimation(int value);
public static native void setMinCloudDepth(float value);
public static native void setPointSize(float value);
public static native void setFOV(float value);
public static native void setOrthoCropFactor(float value);
public static native void setGridRotation(float value);
public static native void setLighting(boolean enabled);
public static native void setBackfaceCulling(boolean enabled);
public static native void setWireframe(boolean enabled);
public static native void setCloudDensityLevel(int value);
public static native void setMeshAngleTolerance(float value);
public static native void setMeshTriangleSize(int value);
public static native void setClusterRatio(float value);
public static native void setMaxGainRadius(float value);
public static native void setRenderingTextureDecimation(int value);
public static native void setBackgroundColor(float gray);
public static native int setMappingParameter(String key, String value);
public static native void resetMapping();
public static native void save(String outputDatabasePath);
public static native boolean exportMesh(String filePath);
public static native void cancelProcessing();
public static native boolean exportMesh(
float cloudVoxelSize,
boolean regenerateCloud,
boolean meshing,
int textureSize,
int textureCount,
int normalK,
boolean optimized,
float optimizedVoxelSize,
int optimizedDepth,
int optimizedMaxPolygons,
float optimizedColorRadius,
boolean optimizedCleanWhitePolygons,
int optimizedMinClusterSize,
float optimizedMaxTextureDistance,
int optimizedMinTextureClusterSize,
boolean blockRendering);
public static native boolean writeExportedMesh(String directory, String name);
public static native boolean postExportation(boolean visualize);
public static native int postProcessing(int approach);
public static native String getStatus();

View File

@@ -16,8 +16,16 @@
package com.introlab.rtabmap;
import java.util.Vector;
import java.util.concurrent.locks.ReentrantLock;
import android.app.Activity;
import android.app.ProgressDialog;
import android.opengl.GLES20;
import android.opengl.GLSurfaceView;
import android.opengl.Matrix;
import android.util.Log;
import android.widget.Toast;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
@@ -26,30 +34,195 @@ import javax.microedition.khronos.opengles.GL10;
// ground grid, camera frustum, camera axis, and trajectory based on the Tango
// device's pose.
public class Renderer implements GLSurfaceView.Renderer {
private final float[] mtrxProjection = new float[16];
private final float[] mtrxView = new float[16];
private final float[] mtrxProjectionAndView = new float[16];
private TextManager mTextManager = null;
private float mSurfaceHeight = 0.0f;
private float mTextColor = 1.0f;
private int mOffset = 0;
private ProgressDialog mProgressDialog;
private Vector<TextObject> mTexts;
private static RTABMapActivity mActivity;
public Renderer(RTABMapActivity c) {
mActivity = c;
}
private ProgressDialog mProgressDialog = null;
private Toast mToast = null;
private boolean mTextChanged = false;
private ReentrantLock mTextLock = new ReentrantLock();
public void setProgressDialog(ProgressDialog progressDialog)
{
mProgressDialog = progressDialog;
}
public void setToast(Toast toast)
{
mToast = toast;
}
// Render loop of the Gl context.
public void onDrawFrame(GL10 gl) {
int value = RTABMapLib.render();
if(value == 1 && mProgressDialog != null)
{
mProgressDialog.dismiss();
}
}
public void setOffset(int offset)
{
mOffset = offset;
}
// Called when the surface size changes.
public void onSurfaceChanged(GL10 gl, int width, int height) {
RTABMapLib.setupGraphic(width, height);
}
// Render loop of the Gl context.
public void onDrawFrame(GL10 useGLES20instead) {
// Called when the surface is created or recreated.
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
RTABMapLib.initGlContent();
}
try
{
final int value = RTABMapLib.render();
if(mTextManager!=null)
{
if(mTextChanged)
{
mTextChanged = false;
Vector<TextObject> txtcollection = new Vector<TextObject>();
mTextLock.lock();
try {
if(mTexts.size() > 0)
{
txtcollection.addAll(mTexts);
}
} finally {
mTextLock.unlock();
}
// Prepare the text for rendering
mTextManager.PrepareDraw(txtcollection);
}
float[] mvp = new float[16];
Matrix.translateM(mvp, 0, mtrxProjectionAndView, 0, 0, mOffset, 0);
mTextManager.Draw(mvp);
}
if(value != 0 && mProgressDialog != null && mProgressDialog.isShowing())
{
mActivity.runOnUiThread(new Runnable() {
public void run() {
if(!RTABMapActivity.DISABLE_LOG) Log.i("RTABMapActivity", "Renderer: dismiss dialog, value received=" + String.valueOf(value));
mProgressDialog.dismiss();
mActivity.resetNoTouchTimer();
}
});
}
if(value==-1)
{
mActivity.runOnUiThread(new Runnable() {
public void run() {
if(mToast!=null)
{
mToast.makeText(mActivity, String.format("Out of Memory!"), Toast.LENGTH_SHORT).show();
}
}
});
}
else if(value==-2)
{
mActivity.runOnUiThread(new Runnable() {
public void run() {
if(mToast!=null)
{
mToast.makeText(mActivity, String.format("Rendering Error!"), Toast.LENGTH_SHORT).show();
}
}
});
}
}
catch(final Exception e)
{
mActivity.runOnUiThread(new Runnable() {
public void run() {
if(mToast!=null)
{
mToast.makeText(mActivity, String.format("Rendering error! %s", e.getMessage()), Toast.LENGTH_SHORT).show();
}
}
});
}
}
// Called when the surface size changes.
public void onSurfaceChanged(GL10 useGLES20instead, int width, int height) {
RTABMapLib.setupGraphic(width, height);
mSurfaceHeight = (float)height;
// Clear our matrices
for(int i=0;i<16;i++)
{
mtrxProjection[i] = 0.0f;
mtrxView[i] = 0.0f;
mtrxProjectionAndView[i] = 0.0f;
}
// Setup our screen width and height for normal sprite translation.
Matrix.orthoM(mtrxProjection, 0, 0f, width, 0.0f, height, 0, 50);
// Set the camera position (View matrix)
Matrix.setLookAtM(mtrxView, 0, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1.0f, 0.0f);
// Calculate the projection and view transformation
Matrix.multiplyMM(mtrxProjectionAndView, 0, mtrxProjection, 0, mtrxView, 0);
}
// Called when the surface is created or recreated.
public void onSurfaceCreated(GL10 useGLES20instead, EGLConfig config) {
RTABMapLib.initGlContent();
// Create our text manager
mTextManager = new TextManager(mActivity);
mTextManager.setColor(mTextColor);
}
public void updateTexts(String[] texts)
{
if(mTextManager != null && mSurfaceHeight > 0.0f)
{
Vector<TextObject> textObjects = new Vector<TextObject>();
float offset = mSurfaceHeight-mTextManager.getMaxTextHeight();
if(texts != null)
{
for(int i=0;i<texts.length; ++i)
{
if(texts[i]!=null && texts[i].length()>0)
{
TextObject txt = new TextObject(texts[i], 0, offset);
textObjects.add(txt);
}
offset-=mTextManager.getMaxTextHeight();
}
}
mTextLock.lock();
try {
mTexts = textObjects;
} finally {
mTextLock.unlock();
}
mTextChanged = true;
}
}
public void setTextColor(float color)
{
mTextColor = color;
if(mTextManager != null)
{
mTextManager.setColor(mTextColor);
}
}
}

View File

@@ -0,0 +1,328 @@
package com.introlab.rtabmap;
import java.io.File;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map.Entry;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.text.InputType;
import android.view.WindowManager;
import android.view.inputmethod.EditorInfo;
import android.widget.EditText;
public class SettingsActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
private SettingsActivity getActivity() {return this;}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.layout.activity_settings);
Preference buttonReset = findPreference(getString(R.string.pref_key_reset_button));
buttonReset.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
getPreferenceScreen().getSharedPreferences().edit().clear().commit();
recreate();
return true;
}
});
Preference buttonOpen = findPreference(getString(R.string.pref_key_open_button));
buttonOpen.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
File prefsdir = new File(getApplicationInfo().dataDir,"shared_prefs");
if(prefsdir.exists() && prefsdir.isDirectory()){
ArrayList<String> filesArray = new ArrayList<String>(Arrays.asList(prefsdir.list()));
ArrayList<String> newList = new ArrayList<String>();
filesArray.remove("com.introlab.rtabmap_preferences.xml");
filesArray.remove("WebViewChromiumPrefs.xml");
for (String s : filesArray) {
newList.add(s.substring(0, s.length()-4)); // rip off the ".xml"
}
final String[] files = newList.toArray(new String[filesArray.size()]);
if(files.length > 0)
{
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Choose Presets:");
builder.setItems(files, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, final int which) {
//sp1 is the shared pref to copy to
SharedPreferences.Editor ed = getPreferenceScreen().getSharedPreferences().edit();
SharedPreferences sp = getActivity().getSharedPreferences(files[which], MODE_PRIVATE); //The shared preferences to copy from
//Cycle through all the entries in the sp
for(Entry<String,?> entry : sp.getAll().entrySet()){
Object v = entry.getValue();
String key = entry.getKey();
//Now we just figure out what type it is, so we can copy it.
// Note that i am using Boolean and Integer instead of boolean and int.
// That's because the Entry class can only hold objects and int and boolean are primatives.
if(v instanceof Boolean)
// Also note that i have to cast the object to a Boolean
// and then use .booleanValue to get the boolean
ed.putBoolean(key, ((Boolean)v).booleanValue());
else if(v instanceof Float)
ed.putFloat(key, ((Float)v).floatValue());
else if(v instanceof Integer)
ed.putInt(key, ((Integer)v).intValue());
else if(v instanceof Long)
ed.putLong(key, ((Long)v).longValue());
else if(v instanceof String)
ed.putString(key, ((String)v));
}
ed.commit(); //save it.
recreate();
return;
}
});
builder.show();
}
}
return true;
}
});
Preference buttonSave = findPreference(getString(R.string.pref_key_save_button));
buttonSave.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Save Presets:");
final EditText input = new EditText(getActivity());
input.setInputType(InputType.TYPE_CLASS_TEXT);
input.setImeOptions(EditorInfo.IME_FLAG_NO_EXTRACT_UI);
builder.setView(input);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which)
{
final String fileName = input.getText().toString();
dialog.dismiss();
if(!fileName.isEmpty())
{
File newFile = new File(getApplicationInfo().dataDir + "/shared_prefs/" + fileName + ".xml");
if(newFile.exists())
{
new AlertDialog.Builder(getActivity())
.setTitle("Presets Already Exist")
.setMessage("Do you want to overwrite the existing file?")
.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
saveConfig(fileName);
}
})
.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.show();
}
else
{
saveConfig(fileName);
}
}
}
});
AlertDialog alertToShow = builder.create();
alertToShow.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE);
alertToShow.show();
return true;
}
});
Preference buttonRemove = findPreference(getString(R.string.pref_key_remove_button));
buttonRemove.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
File prefsdir = new File(getApplicationInfo().dataDir,"shared_prefs");
if(prefsdir.exists() && prefsdir.isDirectory()){
ArrayList<String> filesArray = new ArrayList<String>(Arrays.asList(prefsdir.list()));
ArrayList<String> newList = new ArrayList<String>();
filesArray.remove("com.introlab.rtabmap_preferences.xml");
filesArray.remove("WebViewChromiumPrefs.xml");
for (String s : filesArray) {
newList.add(s.substring(0, s.length()-4)); // rip off the ".xml"
}
final String[] files = newList.toArray(new String[filesArray.size()]);
if(files.length > 0)
{
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Remove Presets:");
builder.setItems(files, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, final int which) {
File file = new File(getApplicationInfo().dataDir + "/shared_prefs/" + files[which] + ".xml");
if(file.exists())
{
file.delete();
}
return;
}
});
builder.show();
}
}
return true;
}
});
((Preference)findPreference(getString(R.string.pref_key_density))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_density))).getEntry() + ") "+getString(R.string.pref_summary_density));
((Preference)findPreference(getString(R.string.pref_key_depth))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_depth))).getEntry() + ") "+getString(R.string.pref_summary_depth));
((Preference)findPreference(getString(R.string.pref_key_min_depth))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_min_depth))).getEntry() + ") "+getString(R.string.pref_summary_min_depth));
((Preference)findPreference(getString(R.string.pref_key_point_size))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_point_size))).getEntry() + ") "+getString(R.string.pref_summary_point_size));
((Preference)findPreference(getString(R.string.pref_key_angle))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_angle))).getEntry() + ") "+getString(R.string.pref_summary_angle));
((Preference)findPreference(getString(R.string.pref_key_triangle))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_triangle))).getEntry() + ") "+getString(R.string.pref_summary_triangle));
((Preference)findPreference(getString(R.string.pref_key_background_color))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_background_color))).getEntry() + ") "+getString(R.string.pref_summary_background_color));
((Preference)findPreference(getString(R.string.pref_key_rendering_texture_decimation))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_rendering_texture_decimation))).getEntry() + ") "+getString(R.string.pref_summary_rendering_texture_decimation));
((Preference)findPreference(getString(R.string.pref_key_update_rate))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_update_rate))).getEntry() + ") "+getString(R.string.pref_summary_update_rate));
((Preference)findPreference(getString(R.string.pref_key_time_thr))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_time_thr))).getEntry() + ") "+getString(R.string.pref_summary_time_thr));
((Preference)findPreference(getString(R.string.pref_key_mem_thr))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_mem_thr))).getEntry() + ") "+getString(R.string.pref_summary_mem_thr));
((Preference)findPreference(getString(R.string.pref_key_loop_thr))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_loop_thr))).getEntry() + ") "+getString(R.string.pref_summary_loop_thr));
((Preference)findPreference(getString(R.string.pref_key_sim_thr))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_sim_thr))).getEntry() + ") "+getString(R.string.pref_summary_sim_thr));
((Preference)findPreference(getString(R.string.pref_key_min_inliers))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_min_inliers))).getEntry() + ") "+getString(R.string.pref_summary_min_inliers));
((Preference)findPreference(getString(R.string.pref_key_opt_error))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_opt_error))).getEntry() + ") "+getString(R.string.pref_summary_opt_error));
((Preference)findPreference(getString(R.string.pref_key_features_voc))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_features_voc))).getEntry() + ") "+getString(R.string.pref_summary_features_voc));
((Preference)findPreference(getString(R.string.pref_key_features))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_features))).getEntry() + ") "+getString(R.string.pref_summary_features));
((Preference)findPreference(getString(R.string.pref_key_features_type))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_features_type))).getEntry() + ") "+getString(R.string.pref_summary_features_type));
((Preference)findPreference(getString(R.string.pref_key_optimizer))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_optimizer))).getEntry() + ") "+getString(R.string.pref_summary_optimizer));
((Preference)findPreference(getString(R.string.pref_key_cloud_voxel))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_cloud_voxel))).getEntry() + ") "+getString(R.string.pref_summary_cloud_voxel));
((Preference)findPreference(getString(R.string.pref_key_texture_size))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_texture_size))).getEntry() + ") "+getString(R.string.pref_summary_texture_size));
((Preference)findPreference(getString(R.string.pref_key_texture_count))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_texture_count))).getEntry() + ") "+getString(R.string.pref_summary_texture_count));
((Preference)findPreference(getString(R.string.pref_key_normal_k))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_normal_k))).getEntry() + ") "+getString(R.string.pref_summary_normal_k));
((Preference)findPreference(getString(R.string.pref_key_max_texture_distance))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_max_texture_distance))).getEntry() + ") "+getString(R.string.pref_summary_max_texture_distance));
((Preference)findPreference(getString(R.string.pref_key_min_texture_cluster_size))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_min_texture_cluster_size))).getEntry() + ") "+getString(R.string.pref_summary_min_texture_cluster_size));
((Preference)findPreference(getString(R.string.pref_key_opt_depth))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_opt_depth))).getEntry() + ") "+getString(R.string.pref_summary_opt_depth));
((Preference)findPreference(getString(R.string.pref_key_opt_color_radius))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_opt_color_radius))).getEntry() + ") "+getString(R.string.pref_summary_opt_color_radius));
((Preference)findPreference(getString(R.string.pref_key_opt_min_cluster_size))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_opt_min_cluster_size))).getEntry() + ") "+getString(R.string.pref_summary_opt_min_cluster_size));
((Preference)findPreference(getString(R.string.pref_key_cluster_ratio))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_cluster_ratio))).getEntry() + ") "+getString(R.string.pref_summary_cluster_ratio));
((Preference)findPreference(getString(R.string.pref_key_gain_max_radius))).setSummary("("+((ListPreference)findPreference(getString(R.string.pref_key_gain_max_radius))).getEntry() + ") "+getString(R.string.pref_summary_gain_max_radius));
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference pref = findPreference(key);
if (pref instanceof ListPreference) {
if(key.compareTo(getString(R.string.pref_key_density))==0) pref.setSummary("("+ ((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_density));
if(key.compareTo(getString(R.string.pref_key_depth))==0)
{
pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_depth));
float maxDepth = Float.parseFloat(((ListPreference)pref).getValue());
float minDepth = Float.parseFloat(((ListPreference)findPreference(getString(R.string.pref_key_min_depth))).getValue());
if(maxDepth > 0.0f && maxDepth <= minDepth)
{
((ListPreference)findPreference(getString(R.string.pref_key_min_depth))).setValueIndex(0);
}
}
if(key.compareTo(getString(R.string.pref_key_min_depth))==0)
{
pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_min_depth));
float maxDepth = Float.parseFloat(((ListPreference)findPreference(getString(R.string.pref_key_depth))).getValue());
float minDepth = Float.parseFloat(((ListPreference)pref).getValue());
if(minDepth >= maxDepth)
{
((ListPreference)findPreference(getString(R.string.pref_key_depth))).setValueIndex(0);
}
}
if(key.compareTo(getString(R.string.pref_key_point_size))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_point_size));
if(key.compareTo(getString(R.string.pref_key_angle))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_angle));
if(key.compareTo(getString(R.string.pref_key_triangle))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_triangle));
if(key.compareTo(getString(R.string.pref_key_background_color))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_background_color));
if(key.compareTo(getString(R.string.pref_key_rendering_texture_decimation))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_rendering_texture_decimation));
if(key.compareTo(getString(R.string.pref_key_update_rate))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_update_rate));
if(key.compareTo(getString(R.string.pref_key_time_thr))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_time_thr));
if(key.compareTo(getString(R.string.pref_key_mem_thr))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_mem_thr));
if(key.compareTo(getString(R.string.pref_key_loop_thr))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_loop_thr));
if(key.compareTo(getString(R.string.pref_key_sim_thr))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_sim_thr));
if(key.compareTo(getString(R.string.pref_key_min_inliers))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_min_inliers));
if(key.compareTo(getString(R.string.pref_key_opt_error))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_opt_error));
if(key.compareTo(getString(R.string.pref_key_features_voc))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_features_voc));
if(key.compareTo(getString(R.string.pref_key_features))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_features));
if(key.compareTo(getString(R.string.pref_key_features_type))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_features_type));
if(key.compareTo(getString(R.string.pref_key_optimizer))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_optimizer));
if(key.compareTo(getString(R.string.pref_key_cloud_voxel))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_cloud_voxel));
if(key.compareTo(getString(R.string.pref_key_texture_size))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_texture_size));
if(key.compareTo(getString(R.string.pref_key_texture_count))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_texture_count));
if(key.compareTo(getString(R.string.pref_key_normal_k))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_normal_k));
if(key.compareTo(getString(R.string.pref_key_max_texture_distance))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_max_texture_distance));
if(key.compareTo(getString(R.string.pref_key_min_texture_cluster_size))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_min_texture_cluster_size));
if(key.compareTo(getString(R.string.pref_key_opt_depth))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_opt_depth));
if(key.compareTo(getString(R.string.pref_key_opt_color_radius))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_opt_color_radius));
if(key.compareTo(getString(R.string.pref_key_opt_min_cluster_size))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_opt_min_cluster_size));
if(key.compareTo(getString(R.string.pref_key_cluster_ratio))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_cluster_ratio));
if(key.compareTo(getString(R.string.pref_key_gain_max_radius))==0) pref.setSummary("("+((ListPreference)pref).getEntry() + ") "+getString(R.string.pref_summary_gain_max_radius));
}
}
@Override
protected void onResume() {
super.onResume();
// Set up a listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
@Override
protected void onPause() {
super.onPause();
// Unregister the listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
private void saveConfig(String fileName)
{
//sp1 is the shared pref to copy to
SharedPreferences.Editor ed = getActivity().getSharedPreferences(fileName, MODE_PRIVATE).edit();
SharedPreferences sp = getPreferenceScreen().getSharedPreferences(); //The shared preferences to copy from
ed.clear(); // This clears the one we are copying to, but you don't necessarily need to do that.
//Cycle through all the entries in the sp
for(Entry<String,?> entry : sp.getAll().entrySet()){
Object v = entry.getValue();
String key = entry.getKey();
//Now we just figure out what type it is, so we can copy it.
// Note that i am using Boolean and Integer instead of boolean and int.
// That's because the Entry class can only hold objects and int and boolean are primatives.
if(v instanceof Boolean)
// Also note that i have to cast the object to a Boolean
// and then use .booleanValue to get the boolean
ed.putBoolean(key, ((Boolean)v).booleanValue());
else if(v instanceof Float)
ed.putFloat(key, ((Float)v).floatValue());
else if(v instanceof Integer)
ed.putInt(key, ((Integer)v).intValue());
else if(v instanceof Long)
ed.putLong(key, ((Long)v).longValue());
else if(v instanceof String)
ed.putString(key, ((String)v));
}
ed.commit(); //save it.
}
}

View File

@@ -0,0 +1,453 @@
package com.introlab.rtabmap;
import java.io.File;
import java.io.IOException;
import java.util.List;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.text.Editable;
import android.text.SpannableString;
import android.text.TextWatcher;
import android.text.method.LinkMovementMethod;
import android.text.util.Linkify;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
public class SketchfabActivity extends Activity implements OnClickListener {
private static final String AUTHORIZE_PATH = "https://sketchfab.com/oauth2/authorize";
private static final String CLIENT_ID = "RXrIJYAwlTELpySsyM8TrK9r3kOGQ5Qjj9VVDIfV";
private static final String REDIRECT_URI = "https://introlab.github.io/rtabmap/oauth2_redirect";
ProgressDialog mProgressDialog;
private Dialog mAuthDialog;
private String mAuthToken;
private String mWorkingDirectory;
EditText mFilename;
EditText mDescription;
EditText mTags;
CheckBox mDraft;
Button mButtonOk;
private SketchfabActivity getActivity() {return this;}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_sketchfab);
mFilename = (EditText)findViewById(R.id.editText_filename);
mDescription = (EditText)findViewById(R.id.editText_description);
mTags = (EditText)findViewById(R.id.editText_tags);
mDraft = (CheckBox)findViewById(R.id.checkBox_draft);
mButtonOk = (Button)findViewById(R.id.button_ok);
mProgressDialog = new ProgressDialog(this);
mProgressDialog.setCanceledOnTouchOutside(false);
mAuthToken = getIntent().getExtras().getString(RTABMapActivity.RTABMAP_AUTH_TOKEN_KEY);
mFilename.setText(getIntent().getExtras().getString(RTABMapActivity.RTABMAP_FILENAME_KEY));
mWorkingDirectory = getIntent().getExtras().getString(RTABMapActivity.RTABMAP_WORKING_DIR_KEY);
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
String tags = sharedPref.getString(getString(R.string.pref_key_tags), getString(R.string.pref_default_tags));
if(tags.isEmpty())
{
tags = getString(R.string.pref_default_tags);
}
mTags.setText(tags);
mButtonOk.setEnabled(mFilename.getText().toString().length()>0);
mButtonOk.setOnClickListener(this);
mFilename.addTextChangedListener(new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {}
@Override
public void beforeTextChanged(CharSequence s, int start,
int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start,
int before, int count) {
mButtonOk.setEnabled(s.length() != 0);
}
});
mFilename.setSelectAllOnFocus(true);
mFilename.requestFocus();
}
@Override
public void onClick(View v) {
// Handle button clicks.
switch (v.getId()) {
case R.id.button_ok:
shareToSketchfab();
break;
default:
return;
}
}
private void shareToSketchfab()
{
if(!mTags.getText().toString().isEmpty())
{
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);
SharedPreferences.Editor editor = sharedPref.edit();
editor.putString(getString(R.string.pref_key_tags), mTags.getText().toString());
// Commit the edits!
editor.commit();
}
authorizeAndPublish(mFilename.getText().toString());
}
private boolean isNetworkAvailable() {
ConnectivityManager connectivityManager
= (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo activeNetworkInfo = connectivityManager.getActiveNetworkInfo();
return activeNetworkInfo != null && activeNetworkInfo.isConnected();
}
private void authorizeAndPublish(final String fileName)
{
if(!isNetworkAvailable())
{
// Visualize the result?
new AlertDialog.Builder(this)
.setTitle("Sharing to Sketchfab...")
.setMessage("Network is not available. Make sure you have internet before continuing.")
.setPositiveButton("Try Again", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
authorizeAndPublish(fileName);
}
})
.setNeutralButton("Abort", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
}
})
.show();
return;
}
// get token the first time
if(mAuthToken == null)
{
Log.i(RTABMapActivity.TAG,"We don't have the token, get it!");
WebView web;
mAuthDialog = new Dialog(this);
mAuthDialog.setContentView(R.layout.auth_dialog);
web = (WebView)mAuthDialog.findViewById(R.id.webv);
web.setWebContentsDebuggingEnabled(!RTABMapActivity.DISABLE_LOG);
web.getSettings().setJavaScriptEnabled(true);
String auth_url = AUTHORIZE_PATH+"?redirect_uri="+REDIRECT_URI+"&response_type=token&client_id="+CLIENT_ID;
Log.i(RTABMapActivity.TAG, "Auhorize url="+auth_url);
web.setWebViewClient(new WebViewClient() {
boolean authComplete = false;
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
//Log.i(TAG,"onPageFinished url="+url);
if(url.contains("error=access_denied")){
Log.e(RTABMapActivity.TAG, "ACCESS_DENIED_HERE");
authComplete = true;
Toast.makeText(getApplicationContext(), "Error Occured", Toast.LENGTH_SHORT).show();
mAuthDialog.dismiss();
}
else if (url.startsWith(REDIRECT_URI) && url.contains("access_token") && authComplete != true) {
//Log.i(TAG,"onPageFinished received token="+url);
String[] sArray = url.split("access_token=");
mAuthToken = (sArray[1].split("&token_type=Bearer"))[0];
authComplete = true;
mAuthDialog.dismiss();
zipAndPublish(fileName);
}
}
});
mAuthDialog.show();
mAuthDialog.setTitle("Authorize RTAB-Map");
mAuthDialog.setCancelable(true);
web.loadUrl(auth_url);
}
else
{
zipAndPublish(fileName);
}
}
private void zipAndPublish(final String fileName)
{
mProgressDialog.setTitle("Upload to Sketchfab");
mProgressDialog.setMessage(String.format("Compressing the files..."));
mProgressDialog.show();
Thread workingThread = new Thread(new Runnable() {
public void run() {
try{
File tmpDir = new File(mWorkingDirectory + RTABMapActivity.RTABMAP_TMP_DIR);
tmpDir.mkdirs();
String[] fileNames = Util.loadFileList(mWorkingDirectory + RTABMapActivity.RTABMAP_TMP_DIR, false);
if(!RTABMapActivity.DISABLE_LOG) Log.i(RTABMapActivity.TAG, String.format("Deleting %d files in \"%s\"", fileNames.length, mWorkingDirectory + RTABMapActivity.RTABMAP_TMP_DIR));
for(int i=0; i<fileNames.length; ++i)
{
File f = new File(mWorkingDirectory + RTABMapActivity.RTABMAP_TMP_DIR + "/" + fileNames[i]);
if(f.delete())
{
if(!RTABMapActivity.DISABLE_LOG) Log.i(RTABMapActivity.TAG, String.format("Deleted \"%s\"", f.getPath()));
}
else
{
if(!RTABMapActivity.DISABLE_LOG) Log.i(RTABMapActivity.TAG, String.format("Failed deleting \"%s\"", f.getPath()));
}
}
File exportDir = new File(mWorkingDirectory + RTABMapActivity.RTABMAP_EXPORT_DIR);
exportDir.mkdirs();
if(RTABMapLib.writeExportedMesh(mWorkingDirectory + RTABMapActivity.RTABMAP_TMP_DIR, RTABMapActivity.RTABMAP_TMP_FILENAME))
{
String[] files = new String[0];
// verify if we have all files
fileNames = Util.loadFileList(mWorkingDirectory + RTABMapActivity.RTABMAP_TMP_DIR, false);
if(fileNames.length > 0)
{
files = new String[fileNames.length];
for(int i=0; i<fileNames.length; ++i)
{
files[i] = mWorkingDirectory + RTABMapActivity.RTABMAP_TMP_DIR + "/" + fileNames[i];
}
}
else
{
if(!RTABMapActivity.DISABLE_LOG) Log.i(RTABMapActivity.TAG, "Missing files!");
}
if(files.length > 0)
{
final String[] filesToZip = files;
final String zipOutput = mWorkingDirectory+fileName+".zip";
Util.zip(filesToZip, zipOutput);
runOnUiThread(new Runnable() {
public void run() {
mProgressDialog.dismiss();
File f = new File(zipOutput);
// Continue?
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("File(s) compressed and ready to upload!");
final int fileSizeMB = (int)f.length()/(1024 * 1024);
final int fileSizeKB = (int)f.length()/(1024);
if(fileSizeMB == 0)
{
Log.i(RTABMapActivity.TAG, String.format("Zipped files = %d KB", fileSizeKB));
builder.setMessage(String.format("Total size to upload = %d KB. Do you want to continue?\n\n", fileSizeKB));
}
else
{
Log.i(RTABMapActivity.TAG, String.format("Zipped files = %d MB", fileSizeMB));
builder.setMessage(String.format("Total size to upload = %d MB. %sDo you want to continue?\n\n"
+ "Tip: To reduce the model size, you can also look at the Settings->Exporting options.", fileSizeMB,
fileSizeMB>=50?"Note that for size over 50 MB, a Sketchfab PRO account is required, otherwise the upload may fail. ":""));
}
builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
mProgressDialog.setTitle("Upload to Sketchfab");
if(fileSizeMB == 0)
{
mProgressDialog.setMessage(String.format("Uploading model \"%s\" (%d KB) to Sketchfab...", fileName, fileSizeKB));
}
else
{
mProgressDialog.setMessage(String.format("Uploading model \"%s\" (%d MB) to Sketchfab...", fileName, fileSizeMB));
}
mProgressDialog.show();
new uploadToSketchfabTask().execute(zipOutput, fileName);
}
});
builder.setNegativeButton("No", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
// do nothing...
}
});
builder.show();
}
});
}
}
else
{
runOnUiThread(new Runnable() {
public void run() {
mProgressDialog.dismiss();
Toast.makeText(getActivity(), String.format("Failed writing files!"), Toast.LENGTH_LONG).show();
}
});
}
}
catch(IOException ex) {
Log.e(RTABMapActivity.TAG, "Failed to zip", ex);
}
}
});
workingThread.start();
}
private class uploadToSketchfabTask extends AsyncTask<String, Void, Void>
{
String mModelUri;
String mModelFilePath;
String error = "";
String mFileName;
protected void onPreExecute() {
//display progress dialog.
}
@Override
protected void onPostExecute(Void result) {
mProgressDialog.dismiss();
//Task you want to do on UIThread after completing Network operation
//onPostExecute is called after doInBackground finishes its task.
if(mModelFilePath!= null)
{
File f = new File(mModelFilePath);
f.delete(); // cleanup
// See on sketchfab?
final SpannableString s = new SpannableString(
"Model \"" + mFileName + "\" is now processing on Sketchfab! You can click "
+ "on the link below to see it on Sketchfab.\n\nhttps://sketchfab.com/models/"+mModelUri);
Linkify.addLinks(s, Linkify.WEB_URLS);
final AlertDialog d = new AlertDialog.Builder(getActivity())
.setTitle("Upload finished!")
.setCancelable(false)
.setMessage(s)
.setPositiveButton("Close", new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
Intent resultIntent = new Intent();
resultIntent.putExtra(RTABMapActivity.RTABMAP_AUTH_TOKEN_KEY, mAuthToken);
setResult(Activity.RESULT_OK, resultIntent);
finish();
}
}).create();
d.show();
((TextView)d.findViewById(android.R.id.message)).setMovementMethod(LinkMovementMethod.getInstance());
}
else
{
Toast.makeText(getApplicationContext(), String.format("Upload failed! Error=\"%s\"", error), Toast.LENGTH_SHORT).show();
}
}
@Override
protected Void doInBackground(String... files) {
String charset = "UTF-8";
File uploadFile = new File(files[0]);
mFileName = files[1];
String requestURL = "https://api.sketchfab.com/v3/models";
Log.i(RTABMapActivity.TAG, "Uploading " + files[0]);
try {
MultipartUtility multipart = new MultipartUtility(requestURL, mAuthToken, charset);
multipart.addFormField("name", mFileName);
multipart.addFormField("description", mDescription.getText().toString());
multipart.addFormField("tags", mTags.getText().toString());
multipart.addFormField("source", "RTAB-Map");
multipart.addFormField("isPublished", mDraft.isChecked()?"false":"true");
multipart.addFilePart("modelFile", uploadFile);
Log.i(RTABMapActivity.TAG, "Starting multipart request");
List<String> response = multipart.finish();
Log.i(RTABMapActivity.TAG, "SERVER REPLIED:");
for (String line : response) {
Log.i(RTABMapActivity.TAG, line);
//{"uri":"https:\/\/api.sketchfab.com\/v3\/models\/XXXXXXXXX","uid":"XXXXXXXXXX"}
if(line.contains("\"uid\":\""))
{
String[] sArray = line.split("\"uid\":\"");
mModelUri = (sArray[1].split("\""))[0];
mModelFilePath = files[0];
//patch model for orientation
/*HttpClient httpClient = new DefaultHttpClient();
try {
String patchURL = "https://api.sketchfab.com/v3/models/"+ mModelUri +"/options";
HttpPatch request = new HttpPatch(patchURL);
String json =
"{\n"+
"uid: "+ mModelUri + "\n" +
"shading: shadeless\n"+
//"orientation:\n"+
//"{\n"+
// "axis : [1, 0, 0]\n"+
// "angle : 0\n"+
//"}\n"+
"}";
request.setHeader("Authorization", "Bearer " + mAuthToken);
StringEntity params =new StringEntity(json, "UTF-8");
params.setContentType("application/json");
request.setEntity(params);
HttpResponse responsePatch = httpClient.execute(request);
int responseStatus = responsePatch.getStatusLine().getStatusCode();
Log.i(RTABMapActivity.TAG, "get data responseStatus: " + responseStatus);
}catch (Exception e) {
Log.e(RTABMapActivity.TAG, "Error while patching model", e);
error = e.getMessage();
}*/
}
}
} catch (IOException ex) {
Log.e(RTABMapActivity.TAG, "Error while uploading", ex);
error = ex.getMessage();
}
return null;
}
}
}

View File

@@ -0,0 +1,419 @@
//package ri.blog.opengl008;
package com.introlab.rtabmap;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.ShortBuffer;
import java.util.Iterator;
import java.util.Vector;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.opengl.GLES20;
import android.opengl.GLUtils;
import android.text.TextPaint;
public class TextManager {
/* SHADER Text
*
* This shader is for rendering 2D text textures straight from a texture
* Color and alpha blended.
*
*/
public static final String vs_Text =
"uniform mat4 uMVPMatrix;" +
"attribute vec4 vPosition;" +
"attribute vec2 a_texCoord;" +
"varying vec2 v_texCoord;" +
"void main() {" +
" gl_Position = uMVPMatrix * vPosition;" +
" v_texCoord = a_texCoord;" +
"}";
public static final String fs_Text =
"precision mediump float;" +
"uniform float uColor;" +
"varying vec2 v_texCoord;" +
"uniform sampler2D s_texture;" +
"void main() {" +
" gl_FragColor = texture2D( s_texture, v_texCoord );" +
" gl_FragColor.rgb *= uColor;" +
"}";
public static int sp_Text;
public static final int RI_TEXT_TEXTURE_SIZE = 512; // 512
public static final float RI_TEXT_HEIGHT_BASE = 32.0f;
public static final char RI_TEXT_START = ' ';
public static final char RI_TEXT_STOP = '~'+1;
public float getMaxTextHeight() {return mTextHeight;}
private float mUVWidth;
private float mUVHeight;
private float mTextHeight;
private float mColor;
private FloatBuffer vertexBuffer;
private FloatBuffer textureBuffer;
private ShortBuffer drawListBuffer;
private float[] vecs;
private float[] uvs;
private short[] indices;
private int index_vecs;
private int index_indices;
private int index_uvs;
private int texturenr;
private int[] mTextures;
private float uniformscale = 1.0f;
float[] mCharacterWidth;
public TextManager(Context context)
{
// Create the arrays
vecs = new float[3 * 10];
uvs = new float[2 * 10];
indices = new short[10];
// init as 0 as default
texturenr = 0;
// Text shader
int vshadert = TextManager.loadShader(GLES20.GL_VERTEX_SHADER, TextManager.vs_Text);
int fshadert = TextManager.loadShader(GLES20.GL_FRAGMENT_SHADER, TextManager.fs_Text);
TextManager.sp_Text = GLES20.glCreateProgram();
GLES20.glAttachShader(TextManager.sp_Text, vshadert);
GLES20.glAttachShader(TextManager.sp_Text, fshadert); // add the fragment shader to program
GLES20.glLinkProgram(TextManager.sp_Text); // creates OpenGL ES program executables
// Generate Textures, if more needed, alter these numbers.
mTextures = new int[1];
GLES20.glGenTextures(1, mTextures, 0);
// Create an empty, mutable bitmap
Bitmap bitmap = Bitmap.createBitmap(RI_TEXT_TEXTURE_SIZE, RI_TEXT_TEXTURE_SIZE, Bitmap.Config.ARGB_4444);
// get a canvas to paint over the bitmap
Canvas canvas = new Canvas(bitmap);
bitmap.eraseColor(0);
// Draw the text
TextPaint textPaint = new TextPaint();
textPaint.setTextSize(RI_TEXT_HEIGHT_BASE);
textPaint.setColor(Color.WHITE);
textPaint.setAntiAlias(true);
textPaint.setTypeface(Typeface.create("Arial", Typeface.BOLD));
// compute real maximum height
mTextHeight=0.0f;
for(char c=RI_TEXT_START; c<RI_TEXT_STOP; ++c)
{
Rect textBounds = new Rect();
textPaint.getTextBounds(String.valueOf(c), 0, 1, textBounds);
if(textBounds.height() + textBounds.bottom > mTextHeight)
{
mTextHeight = textBounds.height() + textBounds.bottom;
}
}
mUVWidth = (float)RI_TEXT_HEIGHT_BASE/(float)RI_TEXT_TEXTURE_SIZE;
mUVHeight = mTextHeight/(float)RI_TEXT_TEXTURE_SIZE;
mColor = 1.0f;
int colCount = RI_TEXT_TEXTURE_SIZE/(int)RI_TEXT_HEIGHT_BASE;
mCharacterWidth = new float[RI_TEXT_STOP-RI_TEXT_START];
int i=0;
for(char c=RI_TEXT_START; c<RI_TEXT_STOP; ++c)
{
Rect textBounds = new Rect();
textPaint.getTextBounds(String.valueOf(c), 0, 1, textBounds);
canvas.drawText(String.valueOf(c), (i%colCount)*RI_TEXT_HEIGHT_BASE, (i/colCount) * mTextHeight + RI_TEXT_HEIGHT_BASE, textPaint);
mCharacterWidth[i] = textPaint.measureText(String.valueOf(c));
++i;
}
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
//Clean up
bitmap.recycle();
}
public void setTextureID(int val)
{
texturenr = val;
}
public static int loadShader(int type, String shaderCode){
// create a vertex shader type (GLES20.GL_VERTEX_SHADER)
// or a fragment shader type (GLES20.GL_FRAGMENT_SHADER)
int shader = GLES20.glCreateShader(type);
// add the source code to the shader and compile it
GLES20.glShaderSource(shader, shaderCode);
GLES20.glCompileShader(shader);
// return the shader
return shader;
}
public void AddCharRenderInformation(float[] vec, float[] cs, float[] uv, short[] indi)
{
// We need a base value because the object has indices related to
// that object and not to this collection so basicly we need to
// translate the indices to align with the vertexlocation in ou
// vecs array of vectors.
short base = (short) (index_vecs / 3);
// We should add the vec, translating the indices to our saved vector
for(int i=0;i<vec.length;i++)
{
vecs[index_vecs] = vec[i];
index_vecs++;
}
// We should add the uvs
for(int i=0;i<uv.length;i++)
{
uvs[index_uvs] = uv[i];
index_uvs++;
}
// We handle the indices
for(int j=0;j<indi.length;j++)
{
indices[index_indices] = (short) (base + indi[j]);
index_indices++;
}
}
public void PrepareDrawInfo(Vector<TextObject> txtcollection)
{
// Reset the indices.
index_vecs = 0;
index_indices = 0;
index_uvs = 0;
// Get the total amount of characters
int charcount = 0;
for (TextObject txt : txtcollection) {
if(txt!=null)
{
if(!(txt.text==null))
{
charcount += txt.text.length();
}
}
}
// Create the arrays we need with the correct size.
vecs = null;
uvs = null;
indices = null;
vecs = new float[charcount * 12];
uvs = new float[charcount * 8];
indices = new short[charcount * 6];
}
public void PrepareDraw(Vector<TextObject> txtcollection)
{
// Setup all the arrays
PrepareDrawInfo(txtcollection);
// Using the iterator protects for problems with concurrency
for( Iterator< TextObject > it = txtcollection.iterator(); it.hasNext() ; )
{
TextObject txt = it.next();
if(txt!=null)
{
if(!(txt.text==null))
{
convertTextToTriangleInfo(txt);
}
}
}
}
public void Draw(float[] m)
{
if(vecs.length > 0)
{
GLES20.glDisable(GLES20.GL_DEPTH_TEST);
GLES20.glEnable(GLES20.GL_BLEND);
// Set the correct shader for our grid object.
GLES20.glUseProgram(sp_Text);
// The vertex buffer.
ByteBuffer bb = ByteBuffer.allocateDirect(vecs.length * 4);
bb.order(ByteOrder.nativeOrder());
vertexBuffer = bb.asFloatBuffer();
vertexBuffer.put(vecs);
vertexBuffer.position(0);
// The texture buffer
ByteBuffer bb2 = ByteBuffer.allocateDirect(uvs.length * 4);
bb2.order(ByteOrder.nativeOrder());
textureBuffer = bb2.asFloatBuffer();
textureBuffer.put(uvs);
textureBuffer.position(0);
// initialize byte buffer for the draw list
ByteBuffer dlb = ByteBuffer.allocateDirect(indices.length * 2);
dlb.order(ByteOrder.nativeOrder());
drawListBuffer = dlb.asShortBuffer();
drawListBuffer.put(indices);
drawListBuffer.position(0);
// get handle to vertex shader's vPosition member
int mPositionHandle = GLES20.glGetAttribLocation(sp_Text, "vPosition");
// Enable a handle to the triangle vertices
GLES20.glEnableVertexAttribArray(mPositionHandle);
// Prepare the background coordinate data
GLES20.glVertexAttribPointer(mPositionHandle, 3,
GLES20.GL_FLOAT, false,
0, vertexBuffer);
int mTexCoordLoc = GLES20.glGetAttribLocation(sp_Text, "a_texCoord" );
// Prepare the texturecoordinates
GLES20.glVertexAttribPointer ( mTexCoordLoc, 2, GLES20.GL_FLOAT,
false,
0, textureBuffer);
GLES20.glEnableVertexAttribArray ( mPositionHandle );
GLES20.glEnableVertexAttribArray ( mTexCoordLoc );
// get handle to shape's transformation matrix
int mtrxhandle = GLES20.glGetUniformLocation(sp_Text, "uMVPMatrix");
// Apply the projection and view transformation
GLES20.glUniformMatrix4fv(mtrxhandle, 1, false, m, 0);
// get handle to color value
int colorhandle = GLES20.glGetUniformLocation(sp_Text, "uColor");
GLES20.glUniform1f(colorhandle, mColor);
int mSamplerLoc = GLES20.glGetUniformLocation (sp_Text, "s_texture" );
// Texture activate unit 0
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
// Bind the texture to this unit.
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, mTextures[0]);
// Set the sampler texture unit to our selected id
GLES20.glUniform1i ( mSamplerLoc, texturenr);
// Draw the triangle
GLES20.glDrawElements(GLES20.GL_TRIANGLES, indices.length, GLES20.GL_UNSIGNED_SHORT, drawListBuffer);
// Disable vertex array
GLES20.glDisableVertexAttribArray(mPositionHandle);
GLES20.glDisableVertexAttribArray(mTexCoordLoc);
}
}
private void convertTextToTriangleInfo(TextObject val)
{
// Get attributes from text object
float x = val.x;
float y = val.y;
String text = val.text;
// Create
for(int j=0; j<text.length(); j++)
{
// get ascii value
char c = text.charAt(j);
int c_val = (int)c;
int indx = c_val-RI_TEXT_START;
if(indx<0 || indx>=mCharacterWidth.length) {
// unknown character, we will add a space for it to be save.
indx = 0;
}
int colCount = RI_TEXT_TEXTURE_SIZE/(int)RI_TEXT_HEIGHT_BASE;
// Calculate the uv parts
int row = indx / colCount;
int col = indx % colCount;
float v = row * mUVHeight;
float v2 = v + mUVHeight;
float u = col * mUVWidth;
float u2 = u + mCharacterWidth[indx]/(float)RI_TEXT_TEXTURE_SIZE;
// Creating the triangle information
float[] vec = new float[12];
float[] uv = new float[8];
float[] colors = new float[16];
vec[0] = x;
vec[1] = y + (mTextHeight * uniformscale);
vec[2] = 0.99f;
vec[3] = x;
vec[4] = y;
vec[5] = 0.99f;
vec[6] = x + (mCharacterWidth[indx] * uniformscale);
vec[7] = y;
vec[8] = 0.99f;
vec[9] = x + (mCharacterWidth[indx] * uniformscale);
vec[10] = y + (mTextHeight * uniformscale);
vec[11] = 0.99f;
colors = new float[]
{val.color[0], val.color[1], val.color[2], val.color[3],
val.color[0], val.color[1], val.color[2], val.color[3],
val.color[0], val.color[1], val.color[2], val.color[3],
val.color[0], val.color[1], val.color[2], val.color[3]
};
// 0.001f = texture bleeding hack/fix
uv[0] = u+0.001f;
uv[1] = v+0.001f;
uv[2] = u+0.001f;
uv[3] = v2-0.001f;
uv[4] = u2-0.001f;
uv[5] = v2-0.001f;
uv[6] = u2-0.001f;
uv[7] = v+0.001f;
short[] inds = {0, 1, 2, 0, 2, 3};
// Add our triangle information to our collection for 1 render call.
AddCharRenderInformation(vec, colors, uv, inds);
// Calculate the new position
x += (mCharacterWidth[indx] * uniformscale);
}
}
public float getUniformscale() {
return uniformscale;
}
public void setUniformscale(float uniformscale) {
this.uniformscale = uniformscale;
}
public void setColor(float color) {
mColor = color;
}
}

View File

@@ -0,0 +1,33 @@
//package ri.blog.opengl008;
package com.introlab.rtabmap;
public class TextObject {
public String text;
public float x;
public float y;
public float[] color;
public TextObject()
{
text = "default";
x = 0f;
y = 0f;
color = new float[] {1f, 1f, 1f, 1.0f};
}
public TextObject(String txt, float xcoord, float ycoord)
{
text = txt;
x = xcoord;
y = ycoord;
color = new float[] {1f, 1f, 1f, 1.0f};
}
/*public boolean validate()
{
if(text.compareTo("")==0) return false;
return true;
}*/
}

View File

@@ -0,0 +1,126 @@
package com.introlab.rtabmap;
import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.util.Arrays;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
import android.content.Context;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.util.Log;
public class Util {
public static final int ZIP_BUFFER_SIZE = 1<<20; // 1MB
public static void zip(String file, String zipFile) throws IOException {
Log.i(RTABMapActivity.TAG, "Zipping " + file +" to " + zipFile);
String[] files = new String[1];
files[0] = file;
zip(files, zipFile);
}
public static void zip(String[] files, String zipFile) throws IOException {
Log.i(RTABMapActivity.TAG, "Zipping " + String.valueOf(files.length) +" files to " + zipFile);
BufferedInputStream origin = null;
ZipOutputStream out = new ZipOutputStream(new BufferedOutputStream(new FileOutputStream(zipFile)));
try {
byte data[] = new byte[ZIP_BUFFER_SIZE];
for (int i = 0; i < files.length; i++) {
FileInputStream fi = new FileInputStream(files[i]);
origin = new BufferedInputStream(fi, ZIP_BUFFER_SIZE);
try {
ZipEntry entry = new ZipEntry(files[i].substring(files[i].lastIndexOf("/") + 1));
out.putNextEntry(entry);
int count;
while ((count = origin.read(data, 0, ZIP_BUFFER_SIZE)) != -1) {
out.write(data, 0, count);
}
}
finally {
origin.close();
}
}
}
finally {
out.close();
}
}
public static String[] loadFileList(String directory, final boolean databasesOnly) {
File path = new File(directory);
String fileList[];
try {
path.mkdirs();
}
catch(SecurityException e) {
Log.e(RTABMapActivity.TAG, "unable to write on the sd card " + e.toString());
}
if(path.exists()) {
FilenameFilter filter = new FilenameFilter() {
@Override
public boolean accept(File dir, String filename) {
File sel = new File(dir, filename);
if(databasesOnly)
{
return filename.compareTo(RTABMapActivity.RTABMAP_TMP_DB) != 0 && filename.endsWith(".db");
}
else
{
return sel.isFile();
}
}
};
fileList = path.list(filter);
Arrays.sort(fileList);
}
else {
fileList = new String[0];
}
return fileList;
}
/**
* https://stackoverflow.com/questions/6701948/efficient-way-to-compare-version-strings-in-java
* Compares two version strings.
*
* Use this instead of String.compareTo() for a non-lexicographical
* comparison that works for version strings. e.g. "1.10".compareTo("1.6").
*
* @note It does not work if "1.10" is supposed to be equal to "1.10.0".
*
* @param str1 a string of ordinal numbers separated by decimal points.
* @param str2 a string of ordinal numbers separated by decimal points.
* @return The result is a negative integer if str1 is _numerically_ less than str2.
* The result is a positive integer if str1 is _numerically_ greater than str2.
* The result is zero if the strings are _numerically_ equal.
*/
public static int versionCompare(String str1, String str2) {
String[] vals1 = str1.split("\\.");
String[] vals2 = str2.split("\\.");
int i = 0;
// set index to first non-equal ordinal or length of shortest version string
while (i < vals1.length && i < vals2.length && vals1[i].equals(vals2[i])) {
i++;
}
// compare first non-equal ordinal number
if (i < vals1.length && i < vals2.length) {
int diff = Integer.valueOf(vals1[i]).compareTo(Integer.valueOf(vals2[i]));
return Integer.signum(diff);
}
// the strings are equal or one string is a substring of the other
// e.g. "1.2.3" = "1.2.3" or "1.2.3" < "1.2.3.4"
return Integer.signum(vals1.length - vals2.length);
}
}

View File

@@ -74,7 +74,11 @@ ELSE()
ENDIF()
TARGET_LINK_LIBRARIES(rtabmap rtabmap_core rtabmap_gui rtabmap_utilite ${LIBRARIES})
IF(Qt5_FOUND)
QT5_USE_MODULES(rtabmap Widgets Core Gui Svg PrintSupport)
IF(Qt5Svg_FOUND)
QT5_USE_MODULES(rtabmap Widgets Core Gui Svg PrintSupport)
ELSE()
QT5_USE_MODULES(rtabmap Widgets Core Gui PrintSupport)
ENDIF()
ENDIF(Qt5_FOUND)
IF(APPLE AND BUILD_AS_BUNDLE)

View File

@@ -50,13 +50,14 @@ signals:
void objDeletionEventReceived(int);
protected:
virtual void handleEvent(UEvent * event)
virtual bool handleEvent(UEvent * event)
{
if(event->getClassName().compare("UObjDeletedEvent") == 0 &&
event->getCode() == _watchedId)
{
emit objDeletionEventReceived(_watchedId);
}
return false;
}
private:
int _watchedId;

View File

@@ -47,6 +47,7 @@ int main(int argc, char* argv[])
/* Create tasks */
QApplication * app = new QApplication(argc, argv);
app->setStyleSheet("QMessageBox { messagebox-text-interaction-flags: 5; }"); // selectable message box
ParametersMap parameters = Parameters::parseArguments(argc, argv, true);
MainWindow * mainWindow = new MainWindow();

View File

@@ -0,0 +1,31 @@
# - Find ORB_SLAM2
#
# It sets the following variables:
# ORB_SLAM2_FOUND - Set to false, or undefined, if ORB_SLAM2 isn't found.
# ORB_SLAM2_INCLUDE_DIRS - The ORB_SLAM2 include directory.
# ORB_SLAM2_LIBRARIES - The ORB_SLAM2 library to link against.
#
# Set ORB_SLAM2_ROOT_DIR environment variable as the path to ORB_SLAM2 root folder.
find_path(ORB_SLAM2_INCLUDE_DIR NAMES System.h PATHS $ENV{ORB_SLAM2_ROOT_DIR}/include)
find_library(ORB_SLAM2_LIBRARY NAMES ORB_SLAM2 PATHS $ENV{ORB_SLAM2_ROOT_DIR}/lib)
find_library(g2o_LIBRARY NAMES g2o PATHS $ENV{ORB_SLAM2_ROOT_DIR}/Thirdparty/g2o/lib)
IF (ORB_SLAM2_INCLUDE_DIR AND ORB_SLAM2_LIBRARY AND g2o_LIBRARY)
SET(ORB_SLAM2_FOUND TRUE)
SET(ORB_SLAM2_INCLUDE_DIRS ${ORB_SLAM2_INCLUDE_DIR} $ENV{ORB_SLAM2_ROOT_DIR})
SET(ORB_SLAM2_LIBRARIES ${g2o_LIBRARY} ${ORB_SLAM2_LIBRARY})
ENDIF (ORB_SLAM2_INCLUDE_DIR AND ORB_SLAM2_LIBRARY AND g2o_LIBRARY)
IF (ORB_SLAM2_FOUND)
# show which ORB_SLAM2 was found only if not quiet
IF (NOT ORB_SLAM2_FIND_QUIETLY)
MESSAGE(STATUS "Found ORB_SLAM2: ${ORB_SLAM2_LIBRARIES}")
ENDIF (NOT ORB_SLAM2_FIND_QUIETLY)
ELSE (ORB_SLAM2_FOUND)
# fatal error if ORB_SLAM2 is required but not found
IF (ORB_SLAM2_FIND_REQUIRED)
MESSAGE(FATAL_ERROR "Could not find ORB_SLAM2")
ENDIF (ORB_SLAM2_FIND_REQUIRED)
ENDIF (ORB_SLAM2_FOUND)

View File

@@ -4,9 +4,18 @@
#
# It sets the following variables:
# RealSense_FOUND - Set to false, or undefined, if RealSense isn't found.
# RealSenseSlam_FOUND - Set to false, or undefined, if RealSense slam module isn't found.
# RealSense_INCLUDE_DIRS - The RealSense include directory.
# RealSense_LIBRARIES - The RealSense library to link against.
# Use find_package( RealSense COMPONENTS slam ) to search for realsense slam library
if( RealSense_FIND_COMPONENTS )
foreach( component ${RealSense_FIND_COMPONENTS} )
string( TOUPPER ${component} _COMPONENT )
set( REALSENSE_USE_${_COMPONENT} 1 )
endforeach()
endif()
#RealSense library
find_path(RealSense_INCLUDE_DIRS NAMES librealsense/rs.hpp PATHS $ENV{RealSense_ROOT_DIR}/include)
if(CMAKE_CL_64)
@@ -19,9 +28,44 @@ IF (RealSense_INCLUDE_DIRS AND RealSense_LIBRARY)
SET(RealSense_FOUND TRUE)
ENDIF (RealSense_INCLUDE_DIRS AND RealSense_LIBRARY)
#SLAM
if(REALSENSE_USE_SLAM)
find_path(RealSenseSlam_INCLUDE_DIRS NAMES librealsense/slam/slam.h PATHS $ENV{RealSense_ROOT_DIR}/include)
if(CMAKE_CL_64)
find_library(RealSenseSlam_LIBRARY NAMES realsense_slam PATHS $ENV{RealSense_ROOT_DIR}/lib $ENV{RealSense_ROOT_DIR}/bin $ENV{RealSense_ROOT_DIR}/bin/x64)
find_library(RealSenseImage_LIBRARY NAMES realsense_image PATHS $ENV{RealSense_ROOT_DIR}/lib $ENV{RealSense_ROOT_DIR}/bin $ENV{RealSense_ROOT_DIR}/bin/x64)
find_library(RealSenseSP_Core_LIBRARY NAMES SP_Core PATHS $ENV{RealSense_ROOT_DIR}/lib $ENV{RealSense_ROOT_DIR}/bin $ENV{RealSense_ROOT_DIR}/bin/x64)
find_library(RealSenseTracker_LIBRARY NAMES tracker PATHS $ENV{RealSense_ROOT_DIR}/lib $ENV{RealSense_ROOT_DIR}/bin $ENV{RealSense_ROOT_DIR}/bin/x64)
else()
find_library(RealSenseSlam_LIBRARY NAMES realsense_slam PATHS $ENV{RealSense_ROOT_DIR}/lib $ENV{RealSense_ROOT_DIR}/bin $ENV{RealSense_ROOT_DIR}/bin/Win32)
find_library(RealSenseImage_LIBRARY NAMES realsense_image PATHS $ENV{RealSense_ROOT_DIR}/lib $ENV{RealSense_ROOT_DIR}/bin $ENV{RealSense_ROOT_DIR}/bin/Win32)
find_library(RealSenseSP_Core_LIBRARY NAMES SP_Core PATHS $ENV{RealSense_ROOT_DIR}/lib $ENV{RealSense_ROOT_DIR}/bin $ENV{RealSense_ROOT_DIR}/bin/Win32)
find_library(RealSenseTracker_LIBRARY NAMES tracker PATHS $ENV{RealSense_ROOT_DIR}/lib $ENV{RealSense_ROOT_DIR}/bin $ENV{RealSense_ROOT_DIR}/bin/Win32)
endif()
else()
set(RealSenseSlam_INCLUDE_DIRS "")
endif()
IF (RealSense_FOUND)
# show which RealSense was found only if not quiet
IF (RealSenseSlam_INCLUDE_DIRS AND RealSenseSlam_LIBRARY AND RealSenseImage_LIBRARY AND RealSenseSP_Core_LIBRARY AND RealSenseTracker_LIBRARY)
SET(RealSenseSlam_FOUND TRUE)
ENDIF (RealSenseSlam_INCLUDE_DIRS AND RealSenseSlam_LIBRARY AND RealSenseImage_LIBRARY AND RealSenseSP_Core_LIBRARY AND RealSenseTracker_LIBRARY)
SET(RealSense_LIBRARIES ${RealSense_LIBRARY})
IF (RealSenseSlam_FOUND)
IF (RealSenseSlam_INCLUDE_DIRS AND RealSenseSlam_LIBRARY AND RealSenseImage_LIBRARY AND RealSenseSP_Core_LIBRARY AND RealSenseTracker_LIBRARY)
SET(RealSenseSlam_FOUND TRUE)
ENDIF (RealSenseSlam_INCLUDE_DIRS AND RealSenseSlam_LIBRARY AND RealSenseImage_LIBRARY AND RealSenseSP_Core_LIBRARY AND RealSenseTracker_LIBRARY)
SET(RealSense_LIBRARIES
${RealSense_LIBRARIES}
${RealSenseSlam_LIBRARY}
${RealSenseImage_LIBRARY}
${RealSenseSP_Core_LIBRARY}
${RealSenseTracker_LIBRARY})
ENDIF(RealSenseSlam_FOUND)
# show which RealSense was found only if not quiet
IF (NOT RealSense_FIND_QUIETLY)
MESSAGE(STATUS "Found RealSense: ${RealSense_LIBRARIES}")
ENDIF (NOT RealSense_FIND_QUIETLY)

View File

@@ -8,8 +8,8 @@
FIND_PATH(Tango_INCLUDE_DIR tango_client_api.h)
FIND_LIBRARY(Tango_LIBRARY NAMES tango_client_api)
FIND_LIBRARY(Tango_support_LIBRARY NAMES tango_support_api)
FIND_LIBRARY(Tango_LIBRARY NAMES tango_client_api PATH_SUFFIXES ${ANDROID_ABI})
FIND_LIBRARY(Tango_support_LIBRARY NAMES tango_support_api PATH_SUFFIXES ${ANDROID_ABI})
IF (Tango_INCLUDE_DIR AND Tango_LIBRARY AND Tango_support_LIBRARY)
SET(Tango_FOUND TRUE)

View File

@@ -107,12 +107,14 @@ public:
_depthFromScanFillHolesFromBorder = fillHolesFromBorder;
}
// Format: 0=Raw, 1=RGBD-SLAM, 2=KITTI, 3=TORO, 4=g2o, 5=NewCollege(t,x,y), 6=Malaga Urban GPS, 7=St Lucia INS, 8=Karlsruhe
void setOdometryPath(const std::string & filePath, int format = 0)
{
_odometryPath = filePath;
_odometryFormat = format;
}
// Format: 0=Raw, 1=RGBD-SLAM, 2=KITTI, 3=TORO, 4=g2o, 5=NewCollege(t,x,y), 6=Malaga Urban GPS, 7=St Lucia INS, 8=Karlsruhe
void setGroundTruthPath(const std::string & filePath, int format = 0)
{
_groundTruthPath = filePath;
@@ -127,7 +129,11 @@ public:
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
bool readPoses(std::list<Transform> & outputPoses, std::list<double> & stamps, const std::string & filePath, int format) const;
bool readPoses(
std::list<Transform> & outputPoses,
std::list<double> & stamps,
const std::string & filePath,
int format) const;
private:
std::string _path;

View File

@@ -69,6 +69,9 @@ namespace rs
{
class context;
class device;
namespace slam {
class slam;
}
}
typedef struct _freenect_context freenect_context;
@@ -290,6 +293,7 @@ private:
/////////////////////////
// CameraRealSense
/////////////////////////
class slam_event_handler;
class RTABMAP_EXP CameraRealSense :
public Camera
{
@@ -302,6 +306,7 @@ public:
int deviceId = 0,
int presetRGB = 0, // 0=best quality, 1=largest image, 2=highest framerate
int presetDepth = 0, // 0=best quality, 1=largest image, 2=highest framerate
bool computeOdometry = false,
float imageRate = 0,
const Transform & localTransform = Transform::getIdentity());
virtual ~CameraRealSense();
@@ -309,6 +314,7 @@ public:
virtual bool init(const std::string & calibrationFolder = ".", const std::string & cameraName = "");
virtual bool isCalibrated() const;
virtual std::string getSerial() const;
virtual bool odomProvided() const;
protected:
virtual SensorData captureImage(CameraInfo * info = 0);
@@ -320,6 +326,16 @@ private:
int deviceId_;
int presetRGB_;
int presetDepth_;
bool computeOdometry_;
int motionSeq_[2];
rs::slam::slam * slam_;
UMutex slamLock_;
std::map<double, std::pair<cv::Mat, cv::Mat> > bufferedFrames_;
std::pair<cv::Mat, cv::Mat> lastSyncFrames_;
UMutex dataMutex_;
USemaphore dataReady_;
#endif
};

View File

@@ -42,11 +42,8 @@ class Camera;
namespace sl
{
namespace zed
{
class Camera;
}
}
namespace rtabmap
{
@@ -121,7 +118,7 @@ public:
int deviceId,
int resolution = 2, // 0=HD2K, 1=HD1080, 2=HD720, 3=VGA
int quality = 1, // 0=NONE, 1=PERFORMANCE, 2=QUALITY
int sensingMode = 1,// 0=FULL, 1=RAW
int sensingMode = 0,// 0=STANDARD, 1=FILL
int confidenceThr = 100,
bool computeOdometry = false,
float imageRate=0.0f,
@@ -130,7 +127,7 @@ public:
CameraStereoZed(
const std::string & svoFilePath,
int quality = 1, // 0=NONE, 1=PERFORMANCE, 2=QUALITY
int sensingMode = 1,// 0=FULL, 1=RAW
int sensingMode = 0,// 0=STANDARD, 1=FILL
int confidenceThr = 100,
bool computeOdometry = false,
float imageRate=0.0f,
@@ -148,7 +145,7 @@ protected:
private:
#ifdef RTABMAP_ZED
sl::zed::Camera * zed_;
sl::Camera * zed_;
StereoCameraModel stereoModel_;
CameraVideo::Source src_;
int usbDevice_;

View File

@@ -42,6 +42,8 @@ namespace rtabmap
{
class Camera;
class CameraInfo;
class SensorData;
class StereoDense;
/**
@@ -80,6 +82,8 @@ public:
_scanNormalsK = normalsK;
}
void postUpdate(SensorData * data, CameraInfo * info = 0) const;
//getters
bool isPaused() const {return !this->isRunning();}
bool isCapturing() const {return this->isRunning();}

View File

@@ -93,10 +93,32 @@ public:
const cv::Mat & obstacles,
float cellSize,
const cv::Point3f & viewpoint);
void updateDepthImage(int nodeId, const cv::Mat & image);
public:
void addInfoAfterRun(int stMemSize, int lastSignAdded, int processMemUsed, int databaseMemUsed, int dictionarySize, const ParametersMap & parameters) const;
void addStatistics(const Statistics & statistics) const;
void savePreviewImage(const cv::Mat & image) const;
cv::Mat loadPreviewImage() const;
void saveOptimizedMesh(
const cv::Mat & cloud,
const std::map<int, Transform> & poses = std::map<int, Transform>(), // if we want to do localization afterward using optimized mesh
const std::vector<std::vector<std::vector<unsigned int> > > & polygons = std::vector<std::vector<std::vector<unsigned int> > >(), // Textures -> polygons -> vertices
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords = std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > >(), // Textures -> uv coords for each vertex of the polygons
#else
const std::vector<std::vector<Eigen::Vector2f> > & texCoords = std::vector<std::vector<Eigen::Vector2f> >(), // Textures -> uv coords for each vertex of the polygons
#endif
const cv::Mat & textures = cv::Mat()) const; // concatenated textures (assuming square textures with all same size);
cv::Mat loadOptimizedMesh(
std::map<int, Transform> * poses = 0,
std::vector<std::vector<std::vector<unsigned int> > > * polygons = 0,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords = 0,
#else
std::vector<std::vector<Eigen::Vector2f> > * texCoords = 0,
#endif
cv::Mat * textures = 0) const;
public:
// Mutex-protected methods of abstract versions below
@@ -106,11 +128,17 @@ public:
bool isConnected() const;
long getMemoryUsed() const; // In bytes
std::string getDatabaseVersion() const;
long getNodesMemoryUsed() const;
long getLinksMemoryUsed() const;
long getImagesMemoryUsed() const;
long getDepthImagesMemoryUsed() const;
long getCalibrationsMemoryUsed() const;
long getGridsMemoryUsed() const;
long getLaserScansMemoryUsed() const;
long getUserDataMemoryUsed() const;
long getWordsMemoryUsed() const;
long getFeaturesMemoryUsed() const;
long getStatisticsMemoryUsed() const;
int getLastNodesSize() const; // working memory
int getLastDictionarySize() const; // working memory
int getTotalNodesSize() const;
@@ -130,7 +158,8 @@ public:
void loadNodeData(std::list<Signature *> & signatures, bool images = true, bool scan = true, bool userData = true, bool occupancyGrid = true) const;
void getNodeData(int signatureId, SensorData & data, bool images = true, bool scan = true, bool userData = true, bool occupancyGrid = true) const;
bool getCalibration(int signatureId, std::vector<CameraModel> & models, StereoCameraModel & stereoModel) const;
bool getNodeInfo(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose) const;
bool getLaserScanInfo(int signatureId, LaserScanInfo & info) const;
bool getNodeInfo(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose, std::vector<float> & velocity) const;
void loadLinks(int signatureId, std::map<int, Link> & links, Link::Type type = Link::kUndef) const;
void getWeight(int signatureId, int & weight) const;
void getAllNodeIds(std::set<int> & ids, bool ignoreChildren = false, bool ignoreBadSignatures = false) const;
@@ -150,11 +179,17 @@ private:
virtual bool isConnectedQuery() const = 0;
virtual long getMemoryUsedQuery() const = 0; // In bytes
virtual bool getDatabaseVersionQuery(std::string & version) const = 0;
virtual long getNodesMemoryUsedQuery() const = 0;
virtual long getLinksMemoryUsedQuery() const = 0;
virtual long getImagesMemoryUsedQuery() const = 0;
virtual long getDepthImagesMemoryUsedQuery() const = 0;
virtual long getCalibrationsMemoryUsedQuery() const = 0;
virtual long getGridsMemoryUsedQuery() const = 0;
virtual long getLaserScansMemoryUsedQuery() const = 0;
virtual long getUserDataMemoryUsedQuery() const = 0;
virtual long getWordsMemoryUsedQuery() const = 0;
virtual long getFeaturesMemoryUsedQuery() const = 0;
virtual long getStatisticsMemoryUsedQuery() const = 0;
virtual int getLastNodesSizeQuery() const = 0;
virtual int getLastDictionarySizeQuery() const = 0;
virtual int getTotalNodesSizeQuery() const = 0;
@@ -181,7 +216,32 @@ private:
float cellSize,
const cv::Point3f & viewpoint) const = 0;
virtual void updateDepthImageQuery(
int nodeId,
const cv::Mat & image) const = 0;
virtual void addStatisticsQuery(const Statistics & statistics) const = 0;
virtual void savePreviewImageQuery(const cv::Mat & image) const = 0;
virtual cv::Mat loadPreviewImageQuery() const = 0;
virtual void saveOptimizedMeshQuery(
const cv::Mat & cloud,
const std::map<int, Transform> & poses,
const std::vector<std::vector<std::vector<unsigned int> > > & polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords,
#else
const std::vector<std::vector<Eigen::Vector2f> > & texCoords,
#endif
const cv::Mat & textures) const = 0;
virtual cv::Mat loadOptimizedMeshQuery(
std::map<int, Transform> * poses,
std::vector<std::vector<std::vector<unsigned int> > > * polygons,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords,
#else
std::vector<std::vector<Eigen::Vector2f> > * texCoords,
#endif
cv::Mat * textures) const = 0;
// Load objects
virtual void loadQuery(VWDictionary * dictionary) const = 0;
@@ -192,7 +252,8 @@ private:
virtual void loadNodeDataQuery(std::list<Signature *> & signatures, bool images=true, bool scan=true, bool userData=true, bool occupancyGrid=true) const = 0;
virtual bool getCalibrationQuery(int signatureId, std::vector<CameraModel> & models, StereoCameraModel & stereoModel) const = 0;
virtual bool getNodeInfoQuery(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose) const = 0;
virtual bool getLaserScanInfoQuery(int signatureId, LaserScanInfo & info) const = 0;
virtual bool getNodeInfoQuery(int signatureId, Transform & pose, int & mapId, int & weight, std::string & label, double & stamp, Transform & groundTruthPose, std::vector<float> & velocity) const = 0;
virtual void getAllNodeIdsQuery(std::set<int> & ids, bool ignoreChildren, bool ignoreBadSignatures) const = 0;
virtual void getAllLinksQuery(std::multimap<int, Link> & links, bool ignoreNullLinks) const = 0;
virtual void getLastIdQuery(const std::string & tableName, int & id) const = 0;

View File

@@ -87,6 +87,8 @@ private:
UTimer _timer;
std::set<int> _ids;
std::set<int>::iterator _currentId;
int _previousMapId;
cv::Mat _previousInfMatrix;
double _previousStamp;
int _previousMapID;
bool _calibrated;

View File

@@ -94,7 +94,8 @@ public:
static int findPairs(
const std::map<int, cv::KeyPoint> & wordsA,
const std::map<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs);
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs,
bool ignoreNegativeIds = true);
/**
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(1,1a) (2,2) (4,4) (6a,6a) (6b,6b)]
@@ -103,7 +104,8 @@ public:
static int findPairs(
const std::multimap<int, cv::KeyPoint> & wordsA,
const std::multimap<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs);
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs,
bool ignoreNegativeIds = true);
/**
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(2,2) (4,4)]
@@ -112,7 +114,8 @@ public:
static int findPairsUnique(
const std::multimap<int, cv::KeyPoint> & wordsA,
const std::multimap<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs);
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs,
bool ignoreNegativeIds = true);
/**
* if a=[1 2 3 4 6 6], b=[1 1 2 4 5 6 6], results= [(1,1a) (1,1b) (2,2) (4,4) (6a,6a) (6a,6b) (6b,6a) (6b,6b)]
@@ -121,7 +124,8 @@ public:
static int findPairsAll(
const std::multimap<int, cv::KeyPoint> & wordsA,
const std::multimap<int, cv::KeyPoint> & wordsB,
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs);
std::list<std::pair<int, std::pair<cv::KeyPoint, cv::KeyPoint> > > & pairs,
bool ignoreNegativeIds = true);
static cv::Mat linearLSTriangulation(
cv::Point3d u, //homogenous image point (u,v,1)

View File

@@ -104,7 +104,8 @@ public:
kFeatureGfttFreak=5,
kFeatureGfttBrief=6,
kFeatureBrisk=7,
kFeatureGfttOrb=8}; //new 0.10.11
kFeatureGfttOrb=8, //new 0.10.11
kFeatureKaze=9}; //new 0.13.2
static Feature2D * create(const ParametersMap & parameters = ParametersMap());
static Feature2D * create(Feature2D::Type type, const ParametersMap & parameters = ParametersMap()); // for convenience
@@ -134,6 +135,7 @@ public:
static void limitKeypoints(std::vector<cv::KeyPoint> & keypoints, int maxKeypoints);
static void limitKeypoints(std::vector<cv::KeyPoint> & keypoints, cv::Mat & descriptors, int maxKeypoints);
static void limitKeypoints(std::vector<cv::KeyPoint> & keypoints, std::vector<cv::Point3f> & keypoints3D, cv::Mat & descriptors, int maxKeypoints);
static void limitKeypoints(const std::vector<cv::KeyPoint> & keypoints, std::vector<bool> & inliers, int maxKeypoints);
static cv::Rect computeRoi(const cv::Mat & image, const std::string & roiRatios);
static cv::Rect computeRoi(const cv::Mat & image, const std::vector<float> & roiRatios);
@@ -431,6 +433,33 @@ private:
cv::Ptr<CV_BRISK> brisk_;
};
//KAZE
class RTABMAP_EXP KAZE : public Feature2D
{
public:
KAZE(const ParametersMap & parameters = ParametersMap());
virtual ~KAZE();
virtual void parseParameters(const ParametersMap & parameters);
virtual Feature2D::Type getType() const { return kFeatureKaze; }
private:
virtual std::vector<cv::KeyPoint> generateKeypointsImpl(const cv::Mat & image, const cv::Rect & roi, const cv::Mat & mask = cv::Mat()) const;
virtual cv::Mat generateDescriptorsImpl(const cv::Mat & image, std::vector<cv::KeyPoint> & keypoints) const;
private:
bool extended_;
bool upright_;
float threshold_;
int nOctaves_;
int nOctaveLayers_;
int diffusivity_;
#if CV_MAJOR_VERSION > 2
cv::Ptr<cv::KAZE> kaze_;
#endif
};
}

View File

@@ -43,7 +43,7 @@ namespace rtabmap {
*/
class RTABMAP_EXP GainCompensator {
public:
GainCompensator(double maxCorrespondenceDistance = 0.02, double minOverlap = 0.05, double alpha = 0.01, double beta = 10);
GainCompensator(double maxCorrespondenceDistance = 0.02, double minOverlap = 0.0, double alpha = 0.01, double beta = 10);
virtual ~GainCompensator();
void feed(
@@ -73,20 +73,24 @@ public:
void apply(
int id,
pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud);
pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
bool rgb = true) const;
void apply(
int id,
pcl::PointCloud<pcl::PointXYZRGB>::Ptr & cloud,
const pcl::IndicesPtr & indices);
const pcl::IndicesPtr & indices,
bool rgb = true) const;
void apply(
int id,
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr & cloud,
const pcl::IndicesPtr & indices);
const pcl::IndicesPtr & indices,
bool rgb = true) const;
void apply(
int id,
cv::Mat & image);
cv::Mat & image,
bool rgb = true) const;
double getGain(int id) const;
double getGain(int id, double * r=0, double * g=0, double * b=0) const;
int getIndex(int id) const;
private:

View File

@@ -53,11 +53,25 @@ bool RTABMAP_EXP exportPoses(
bool RTABMAP_EXP importPoses(
const std::string & filePath,
int format, // 0=Raw, 1=RGBD-SLAM, 2=KITTI, 3=TORO, 4=g2o, GPS (t,x,y)
int format, // 0=Raw, 1=RGBD-SLAM, 2=KITTI, 3=TORO, 4=g2o, 5=NewCollege(t,x,y), 6=Malaga Urban GPS, 7=St Lucia INS, 8=Karlsruhe
std::map<int, Transform> & poses,
std::multimap<int, Link> * constraints = 0, // optional for formats 3 and 4
std::map<int, double> * stamps = 0); // optional for format 1
/**
* Compute translation and rotation errors for KITTI datasets.
* See http://www.cvlibs.net/datasets/kitti/eval_odometry.php.
* @param poses_gt, Ground Truth poses
* @param poses_result, Estimated poses
* @param t_err, Output translation error (%)
* @param r_err, Output rotation error (deg/m)
*/
void RTABMAP_EXP calcKittiSequenceErrors(
const std::vector<Transform> &poses_gt,
const std::vector<Transform> &poses_result,
float & t_err,
float & r_err);
std::multimap<int, Link>::iterator RTABMAP_EXP findLink(
std::multimap<int, Link> & links,
int from,
@@ -205,6 +219,10 @@ float RTABMAP_EXP computePathLength(
unsigned int fromIndex = 0,
unsigned int toIndex = 0);
// assuming they are all linked in map order
float RTABMAP_EXP computePathLength(
const std::map<int, Transform> & path);
std::list<std::map<int, Transform> > RTABMAP_EXP getPaths(
std::map<int, Transform> poses,
const std::multimap<int, Link> & links);

View File

@@ -46,20 +46,14 @@ public:
kUserClosure,
kVirtualClosure,
kNeighborMerged,
kUndef};
kPosePrior,
kUndef = 99};
Link();
Link(int from,
int to,
Type type,
const Transform & transform,
const cv::Mat & infMatrix = cv::Mat::eye(6,6,CV_64FC1),
const cv::Mat & userData = cv::Mat());
Link(int from,
int to,
Type type,
const Transform & transform,
double rotVariance,
double transVariance,
const cv::Mat & infMatrix = cv::Mat::eye(6,6,CV_64FC1), // information matrix: inverse of covariance matrix
const cv::Mat & userData = cv::Mat());
bool isValid() const {return from_ > 0 && to_ > 0 && !transform_.isNull() && type_!=kUndef;}
@@ -87,7 +81,6 @@ public:
private:
void setInfMatrix(const cv::Mat & infMatrix);
void setVariance(double rotVariance, double transVariance);
private:
int from_;

View File

@@ -42,6 +42,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/utilite/UStl.h"
#include <opencv2/core/core.hpp>
#include <opencv2/features2d/features2d.hpp>
#include <pcl/pcl_config.h>
namespace rtabmap {
@@ -75,6 +76,7 @@ public:
bool update(const SensorData & data,
const Transform & pose,
const cv::Mat & covariance,
const std::vector<float> & velocity = std::vector<float>(), // vx,vy,vz,vroll,vpitch,vyaw
Statistics * stats = 0);
bool init(const std::string & dbUrl,
bool dbOverwritten = false,
@@ -91,6 +93,27 @@ public:
int cleanup();
void saveStatistics(const Statistics & statistics);
void savePreviewImage(const cv::Mat & image) const;
cv::Mat loadPreviewImage() const;
void saveOptimizedMesh(
const cv::Mat & cloud,
const std::map<int, Transform> & poses = std::map<int, Transform>(), // if we want to do localization afterward using optimized mesh
const std::vector<std::vector<std::vector<unsigned int> > > & polygons = std::vector<std::vector<std::vector<unsigned int> > >(), // Textures -> polygons -> vertices
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
const std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > & texCoords = std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > >(), // Textures -> uv coords for each vertex of the polygons
#else
const std::vector<std::vector<Eigen::Vector2f> > & texCoords = std::vector<std::vector<Eigen::Vector2f> >(), // Textures -> uv coords for each vertex of the polygons
#endif
const cv::Mat & textures = cv::Mat()) const; // concatenated textures (assuming square textures with all same size)
cv::Mat loadOptimizedMesh(
std::map<int, Transform> * poses = 0,
std::vector<std::vector<std::vector<unsigned int> > > * polygons = 0,
#if PCL_VERSION_COMPARE(>=, 1, 8, 0)
std::vector<std::vector<Eigen::Vector2f, Eigen::aligned_allocator<Eigen::Vector2f> > > * texCoords = 0,
#else
std::vector<std::vector<Eigen::Vector2f> > * texCoords = 0,
#endif
cv::Mat * textures = 0) const;
void emptyTrash();
void joinTrashThread();
bool addLink(const Link & link, bool addInDatabase = false);
@@ -153,6 +176,7 @@ public:
std::string & label,
double & stamp,
Transform & groundTruth,
std::vector<float> & velocity,
bool lookInDatabase = false) const;
cv::Mat getImageCompressed(int signatureId) const;
SensorData getNodeData(int nodeId, bool uncompressedData = false) const;
@@ -244,6 +268,7 @@ private:
bool _rawDescriptorsKept;
bool _saveDepth16Format;
bool _notLinkedNodesKeptInDb;
bool _saveIntermediateNodeData;
bool _incrementalMemory;
bool _reduceGraph;
int _maxStMemSize;
@@ -255,6 +280,7 @@ private:
bool _mapLabelsAdded;
int _imagePreDecimation;
int _imagePostDecimation;
bool _compressionParallelized;
float _laserScanDownsampleStepSize;
int _laserScanNormalK;
bool _reextractLoopClosureFeatures;
@@ -263,6 +289,7 @@ private:
bool _rehearsalWeightIgnoredWhileMoving;
bool _useOdometryFeatures;
bool _createOccupancyGrid;
int _visMaxFeatures;
int _idCount;
int _idMapCount;

View File

@@ -44,7 +44,12 @@ public:
void parseParameters(const ParametersMap & parameters);
void setCellSize(float cellSize);
float getCellSize() const {return cellSize_;}
float getMinMapSize() const {return minMapSize_;}
bool isGridFromDepth() const {return occupancyFromCloud_;}
bool isFullUpdate() const {return fullUpdate_;}
bool isMapFrameProjection() const {return projMapFrame_;}
const std::map<int, Transform> & addedNodes() const {return addedNodes_;}
int cacheSize() const {return (int)cache_.size();}
template<typename PointT>
typename pcl::PointCloud<PointT>::Ptr segmentCloud(
@@ -67,13 +72,8 @@ public:
int nodeId,
const cv::Mat & ground,
const cv::Mat & obstacles);
void update(const std::map<int, Transform> & poses, float minMapSize = 0.0f, float footprintRadius = 0.0f);
const cv::Mat & getMap(float & xMin, float & yMin) const
{
xMin = xMin_;
yMin = yMin_;
return map_;
}
void update(const std::map<int, Transform> & poses);
const cv::Mat getMap(float & xMin, float & yMin) const;
private:
ParametersMap parameters_;
@@ -103,6 +103,11 @@ private:
int noiseFilteringMinNeighbors_;
bool scan2dUnknownSpaceFilled_;
double scan2dMaxUnknownSpaceFilledRange_;
bool projRayTracing_;
bool fullUpdate_;
float minMapSize_;
bool erode_;
float footprintRadius_;
std::map<int, std::pair<cv::Mat, cv::Mat> > cache_;
cv::Mat map_;

View File

@@ -57,7 +57,7 @@ public:
class RTABMAP_EXP OctoMap {
public:
OctoMap(float voxelSize = 0.1f, float occupancyThr = 0.5f);
OctoMap(float voxelSize = 0.1f, float occupancyThr = 0.5f, bool fullUpdate = false);
const std::map<int, Transform> & addedNodes() const {return addedNodes_;}
void addToCache(int nodeId,
@@ -81,7 +81,8 @@ public:
float & xMin,
float & yMin,
float & gridCellSize,
float minGridSize);
float minGridSize = 0.0f,
unsigned int treeDepth = 0);
bool writeBinary(const std::string & path);
@@ -97,6 +98,7 @@ private:
std::map<int, Transform> addedNodes_;
octomap::KeyRay keyRay_;
bool hasColor_;
bool fullUpdate_;
};
} /* namespace rtabmap */

View File

@@ -45,7 +45,11 @@ public:
enum Type {
kTypeUndef = -1,
kTypeF2M = 0,
kTypeF2F = 1
kTypeF2F = 1,
kTypeFovis = 2,
kTypeViso2 = 3,
kTypeDVO = 4,
kTypeORBSLAM2 = 5
};
public:

View File

@@ -0,0 +1,67 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ODOMETRYDVO_H_
#define ODOMETRYDVO_H_
#include <rtabmap/core/Odometry.h>
namespace dvo {
class DenseTracker;
namespace core {
class RgbdImagePyramid;
class RgbdCameraPyramid;
}
}
namespace rtabmap {
class RTABMAP_EXP OdometryDVO : public Odometry
{
public:
OdometryDVO(const rtabmap::ParametersMap & parameters = rtabmap::ParametersMap());
virtual ~OdometryDVO();
virtual void reset(const Transform & initialPose = Transform::getIdentity());
virtual Odometry::Type getType() {return Odometry::kTypeDVO;}
private:
virtual Transform computeTransform(SensorData & image, const Transform & guess = Transform(), OdometryInfo * info = 0);
private:
dvo::DenseTracker * dvo_;
dvo::core::RgbdImagePyramid * reference_;
dvo::core::RgbdCameraPyramid * camera_;
bool lost_;
Transform motionFromKeyFrame_;
Transform previousLocalTransform_;
};
}
#endif /* ODOMETRYDVO_H_ */

View File

@@ -39,53 +39,29 @@ namespace rtabmap {
class OdometryEvent : public UEvent
{
public:
static cv::Mat generateCovarianceMatrix(float rotVariance, float transVariance)
{
UASSERT(uIsFinite(rotVariance) && rotVariance>0);
UASSERT(uIsFinite(transVariance) && transVariance>0);
cv::Mat covariance = cv::Mat::eye(6,6,CV_64FC1);
covariance.at<double>(0,0) = transVariance;
covariance.at<double>(1,1) = transVariance;
covariance.at<double>(2,2) = transVariance;
covariance.at<double>(3,3) = rotVariance;
covariance.at<double>(4,4) = rotVariance;
covariance.at<double>(5,5) = rotVariance;
return covariance;
}
public:
OdometryEvent() :
_covariance(cv::Mat::eye(6,6,CV_64FC1))
OdometryEvent()
{
_info.covariance = cv::Mat::eye(6,6,CV_64FC1);
}
OdometryEvent(
const SensorData & data,
const Transform & pose,
const cv::Mat & covariance = cv::Mat::eye(6,6,CV_64FC1),
const OdometryInfo & info = OdometryInfo()) :
_data(data),
_pose(pose),
_info(info)
{
UASSERT(covariance.cols == 6 && covariance.rows == 6 && covariance.type() == CV_64FC1);
UASSERT_MSG(uIsFinite(covariance.at<double>(0,0)) && covariance.at<double>(0,0)>0, "Transitional variance should not be null! (set to 1 if unknown)");
UASSERT_MSG(uIsFinite(covariance.at<double>(1,1)) && covariance.at<double>(1,1)>0, "Transitional variance should not be null! (set to 1 if unknown)");
UASSERT_MSG(uIsFinite(covariance.at<double>(2,2)) && covariance.at<double>(2,2)>0, "Transitional variance should not be null! (set to 1 if unknown)");
UASSERT_MSG(uIsFinite(covariance.at<double>(3,3)) && covariance.at<double>(3,3)>0, "Rotational variance should not be null! (set to 1 if unknown)");
UASSERT_MSG(uIsFinite(covariance.at<double>(4,4)) && covariance.at<double>(4,4)>0, "Rotational variance should not be null! (set to 1 if unknown)");
UASSERT_MSG(uIsFinite(covariance.at<double>(5,5)) && covariance.at<double>(5,5)>0, "Rotational variance should not be null! (set to 1 if unknown)");
_covariance = covariance;
}
OdometryEvent(
const SensorData & data,
const Transform & pose,
double rotVariance = 1.0,
double transVariance = 1.0,
const OdometryInfo & info = OdometryInfo()) :
_data(data),
_pose(pose),
_covariance(generateCovarianceMatrix(rotVariance, transVariance)),
_info(info)
{
if(_info.covariance.empty())
{
_info.covariance = cv::Mat::eye(6,6,CV_64FC1);
}
UASSERT(_info.covariance.cols == 6 && _info.covariance.rows == 6 && _info.covariance.type() == CV_64FC1);
UASSERT_MSG(uIsFinite(_info.covariance.at<double>(0,0)) && _info.covariance.at<double>(0,0)>0, "Transitional variance should not be null! (set to 1 if unknown)");
UASSERT_MSG(uIsFinite(_info.covariance.at<double>(1,1)) && _info.covariance.at<double>(1,1)>0, "Transitional variance should not be null! (set to 1 if unknown)");
UASSERT_MSG(uIsFinite(_info.covariance.at<double>(2,2)) && _info.covariance.at<double>(2,2)>0, "Transitional variance should not be null! (set to 1 if unknown)");
UASSERT_MSG(uIsFinite(_info.covariance.at<double>(3,3)) && _info.covariance.at<double>(3,3)>0, "Rotational variance should not be null! (set to 1 if unknown)");
UASSERT_MSG(uIsFinite(_info.covariance.at<double>(4,4)) && _info.covariance.at<double>(4,4)>0, "Rotational variance should not be null! (set to 1 if unknown)");
UASSERT_MSG(uIsFinite(_info.covariance.at<double>(5,5)) && _info.covariance.at<double>(5,5)>0, "Rotational variance should not be null! (set to 1 if unknown)");
}
virtual ~OdometryEvent() {}
virtual std::string getClassName() const {return "OdometryEvent";}
@@ -93,15 +69,27 @@ public:
SensorData & data() {return _data;}
const SensorData & data() const {return _data;}
const Transform & pose() const {return _pose;}
const cv::Mat & covariance() const {return _covariance;}
const cv::Mat & covariance() const {return _info.covariance;}
std::vector<float> velocity() const {
if(_info.interval>0.0)
{
std::vector<float> velocity(6,0);
float x,y,z,roll,pitch,yaw;
_info.transform.getTranslationAndEulerAngles(x,y,z,roll,pitch,yaw);
velocity[0] = x/_info.interval;
velocity[1] = y/_info.interval;
velocity[2] = z/_info.interval;
velocity[3] = roll/_info.interval;
velocity[4] = pitch/_info.interval;
velocity[5] = yaw/_info.interval;
}
return std::vector<float>();
}
const OdometryInfo & info() const {return _info;}
double rotVariance() const {return uMax3(_covariance.at<double>(3,3), _covariance.at<double>(4,4), _covariance.at<double>(5,5));}
double transVariance() const {return uMax3(_covariance.at<double>(0,0), _covariance.at<double>(1,1), _covariance.at<double>(2,2));}
private:
SensorData _data;
Transform _pose;
cv::Mat _covariance;
OdometryInfo _info;
};

View File

@@ -77,6 +77,7 @@ private:
std::multimap<int, Link> bundleLinks_;
std::map<int, CameraModel> bundleModels_;
std::map<int, int> bundlePoseReferences_;
int bundleSeq_;
Optimizer * sba_;
};

View File

@@ -0,0 +1,68 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ODOMETRYFOVIS_H_
#define ODOMETRYFOVIS_H_
#include <rtabmap/core/Odometry.h>
namespace fovis {
class VisualOdometry;
class Rectification;
class StereoCalibration;
class DepthImage;
class StereoDepth;
}
namespace rtabmap {
class RTABMAP_EXP OdometryFovis : public Odometry
{
public:
OdometryFovis(const rtabmap::ParametersMap & parameters = rtabmap::ParametersMap());
virtual ~OdometryFovis();
virtual void reset(const Transform & initialPose = Transform::getIdentity());
virtual Odometry::Type getType() {return Odometry::kTypeFovis;}
private:
virtual Transform computeTransform(SensorData & image, const Transform & guess = Transform(), OdometryInfo * info = 0);
private:
fovis::VisualOdometry * fovis_;
fovis::Rectification * rect_;
fovis::StereoCalibration * stereoCalib_;
fovis::DepthImage * depthImage_;
fovis::StereoDepth * stereoDepth_;
ParametersMap fovisParameters_;
bool lost_;
Transform previousLocalTransform_;
};
}
#endif /* ODOMETRYFOVIS_H_ */

View File

@@ -42,8 +42,6 @@ public:
matches(0),
inliers(0),
icpInliersRatio(0.0f),
varianceLin(0.0f),
varianceAng(0.0f),
features(0),
localMapSize(0),
localScanMapSize(0),
@@ -67,8 +65,7 @@ public:
output.matches = matches;
output.inliers = inliers;
output.icpInliersRatio = icpInliersRatio;
output.varianceLin = varianceLin;
output.varianceAng = varianceAng;
output.covariance = covariance.clone();
output.features = features;
output.localMapSize = localMapSize;
output.localScanMapSize = localScanMapSize;
@@ -80,6 +77,7 @@ public:
output.timeEstimation = timeEstimation;
output.timeParticleFiltering = timeParticleFiltering;
output.stamp = stamp;
output.interval = interval;
output.transform = transform;
output.transformFiltered = transformFiltered;
output.transformGroundTruth = transformGroundTruth;
@@ -92,8 +90,7 @@ public:
int matches;
int inliers;
float icpInliersRatio;
float varianceLin;
float varianceAng;
cv::Mat covariance;
int features;
int localMapSize;
int localScanMapSize;

View File

@@ -0,0 +1,63 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ODOMETRYORBSLAM2_H_
#define ODOMETRYORBSLAM2_H_
#include <rtabmap/core/Odometry.h>
namespace ORB_SLAM2 {
class System;
}
class ORBSLAM2System;
namespace rtabmap {
class RTABMAP_EXP OdometryORBSLAM2 : public Odometry
{
public:
OdometryORBSLAM2(const rtabmap::ParametersMap & parameters = rtabmap::ParametersMap());
virtual ~OdometryORBSLAM2();
virtual void reset(const Transform & initialPose = Transform::getIdentity());
virtual Odometry::Type getType() {return Odometry::kTypeORBSLAM2;}
private:
virtual Transform computeTransform(SensorData & image, const Transform & guess = Transform(), OdometryInfo * info = 0);
private:
ORBSLAM2System * orbslam2_;
ORB_SLAM2::System * system_;
bool firstFrame_;
Transform originLocalTransform_;
};
}
#endif /* ODOMETRYORBSLAM2_H_ */

View File

@@ -45,7 +45,7 @@ public:
virtual ~OdometryThread();
protected:
virtual void handleEvent(UEvent * event);
virtual bool handleEvent(UEvent * event);
private:
virtual void mainLoopBegin();

View File

@@ -0,0 +1,63 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef ODOMETRYVISO2_H_
#define ODOMETRYVISO2_H_
#include <rtabmap/core/Odometry.h>
class VisualOdometryStereo;
namespace rtabmap {
class RTABMAP_EXP OdometryViso2 : public Odometry
{
public:
OdometryViso2(const rtabmap::ParametersMap & parameters = rtabmap::ParametersMap());
virtual ~OdometryViso2();
virtual void reset(const Transform & initialPose = Transform::getIdentity());
virtual Odometry::Type getType() {return Odometry::kTypeViso2;}
private:
virtual Transform computeTransform(SensorData & image, const Transform & guess = Transform(), OdometryInfo * info = 0);
private:
VisualOdometryStereo * viso2_;
int ref_frame_change_method_; // Reference frame method (defautl 0): 0=under inliers threshold, 1=min pixel motion,
int ref_frame_inlier_threshold_; // method 0. Change the reference frame if the number of inliers is low
double ref_frame_motion_threshold_; // method 1. Change the reference frame if last motion is small
bool lost_;
bool keep_reference_frame_;
Transform reference_motion_;
Transform previousLocalTransform_;
ParametersMap viso2Parameters_;
};
}
#endif /* ODOMETRYVISO2_H_ */

View File

@@ -40,20 +40,18 @@ public:
static bool available();
public:
OptimizerGTSAM(
int iterations = Parameters::defaultOptimizerIterations(),
bool slam2d = Parameters::defaultRegForce3DoF(),
bool covarianceIgnored = Parameters::defaultOptimizerVarianceIgnored(),
double epsilon = Parameters::defaultOptimizerEpsilon(),
bool robust = Parameters::defaultOptimizerRobust()) :
Optimizer(iterations, slam2d, covarianceIgnored, epsilon, robust) {}
OptimizerGTSAM(const ParametersMap & parameters) :
Optimizer(parameters) {}
OptimizerGTSAM(const ParametersMap & parameters = ParametersMap()) :
Optimizer(parameters),
optimizer_(Parameters::defaultGTSAMOptimizer())
{
parseParameters(parameters);
}
virtual ~OptimizerGTSAM() {}
virtual Type type() const {return kTypeGTSAM;}
virtual void parseParameters(const ParametersMap & parameters);
virtual std::map<int, Transform> optimize(
int rootId,
const std::map<int, Transform> & poses,
@@ -61,6 +59,9 @@ public:
std::list<std::map<int, Transform> > * intermediateGraphes = 0,
double * finalError = 0,
int * iterationsDone = 0);
private:
int optimizer_;
};
} /* namespace rtabmap */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,59 @@
/*
Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
* Neither the name of the Universite de Sherbrooke nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef CORELIB_INCLUDE_RTABMAP_CORE_PROGRESSSTATE_H_
#define CORELIB_INCLUDE_RTABMAP_CORE_PROGRESSSTATE_H_
#include <rtabmap/utilite/ULogger.h>
class ProgressState
{
public:
ProgressState():canceled_(false){}
virtual bool callback(const std::string & msg) const
{
if(!msg.empty())
UDEBUG("msg=%s", msg.c_str());
return true;
}
virtual ~ProgressState(){}
void setCanceled(bool canceled)
{
canceled_ = canceled;
}
bool isCanceled() const
{
return canceled_;
}
private:
bool canceled_;
};
#endif /* CORELIB_INCLUDE_RTABMAP_CORE_PROGRESSSTATE_H_ */

View File

@@ -25,8 +25,8 @@ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef REGISTRATION_H_
#define REGISTRATION_H_
#ifndef RTABMAP_REGISTRATION_H_
#define RTABMAP_REGISTRATION_H_
#include "rtabmap/core/RtabmapExp.h" // DLL export/import defines
@@ -63,6 +63,7 @@ public:
bool varianceFromInliersCount() const {return varianceFromInliersCount_;}
bool force3DoF() const {return force3DoF_;}
bool covarianceNormalized() const {return covarianceNormalized_;}
// take ownership!
void setChildRegistration(Registration * child);
@@ -75,7 +76,7 @@ public:
Transform computeTransformation(
const SensorData & from,
const SensorData & to,
Transform SensorData = Transform::getIdentity(),
Transform guess = Transform::getIdentity(),
RegistrationInfo * info = 0) const;
Transform computeTransformationMod(
@@ -84,6 +85,8 @@ public:
Transform guess = Transform::getIdentity(),
RegistrationInfo * info = 0) const;
void normalizeCovariance(cv::Mat & covariance, const Transform & transform) const;
protected:
// take ownership of child
Registration(const ParametersMap & parameters = ParametersMap(), Registration * child = 0);
@@ -104,6 +107,7 @@ protected:
private:
bool varianceFromInliersCount_;
bool covarianceNormalized_;
bool force3DoF_;
Registration * child_;
@@ -111,4 +115,4 @@ private:
}
#endif /* REGISTRATION_H_ */
#endif /* RTABMAP_REGISTRATION_H_ */

View File

@@ -35,8 +35,6 @@ class RegistrationInfo
{
public:
RegistrationInfo() :
varianceLin(0),
varianceAng(0),
inliers(0),
matches(0),
icpInliersRatio(0),
@@ -45,8 +43,7 @@ public:
{
}
float varianceLin;
float varianceAng;
cv::Mat covariance;
std::string rejectedMsg;
// RegistrationVis

View File

@@ -34,6 +34,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/SensorData.h"
#include "rtabmap/core/Statistics.h"
#include "rtabmap/core/Link.h"
#include "rtabmap/core/ProgressState.h"
#include <opencv2/core/core.hpp>
#include <list>
@@ -58,11 +59,32 @@ public:
Rtabmap();
virtual ~Rtabmap();
bool process(const cv::Mat & image, int id=0); // for convenience, an id is automatically generated if id=0
/**
* @brief Main loop of rtabmap.
* @param data Sensor data to process.
* @param odomPose Odometry pose, should be non-null for RGB-D SLAM mode.
* @param covariance Odometry covariance.
* @param externalStats External statistics to be saved in the database for convenience
* @return true if data has been added to map.
*/
bool process(
const SensorData & data,
Transform odomPose,
const cv::Mat & covariance = cv::Mat::eye(6,6,CV_64FC1)); // for convenience
const cv::Mat & odomCovariance = cv::Mat::eye(6,6,CV_64FC1),
const std::vector<float> & odomVelocity = std::vector<float>(),
const std::map<std::string, float> & externalStats = std::map<std::string, float>());
// for convenience
bool process(
const SensorData & data,
Transform odomPose,
float odomLinearVariance,
float odomAngularVariance,
const std::vector<float> & odomVelocity = std::vector<float>(),
const std::map<std::string, float> & externalStats = std::map<std::string, float>());
// for convenience, loop closure detection only
bool process(
const cv::Mat & image,
int id=0, const std::map<std::string, float> & externalStats = std::map<std::string, float>());
void init(const ParametersMap & parameters, const std::string & databasePath = "");
void init(const std::string & configFile = "", const std::string & databasePath = "");
@@ -141,7 +163,7 @@ public:
bool optimized,
bool global,
std::map<int, Signature> * signatures = 0);
int detectMoreLoopClosures(float clusterRadius = 0.5f, float clusterAngle = M_PI/6.0f, int iterations = 1);
int detectMoreLoopClosures(float clusterRadius = 0.5f, float clusterAngle = M_PI/6.0f, int iterations = 1, const ProgressState * state = 0);
int refineLinks();
int getPathStatus() const {return _pathStatus;} // -1=failed 0=idle/executing 1=success
@@ -193,6 +215,7 @@ private:
unsigned int _maxMemoryAllowed; // signatures count in WM
float _loopThr;
float _loopRatio;
bool _verifyLoopClosureHypothesis;
unsigned int _maxRetrieved;
unsigned int _maxLocalRetrieved;
bool _rawDataKept;

View File

@@ -40,7 +40,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "rtabmap/core/Parameters.h"
#include "rtabmap/core/OdometryEvent.h"
#include <stack>
#include <queue>
class UTimer;
@@ -82,6 +82,10 @@ public:
void setDataBufferSize(unsigned int bufferSize);
void createIntermediateNodes(bool enabled);
float getDetectorRate() const {return _rate;}
unsigned int getDataBufferSize() const {return _dataBufferMaxSize;}
bool getCreateIntermediateNodes() const {return _createIntermediateNodes;}
/**
* Close rtabmap. This will delete rtabmap object if set.
* @param databaseSaved true=database saved, false=database discarded.
@@ -92,7 +96,7 @@ public:
void close(bool databaseSaved, const std::string & databasePath = "");
protected:
virtual void handleEvent(UEvent * anEvent);
virtual bool handleEvent(UEvent * anEvent);
private:
virtual void mainLoopBegin();
@@ -106,8 +110,8 @@ private:
private:
UMutex _stateMutex;
std::stack<State> _state;
std::stack<ParametersMap> _stateParam;
std::queue<State> _state;
std::queue<ParametersMap> _stateParam;
std::list<OdometryEvent> _dataBuffer;
UMutex _dataMutex;
@@ -121,8 +125,7 @@ private:
Rtabmap * _rtabmap;
bool _paused;
Transform lastPose_;
double _rotVariance;
double _transVariance;
cv::Mat covariance_;
cv::Mat _userData;
UMutex _userDataMutex;

View File

@@ -221,6 +221,10 @@ public:
void setGroundTruth(const Transform & pose) {groundTruth_ = pose;}
const Transform & groundTruth() const {return groundTruth_;}
void setGlobalPose(const Transform & pose, const cv::Mat & covariance) {globalPose_ = pose; globalPoseCovariance_ = covariance;}
const Transform & globalPose() const {return globalPose_;}
const cv::Mat & globalPoseCovariance() const {return globalPoseCovariance_;}
long getMemoryUsed() const; // Return memory usage in Bytes
private:
@@ -258,6 +262,9 @@ private:
cv::Mat _descriptors;
Transform groundTruth_;
Transform globalPose_;
cv::Mat globalPoseCovariance_; // 6x6 double
};
}

View File

@@ -102,10 +102,11 @@ public:
void removeAllWords();
void removeWord(int wordId);
void changeWordsRef(int oldWordId, int activeWordId);
void setWords(const std::multimap<int, cv::KeyPoint> & words) {_enabled = false;_words = words;}
void setWords(const std::multimap<int, cv::KeyPoint> & words);
bool isEnabled() const {return _enabled;}
void setEnabled(bool enabled) {_enabled = enabled;}
const std::multimap<int, cv::KeyPoint> & getWords() const {return _words;}
int getInvalidWordsCount() const {return _invalidWordsCount;}
const std::map<int, int> & getWordsChanged() const {return _wordsChanged;}
const std::multimap<int, cv::Mat> & getWordsDescriptors() const {return _wordsDescriptors;}
void setWordsDescriptors(const std::multimap<int, cv::Mat> & descriptors) {_wordsDescriptors = descriptors;}
@@ -114,11 +115,21 @@ public:
void setWords3(const std::multimap<int, cv::Point3f> & words3) {_words3 = words3;}
void setPose(const Transform & pose) {_pose = pose;}
void setGroundTruthPose(const Transform & pose) {_groundTruthPose = pose;}
void setVelocity(float vx, float vy, float vz, float vroll, float vpitch, float vyaw) {
_velocity = std::vector<float>(6,0);
_velocity[0]=vx;
_velocity[1]=vy;
_velocity[2]=vz;
_velocity[3]=vroll;
_velocity[4]=vpitch;
_velocity[5]=vyaw;
}
const std::multimap<int, cv::Point3f> & getWords3() const {return _words3;}
const Transform & getPose() const {return _pose;}
cv::Mat getPoseCovariance() const;
const Transform & getGroundTruthPose() const {return _groundTruthPose;}
const std::vector<float> & getVelocity() const {return _velocity;}
SensorData & sensorData() {return _sensorData;}
const SensorData & sensorData() const {return _sensorData;}
@@ -142,9 +153,11 @@ private:
std::multimap<int, cv::Mat> _wordsDescriptors;
std::map<int, int> _wordsChanged; // <oldId, newId>
bool _enabled;
int _invalidWordsCount;
Transform _pose;
Transform _groundTruthPose;
std::vector<float> _velocity;
SensorData _sensorData;
};

View File

@@ -61,6 +61,7 @@ class RTABMAP_EXP Statistics
RTABMAP_STATS(Loop, Hypothesis_ratio,);
RTABMAP_STATS(Loop, Hypothesis_reactivated,);
RTABMAP_STATS(Loop, Visual_inliers,);
RTABMAP_STATS(Loop, Visual_matches,);
RTABMAP_STATS(Loop, Last_id,);
RTABMAP_STATS(Loop, Optimization_max_error, m);
RTABMAP_STATS(Loop, Optimization_error, );

View File

@@ -32,6 +32,7 @@ RTAB-Map integration: Mathieu Labbe
#include <assert.h>
#include <vector>
#include <set>
#include <Eigen/Core>
#include <opencv2/opencv.hpp>
#include <rtabmap/utilite/UMutex.h>
@@ -42,7 +43,7 @@ namespace clams
class RTABMAP_EXP DiscreteFrustum
{
public:
DiscreteFrustum(int smoothing = 1, double bin_depth = 1.0);
DiscreteFrustum(int smoothing = 1, double bin_depth = 1.0, double max_dist = 10.0);
//! z value, not distance to origin.
//! thread-safe.
void addExample(double ground_truth, double measurement);
@@ -66,6 +67,16 @@ namespace clams
class RTABMAP_EXP DiscreteDepthDistortionModel
{
public:
// returns all divisors of num
static std::set<size_t> getDivisors(const size_t &num);
// returns divisor from divisors closest to ref
static size_t getClosestToRef(const std::set<size_t> &divisors, const double &ref);
// sets bin_width and bin_height to appropriate values
static void getBinSize(const size_t &width, const size_t &height, size_t &bin_width, size_t &bin_height);
public:
DiscreteDepthDistortionModel() :
width_(0),
@@ -78,7 +89,7 @@ namespace clams
training_samples_(0)
{}
virtual ~DiscreteDepthDistortionModel();
DiscreteDepthDistortionModel(int width, int height, int bin_width = 8, int bin_height = 6, double bin_depth = 2.0, int smoothing = 1);
DiscreteDepthDistortionModel(int width, int height, int bin_width = 8, int bin_height = 6, double bin_depth = 2.0, int smoothing = 1, double max_depth = 10.0);
DiscreteDepthDistortionModel(const DiscreteDepthDistortionModel& other);
DiscreteDepthDistortionModel& operator=(const DiscreteDepthDistortionModel& other);
void undistort(cv::Mat & depth) const;

View File

@@ -82,7 +82,7 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
}
// filter ground/obstacles zone
if(minGroundHeight_ != 0.0f || maxObstacleHeight_ > 0.0f)
if(minGroundHeight_ != 0.0f || maxObstacleHeight_ != 0.0f)
{
indices = util3d::passThrough(cloud, indices, "z",
minGroundHeight_!=0.0f?minGroundHeight_:std::numeric_limits<int>::min(),
@@ -92,13 +92,13 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
if(indices->size())
{
if(normalsSegmentation_)
if(normalsSegmentation_ && !groundIsObstacle_)
{
UDEBUG("normalKSearch=%d", normalKSearch_);
UDEBUG("maxGroundAngle=%f", maxGroundAngle_);
UDEBUG("Cluster radius=%f", clusterRadius_);
UDEBUG("flatObstaclesDetected=%d", flatObstaclesDetected_?1:0);
UDEBUG("maxGroundHeight=%f", maxGroundHeight_?1:0);
UDEBUG("maxGroundHeight=%f", maxGroundHeight_);
util3d::segmentObstaclesFromGround<PointT>(
cloud,
indices,
@@ -121,8 +121,17 @@ typename pcl::PointCloud<PointT>::Ptr OccupancyGrid::segmentCloud(
{
UDEBUG("");
// passthrough filter
groundIndices = rtabmap::util3d::passThrough(cloud, indices, "z", minGroundHeight_<0.0f?minGroundHeight_:std::numeric_limits<int>::min(), maxGroundHeight_);
obstaclesIndices = rtabmap::util3d::extractIndices(cloud, groundIndices, true);
groundIndices = rtabmap::util3d::passThrough(cloud, indices, "z",
minGroundHeight_!=0.0f?minGroundHeight_:std::numeric_limits<int>::min(),
maxGroundHeight_!=0.0f?maxGroundHeight_:std::numeric_limits<int>::max());
pcl::IndicesPtr notObstacles = groundIndices;
if(indices->size())
{
notObstacles = util3d::extractIndices(cloud, indices, true);
notObstacles = util3d::concatenate(notObstacles, groundIndices);
}
obstaclesIndices = rtabmap::util3d::extractIndices(cloud, notObstacles, true);
}
UDEBUG("groundIndices=%d obstaclesIndices=%d", (int)groundIndices->size(), (int)obstaclesIndices->size());

View File

@@ -104,7 +104,7 @@ void segmentObstaclesFromGround(
Eigen::Vector4f min,max;
pcl::getMinMax3D(*cloud, *clusteredFlatSurfaces.at(biggestFlatSurfaceIndex), min, max);
if(maxGroundHeight <= 0 || min[2] < maxGroundHeight)
if(maxGroundHeight == 0.0f || min[2] < maxGroundHeight)
{
for(unsigned int i=0; i<clusteredFlatSurfaces.size(); ++i)
{
@@ -113,7 +113,7 @@ void segmentObstaclesFromGround(
Eigen::Vector4f centroid(0,0,0,1);
pcl::compute3DCentroid(*cloud, *clusteredFlatSurfaces.at(i), centroid);
if(centroid[2] >= min[2]-0.01 &&
(centroid[2] <= max[2]+0.01 || (maxGroundHeight>0 && centroid[2] <= maxGroundHeight+0.01))) // epsilon
(centroid[2] <= max[2]+0.01 || (maxGroundHeight!=0.0f && centroid[2] <= maxGroundHeight+0.01))) // epsilon
{
ground = util3d::concatenate(ground, clusteredFlatSurfaces.at(i));
}
@@ -154,7 +154,7 @@ void segmentObstaclesFromGround(
pcl::IndicesPtr otherStuffIndices = util3d::extractIndices(cloud, notObstacles, true);
// If ground height is set, remove obstacles under it
if(maxGroundHeight > 0.0f)
if(maxGroundHeight != 0.0f)
{
otherStuffIndices = rtabmap::util3d::passThrough(cloud, otherStuffIndices, "z", maxGroundHeight, std::numeric_limits<float>::max());
}
@@ -255,8 +255,9 @@ void occupancy2DFromGroundObstacles(
ground = cv::Mat(1, (int)groundCloudProjected->size(), CV_32FC2);
for(unsigned int i=0;i<groundCloudProjected->size(); ++i)
{
ground.at<cv::Vec2f>(i)[0] = groundCloudProjected->at(i).x;
ground.at<cv::Vec2f>(i)[1] = groundCloudProjected->at(i).y;
cv::Vec2f * ptr = ground.ptr<cv::Vec2f>();
ptr[i][0] = groundCloudProjected->at(i).x;
ptr[i][1] = groundCloudProjected->at(i).y;
}
}
@@ -272,8 +273,9 @@ void occupancy2DFromGroundObstacles(
obstacles = cv::Mat(1, (int)obstaclesCloudProjected->size(), CV_32FC2);
for(unsigned int i=0;i<obstaclesCloudProjected->size(); ++i)
{
obstacles.at<cv::Vec2f>(i)[0] = obstaclesCloudProjected->at(i).x;
obstacles.at<cv::Vec2f>(i)[1] = obstaclesCloudProjected->at(i).y;
cv::Vec2f * ptr = obstacles.ptr<cv::Vec2f>();
ptr[i][0] = obstaclesCloudProjected->at(i).x;
ptr[i][1] = obstaclesCloudProjected->at(i).y;
}
}
}

View File

@@ -8,6 +8,9 @@
#ifndef CORELIB_INCLUDE_RTABMAP_CORE_IMPL_UTIL3D_SURFACE_HPP_
#define CORELIB_INCLUDE_RTABMAP_CORE_IMPL_UTIL3D_SURFACE_HPP_
#include <pcl/search/kdtree.h>
#include <rtabmap/utilite/UConversion.h>
namespace rtabmap {
namespace util3d {
@@ -42,6 +45,278 @@ std::vector<pcl::Vertices> normalizePolygonsSide(
return output;
}
template<typename pointRGBT>
void denseMeshPostProcessing(
pcl::PolygonMeshPtr & mesh,
float meshDecimationFactor,
int maximumPolygons,
const typename pcl::PointCloud<pointRGBT>::Ptr & cloud,
float transferColorRadius,
bool coloredOutput,
bool cleanMesh,
int minClusterSize,
ProgressState * progressState)
{
// compute normals for the mesh if not already here
bool hasNormals = false;
bool hasColors = false;
for(unsigned int i=0; i<mesh->cloud.fields.size(); ++i)
{
if(mesh->cloud.fields[i].name.compare("normal_x") == 0)
{
hasNormals = true;
}
else if(mesh->cloud.fields[i].name.compare("rgb") == 0)
{
hasColors = true;
}
}
if(maximumPolygons > 0)
{
double factor = 1.0-double(maximumPolygons)/double(mesh->polygons.size());
if(factor > meshDecimationFactor)
{
meshDecimationFactor = factor;
}
}
if(meshDecimationFactor > 0.0)
{
unsigned int count = mesh->polygons.size();
if(progressState) progressState->callback(uFormat("Mesh decimation (factor=%f) from %d polygons...",meshDecimationFactor, (int)count));
mesh = util3d::meshDecimation(mesh, (float)meshDecimationFactor);
if(progressState) progressState->callback(uFormat("Mesh decimated (factor=%f) from %d to %d polygons", meshDecimationFactor, (int)count, (int)mesh->polygons.size()));
if(count < mesh->polygons.size())
{
if(progressState) progressState->callback(uFormat("Decimated mesh has more polygons than before!"));
}
hasNormals = false;
hasColors = false;
}
if(cloud.get()!=0 &&
!hasColors &&
transferColorRadius >= 0.0)
{
if(progressState) progressState->callback(uFormat("Transferring color from point cloud to mesh..."));
// transfer color from point cloud to mesh
typename pcl::search::KdTree<pointRGBT>::Ptr tree (new pcl::search::KdTree<pointRGBT>(true));
tree->setInputCloud(cloud);
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr coloredCloud(new pcl::PointCloud<pcl::PointXYZRGBNormal>);
pcl::fromPCLPointCloud2(mesh->cloud, *coloredCloud);
std::vector<bool> coloredPts(coloredCloud->size());
for(unsigned int i=0; i<coloredCloud->size(); ++i)
{
std::vector<int> kIndices;
std::vector<float> kDistances;
pointRGBT pt;
pt.x = coloredCloud->at(i).x;
pt.y = coloredCloud->at(i).y;
pt.z = coloredCloud->at(i).z;
if(transferColorRadius > 0.0)
{
tree->radiusSearch(pt, transferColorRadius, kIndices, kDistances);
}
else
{
tree->nearestKSearch(pt, 1, kIndices, kDistances);
}
if(kIndices.size())
{
//compute average color
int r=0;
int g=0;
int b=0;
int a=0;
for(unsigned int j=0; j<kIndices.size(); ++j)
{
r+=(int)cloud->at(kIndices[j]).r;
g+=(int)cloud->at(kIndices[j]).g;
b+=(int)cloud->at(kIndices[j]).b;
a+=(int)cloud->at(kIndices[j]).a;
}
coloredCloud->at(i).r = r/kIndices.size();
coloredCloud->at(i).g = g/kIndices.size();
coloredCloud->at(i).b = b/kIndices.size();
coloredCloud->at(i).a = a/kIndices.size();
coloredPts.at(i) = true;
}
else
{
//white
coloredCloud->at(i).r = coloredCloud->at(i).g = coloredCloud->at(i).b = 255;
coloredPts.at(i) = false;
}
}
pcl::toPCLPointCloud2(*coloredCloud, mesh->cloud);
// remove polygons with no color
if(cleanMesh)
{
std::vector<pcl::Vertices> filteredPolygons(mesh->polygons.size());
int oi=0;
for(unsigned int i=0; i<mesh->polygons.size(); ++i)
{
bool coloredPolygon = true;
for(unsigned int j=0; j<mesh->polygons[i].vertices.size(); ++j)
{
if(!coloredPts.at(mesh->polygons[i].vertices[j]))
{
coloredPolygon = false;
break;
}
}
if(coloredPolygon)
{
filteredPolygons[oi++] = mesh->polygons[i];
}
}
filteredPolygons.resize(oi);
mesh->polygons = filteredPolygons;
}
hasColors = true;
}
if(minClusterSize)
{
if(progressState) progressState->callback(uFormat("Filter small polygon clusters..."));
// filter polygons
std::vector<std::set<int> > neighbors;
std::vector<std::set<int> > vertexToPolygons;
util3d::createPolygonIndexes(mesh->polygons,
mesh->cloud.height*mesh->cloud.width,
neighbors,
vertexToPolygons);
std::list<std::list<int> > clusters = util3d::clusterPolygons(
neighbors,
minClusterSize<0?0:minClusterSize);
std::vector<pcl::Vertices> filteredPolygons(mesh->polygons.size());
if(minClusterSize < 0)
{
// only keep the biggest cluster
std::list<std::list<int> >::iterator biggestClusterIndex = clusters.end();
unsigned int biggestClusterSize = 0;
for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
{
if(iter->size() > biggestClusterSize)
{
biggestClusterIndex = iter;
biggestClusterSize = iter->size();
}
}
if(biggestClusterIndex != clusters.end())
{
int oi=0;
for(std::list<int>::iterator jter=biggestClusterIndex->begin(); jter!=biggestClusterIndex->end(); ++jter)
{
filteredPolygons[oi++] = mesh->polygons.at(*jter);
}
filteredPolygons.resize(oi);
}
}
else
{
int oi=0;
for(std::list<std::list<int> >::iterator iter=clusters.begin(); iter!=clusters.end(); ++iter)
{
for(std::list<int>::iterator jter=iter->begin(); jter!=iter->end(); ++jter)
{
filteredPolygons[oi++] = mesh->polygons.at(*jter);
}
}
filteredPolygons.resize(oi);
}
int before = (int)mesh->polygons.size();
mesh->polygons = filteredPolygons;
if(progressState) progressState->callback(uFormat("Filtered %d polygons.", before-(int)mesh->polygons.size()));
}
// compute normals for the mesh if not already here, add also white color if colored output is required
if(!hasNormals || (!hasColors && coloredOutput))
{
// use polygons
if(hasColors || coloredOutput)
{
pcl::PointCloud<pcl::PointXYZRGBNormal>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZRGBNormal>);
pcl::fromPCLPointCloud2(mesh->cloud, *cloud);
Eigen::Vector3f normal(1,0,0);
for(unsigned int i=0; i<mesh->polygons.size(); ++i)
{
pcl::Vertices & v = mesh->polygons[i];
if(!hasNormals)
{
UASSERT(v.vertices.size()>2);
Eigen::Vector3f v0(
cloud->at(v.vertices[1]).x - cloud->at(v.vertices[0]).x,
cloud->at(v.vertices[1]).y - cloud->at(v.vertices[0]).y,
cloud->at(v.vertices[1]).z - cloud->at(v.vertices[0]).z);
int last = v.vertices.size()-1;
Eigen::Vector3f v1(
cloud->at(v.vertices[last]).x - cloud->at(v.vertices[0]).x,
cloud->at(v.vertices[last]).y - cloud->at(v.vertices[0]).y,
cloud->at(v.vertices[last]).z - cloud->at(v.vertices[0]).z);
normal = v0.cross(v1);
normal.normalize();
}
// flat normal (per face)
for(unsigned int j=0; j<v.vertices.size(); ++j)
{
if(!hasNormals)
{
cloud->at(v.vertices[j]).normal_x = normal[0];
cloud->at(v.vertices[j]).normal_y = normal[1];
cloud->at(v.vertices[j]).normal_z = normal[2];
}
if(!hasColors)
{
cloud->at(v.vertices[j]).r = 255;
cloud->at(v.vertices[j]).g = 255;
cloud->at(v.vertices[j]).b = 255;
}
}
}
pcl::toPCLPointCloud2 (*cloud, mesh->cloud);
}
else
{
pcl::PointCloud<pcl::PointNormal>::Ptr cloud (new pcl::PointCloud<pcl::PointNormal>);
pcl::fromPCLPointCloud2(mesh->cloud, *cloud);
for(unsigned int i=0; i<mesh->polygons.size(); ++i)
{
pcl::Vertices & v = mesh->polygons[i];
UASSERT(v.vertices.size()>2);
Eigen::Vector3f v0(
cloud->at(v.vertices[1]).x - cloud->at(v.vertices[0]).x,
cloud->at(v.vertices[1]).y - cloud->at(v.vertices[0]).y,
cloud->at(v.vertices[1]).z - cloud->at(v.vertices[0]).z);
int last = v.vertices.size()-1;
Eigen::Vector3f v1(
cloud->at(v.vertices[last]).x - cloud->at(v.vertices[0]).x,
cloud->at(v.vertices[last]).y - cloud->at(v.vertices[0]).y,
cloud->at(v.vertices[last]).z - cloud->at(v.vertices[0]).z);
Eigen::Vector3f normal = v0.cross(v1);
normal.normalize();
// flat normal (per face)
for(unsigned int j=0; j<v.vertices.size(); ++j)
{
cloud->at(v.vertices[j]).normal_x = normal[0];
cloud->at(v.vertices[j]).normal_y = normal[1];
cloud->at(v.vertices[j]).normal_z = normal[2];
}
}
pcl::toPCLPointCloud2 (*cloud, mesh->cloud);
}
}
}
}
}

View File

@@ -33,6 +33,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <opencv2/core/core.hpp>
#include <rtabmap/core/Transform.h>
#include <rtabmap/core/Parameters.h>
#include <vector>
namespace rtabmap
{
@@ -142,6 +143,15 @@ cv::Mat RTABMAP_EXP fastBilateralFiltering(
float sigmaR = 0.05f,
bool earlyDivision = false);
cv::Mat RTABMAP_EXP brightnessAndContrastAuto(
const cv::Mat & src,
const cv::Mat & mask,
float clipLowHistPercent=0,
float clipHighHistPercent=0);
cv::Mat RTABMAP_EXP exposureFusion(
const std::vector<cv::Mat> & images);
} // namespace util3d
} // namespace rtabmap

Some files were not shown because too many files have changed in this diff Show More