Skip to content

[GSoC] Add Submaps and PoseGraph optimization for Large Scale Depth Fusion #2619

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 45 commits into from
Oct 13, 2020
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
4dbdee4
Merge pull request #1 from opencv/master
akashsharma02 Mar 22, 2020
dcbe5a8
Merge remote-tracking branch 'upstream/master'
akashsharma02 May 9, 2020
a7c3ab0
Merge remote-tracking branch 'upstream/master'
akashsharma02 May 22, 2020
3fa8a3c
- Add HashTSDF class
akashsharma02 May 24, 2020
98ce3d0
Integration seems to be working, raycasting does not
akashsharma02 Jun 3, 2020
01a172c
Update integration code
akashsharma02 Jun 4, 2020
5a3f537
Integration and Raycasting fixes, (both work now)
akashsharma02 Jun 7, 2020
9b5b0ce
- Format code
akashsharma02 Jun 9, 2020
bdbafd0
Add Kinect Fusion backup file
akashsharma02 Jun 10, 2020
70b1dfb
- Add interpolation for vertices and normals (slow and unreliable!)
akashsharma02 Jun 10, 2020
fcfd6dd
Bug fix for integration and noisy odometry
akashsharma02 Jun 12, 2020
ddf5c18
- Create volume abstract class
akashsharma02 Jun 15, 2020
a00d7eb
- Add getPoints and getNormals function
akashsharma02 Jun 18, 2020
75656bd
- Add tests for hashTSDF
akashsharma02 Jun 23, 2020
776c8f8
Merge branch 'master' of https://github.com/opencv/opencv_contrib
akashsharma02 Jul 29, 2020
d5ccfde
- Use CRTP based static polymorphism to choose between CPU and GPU for
akashsharma02 Jul 4, 2020
8eaa125
Create submap and submapMgr
akashsharma02 Jul 6, 2020
362ec1a
Early draft of posegraph and submaps (Doesn't even compile)
akashsharma02 Jul 15, 2020
7264be2
Minor cleanup (no compilation)
akashsharma02 Jul 15, 2020
a96cf66
Track all submaps (no posegraph update yet)
akashsharma02 Jul 19, 2020
02fd312
Return inliers from ICP for weighting the constraints
akashsharma02 Jul 28, 2020
034970a
Add updating constraints between submaps and retain same current map
akashsharma02 Aug 1, 2020
8553212
Fix constraints creation between submaps and allow for switching between
akashsharma02 Aug 4, 2020
05db54b
- Fix bug in allocate volumeUnits
akashsharma02 Aug 4, 2020
5085884
Remove inlier calculation in fast_icp (not required)
akashsharma02 Aug 4, 2020
de7ba96
Modify readFile to allow reading other datasets easily
akashsharma02 Aug 4, 2020
963b086
- Implement posegraph update, Gauss newton is unstable
akashsharma02 Aug 8, 2020
713cdef
Implement simplified levenberg marquardt
akashsharma02 Aug 17, 2020
64dca2f
Merge branch 'master' of https://github.com/opencv/opencv_contrib int…
akashsharma02 Aug 18, 2020
bac316b
Bug fixes for Levenberg Marquardt and minor changes
akashsharma02 Aug 19, 2020
bbe56b7
minor changes
akashsharma02 Aug 19, 2020
6c0cd5c
Fixes, but Optimizer is still not well behaved
akashsharma02 Aug 22, 2020
53b149d
Working Ceres optimizer
akashsharma02 Aug 24, 2020
5ede5b1
- Reorganize IO code for samples in a separate file
akashsharma02 Aug 27, 2020
386b2ac
- Reorganize IO code for samples in a separate file
akashsharma02 Aug 27, 2020
4099a0e
Merge branch 'submap' of https://github.com/akashsharma02/opencv_cont…
akashsharma02 Aug 27, 2020
60523b6
- Add Python bindings for volume struct
akashsharma02 Aug 28, 2020
aea037a
- Remove dynafu::Params() since it is identical to kinfu::Params()
akashsharma02 Aug 31, 2020
fe01b57
Merge branch 'master' of https://github.com/akashsharma02/opencv_cont…
akashsharma02 Sep 22, 2020
9599c3a
Minor API changes
akashsharma02 Sep 22, 2020
b5051a4
Merge branch 'master' of https://github.com/opencv/opencv_contrib int…
akashsharma02 Sep 22, 2020
dfce899
Minor
akashsharma02 Sep 22, 2020
8f82ccc
Merge branch 'master' of https://github.com/opencv/opencv_contrib int…
akashsharma02 Oct 10, 2020
48ee51e
Remove CRTP for HashTSDF class
akashsharma02 Oct 10, 2020
daa800f
Bug fixes for HashTSDF integration
akashsharma02 Oct 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions modules/rgbd/include/opencv2/rgbd.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include "opencv2/rgbd/depth.hpp"
#include "opencv2/rgbd/kinfu.hpp"
#include "opencv2/rgbd/dynafu.hpp"
#include "opencv2/rgbd/large_kinfu.hpp"


/** @defgroup rgbd RGB-Depth Processing
Expand Down
2 changes: 1 addition & 1 deletion modules/rgbd/include/opencv2/rgbd/kinfu.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ struct CV_EXPORTS_W Params
/** @brief frame size in pixels */
CV_PROP_RW Size frameSize;

CV_PROP_RW cv::kinfu::VolumeType volumeType;
CV_PROP_RW kinfu::VolumeType volumeType;

/** @brief camera intrinsics */
CV_PROP_RW Matx33f intr;
Expand Down
137 changes: 137 additions & 0 deletions modules/rgbd/include/opencv2/rgbd/large_kinfu.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
// This file is part of OpenCV project.
// It is subject to the license terms in the LICENSE file found in the top-level directory
// of this distribution and at http://opencv.org/license.html

// This code is also subject to the license terms in the LICENSE_KinectFusion.md file found in this
// module's directory

#ifndef __OPENCV_RGBD_LARGEKINFU_HPP__
#define __OPENCV_RGBD_LARGEKINFU_HPP__

#include <opencv2/rgbd/volume.hpp>

#include "opencv2/core.hpp"
#include "opencv2/core/affine.hpp"

namespace cv
{
namespace large_kinfu
{
struct CV_EXPORTS_W Params
{
/** @brief Default parameters
A set of parameters which provides better model quality, can be very slow.
*/
CV_WRAP static Ptr<Params> defaultParams();

/** @brief Coarse parameters
A set of parameters which provides better speed, can fail to match frames
in case of rapid sensor motion.
*/
CV_WRAP static Ptr<Params> coarseParams();

/** @brief HashTSDF parameters
A set of parameters suitable for use with HashTSDFVolume
*/
CV_WRAP static Ptr<Params> hashTSDFParams(bool isCoarse);

/** @brief frame size in pixels */
CV_PROP_RW Size frameSize;

/** @brief camera intrinsics */
CV_PROP_RW Matx33f intr;

/** @brief pre-scale per 1 meter for input values
Typical values are:
* 5000 per 1 meter for the 16-bit PNG files of TUM database
* 1000 per 1 meter for Kinect 2 device
* 1 per 1 meter for the 32-bit float images in the ROS bag files
*/
CV_PROP_RW float depthFactor;

/** @brief Depth sigma in meters for bilateral smooth */
CV_PROP_RW float bilateral_sigma_depth;
/** @brief Spatial sigma in pixels for bilateral smooth */
CV_PROP_RW float bilateral_sigma_spatial;
/** @brief Kernel size in pixels for bilateral smooth */
CV_PROP_RW int bilateral_kernel_size;

/** @brief Number of pyramid levels for ICP */
CV_PROP_RW int pyramidLevels;

/** @brief Minimal camera movement in meters
Integrate new depth frame only if camera movement exceeds this value.
*/
CV_PROP_RW float tsdf_min_camera_movement;

/** @brief light pose for rendering in meters */
CV_PROP_RW Vec3f lightPose;

/** @brief distance theshold for ICP in meters */
CV_PROP_RW float icpDistThresh;
/** @brief angle threshold for ICP in radians */
CV_PROP_RW float icpAngleThresh;
/** @brief number of ICP iterations for each pyramid level */
CV_PROP_RW std::vector<int> icpIterations;

/** @brief Threshold for depth truncation in meters
All depth values beyond this threshold will be set to zero
*/
CV_PROP_RW float truncateThreshold;

/** @brief Volume parameters
*/
kinfu::VolumeParams volumeParams;
};

/** @brief KinectFusion implementation

This class implements a 3d reconstruction algorithm described in
@cite kinectfusion paper.

It takes a sequence of depth images taken from depth sensor
(or any depth images source such as stereo camera matching algorithm or even raymarching
renderer). The output can be obtained as a vector of points and their normals or can be
Phong-rendered from given camera pose.

An internal representation of a model is a voxel cuboid that keeps TSDF values
which are a sort of distances to the surface (for details read the @cite kinectfusion article
about TSDF). There is no interface to that representation yet.

LargeKinfu uses OpenCL acceleration automatically if available.
To enable or disable it explicitly use cv::setUseOptimized() or cv::ocl::setUseOpenCL().

This implementation is based on [kinfu-remake](https://github.com/Nerei/kinfu_remake).

Note that the KinectFusion algorithm was patented and its use may be restricted by
the list of patents mentioned in README.md file in this module directory.

That's why you need to set the OPENCV_ENABLE_NONFREE option in CMake to use KinectFusion.
*/
class CV_EXPORTS_W LargeKinfu
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docs should be rewritten later

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have modified the docs a bit. Do let me know if there are any concerns or issues.

{
public:
CV_WRAP static Ptr<LargeKinfu> create(const Ptr<Params>& _params);
virtual ~LargeKinfu() = default;

virtual const Params& getParams() const = 0;

CV_WRAP virtual void render(OutputArray image,
const Matx44f& cameraPose = Matx44f::eye()) const = 0;

CV_WRAP virtual void getCloud(OutputArray points, OutputArray normals) const = 0;

CV_WRAP virtual void getPoints(OutputArray points) const = 0;

CV_WRAP virtual void getNormals(InputArray points, OutputArray normals) const = 0;

CV_WRAP virtual void reset() = 0;

virtual const Affine3f getPose() const = 0;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use Matx44f instead, Affine3f has problems with Python bindings

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.


CV_WRAP virtual bool update(InputArray depth) = 0;
};

} // namespace large_kinfu
} // namespace cv
#endif
74 changes: 63 additions & 11 deletions modules/rgbd/include/opencv2/rgbd/volume.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,20 +19,16 @@ class Volume
{
public:
Volume(float _voxelSize, cv::Affine3f _pose, float _raycastStepFactor)
: voxelSize(_voxelSize),
voxelSizeInv(1.0f / voxelSize),
pose(_pose),
raycastStepFactor(_raycastStepFactor)
: voxelSize(_voxelSize), voxelSizeInv(1.0f / voxelSize), pose(_pose), raycastStepFactor(_raycastStepFactor)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The code in this file is under active refactoring in another PR, a rebase will be required later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

{
}

virtual ~Volume(){};

virtual void integrate(InputArray _depth, float depthFactor, const cv::Affine3f& cameraPose,
const cv::kinfu::Intr& intrinsics) = 0;
virtual void raycast(const cv::Affine3f& cameraPose, const cv::kinfu::Intr& intrinsics,
cv::Size frameSize, cv::OutputArray points,
cv::OutputArray normals) const = 0;
const cv::kinfu::Intr& intrinsics, const int frameId = 0) = 0;
virtual void raycast(const cv::Affine3f& cameraPose, const cv::kinfu::Intr& intrinsics, cv::Size frameSize,
cv::OutputArray points, cv::OutputArray normals) const = 0;
virtual void fetchNormals(cv::InputArray points, cv::OutputArray _normals) const = 0;
virtual void fetchPointsNormals(cv::OutputArray points, cv::OutputArray normals) const = 0;
virtual void reset() = 0;
Expand All @@ -50,9 +46,65 @@ enum class VolumeType
HASHTSDF = 1
};

