Commit 08a4a4e9 authored by Yiting Shao's avatar Yiting Shao Committed by David Flynn
Browse files

slice/m44910: add octree slice partitioning scheme

This partitioning method (--partitionMethod=3) decomposes the input
pointcloud into an octree of depth --partitionOctreeDepth=d, with
each leaf node corresponding to a slice.
parent 81bde409
......@@ -128,12 +128,19 @@ Selects the partitioning method to map points to tiles and slices:
|:-----:| ----------------------------------------|
| 0 | none (single slice) |
| 2 | uniform partitioning along longest edge |
| 3 | uniform octree partitions |
### `--partitionNumUniformGeom=INT-VALUE`
Sets the number of slices to generate using `partitionMethod=2`.
If equal to zero, the number of slices is the integer ratio of the
longest to shortest edges of the point cloud bounding box.
### `--partitionOctreeDepth=INT-VALUE`
Sets the depth of the octree for slice generation using
`partitionMethod=3`.
The input point cloud is decomposed using an octree with the configured
depth. Each occupied leaf of the octree represents a single slice.
Geometry coding
---------------
......
......@@ -56,6 +56,9 @@ enum class PartitionMethod
// Partition according to uniform geometry
kUniformGeom = 2,
// Partition according to the depth of octree
kOctreeUniform = 3,
};
//============================================================================
......@@ -79,6 +82,9 @@ struct EncoderParams {
// Number of slices used by PartitionMethod::kUniformGeom
int partitionNumUniformGeom;
// Depth of octree used by PartitionMethod::kOctreeUniform
int partitionOctreeDepth;
};
//============================================================================
......
......@@ -169,6 +169,7 @@ operator<<(std::ostream& out, const PartitionMethod& val)
switch (val) {
case PartitionMethod::kNone: out << "0 (None)"; break;
case PartitionMethod::kUniformGeom: out << "0 (UniformGeom)"; break;
case PartitionMethod::kOctreeUniform: out << "0 (UniformOctree)"; break;
default: out << int(val) << " (Unknown)"; break;
}
return out;
......@@ -323,7 +324,8 @@ ParseParameters(int argc, char* argv[], Parameters& params)
"Method used to partition input point cloud into slices/tiles:\n"
" 0: none\n"
" 1: none (deprecated)\n"
" 2: n Uniform-Geometry partition bins along the longest edge")
" 2: n Uniform-Geometry partition bins along the longest edge\n"
" 3: Uniform Geometry partition at n octree depth")
("partitionNumUniformGeom",
params.encoder.partitionNumUniformGeom, 0,
......@@ -331,6 +333,10 @@ ParseParameters(int argc, char* argv[], Parameters& params)
" 0: slice partition with adaptive-defined bins\n"
" >=1: slice partition with user-defined bins\n")
("partitionOctreeDepth",
params.encoder.partitionOctreeDepth, 2,
"Depth of octree partition for partitionMethod=3")
("disableAttributeCoding",
params.disableAttributeCoding, false,
"Ignore attribute coding configuration")
......
......@@ -127,6 +127,11 @@ PCCTMC3Encoder3::compress(
partitions = partitionByUniformGeom(
quantizedInputCloud, params->partitionNumUniformGeom);
break;
case PartitionMethod::kOctreeUniform:
partitions = partitionByOctreeDepth(
quantizedInputCloud, params->partitionOctreeDepth);
break;
}
} while (0);
......
......@@ -136,6 +136,73 @@ partitionByUniformGeom(const PCCPointSet3& cloud, int numPartitions)
return partitions;
}
//----------------------------------------------------------------------------
// Split point cloud into several parts according to octree depth.
// No tile metadata is generated.
PartitionSet
partitionByOctreeDepth(const PCCPointSet3& cloud, int depOctree)
{
PartitionSet partitions;
// noting that there is a correspondence between point position
// and octree node, calculate the position mask and shift required
// to determine the node address for a point.
PCCBox3<double> bbox = cloud.computeBoundingBox();
int maxBb = (int)std::max({bbox.max[0], bbox.max[1], bbox.max[2]});
int cloudSizeLog2 = ceillog2(maxBb + 1);
int posShift = cloudSizeLog2 - depOctree;
int posMask = (1 << depOctree) - 1;
// initially: number of points in each partition
// then: mapping of partId to sliceId
std::vector<int> partMap(1 << (3 * depOctree));
// per-point indexes used for assigning to a partition
std::vector<int> pointToPartId(cloud.getPointCount());
// for each point, determine a partition based upon the position
for (int i = 0, last = cloud.getPointCount(); i < last; i++) {
int x = ((int(cloud[i].x()) >> posShift) & posMask) << (2 * depOctree);
int y = ((int(cloud[i].y()) >> posShift) & posMask) << depOctree;
int z = (int(cloud[i].z()) >> posShift) & posMask;
int partId = x | y | z;
partMap[partId]++;
pointToPartId[i] = partId;
}
// generate slice mapping
// - allocate slice map storage and determine contiguous sliceIds
// NB: the sliceIds replace partPointCount.
// - map points to each slice.
int numSlices =
partMap.size() - std::count(partMap.begin(), partMap.end(), 0);
partitions.slices.resize(numSlices);
int sliceId = 0;
for (auto& part : partMap) {
if (!part)
continue;
auto& slice = partitions.slices[sliceId];
slice.sliceId = sliceId;
slice.tileId = -1;
slice.origin = PCCVector3<int>{0};
slice.pointIndexes.reserve(part);
part = sliceId++;
}
for (int i = 0, last = cloud.getPointCount(); i < last; i++) {
int partId = pointToPartId[i];
int sliceId = partMap[partId];
partitions.slices[sliceId].pointIndexes.push_back(i);
}
return partitions;
}
//============================================================================
} // namespace pcc
......@@ -75,6 +75,8 @@ struct PartitionSet {
PartitionSet
partitionByUniformGeom(const PCCPointSet3& cloud, int numPartitions);
PartitionSet partitionByOctreeDepth(const PCCPointSet3& cloud, int depOctree);
//============================================================================
} // namespace pcc
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment