13 #include <unordered_set>
20 namespace integration {
27 int volume_unit_resolution ,
28 int depth_sampling_stride )
29 :
TSDFVolume(voxel_length, sdf_trunc, color_type),
30 volume_unit_resolution_(volume_unit_resolution),
31 volume_unit_length_(voxel_length * volume_unit_resolution),
32 depth_sampling_stride_(depth_sampling_stride) {}
41 const Eigen::Matrix4d &extrinsic) {
42 if ((
image.depth_.num_of_channels_ != 1) ||
43 (
image.depth_.bytes_per_channel_ != 4) ||
45 image.color_.num_of_channels_ != 3) ||
47 image.color_.bytes_per_channel_ != 1) ||
49 image.color_.num_of_channels_ != 1) ||
51 image.color_.bytes_per_channel_ != 4)) {
53 "[ScalableTSDFVolume::Integrate] Unsupported image format.");
58 "[ScalableTSDFVolume::Integrate] depth image size is ({} x "
60 "but got ({} x {}) from intrinsic.",
68 "[ScalableTSDFVolume::Integrate] color image size is ({} x "
70 "but got ({} x {}) from intrinsic.",
75 auto depth2cameradistance =
79 image.depth_, intrinsic, extrinsic, 1000.0, 1000.0,
81 std::unordered_set<Eigen::Vector3i, utility::hash_eigen<Eigen::Vector3i>>
82 touched_volume_units_;
83 for (
const auto &
point : pointcloud->getEigenPoints()) {
84 auto min_bound = LocateVolumeUnit(
86 auto max_bound = LocateVolumeUnit(
88 for (
auto x = min_bound(0); x <= max_bound(0); x++) {
89 for (
auto y = min_bound(1); y <= max_bound(1); y++) {
90 for (
auto z = min_bound(2); z <= max_bound(2); z++) {
92 if (touched_volume_units_.find(loc) ==
93 touched_volume_units_.end()) {
94 touched_volume_units_.insert(loc);
96 volume->IntegrateWithDepthToCameraDistanceMultiplier(
97 image, intrinsic, extrinsic,
98 *depth2cameradistance);
107 auto pointcloud = std::make_shared<ccPointCloud>();
109 float w0, w1, f0, f1;
110 Eigen::Vector3f c0, c1;
112 if (unit.second.volume_) {
113 const auto &volume0 = *unit.second.volume_;
114 const auto &index0 = unit.second.index_;
115 for (
int x = 0; x < volume0.resolution_; x++) {
116 for (
int y = 0; y < volume0.resolution_; y++) {
117 for (
int z = 0; z < volume0.resolution_; z++) {
119 w0 = volume0.voxels_[volume0.IndexOf(idx0)].weight_;
120 f0 = volume0.voxels_[volume0.IndexOf(idx0)].tsdf_;
122 c0 = volume0.voxels_[volume0.IndexOf(idx0)]
123 .color_.cast<
float>();
124 if (w0 != 0.0f && f0 < 0.98f && f0 >= -0.98f) {
126 Eigen::Vector3d(half_voxel_length +
133 for (
int i = 0; i < 3; i++) {
134 Eigen::Vector3d p1 = p0;
139 if (idx1(i) < volume0.resolution_) {
140 w1 = volume0.voxels_[volume0.IndexOf(idx1)]
142 f1 = volume0.voxels_[volume0.IndexOf(idx1)]
146 c1 = volume0.voxels_[volume0.IndexOf(
148 .color_.cast<
float>();
150 idx1(i) -= volume0.resolution_;
157 const auto &volume1 =
158 *unit_itr->second.volume_;
159 w1 = volume1.voxels_[volume1.IndexOf(
162 f1 = volume1.voxels_[volume1.IndexOf(
168 [volume1.IndexOf(idx1)]
173 if (w1 != 0.0f && f1 < 0.98f && f1 >= -0.98f &&
177 Eigen::Vector3d p = p0;
178 p(i) = (p0(i) * r1 + p1(i) * r0) /
181 pointcloud->addEigenPoint(p);
182 if (!pointcloud->hasColors())
183 if (!pointcloud->reserveTheRGBTable())
188 pointcloud->addEigenColor(
189 ((c0 * r1 + c1 * r0) /
194 pointcloud->addEigenColor(
195 ((c0 * r1 + c1 * r0) /
201 if (!pointcloud->hasNormals() &&
202 !pointcloud->reserveTheNormsTable()) {
206 pointcloud->addEigenNorm(GetNormalAt(p));
222 assert(baseVertices);
226 auto mesh = std::make_shared<ccMesh>(baseVertices);
227 mesh->addChild(baseVertices);
232 std::equal_to<Eigen::Vector4i>,
233 Eigen::aligned_allocator<std::pair<const Eigen::Vector4i, int>>>
234 edgeindex_to_vertexindex;
236 int edge_to_index[12];
238 if (unit.second.volume_) {
239 const auto &volume0 = *unit.second.volume_;
240 const auto &index0 = unit.second.index_;
241 for (
int x = 0; x < volume0.resolution_; x++) {
242 for (
int y = 0; y < volume0.resolution_; y++) {
243 for (
int z = 0; z < volume0.resolution_; z++) {
248 Eigen::Vector3d c[8];
249 for (
int i = 0; i < 8; i++) {
255 w[i] = volume0.voxels_[volume0.IndexOf(idx1)]
257 f[i] = volume0.voxels_[volume0.IndexOf(idx1)]
260 c[i] = volume0.voxels_[volume0.IndexOf(
262 .color_.cast<
double>() /
266 c[i] = volume0.voxels_[volume0.IndexOf(
268 .color_.cast<
double>();
270 for (
int j = 0; j < 3; j++) {
281 const auto &volume1 =
282 *unit_itr1->second.volume_;
283 w[i] = volume1.voxels_[volume1.IndexOf(
286 f[i] = volume1.voxels_[volume1.IndexOf(
291 c[i] = volume1.voxels_[volume1.IndexOf(
293 .color_.cast<
double>() /
297 c[i] = volume1.voxels_[volume1.IndexOf(
299 .color_.cast<
double>();
307 cube_index |= (1 << i);
311 if (cube_index == 0 || cube_index == 255) {
314 for (
int i = 0; i < 12; i++) {
315 if (edge_table[cube_index] & (1 << i)) {
322 if (edgeindex_to_vertexindex.find(edge_index) ==
323 edgeindex_to_vertexindex.end()) {
325 (int)baseVertices->
size();
326 edgeindex_to_vertexindex[edge_index] =
327 (int)baseVertices->
size();
339 (
double)f[edge_to_vert[i][0]]);
341 (
double)f[edge_to_vert[i][1]]);
347 const auto &c0 = c[edge_to_vert[i][0]];
348 const auto &c1 = c[edge_to_vert[i][1]];
352 ->reserveTheRGBTable())
355 (f1 * c0 + f0 * c1) /
359 edge_to_index[i] = edgeindex_to_vertexindex
364 for (
int i = 0; tri_table[cube_index][i] != -1;
367 edge_to_index[tri_table[cube_index][i]],
368 edge_to_index[tri_table[cube_index][i + 2]],
369 edge_to_index[tri_table[cube_index]
391 auto voxel = std::make_shared<ccPointCloud>();
393 if (unit.second.volume_) {
394 auto v = unit.second.volume_->ExtractVoxelPointCloud();
401 std::shared_ptr<UniformTSDFVolume> ScalableTSDFVolume::OpenVolumeUnit(
413 Eigen::Vector3d ScalableTSDFVolume::GetNormalAt(
const Eigen::Vector3d &p) {
416 for (
int i = 0; i < 3; i++) {
417 Eigen::Vector3d p0 = p;
419 Eigen::Vector3d p1 = p;
421 n(i) = GetTSDFAt(p1) - GetTSDFAt(p0);
423 return n.normalized();
426 double ScalableTSDFVolume::GetTSDFAt(
const Eigen::Vector3d &p) {
427 Eigen::Vector3d p_locate =
434 const auto &volume0 = *unit_itr->second.volume_;
436 Eigen::Vector3d p_grid =
439 for (
int i = 0; i < 3; i++) {
441 if (idx0(i) < 0) idx0(i) = 0;
445 Eigen::Vector3d r = p_grid - idx0.cast<
double>();
447 for (
int i = 0; i < 8; i++) {
453 f[i] = volume0.voxels_[volume0.IndexOf(idx1)].tsdf_;
455 for (
int j = 0; j < 3; j++) {
465 const auto &volume1 = *unit_itr1->second.volume_;
466 f[i] = volume1.voxels_[volume1.IndexOf(idx1)].tsdf_;
470 return (1 - r(0)) * ((1 - r(1)) * ((1 - r(2)) * f[0] + r(2) * f[4]) +
471 r(1) * ((1 - r(2)) * f[3] + r(2) * f[7])) +
472 r(0) * ((1 - r(1)) * ((1 - r(2)) * f[1] + r(2) * f[5]) +
473 r(1) * ((1 - r(2)) * f[2] + r(2) * f[6]));
std::shared_ptr< core::Tensor > image
Array of compressed 3D normals (single index)
virtual void setLocked(bool state)
Sets the "enabled" property.
virtual void setEnabled(bool state)
Sets the "enabled" property.
A 3D cloud and its associated features (color, normals, scalar fields, etc.)
static std::shared_ptr< ccPointCloud > CreateFromDepthImage(const cloudViewer::geometry::Image &depth, const cloudViewer::camera::PinholeCameraIntrinsic &intrinsic, const Eigen::Matrix4d &extrinsic=Eigen::Matrix4d::Identity(), double depth_scale=1000.0, double depth_trunc=1000.0, int stride=1, bool project_valid_depth_only=true)
Factory function to create a pointcloud from a depth image and a camera model.
void addEigenColor(const Eigen::Vector3d &color)
bool hasColors() const override
Returns whether colors are enabled or not.
void shrinkToFit()
Removes unused capacity.
void addEigenPoint(const Eigen::Vector3d &point)
unsigned size() const override
Contains the pinhole camera intrinsic parameters.
int height_
Height of the image.
int width_
Width of the image.
static std::shared_ptr< Image > CreateDepthToCameraDistanceMultiplierFloatImage(const camera::PinholeCameraIntrinsic &intrinsic)
RGBDImage is for a pair of registered color and depth images,.
int volume_unit_resolution_
double volume_unit_length_
void Integrate(const geometry::RGBDImage &image, const camera::PinholeCameraIntrinsic &intrinsic, const Eigen::Matrix4d &extrinsic) override
Function to integrate an RGB-D image into the volume.
std::shared_ptr< ccPointCloud > ExtractVoxelPointCloud()
Debug function to extract the voxel data into a point cloud.
std::shared_ptr< ccMesh > ExtractTriangleMesh() override
Function to extract a triangle mesh, using the marching cubes algorithm. (https://en....
int depth_sampling_stride_
ScalableTSDFVolume(double voxel_length, double sdf_trunc, TSDFVolumeColorType color_type, int volume_unit_resolution=16, int depth_sampling_stride=4)
void Reset() override
Function to reset the TSDFVolume.
~ScalableTSDFVolume() override
std::shared_ptr< ccPointCloud > ExtractPointCloud() override
Function to extract a point cloud with normals.
std::unordered_map< Eigen::Vector3i, VolumeUnit, utility::hash_eigen< Eigen::Vector3i > > volume_units_
Base class of the Truncated Signed Distance Function (TSDF) volume.
double sdf_trunc_
Truncation value for signed distance function (SDF).
double voxel_length_
Length of the voxel in meters.
TSDFVolumeColorType color_type_
Color type of the TSDF volume.
__host__ __device__ float2 fabs(float2 v)
__host__ __device__ int2 abs(int2 v)
@ Gray32
32 bit GrayScale.
MiniVec< float, N > floor(const MiniVec< float, N > &a)
Generic file read and write utility for python interface.
Eigen::Matrix< Index, 3, 1 > Vector3i
Eigen::Matrix< Index, 4, 1 > Vector4i