Commit 220acf28 authored by Xiang Zhang's avatar Xiang Zhang Committed by David Flynn
Browse files

geom/m50927: slice-based geometry quantization

This extends the geometry based quantisation scheme to:
 - add a per-slice QP offset, and
 - permit uniform quantisation of the whole slice without
   requiring signalling of an additional node QP offset.

Per node QP offset signalling is disabled by setting
positionQuantisationOctreeDepth=-1
parent 4d0d1e66
......@@ -222,13 +222,18 @@ position scaling due to `positionQuantizationScale`.
### `--positionBaseQp=INT-VALUE`
The quantisation parameter used to quantise geometry positions. The
effective QP may be varied according to `positionQuantisationOctreeDepth`.
effective QP may be varied according to `positionSliceQpOffset` and
`positionQuantisationOctreeDepth`.
A QP equal to 4 results in a scale factor of 1.
### `--positionSliceQpOffset=INT-VALUE`
A per-slice offset to be applied to `positionBaseQp`.
### `--positionQuantisationOctreeDepth=INT-VALUE`
The depth in the octree at which per-node QP offsets are signalled.
A non-normative encoder process determines the QP offset based upon
the local density of the octree.
the local density of the octree. A value of -1 disables signalling
of per-node QP offsets.
### `--bitwiseOccupancyCoding=0|1`
In octree geometry coding, there are both byte-wise and bit-wise tools to
......
......@@ -551,9 +551,13 @@ ParseParameters(int argc, char* argv[], Parameters& params)
params.encoder.gps.geom_base_qp, 4,
"Base QP used in position quantisation")
("positionSliceQpOffset",
params.encoder.gbh.geom_slice_qp_offset, 0,
"Per-slice QP offset used in position quantisation")
("positionQuantisationOctreeDepth",
params.encoder.gbh.geom_octree_qp_offset_depth, 3,
"Octree depth used for signalling position QP offsets\n")
params.encoder.gbh.geom_octree_qp_offset_depth, -1,
"Octree depth used for signalling position QP offsets (-1 => disabled)")
(po::Section("Attributes"))
......
......@@ -282,6 +282,10 @@ PCCTMC3Encoder3::fixupParameterSets(EncoderParams* params)
params->gps.geom_box_log2_scale_present_flag = true;
params->gps.gps_geom_box_log2_scale = 0;
// don't enable octree qp offset signalling if disabled
params->gbh.geom_octree_qp_offset_enabled_flag =
params->gbh.geom_octree_qp_offset_depth >= 0;
// fixup attribute parameters
for (auto it : params->attributeIdxMap) {
auto& attr_sps = params->sps.attributeSets[it.second];
......@@ -463,7 +467,9 @@ PCCTMC3Encoder3::encodeGeometryBrick(
gbh.geom_box_log2_scale = 0;
gbh.geom_max_node_size_log2 = nodeSizeLog2;
gbh.geom_num_points = int(pointCloud.getPointCount());
gbh.geom_octree_qp_offset_enabled_flag = _gps->geom_scaling_enabled_flag;
gbh.geom_slice_qp_offset = params->gbh.geom_slice_qp_offset;
gbh.geom_octree_qp_offset_enabled_flag =
params->gbh.geom_octree_qp_offset_enabled_flag;
gbh.geom_octree_qp_offset_depth = params->gbh.geom_octree_qp_offset_depth;
write(*_sps, *_gps, gbh, buf);
......
......@@ -472,9 +472,13 @@ decodeGeometryOctree(
occupancyAtlas.clear();
}
int sliceQp = gps.geom_base_qp + gbh.geom_slice_qp_offset;
int numLvlsUntilQpOffset = -1;
if (gbh.geom_octree_qp_offset_enabled_flag)
numLvlsUntilQpOffset = gbh.geom_octree_qp_offset_depth;
else if (gps.geom_scaling_enabled_flag)
node00.qp = sliceQp;
for (; !fifo.empty(); fifo.pop_front()) {
if (fifo.begin() == fifoCurrLvlEnd) {
......@@ -500,7 +504,7 @@ decodeGeometryOctree(
PCCOctree3Node& node0 = fifo.front();
if (numLvlsUntilQpOffset == 0) {
node0.qp = decoder.decodeQpOffset() + gps.geom_base_qp;
node0.qp = decoder.decodeQpOffset() + sliceQp;
node0.pos_base = node0.pos;
node0.pos_quant = {0, 0, 0};
}
......
......@@ -561,15 +561,20 @@ encodeGeometryOctree(
}
Vec3<uint32_t> occupancyAtlasOrigin(0xffffffff);
int numLvlsUntilQpOffset = -1;
int numLvlsUntilQuantization = -1;
if (gps.geom_scaling_enabled_flag) {
numLvlsUntilQuantization = 0;
if (gbh.geom_octree_qp_offset_enabled_flag)
numLvlsUntilQpOffset = gbh.geom_octree_qp_offset_depth;
numLvlsUntilQuantization = gbh.geom_octree_qp_offset_depth;
}
int sliceQp = gps.geom_base_qp + gbh.geom_slice_qp_offset;
// applied to the root node, just set the node qp
if (numLvlsUntilQpOffset == 0)
node00.qp = gps.geom_base_qp;
if (numLvlsUntilQuantization == 0)
node00.qp = sliceQp;
if (gbh.geom_octree_qp_offset_enabled_flag)
if (gps.geom_scaling_enabled_flag)
pointCloud.copyPositions();
for (; !fifo.empty(); fifo.pop_front()) {
......@@ -588,20 +593,21 @@ encodeGeometryOctree(
// determing a per node QP at the appropriate level
// NB: this has no effect here if geom_octree_qp_offset_depth=0
if (--numLvlsUntilQpOffset == 0)
if (--numLvlsUntilQuantization == 0)
calculateNodeQps(gps.geom_base_qp, fifo.begin(), fifoCurrLvlEnd);
}
PCCOctree3Node& node0 = fifo.front();
// encode delta qp for each octree block
if (numLvlsUntilQpOffset == 0)
encoder.encodeQpOffset(node0.qp - gps.geom_base_qp);
if (
numLvlsUntilQuantization == 0 && gbh.geom_octree_qp_offset_enabled_flag)
encoder.encodeQpOffset(node0.qp - sliceQp);
int shiftBits = (node0.qp - 4) / 6;
int effectiveNodeSizeLog2 = nodeSizeLog2 - shiftBits;
int effectiveChildSizeLog2 = effectiveNodeSizeLog2 - 1;
if (numLvlsUntilQpOffset == 0) {
if (numLvlsUntilQuantization == 0) {
geometryQuantization(pointCloud, node0, nodeSizeLog2);
if (gps.geom_unique_points_flag)
checkDuplicatePoints(pointCloud, node0, pointIdxToDmIdx);
......@@ -784,7 +790,7 @@ encodeGeometryOctree(
// inverse quantise the point cloud
// NB: this is done here to handle the partial tree coding case
if (gbh.geom_octree_qp_offset_enabled_flag)
if (gps.geom_scaling_enabled_flag)
for (int i = 0; i < pointCloud.getPointCount(); i++)
pointCloud[i] = pointCloud.getPositionReconstructed(i);
......
......@@ -288,6 +288,9 @@ struct GeometryBrickHeader {
int geom_max_node_size_log2;
int geom_num_points;
// qp offset for geometry scaling (if enabled)
int geom_slice_qp_offset;
// enables signalling of qp offsets within the octree
bool geom_octree_qp_offset_enabled_flag;
......
......@@ -406,6 +406,7 @@ write(
bs.writeUn(sps.log2_max_frame_idx, gbh.frame_idx);
if (gps.geom_scaling_enabled_flag) {
bs.writeSe(gbh.geom_slice_qp_offset);
bs.write(gbh.geom_octree_qp_offset_enabled_flag);
if (gbh.geom_octree_qp_offset_enabled_flag) {
bs.writeUe(gbh.geom_octree_qp_offset_depth);
......@@ -450,6 +451,7 @@ parseGbh(
gbh.geom_octree_qp_offset_enabled_flag = false;
if (gps.geom_scaling_enabled_flag) {
bs.readSe(&gbh.geom_slice_qp_offset);
bs.read(&gbh.geom_octree_qp_offset_enabled_flag);
if (gbh.geom_octree_qp_offset_enabled_flag)
bs.readUe(&gbh.geom_octree_qp_offset_depth);
......
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