Commit 82a0c430 authored by David Flynn's avatar David Flynn
Browse files

geom/m44753: contextualisation of occupancy using adjacency

Each occupancy bit is contextualised based on the number of occupied
(directly) adjacent child nodes in the (x-1), (y-1), and (z-1)
neighbour nodes used to generate the neighbour pattern.

Three contextualisation states are added:
 - no adjacent neighbours
 - one adjacent neigbour (=adjacencyGt0)
 - two adjacent neighoburs (=adjacencyGt1)
parent 62b05926
......@@ -94,13 +94,13 @@ updateGeometryOccupancyAtlasOccChild(
//----------------------------------------------------------------------------
// neighIdx: 0 => (x-1), 1 => (y-1), 2 => (z-1)
//
static uint32_t
static GeometryNeighPattern
updatePatternFromNeighOccupancy(
const MortonMap3D& occupancyAtlas,
int x,
int y,
int z,
uint32_t neighPattern,
GeometryNeighPattern gnp,
int neighIdx)
{
static const uint8_t childMasks[] = {
......@@ -110,21 +110,29 @@ updatePatternFromNeighOccupancy(
uint32_t patternBit = 1 << (1 << neighIdx);
uint8_t childMask = childMasks[neighIdx];
if (neighPattern & patternBit) {
// conversions between neighbour occupancy and adjacency:
// x: >> 4, y: >> 2, z: >> 1
int adjacencyShift = 4 >> neighIdx;
if (gnp.neighPattern & patternBit) {
uint8_t child_occ = occupancyAtlas.getChildOcc(x, y, z);
child_occ &= childMask;
if (!child_occ) {
/* neighbour is falsely occupied */
neighPattern ^= patternBit;
gnp.neighPattern ^= patternBit;
} else {
child_occ >>= adjacencyShift;
gnp.adjacencyGt1 |= gnp.adjacencyGt0 & child_occ;
gnp.adjacencyGt0 |= child_occ;
}
}
return neighPattern;
return gnp;
}
//----------------------------------------------------------------------------
uint32_t
GeometryNeighPattern
makeGeometryNeighPattern(
const PCCVector3<uint32_t>& position,
const int nodeSizeLog2,
......@@ -135,7 +143,7 @@ makeGeometryNeighPattern(
const int32_t x = (position[0] >> nodeSizeLog2) & mask;
const int32_t y = (position[1] >> nodeSizeLog2) & mask;
const int32_t z = (position[2] >> nodeSizeLog2) & mask;
uint32_t neighPattern;
uint8_t neighPattern;
if (
x > 0 && x < cubeSizeMinusOne && y > 0 && y < cubeSizeMinusOne && z > 0
&& z < cubeSizeMinusOne) {
......@@ -159,19 +167,20 @@ makeGeometryNeighPattern(
// The patten is then refined by examining the available children
// of the same neighbours.
// NB: the process of updating neighpattern below also derives
// the occupancy contextualisation bits.
GeometryNeighPattern gnp = {neighPattern, 0, 0};
if (x > 0)
neighPattern = updatePatternFromNeighOccupancy(
occupancyAtlas, x - 1, y, z, neighPattern, 0);
gnp = updatePatternFromNeighOccupancy(occupancyAtlas, x - 1, y, z, gnp, 0);
if (y > 0)
neighPattern = updatePatternFromNeighOccupancy(
occupancyAtlas, x, y - 1, z, neighPattern, 1);
gnp = updatePatternFromNeighOccupancy(occupancyAtlas, x, y - 1, z, gnp, 1);
if (z > 0)
neighPattern = updatePatternFromNeighOccupancy(
occupancyAtlas, x, y, z - 1, neighPattern, 2);
gnp = updatePatternFromNeighOccupancy(occupancyAtlas, x, y, z - 1, gnp, 2);
return neighPattern;
return gnp;
}
//============================================================================
......
......@@ -157,9 +157,19 @@ private:
//============================================================================
struct GeometryNeighPattern {
// Mask indicating presence of neigbours of the corresponding tree node
uint8_t neighPattern;
uint8_t adjacencyGt0;
uint8_t adjacencyGt1;
};
//============================================================================
// determine the occupancy pattern of the six neighbours of the node at
// @position.
uint32_t makeGeometryNeighPattern(
GeometryNeighPattern makeGeometryNeighPattern(
const PCCVector3<uint32_t>& currentPosition,
const int nodeSizeLog2,
const MortonMap3D& occupancyAtlas);
......
......@@ -55,18 +55,34 @@ public:
int decodePositionLeafNumPoints();
int decodeOccupancyNeighZ(int mappedOccIsPredicted, int mappedOccPrediction);
int decodeOccupancyNeighZ(
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1);
int decodeOccupancyNeighNZ(
int neighPattern10, int mappedOccIsPredicted, int mappedOccPrediction);
int neighPattern10,
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1);
int decodeOccupancyBitwise(
int neighPattern, int mappedOccIsPredicted, int mappedOccPrediction);
int neighPattern,
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1);
int decodeOccupancyBytewise(int neighPattern);
uint32_t decodeOccupancy(
int neighPattern, int occupancyIsPredicted, int occupancyPrediction);
int neighPattern,
int occupancyIsPredicted,
int occupancyPrediction,
int occupancyAdjGt0,
int occupancyAdjGt1);
PCCVector3<uint32_t> decodePointPosition(int nodeSizeLog2);
......@@ -89,11 +105,14 @@ private:
AdaptiveBitModel _ctxNumIdcmPointsEq1;
// For bitwise occupancy coding
// map 0 = not predicted
// map 1 = predicted unnoccupied
// map 2 = predicted occupied
// maps 0 + i: no adjacency
// maps 3 + i: adjacency > 0
// maps 6 + i: adjacency > 1
// map i = 0 = not predicted
// map i = 1 = predicted unnoccupied
// map i = 2 = predicted occupied
CtxModelOctreeOccupancy _ctxOccupancy;
CtxMapOctreeOccupancy _ctxIdxMaps[3];
CtxMapOctreeOccupancy _ctxIdxMaps[9];
// For bytewise occupancy coding
DualLutCoder<true> _bytewiseOccupancyCoder[10];
......@@ -147,7 +166,10 @@ GeometryOctreeDecoder::decodePositionLeafNumPoints()
int
GeometryOctreeDecoder::decodeOccupancyNeighZ(
int mappedOccIsPredicted, int mappedOccPrediction)
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1)
{
static const int8_t bitCodingOrder[8]{1, 7, 5, 3, 2, 4, 6, 0};
int minOccupied = 2;
......@@ -158,8 +180,11 @@ GeometryOctreeDecoder::decodeOccupancyNeighZ(
int bit = 1;
int bitIsPredicted = (mappedOccIsPredicted >> bitCodingOrder[i]) & 1;
int bitPrediction = (mappedOccPrediction >> bitCodingOrder[i]) & 1;
int bitAdjGt0 = (mappedOccAdjGt0 >> bitCodingOrder[i]) & 1;
int bitAdjGt1 = (mappedOccAdjGt1 >> bitCodingOrder[i]) & 1;
int ctxIdxMapIdx = bitIsPredicted + bitPrediction;
int ctxIdxMapIdx =
3 * (bitAdjGt0 + bitAdjGt1) + bitIsPredicted + bitPrediction;
auto& ctxIdxMap = _ctxIdxMaps[ctxIdxMapIdx];
// NB: There must be at least two occupied child nodes
......@@ -181,7 +206,11 @@ GeometryOctreeDecoder::decodeOccupancyNeighZ(
int
GeometryOctreeDecoder::decodeOccupancyNeighNZ(
int neighPattern10, int mappedOccIsPredicted, int mappedOccPrediction)
int neighPattern10,
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1)
{
static const int8_t bitCodingOrder[8]{1, 7, 5, 3, 2, 4, 6, 0};
......@@ -210,8 +239,11 @@ GeometryOctreeDecoder::decodeOccupancyNeighNZ(
int bit = 1;
int bitIsPredicted = (mappedOccIsPredicted >> bitCodingOrder[i]) & 1;
int bitPrediction = (mappedOccPrediction >> bitCodingOrder[i]) & 1;
int bitAdjGt0 = (mappedOccAdjGt0 >> bitCodingOrder[i]) & 1;
int bitAdjGt1 = (mappedOccAdjGt1 >> bitCodingOrder[i]) & 1;
int ctxIdxMapIdx = bitIsPredicted + bitPrediction;
int ctxIdxMapIdx =
3 * (bitAdjGt0 + bitAdjGt1) + bitIsPredicted + bitPrediction;
auto& ctxIdxMap = _ctxIdxMaps[ctxIdxMapIdx];
if (i < 7 || partialOccupancy) {
......@@ -231,17 +263,24 @@ GeometryOctreeDecoder::decodeOccupancyNeighNZ(
int
GeometryOctreeDecoder::decodeOccupancyBitwise(
int neighPattern, int mappedOccIsPredicted, int mappedOccPrediction)
int neighPattern,
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1)
{
if (neighPattern == 0) {
return decodeOccupancyNeighZ(mappedOccIsPredicted, mappedOccPrediction);
return decodeOccupancyNeighZ(
mappedOccIsPredicted, mappedOccPrediction, mappedOccAdjGt0,
mappedOccAdjGt1);
}
// code occupancy using the neighbour configuration context
// with reduction from 64 states to 10 (or 6).
int neighPatternR1 = _neighPattern64toR1[neighPattern];
return decodeOccupancyNeighNZ(
neighPatternR1, mappedOccIsPredicted, mappedOccPrediction);
neighPatternR1, mappedOccIsPredicted, mappedOccPrediction, mappedOccAdjGt0,
mappedOccAdjGt1);
}
//-------------------------------------------------------------------------
......@@ -262,7 +301,11 @@ GeometryOctreeDecoder::decodeOccupancyBytewise(int neighPattern)
uint32_t
GeometryOctreeDecoder::decodeOccupancy(
int neighPattern, int occupancyIsPred, int occupancyPred)
int neighPattern,
int occupancyIsPred,
int occupancyPred,
int occupancyAdjGt0,
int occupancyAdjGt1)
{
// decode occupancy pattern
uint32_t occupancy;
......@@ -279,10 +322,13 @@ GeometryOctreeDecoder::decodeOccupancy(
uint32_t mapOccIsP = mapGeometryOccupancy(occupancyIsPred, neighPattern);
uint32_t mapOccP = mapGeometryOccupancy(occupancyPred, neighPattern);
uint32_t mapAdjGt0 = mapGeometryOccupancy(occupancyAdjGt0, neighPattern);
uint32_t mapAdjGt1 = mapGeometryOccupancy(occupancyAdjGt1, neighPattern);
uint32_t mappedOccupancy;
if (_useBitwiseOccupancyCoder)
mappedOccupancy = decodeOccupancyBitwise(neighPattern, mapOccIsP, mapOccP);
mappedOccupancy = decodeOccupancyBitwise(
neighPattern, mapOccIsP, mapOccP, mapAdjGt0, mapAdjGt1);
else
mappedOccupancy = decodeOccupancyBytewise(neighPattern);
......@@ -397,13 +443,19 @@ decodeGeometryOctree(
PCCOctree3Node& node0 = fifo.front();
int occupancyAdjacencyGt0 = 0;
int occupancyAdjacencyGt1 = 0;
if (gps.neighbour_avail_boundary_log2) {
updateGeometryOccupancyAtlas(
node0.pos, nodeSizeLog2, fifo, fifoCurrLvlEnd, &occupancyAtlas,
&occupancyAtlasOrigin);
node0.neighPattern =
GeometryNeighPattern gnp =
makeGeometryNeighPattern(node0.pos, nodeSizeLog2, occupancyAtlas);
node0.neighPattern = gnp.neighPattern;
occupancyAdjacencyGt0 = gnp.adjacencyGt0;
occupancyAdjacencyGt1 = gnp.adjacencyGt1;
}
int occupancyIsPredicted = 0;
......@@ -418,7 +470,8 @@ decodeGeometryOctree(
// decode occupancy pattern
uint8_t occupancy = decoder.decodeOccupancy(
node0.neighPattern, occupancyIsPredicted, occupancyPrediction);
node0.neighPattern, occupancyIsPredicted, occupancyPrediction,
occupancyAdjacencyGt0, occupancyAdjacencyGt1);
assert(occupancy > 0);
......
......@@ -56,19 +56,27 @@ public:
int encodePositionLeafNumPoints(int count);
void encodeOccupancyNeighZ(
int mappedOccupancy, int mappedOccIsPredicted, int mappedOccPrediction);
int mappedOccupancy,
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1);
void encodeOccupancyNeighNZ(
int neighPattern10,
int mappedOccupancy,
int mappedOccIsPredicted,
int mappedOccPrediction);
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1);
void encodeOccupancyBitwise(
int neighPattern,
int mappedOccupancy,
int mappedOccIsPredicted,
int mappedOccPrediction);
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1);
void encodeOccupancyBytewise(int neighPattern, int mappedOccupancy);
......@@ -76,7 +84,9 @@ public:
int neighPattern,
int occupancy,
int occupancyIsPredicted,
int occupancyPrediction);
int occupancyPrediction,
int occupancyAdjGt0,
int occupancyAdjGt1);
void encodePointPosition(int nodeSizeLog2, const PCCVector3<uint32_t>& pos);
......@@ -100,11 +110,14 @@ private:
AdaptiveBitModel _ctxNumIdcmPointsEq1;
// For bitwise occupancy coding
// map 0 = not predicted
// map 1 = predicted unnoccupied
// map 2 = predicted occupied
// maps 0 + i: no adjacency
// maps 3 + i: adjacency > 0
// maps 6 + i: adjacency > 1
// map i = 0 = not predicted
// map i = 1 = predicted unnoccupied
// map i = 2 = predicted occupied
CtxModelOctreeOccupancy _ctxOccupancy;
CtxMapOctreeOccupancy _ctxIdxMaps[3];
CtxMapOctreeOccupancy _ctxIdxMaps[9];
// For bytewise occupancy coding
DualLutCoder<true> _bytewiseOccupancyCoder[10];
......@@ -157,7 +170,11 @@ GeometryOctreeEncoder::encodePositionLeafNumPoints(int count)
void
GeometryOctreeEncoder::encodeOccupancyNeighZ(
int mappedOccupancy, int mappedOccIsPredicted, int mappedOccPrediction)
int mappedOccupancy,
int mappedOccIsPredicted,
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1)
{
static const int8_t bitCodingOrder[8]{1, 7, 5, 3, 2, 4, 6, 0};
int minOccupied = 2;
......@@ -167,8 +184,11 @@ GeometryOctreeEncoder::encodeOccupancyNeighZ(
int bit = (mappedOccupancy >> bitCodingOrder[i]) & 1;
int bitIsPredicted = (mappedOccIsPredicted >> bitCodingOrder[i]) & 1;
int bitPrediction = (mappedOccPrediction >> bitCodingOrder[i]) & 1;
int bitAdjGt0 = (mappedOccAdjGt0 >> bitCodingOrder[i]) & 1;
int bitAdjGt1 = (mappedOccAdjGt1 >> bitCodingOrder[i]) & 1;
int ctxIdxMapIdx = bitIsPredicted + bitPrediction;
int ctxIdxMapIdx =
3 * (bitAdjGt0 + bitAdjGt1) + bitIsPredicted + bitPrediction;
auto& ctxIdxMap = _ctxIdxMaps[ctxIdxMapIdx];
int idx = numOccupiedAcc;
......@@ -192,7 +212,9 @@ GeometryOctreeEncoder::encodeOccupancyNeighNZ(
int neighPattern10,
int mappedOccupancy,
int mappedOccIsPredicted,
int mappedOccPrediction)
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1)
{
static const int8_t bitCodingOrder[8]{1, 7, 5, 3, 2, 4, 6, 0};
......@@ -218,8 +240,11 @@ GeometryOctreeEncoder::encodeOccupancyNeighNZ(
int bit = (mappedOccupancy >> bitCodingOrder[i]) & 1;
int bitIsPredicted = (mappedOccIsPredicted >> bitCodingOrder[i]) & 1;
int bitPrediction = (mappedOccPrediction >> bitCodingOrder[i]) & 1;
int bitAdjGt0 = (mappedOccAdjGt0 >> bitCodingOrder[i]) & 1;
int bitAdjGt1 = (mappedOccAdjGt1 >> bitCodingOrder[i]) & 1;
int ctxIdxMapIdx = bitIsPredicted + bitPrediction;
int ctxIdxMapIdx =
3 * (bitAdjGt0 + bitAdjGt1) + bitIsPredicted + bitPrediction;
auto& ctxIdxMap = _ctxIdxMaps[ctxIdxMapIdx];
int ctxIdx = ctxIdxMap.evolve(bit, &ctxIdxMap[i][idx]);
......@@ -239,11 +264,14 @@ GeometryOctreeEncoder::encodeOccupancyBitwise(
int neighPattern,
int mappedOccupancy,
int mappedOccIsPredicted,
int mappedOccPrediction)
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1)
{
if (neighPattern == 0) {
encodeOccupancyNeighZ(
mappedOccupancy, mappedOccIsPredicted, mappedOccPrediction);
mappedOccupancy, mappedOccIsPredicted, mappedOccPrediction,
mappedOccAdjGt0, mappedOccAdjGt1);
return;
}
......@@ -251,8 +279,8 @@ GeometryOctreeEncoder::encodeOccupancyBitwise(
// with reduction from 64 states to 10 (or 6).
int neighPatternR1 = _neighPattern64toR1[neighPattern];
encodeOccupancyNeighNZ(
neighPatternR1, mappedOccupancy, mappedOccIsPredicted,
mappedOccPrediction);
neighPatternR1, mappedOccupancy, mappedOccIsPredicted, mappedOccPrediction,
mappedOccAdjGt0, mappedOccAdjGt1);
}
//-------------------------------------------------------------------------
......@@ -274,7 +302,12 @@ GeometryOctreeEncoder::encodeOccupancyBytewise(
void
GeometryOctreeEncoder::encodeOccupancy(
int neighPattern, int occupancy, int occupancyIsPred, int occupancyPred)
int neighPattern,
int occupancy,
int occupancyIsPred,
int occupancyPred,
int occupancyAdjGt0,
int occupancyAdjGt1)
{
if (neighPattern == 0) {
bool singleChild = !popcntGt1(occupancy);
......@@ -292,9 +325,12 @@ GeometryOctreeEncoder::encodeOccupancy(
uint32_t mapOcc = mapGeometryOccupancy(occupancy, neighPattern);
uint32_t mapOccIsP = mapGeometryOccupancy(occupancyIsPred, neighPattern);
uint32_t mapOccP = mapGeometryOccupancy(occupancyPred, neighPattern);
uint32_t mapAdjGt0 = mapGeometryOccupancy(occupancyAdjGt0, neighPattern);
uint32_t mapAdjGt1 = mapGeometryOccupancy(occupancyAdjGt1, neighPattern);
if (_useBitwiseOccupancyCoder)
encodeOccupancyBitwise(neighPattern, mapOcc, mapOccIsP, mapOccP);
encodeOccupancyBitwise(
neighPattern, mapOcc, mapOccIsP, mapOccP, mapAdjGt0, mapAdjGt1);
else
encodeOccupancyBytewise(neighPattern, mapOcc);
}
......@@ -435,13 +471,19 @@ encodeGeometryOctree(
}
}
int occupancyAdjacencyGt0 = 0;
int occupancyAdjacencyGt1 = 0;
if (gps.neighbour_avail_boundary_log2) {
updateGeometryOccupancyAtlas(
node0.pos, nodeSizeLog2, fifo, fifoCurrLvlEnd, &occupancyAtlas,
&occupancyAtlasOrigin);
node0.neighPattern =
GeometryNeighPattern gnp =
makeGeometryNeighPattern(node0.pos, nodeSizeLog2, occupancyAtlas);
node0.neighPattern = gnp.neighPattern;
occupancyAdjacencyGt0 = gnp.adjacencyGt0;
occupancyAdjacencyGt1 = gnp.adjacencyGt1;
}
int occupancyIsPredicted = 0;
......@@ -461,8 +503,8 @@ encodeGeometryOctree(
// encode child occupancy map
assert(occupancy > 0);
encoder.encodeOccupancy(
node0.neighPattern, occupancy, occupancyIsPredicted,
occupancyPrediction);
node0.neighPattern, occupancy, occupancyIsPredicted, occupancyPrediction,
occupancyAdjacencyGt0, occupancyAdjacencyGt1);
// when nodeSizeLog2 == 1, children are indivisible (ie leaf nodes)
// and are immediately coded. No further splitting occurs.
......
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