Commit 667f9209 authored by Xiang Zhang's avatar Xiang Zhang Committed by David Flynn
Browse files

geom/m49231: add support for non-cubic nodes with implicit qtbt

This adoption permits coding geometry with non-cubic bounding boxes.
Since the depth of the tree remains constant for cubic and non-cubic
bounding boxes with identical largest dimensions, quad-tree and
binary-tree partitions are introduced to avoid coding 'fractional'
positions.

The following configuration options control the placement of non-octree
partitions within the coding tree:

 --max_num_implicit_qtbt_before_ot
 --min_implicit_qtbt_size_log2
parent e156f8aa
...@@ -16,6 +16,13 @@ categories: ...@@ -16,6 +16,13 @@ categories:
- intra_pred_max_node_size_log2: 6 - intra_pred_max_node_size_log2: 6
- positionQuantizationScale: 1 - positionQuantizationScale: 1
# default qtbt with cat3-frame exception
- max_num_implicit_qtbt_before_ot: 4
- min_implicit_qtbt_size_log2: 0
-
- !conditional '"${group}" eq "cat3-frame"'
- max_num_implicit_qtbt_before_ot: 0
#### ####
# attribute coding (common options -- relies on option ordering) # attribute coding (common options -- relies on option ordering)
# - use lifting transform for lossy conditions # - use lifting transform for lossy conditions
......
...@@ -21,6 +21,13 @@ categories: ...@@ -21,6 +21,13 @@ categories:
r05: '$eval{ $rp = 1; $gp = ${src-geometry-precision}; $p_min = max(gp - 9, 7); $start = min(1, $gp - ($p_min + 6)); $step = max(1, (min($gp - 1, $p_min + 7) - $p_min) / 5); $y = $start + round($rp * $step); $div = 1 << (abs($y) + 1); ((1 - 2*signbit($y)) % $div) / $div }' r05: '$eval{ $rp = 1; $gp = ${src-geometry-precision}; $p_min = max(gp - 9, 7); $start = min(1, $gp - ($p_min + 6)); $step = max(1, (min($gp - 1, $p_min + 7) - $p_min) / 5); $y = $start + round($rp * $step); $div = 1 << (abs($y) + 1); ((1 - 2*signbit($y)) % $div) / $div }'
r06: '$eval{ $rp = 0; $gp = ${src-geometry-precision}; $p_min = max(gp - 9, 7); $start = min(1, $gp - ($p_min + 6)); $step = max(1, (min($gp - 1, $p_min + 7) - $p_min) / 5); $y = $start + round($rp * $step); $div = 1 << (abs($y) + 1); ((1 - 2*signbit($y)) % $div) / $div }' r06: '$eval{ $rp = 0; $gp = ${src-geometry-precision}; $p_min = max(gp - 9, 7); $start = min(1, $gp - ($p_min + 6)); $step = max(1, (min($gp - 1, $p_min + 7) - $p_min) / 5); $y = $start + round($rp * $step); $div = 1 << (abs($y) + 1); ((1 - 2*signbit($y)) % $div) / $div }'
# default qtbt with cat3-frame exception
- max_num_implicit_qtbt_before_ot: 4
- min_implicit_qtbt_size_log2: 0
-
- !conditional '"${group}" eq "cat3-frame"'
- max_num_implicit_qtbt_before_ot: 0
#### ####
# attribute coding (common options -- relies on option ordering) # attribute coding (common options -- relies on option ordering)
# - skip attribute coding if dist2 parameters are not defined # - skip attribute coding if dist2 parameters are not defined
......
...@@ -17,6 +17,13 @@ categories: ...@@ -17,6 +17,13 @@ categories:
- neighbourAvailBoundaryLog2: 8 - neighbourAvailBoundaryLog2: 8
- intra_pred_max_node_size_log2: 6 - intra_pred_max_node_size_log2: 6
# default qtbt with cat3-frame exception
- max_num_implicit_qtbt_before_ot: 4
- min_implicit_qtbt_size_log2: 0
-
- !conditional '"${group}" eq "cat3-frame"'
- max_num_implicit_qtbt_before_ot: 0
#### ####
# attribute coding (common options -- relies on option ordering) # attribute coding (common options -- relies on option ordering)
# - skip attribute coding if dist2 parameters are not defined # - skip attribute coding if dist2 parameters are not defined
......
...@@ -17,6 +17,13 @@ categories: ...@@ -17,6 +17,13 @@ categories:
- neighbourAvailBoundaryLog2: 8 - neighbourAvailBoundaryLog2: 8
- intra_pred_max_node_size_log2: 6 - intra_pred_max_node_size_log2: 6
# default qtbt with cat3-frame exception
- max_num_implicit_qtbt_before_ot: 4
- min_implicit_qtbt_size_log2: 0
-
- !conditional '"${group}" eq "cat3-frame"'
- max_num_implicit_qtbt_before_ot: 0
#### ####
# attribute coding (common options -- relies on option ordering) # attribute coding (common options -- relies on option ordering)
# - code directly GBR (no need to perform colourspace conversion) # - code directly GBR (no need to perform colourspace conversion)
......
...@@ -16,6 +16,13 @@ categories: ...@@ -16,6 +16,13 @@ categories:
- intra_pred_max_node_size_log2: 6 - intra_pred_max_node_size_log2: 6
- positionQuantizationScale: 1 - positionQuantizationScale: 1
# default qtbt with cat3-frame exception
- max_num_implicit_qtbt_before_ot: 4
- min_implicit_qtbt_size_log2: 0
-
- !conditional '"${group}" eq "cat3-frame"'
- max_num_implicit_qtbt_before_ot: 0
#### ####
# attribute coding (common options -- relies on option ordering) # attribute coding (common options -- relies on option ordering)
# - uses raht transform # - uses raht transform
......
...@@ -21,6 +21,13 @@ categories: ...@@ -21,6 +21,13 @@ categories:
r05: '$eval{ $rp = 1; $gp = ${src-geometry-precision}; $p_min = max(gp - 9, 7); $start = min(1, $gp - ($p_min + 6)); $step = max(1, (min($gp - 1, $p_min + 7) - $p_min) / 5); $y = $start + round($rp * $step); $div = 1 << (abs($y) + 1); ((1 - 2*signbit($y)) % $div) / $div }' r05: '$eval{ $rp = 1; $gp = ${src-geometry-precision}; $p_min = max(gp - 9, 7); $start = min(1, $gp - ($p_min + 6)); $step = max(1, (min($gp - 1, $p_min + 7) - $p_min) / 5); $y = $start + round($rp * $step); $div = 1 << (abs($y) + 1); ((1 - 2*signbit($y)) % $div) / $div }'
r06: '$eval{ $rp = 0; $gp = ${src-geometry-precision}; $p_min = max(gp - 9, 7); $start = min(1, $gp - ($p_min + 6)); $step = max(1, (min($gp - 1, $p_min + 7) - $p_min) / 5); $y = $start + round($rp * $step); $div = 1 << (abs($y) + 1); ((1 - 2*signbit($y)) % $div) / $div }' r06: '$eval{ $rp = 0; $gp = ${src-geometry-precision}; $p_min = max(gp - 9, 7); $start = min(1, $gp - ($p_min + 6)); $step = max(1, (min($gp - 1, $p_min + 7) - $p_min) / 5); $y = $start + round($rp * $step); $div = 1 << (abs($y) + 1); ((1 - 2*signbit($y)) % $div) / $div }'
# default qtbt with cat3-frame exception
- max_num_implicit_qtbt_before_ot: 4
- min_implicit_qtbt_size_log2: 0
-
- !conditional '"${group}" eq "cat3-frame"'
- max_num_implicit_qtbt_before_ot: 0
#### ####
# attribute coding (common options -- relies on option ordering) # attribute coding (common options -- relies on option ordering)
# - use raht # - use raht
......
...@@ -235,6 +235,18 @@ A non-normative encoder process determines the QP offset based upon ...@@ -235,6 +235,18 @@ A non-normative encoder process determines the QP offset based upon
the local density of the octree. A value of -1 disables signalling the local density of the octree. A value of -1 disables signalling
of per-node QP offsets. of per-node QP offsets.
### `implicitQtBtEnabled=0|1`
Enables non-cubic geometry tree coding. When enabled, the geometry
tree may have a cuboid bounding box. Internal tree nodes are
implicitly determined to be octree, quadtree or binary tree nodes.
### `max_num_implicit_qtbt_before_ot=INT-VALUE`
Limits the maximal number of implicit quadtree and binary tree
partitions used before the first octree partition.
### `min_implicit_qtbt_size_log2=INT-VALUE`
Specifies the minimum size of implicit quadtree and binary tree partitions
### `--bitwiseOccupancyCoding=0|1` ### `--bitwiseOccupancyCoding=0|1`
In octree geometry coding, there are both byte-wise and bit-wise tools to In octree geometry coding, there are both byte-wise and bit-wise tools to
encode the occupancy data. This option selects between the two methods. encode the occupancy data. This option selects between the two methods.
......
...@@ -44,6 +44,7 @@ namespace pcc { ...@@ -44,6 +44,7 @@ namespace pcc {
void void
updateGeometryOccupancyAtlas( updateGeometryOccupancyAtlas(
const Vec3<uint32_t>& currentPosition, const Vec3<uint32_t>& currentPosition,
const int atlasShift,
const pcc::ringbuf<PCCOctree3Node>& fifo, const pcc::ringbuf<PCCOctree3Node>& fifo,
const pcc::ringbuf<PCCOctree3Node>::iterator& fifoCurrLvlEnd, const pcc::ringbuf<PCCOctree3Node>::iterator& fifoCurrLvlEnd,
MortonMap3D* occupancyAtlas, MortonMap3D* occupancyAtlas,
...@@ -51,6 +52,10 @@ updateGeometryOccupancyAtlas( ...@@ -51,6 +52,10 @@ updateGeometryOccupancyAtlas(
{ {
const uint32_t mask = (1 << occupancyAtlas->cubeSizeLog2()) - 1; const uint32_t mask = (1 << occupancyAtlas->cubeSizeLog2()) - 1;
const int shift = occupancyAtlas->cubeSizeLog2(); const int shift = occupancyAtlas->cubeSizeLog2();
const int shiftX = (atlasShift & 4 ? 1 : 0);
const int shiftY = (atlasShift & 2 ? 1 : 0);
const int shiftZ = (atlasShift & 1 ? 1 : 0);
const auto currentOrigin = currentPosition >> shift; const auto currentOrigin = currentPosition >> shift;
// only refresh the atlas if the current position lies outside the // only refresh the atlas if the current position lies outside the
...@@ -65,10 +70,9 @@ updateGeometryOccupancyAtlas( ...@@ -65,10 +70,9 @@ updateGeometryOccupancyAtlas(
for (auto it = fifo.begin(); it != fifoCurrLvlEnd; ++it) { for (auto it = fifo.begin(); it != fifoCurrLvlEnd; ++it) {
if (currentOrigin != it->pos >> shift) if (currentOrigin != it->pos >> shift)
break; break;
const uint32_t x = (it->pos[0] & mask) >> shiftX;
const uint32_t x = it->pos[0] & mask; const uint32_t y = (it->pos[1] & mask) >> shiftY;
const uint32_t y = it->pos[1] & mask; const uint32_t z = (it->pos[2] & mask) >> shiftZ;
const uint32_t z = it->pos[2] & mask;
occupancyAtlas->setByte(x, y, z, it->siblingOccupancy); occupancyAtlas->setByte(x, y, z, it->siblingOccupancy);
} }
} }
...@@ -138,6 +142,7 @@ GeometryNeighPattern ...@@ -138,6 +142,7 @@ GeometryNeighPattern
makeGeometryNeighPattern( makeGeometryNeighPattern(
bool adjacent_child_contextualization_enabled_flag, bool adjacent_child_contextualization_enabled_flag,
const Vec3<uint32_t>& position, const Vec3<uint32_t>& position,
const int atlasShift,
const MortonMap3D& occupancyAtlas) const MortonMap3D& occupancyAtlas)
{ {
const int mask = occupancyAtlas.cubeSize() - 1; const int mask = occupancyAtlas.cubeSize() - 1;
...@@ -146,6 +151,7 @@ makeGeometryNeighPattern( ...@@ -146,6 +151,7 @@ makeGeometryNeighPattern(
const int32_t y = position[1] & mask; const int32_t y = position[1] & mask;
const int32_t z = position[2] & mask; const int32_t z = position[2] & mask;
uint8_t neighPattern; uint8_t neighPattern;
if (atlasShift == 0) {
if ( if (
x > 0 && x < cubeSizeMinusOne && y > 0 && y < cubeSizeMinusOne && z > 0 x > 0 && x < cubeSizeMinusOne && y > 0 && y < cubeSizeMinusOne && z > 0
&& z < cubeSizeMinusOne) { && z < cubeSizeMinusOne) {
...@@ -163,6 +169,40 @@ makeGeometryNeighPattern( ...@@ -163,6 +169,40 @@ makeGeometryNeighPattern(
neighPattern |= occupancyAtlas.getWithCheck(x, y, z - 1) << 4; neighPattern |= occupancyAtlas.getWithCheck(x, y, z - 1) << 4;
neighPattern |= occupancyAtlas.getWithCheck(x, y, z + 1) << 5; neighPattern |= occupancyAtlas.getWithCheck(x, y, z + 1) << 5;
} }
} else {
const int shiftX = (atlasShift & 4 ? 1 : 0);
const int shiftY = (atlasShift & 2 ? 1 : 0);
const int shiftZ = (atlasShift & 1 ? 1 : 0);
if (
x > 0 && x < cubeSizeMinusOne && y > 0 && y < cubeSizeMinusOne && z > 0
&& z < cubeSizeMinusOne) {
neighPattern = occupancyAtlas.get(x + 1, y, z, shiftX, shiftY, shiftZ);
neighPattern |= occupancyAtlas.get(x - 1, y, z, shiftX, shiftY, shiftZ)
<< 1;
neighPattern |= occupancyAtlas.get(x, y - 1, z, shiftX, shiftY, shiftZ)
<< 2;
neighPattern |= occupancyAtlas.get(x, y + 1, z, shiftX, shiftY, shiftZ)
<< 3;
neighPattern |= occupancyAtlas.get(x, y, z - 1, shiftX, shiftY, shiftZ)
<< 4;
neighPattern |= occupancyAtlas.get(x, y, z + 1, shiftX, shiftY, shiftZ)
<< 5;
} else {
neighPattern =
occupancyAtlas.getWithCheck(x + 1, y, z, shiftX, shiftY, shiftZ);
neighPattern |=
occupancyAtlas.getWithCheck(x - 1, y, z, shiftX, shiftY, shiftZ) << 1;
neighPattern |=
occupancyAtlas.getWithCheck(x, y - 1, z, shiftX, shiftY, shiftZ) << 2;
neighPattern |=
occupancyAtlas.getWithCheck(x, y + 1, z, shiftX, shiftY, shiftZ) << 3;
neighPattern |=
occupancyAtlas.getWithCheck(x, y, z - 1, shiftX, shiftY, shiftZ) << 4;
neighPattern |=
occupancyAtlas.getWithCheck(x, y, z + 1, shiftX, shiftY, shiftZ) << 5;
}
}
// Above, the neighbour pattern corresponds directly to the six same // Above, the neighbour pattern corresponds directly to the six same
// sized neighbours of the given node. // sized neighbours of the given node.
......
...@@ -62,7 +62,7 @@ public: ...@@ -62,7 +62,7 @@ public:
const uint32_t halfCubeSizeLog2 = cubeSizeLog2 ? cubeSizeLog2 - 1 : 0; const uint32_t halfCubeSizeLog2 = cubeSizeLog2 ? cubeSizeLog2 - 1 : 0;
_cubeSizeLog2 = cubeSizeLog2; _cubeSizeLog2 = cubeSizeLog2;
_cubeSize = 1 << cubeSizeLog2; _cubeSize = 1 << cubeSizeLog2;
_bufferSizeInBytes = 1 << (3 * halfCubeSizeLog2); _bufferSizeInBytes = 1 << (3 * cubeSizeLog2);
_buffer.reset(new uint8_t[_bufferSizeInBytes]); _buffer.reset(new uint8_t[_bufferSizeInBytes]);
_childOccupancy.reset(new uint8_t[_bufferSizeInBytes << 3]); _childOccupancy.reset(new uint8_t[_bufferSizeInBytes << 3]);
_updates.reserve(1 << 16); _updates.reserve(1 << 16);
...@@ -98,12 +98,44 @@ public: ...@@ -98,12 +98,44 @@ public:
} }
} }
uint32_t get(
const int32_t x,
const int32_t y,
const int32_t z,
const int shiftX,
const int shiftY,
const int shiftZ) const
{
assert(
x >= 0 && y >= 0 && z >= 0 && x < _cubeSize && y < _cubeSize
&& z < _cubeSize);
return (_buffer[getByteIndex(x >> shiftX, y >> shiftY, z >> shiftZ)]
>> getBitIndex(shiftX ? x : 0, shiftY ? y : 0, shiftZ ? z : 0))
& 1;
}
uint32_t getWithCheck(
const int32_t x,
const int32_t y,
const int32_t z,
const int shiftX,
const int shiftY,
const int shiftZ) const
{
if (
x < 0 || x >= _cubeSize || y < 0 || y >= _cubeSize || z < 0
|| z >= _cubeSize) {
return false;
}
return get(x, y, z, shiftX, shiftY, shiftZ);
}
uint32_t get(const int32_t x, const int32_t y, const int32_t z) const uint32_t get(const int32_t x, const int32_t y, const int32_t z) const
{ {
assert( assert(
x >= 0 && y >= 0 && z >= 0 && x < _cubeSize && y < _cubeSize x >= 0 && y >= 0 && z >= 0 && x < _cubeSize && y < _cubeSize
&& z < _cubeSize); && z < _cubeSize);
return (_buffer[getByteIndex(x, y, z)] >> getBitIndex(x, y, z)) & 1; return _buffer[getByteIndex(x, y, z)] & 1;
} }
uint32_t uint32_t
...@@ -119,13 +151,12 @@ public: ...@@ -119,13 +151,12 @@ public:
void setChildOcc(int32_t x, int32_t y, int32_t z, uint8_t childOccupancy) void setChildOcc(int32_t x, int32_t y, int32_t z, uint8_t childOccupancy)
{ {
_childOccupancy[getByteIndex(x << 1, y << 1, z << 1)] = childOccupancy; _childOccupancy[getByteIndex(x, y, z)] = childOccupancy;
} }
uint8_t getChildOcc(int32_t x, int32_t y, int32_t z) const uint8_t getChildOcc(int32_t x, int32_t y, int32_t z) const
{ {
uint8_t childOccupancy = uint8_t childOccupancy = _childOccupancy[getByteIndex(x, y, z)];
_childOccupancy[getByteIndex(x << 1, y << 1, z << 1)];
return childOccupancy; return childOccupancy;
} }
...@@ -138,8 +169,7 @@ private: ...@@ -138,8 +169,7 @@ private:
uint32_t uint32_t
getByteIndex(const int32_t x, const int32_t y, const int32_t z) const getByteIndex(const int32_t x, const int32_t y, const int32_t z) const
{ {
return kMortonCode256X[x >> 1] | kMortonCode256Y[y >> 1] return kMortonCode256X[x] | kMortonCode256Y[y] | kMortonCode256Z[z];
| kMortonCode256Z[z >> 1];
} }
int _cubeSize = 0; int _cubeSize = 0;
...@@ -177,12 +207,14 @@ struct GeometryNeighPattern { ...@@ -177,12 +207,14 @@ struct GeometryNeighPattern {
GeometryNeighPattern makeGeometryNeighPattern( GeometryNeighPattern makeGeometryNeighPattern(
bool adjacent_child_contextualization_enabled_flag, bool adjacent_child_contextualization_enabled_flag,
const Vec3<uint32_t>& currentPosition, const Vec3<uint32_t>& currentPosition,
const int atlasShift,
const MortonMap3D& occupancyAtlas); const MortonMap3D& occupancyAtlas);
// populate (if necessary) the occupancy atlas with occupancy information // populate (if necessary) the occupancy atlas with occupancy information
// from @fifo. // from @fifo.
void updateGeometryOccupancyAtlas( void updateGeometryOccupancyAtlas(
const Vec3<uint32_t>& position, const Vec3<uint32_t>& position,
const int atlasShift,
const ringbuf<PCCOctree3Node>& fifo, const ringbuf<PCCOctree3Node>& fifo,
const ringbuf<PCCOctree3Node>::iterator& fifoCurrLvlEnd, const ringbuf<PCCOctree3Node>::iterator& fifoCurrLvlEnd,
MortonMap3D* occupancyAtlas, MortonMap3D* occupancyAtlas,
......
...@@ -46,6 +46,8 @@ ...@@ -46,6 +46,8 @@
#include "PCCMisc.h" #include "PCCMisc.h"
#include "tables.h" #include "tables.h"
#include <algorithm>
namespace pcc { namespace pcc {
/// Vector dim 3 /// Vector dim 3
template<typename T> template<typename T>
......
...@@ -506,6 +506,18 @@ ParseParameters(int argc, char* argv[], Parameters& params) ...@@ -506,6 +506,18 @@ ParseParameters(int argc, char* argv[], Parameters& params)
(po::Section("Geometry")) (po::Section("Geometry"))
("implicitQtBtEnabled",
params.encoder.gps.implicit_qtbt_enabled_flag, true,
"Enables non-cubic geometry bounding box")
("max_num_implicit_qtbt_before_ot",
params.encoder.gps.max_num_implicit_qtbt_before_ot, 4,
"Max number of implicit qtbt before ot")
("min_implicit_qtbt_size_log2",
params.encoder.gps.min_implicit_qtbt_size_log2, 0,
"Minimum size of implicit qtbt")
// tools // tools
("bitwiseOccupancyCoding", ("bitwiseOccupancyCoding",
params.encoder.gps.bitwise_occupancy_coding_flag, true, params.encoder.gps.bitwise_occupancy_coding_flag, true,
......
...@@ -451,13 +451,6 @@ void ...@@ -451,13 +451,6 @@ void
PCCTMC3Encoder3::encodeGeometryBrick( PCCTMC3Encoder3::encodeGeometryBrick(
const EncoderParams* params, PayloadBuffer* buf) const EncoderParams* params, PayloadBuffer* buf)
{ {
// todo(df): confirm minimum of 1 isn't needed
int32_t maxBB =
std::max({1, _sliceBoxWhd[0], _sliceBoxWhd[1], _sliceBoxWhd[2]});
// the current node dimension (log2) encompasing maxBB
int nodeSizeLog2 = ceillog2(maxBB + 1);
GeometryBrickHeader gbh; GeometryBrickHeader gbh;
gbh.geom_geom_parameter_set_id = _gps->gps_geom_parameter_set_id; gbh.geom_geom_parameter_set_id = _gps->gps_geom_parameter_set_id;
gbh.geom_slice_id = _sliceId; gbh.geom_slice_id = _sliceId;
...@@ -465,7 +458,19 @@ PCCTMC3Encoder3::encodeGeometryBrick( ...@@ -465,7 +458,19 @@ PCCTMC3Encoder3::encodeGeometryBrick(
gbh.frame_idx = _frameCounter & ((1 << _sps->log2_max_frame_idx) - 1); gbh.frame_idx = _frameCounter & ((1 << _sps->log2_max_frame_idx) - 1);
gbh.geomBoxOrigin = _sliceOrigin; gbh.geomBoxOrigin = _sliceOrigin;
gbh.geom_box_log2_scale = 0; gbh.geom_box_log2_scale = 0;
gbh.geom_max_node_size_log2 = nodeSizeLog2;
if (!_gps->implicit_qtbt_enabled_flag) {
// todo(df): confirm minimum of 1 isn't needed
int32_t maxBB =
std::max({1, _sliceBoxWhd[0], _sliceBoxWhd[1], _sliceBoxWhd[2]});
gbh.geom_max_node_size_log2 = ceillog2(maxBB + 1);
} else {
// different node dimension for xyz, for the purpose of implicit qtbt
gbh.geom_max_node_size_log2_xyz[0] = ceillog2(_sliceBoxWhd[0] + 1);
gbh.geom_max_node_size_log2_xyz[1] = ceillog2(_sliceBoxWhd[1] + 1);
gbh.geom_max_node_size_log2_xyz[2] = ceillog2(_sliceBoxWhd[2] + 1);
}
gbh.geom_num_points = int(pointCloud.getPointCount()); gbh.geom_num_points = int(pointCloud.getPointCount());
gbh.geom_slice_qp_offset = params->gbh.geom_slice_qp_offset; gbh.geom_slice_qp_offset = params->gbh.geom_slice_qp_offset;
gbh.geom_octree_qp_offset_enabled_flag = gbh.geom_octree_qp_offset_enabled_flag =
......
...@@ -63,6 +63,7 @@ void ...@@ -63,6 +63,7 @@ void
predictGeometryOccupancyIntra( predictGeometryOccupancyIntra(
const MortonMap3D& occupancyAtlas, const MortonMap3D& occupancyAtlas,
Vec3<uint32_t> pos, Vec3<uint32_t> pos,
const int atlasShift,
int* occupancyIsPredicted, int* occupancyIsPredicted,
int* occupancyPrediction) int* occupancyPrediction)
{ {
...@@ -75,7 +76,7 @@ predictGeometryOccupancyIntra( ...@@ -75,7 +76,7 @@ predictGeometryOccupancyIntra(
int numOccupied = 0; int numOccupied = 0;
const int8_t* p = &LUT_dist[0][0]; const int8_t* p = &LUT_dist[0][0];
if (atlasShift == 0) {
for (int dx = -1; dx <= 1; dx++) { for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) { for (int dy = -1; dy <= 1; dy++) {
for (int dz = -1; dz <= 1; dz++) { for (int dz = -1; dz <= 1; dz++) {
...@@ -85,6 +86,34 @@ predictGeometryOccupancyIntra( ...@@ -85,6 +86,34 @@ predictGeometryOccupancyIntra(
// todo(df): remove unnecessary checks // todo(df): remove unnecessary checks
bool occupied = occupancyAtlas.getWithCheck(x + dx, y + dy, z + dz); bool occupied = occupancyAtlas.getWithCheck(x + dx, y + dy, z + dz);
if (occupied) {
for (int i = 0; i < 8; i++)
score[i] += LUT1[p[i]];
numOccupied++;
} else {
for (int i = 0; i < 8; i++)
score[i] += LUT0[p[i]];
}
// next pattern
p += 8;
}
}
}
} else {
const int shiftX = (atlasShift & 4 ? 1 : 0);
const int shiftY = (atlasShift & 2 ? 1 : 0);
const int shiftZ = (atlasShift & 1 ? 1 : 0);
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
for (int dz = -1; dz <= 1; dz++) {
if (dz == 0 && dy == 0 && dx == 0)
continue;
// todo(df): remove unnecessary checks
bool occupied = occupancyAtlas.getWithCheck(
x + dx, y + dy, z + dz, shiftX, shiftY, shiftZ);
if (occupied) { if (occupied) {
for (int i = 0; i < 8; i++) for (int i = 0; i < 8; i++)
score[i] += LUT1[p[i]]; score[i] += LUT1[p[i]];
...@@ -99,6 +128,7 @@ predictGeometryOccupancyIntra( ...@@ -99,6 +128,7 @@ predictGeometryOccupancyIntra(
} }
} }
} }
}
if (numOccupied <= 8) { if (numOccupied <= 8) {
*occupancyIsPredicted = 0; *occupancyIsPredicted = 0;
......
...@@ -47,6 +47,7 @@ namespace pcc { ...@@ -47,6 +47,7 @@ namespace pcc {
void predictGeometryOccupancyIntra( void predictGeometryOccupancyIntra(
const MortonMap3D& occupancyAtlas, const MortonMap3D& occupancyAtlas,
Vec3<uint32_t> pos, Vec3<uint32_t> pos,
const int atlasShift,
int* occupacyIsPredIntra, int* occupacyIsPredIntra,
int* occupacyPredIntra); int* occupacyPredIntra);
......
...@@ -114,6 +114,18 @@ void decodeGeometryOctree( ...@@ -114,6 +114,18 @@ void decodeGeometryOctree(
EntropyDecoder* arithmeticDecoder, EntropyDecoder* arithmeticDecoder,
pcc::ringbuf<PCCOctree3Node>* nodesRemaining); pcc::ringbuf<PCCOctree3Node>* nodesRemaining);
//---------------------------------------------------------------------------
// Determine if a node is a leaf node based on size.
// A node with all dimension = 0 is a leaf node.
// NB: some dimensions may be less than zero if coding of that dimension
// has already terminated.
inline bool
isLeafNode(const Vec3<int>& sizeLog2)