cv::Ptr<Volume> makeVolume(VolumeType _volumeType, float _voxelSize, cv::Affine3f _pose,
float _raycastStepFactor, float _truncDist, int _maxWeight,
float _truncateThreshold, Point3i _resolution);
struct VolumeParams
{
/** @brief Type of Volume
Values can be TSDF (single volume) or HASHTSDF (hashtable of volume units)
*/
VolumeType type;

/** @brief Resolution of voxel space
Number of voxels in each dimension.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"Applicable only for single volume TSDF"

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

*/
Vec3i resolution;

/** @brief Resolution of volumeUnit in voxel space
Number of voxels in each dimension for volumeUnit
Applicable only for hashTSDF.
*/
int unitResolution = 0;

/** @brief Initial pose of the volume in meters */
cv::Affine3f pose;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use Matx44f instead, Affine3f has problems with Python bindings

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As far as I know Affine3f coerces the matrix into SE3, i.e., the R matrix has determinant always +1, so changing to Matx44f is not advisable I think.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In fact nothing stops a user from spoiling Affine3f since:

  • it can be constructed from arbitrary 4x4 matrix (or 3x3 R + 1x3 t matrices)
  • it keeps the same Matx44f inside as a public member
    So in both cases a user should be careful about the value.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Changed most interfaces into Matx44f. Personally though I think we should consider adding a proper SE3 pose class

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are plans to add quaternions and possibly dual quaternions into OpenCV 5.0. If they are done properly, there will be consistent data structures to keep both SO(3) and SE(3) transforms.


/** @brief Length of voxels in meters */
float voxelSize;

/** @brief TSDF truncation distance
Distances greater than value from surface will be truncated to 1.0
*/
float tsdfTruncDist;

/** @brief Max number of frames to integrate per voxel
Each voxel stops integration after the maxWeight is crossed
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A voxel does not stop integration, it works like a running average across last maxWeight frames. Need to rephrase this somehow.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

*/
int maxWeight;

/** @brief Threshold for depth truncation in meters
Truncates the depth greater than threshold to 0
*/
float depthTruncThreshold;

/** @brief Length of single raycast step
Describes the percentage of voxel length that is skipped per march
*/
float raycastStepFactor;

/** @brief Default set of parameters that provide higher quality reconstruction
at the cost of slow performance.
*/
static Ptr<VolumeParams> defaultParams(VolumeType _volumeType);

/** @brief Coarse set of parameters that provides relatively higher performance
at the cost of reconstrution quality.
*/
static Ptr<VolumeParams> coarseParams(VolumeType _volumeType);
};

cv::Ptr<Volume> makeVolume(const VolumeParams& _volumeParams);

cv::Ptr<Volume> makeVolume(VolumeType _volumeType, float _voxelSize, cv::Affine3f _pose, float _raycastStepFactor,
float _truncDist, int _maxWeight, float _truncateThreshold, Point3i _resolution);
} // namespace kinfu
} // namespace cv
#endif
Loading