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:
- intra_pred_max_node_size_log2: 6
- 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)
# - use lifting transform for lossy conditions
......
......@@ -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 }'
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)
# - skip attribute coding if dist2 parameters are not defined
......
......@@ -17,6 +17,13 @@ categories:
- neighbourAvailBoundaryLog2: 8
- 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)
# - skip attribute coding if dist2 parameters are not defined
......
......@@ -17,6 +17,13 @@ categories:
- neighbourAvailBoundaryLog2: 8
- 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)
# - code directly GBR (no need to perform colourspace conversion)
......
......@@ -16,6 +16,13 @@ categories:
- intra_pred_max_node_size_log2: 6
- 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)
# - uses raht transform
......
......@@ -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 }'
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)
# - use raht
......
......@@ -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
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`
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.
......
......@@ -44,6 +44,7 @@ namespace pcc {
void
updateGeometryOccupancyAtlas(
const Vec3<uint32_t>& currentPosition,
const int atlasShift,
const pcc::ringbuf<PCCOctree3Node>& fifo,
const pcc::ringbuf<PCCOctree3Node>::iterator& fifoCurrLvlEnd,
MortonMap3D* occupancyAtlas,
......@@ -51,6 +52,10 @@ updateGeometryOccupancyAtlas(
{
const uint32_t mask = (1 << occupancyAtlas->cubeSizeLog2()) - 1;
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;
// only refresh the atlas if the current position lies outside the
......@@ -65,10 +70,9 @@ updateGeometryOccupancyAtlas(
for (auto it = fifo.begin(); it != fifoCurrLvlEnd; ++it) {
if (currentOrigin != it->pos >> shift)
break;
const uint32_t x = it->pos[0] & mask;
const uint32_t y = it->pos[1] & mask;
const uint32_t z = it->pos[2] & mask;
const uint32_t x = (it->pos[0] & mask) >> shiftX;
const uint32_t y = (it->pos[1] & mask) >> shiftY;
const uint32_t z = (it->pos[2] & mask) >> shiftZ;
occupancyAtlas->setByte(x, y, z, it->siblingOccupancy);
}
}
......@@ -138,6 +142,7 @@ GeometryNeighPattern
makeGeometryNeighPattern(
bool adjacent_child_contextualization_enabled_flag,
const Vec3<uint32_t>& position,
const int atlasShift,
const MortonMap3D& occupancyAtlas)
{
const int mask = occupancyAtlas.cubeSize() - 1;
......@@ -146,6 +151,7 @@ makeGeometryNeighPattern(
const int32_t y = position[1] & mask;
const int32_t z = position[2] & mask;
uint8_t neighPattern;
if (atlasShift == 0) {
if (
x > 0 && x < cubeSizeMinusOne && y > 0 && y < cubeSizeMinusOne && z > 0
&& z < cubeSizeMinusOne) {
......@@ -163,6 +169,40 @@ makeGeometryNeighPattern(
neighPattern |= occupancyAtlas.getWithCheck(x, y, z - 1) << 4;
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
// sized neighbours of the given node.
......
......@@ -62,7 +62,7 @@ public:
const uint32_t halfCubeSizeLog2 = cubeSizeLog2 ? cubeSizeLog2 - 1 : 0;
_cubeSizeLog2 = cubeSizeLog2;
_cubeSize = 1 << cubeSizeLog2;
_bufferSizeInBytes = 1 << (3 * halfCubeSizeLog2);
_bufferSizeInBytes = 1 << (3 * cubeSizeLog2);
_buffer.reset(new uint8_t[_bufferSizeInBytes]);
_childOccupancy.reset(new uint8_t[_bufferSizeInBytes << 3]);
_updates.reserve(1 << 16);
......@@ -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
{
assert(
x >= 0 && y >= 0 && z >= 0 && x < _cubeSize && y < _cubeSize
&& z < _cubeSize);
return (_buffer[getByteIndex(x, y, z)] >> getBitIndex(x, y, z)) & 1;
return _buffer[getByteIndex(x, y, z)] & 1;
}
uint32_t
......@@ -119,13 +151,12 @@ public:
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 childOccupancy =
_childOccupancy[getByteIndex(x << 1, y << 1, z << 1)];
uint8_t childOccupancy = _childOccupancy[getByteIndex(x, y, z)];
return childOccupancy;
}
......@@ -138,8 +169,7 @@ private:
uint32_t
getByteIndex(const int32_t x, const int32_t y, const int32_t z) const
{
return kMortonCode256X[x >> 1] | kMortonCode256Y[y >> 1]
| kMortonCode256Z[z >> 1];
return kMortonCode256X[x] | kMortonCode256Y[y] | kMortonCode256Z[z];
}
int _cubeSize = 0;
......@@ -177,12 +207,14 @@ struct GeometryNeighPattern {
GeometryNeighPattern makeGeometryNeighPattern(
bool adjacent_child_contextualization_enabled_flag,
const Vec3<uint32_t>& currentPosition,
const int atlasShift,
const MortonMap3D& occupancyAtlas);
// populate (if necessary) the occupancy atlas with occupancy information
// from @fifo.
void updateGeometryOccupancyAtlas(
const Vec3<uint32_t>& position,
const int atlasShift,
const ringbuf<PCCOctree3Node>& fifo,
const ringbuf<PCCOctree3Node>::iterator& fifoCurrLvlEnd,
MortonMap3D* occupancyAtlas,
......
......@@ -46,6 +46,8 @@
#include "PCCMisc.h"
#include "tables.h"
#include <algorithm>
namespace pcc {
/// Vector dim 3
template<typename T>
......
......@@ -506,6 +506,18 @@ ParseParameters(int argc, char* argv[], Parameters& params)
(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
("bitwiseOccupancyCoding",
params.encoder.gps.bitwise_occupancy_coding_flag, true,
......
......@@ -451,13 +451,6 @@ void
PCCTMC3Encoder3::encodeGeometryBrick(
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;
gbh.geom_geom_parameter_set_id = _gps->gps_geom_parameter_set_id;
gbh.geom_slice_id = _sliceId;
......@@ -465,7 +458,19 @@ PCCTMC3Encoder3::encodeGeometryBrick(
gbh.frame_idx = _frameCounter & ((1 << _sps->log2_max_frame_idx) - 1);
gbh.geomBoxOrigin = _sliceOrigin;
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_slice_qp_offset = params->gbh.geom_slice_qp_offset;
gbh.geom_octree_qp_offset_enabled_flag =
......
......@@ -63,6 +63,7 @@ void
predictGeometryOccupancyIntra(
const MortonMap3D& occupancyAtlas,
Vec3<uint32_t> pos,
const int atlasShift,
int* occupancyIsPredicted,
int* occupancyPrediction)
{
......@@ -75,7 +76,7 @@ predictGeometryOccupancyIntra(
int numOccupied = 0;
const int8_t* p = &LUT_dist[0][0];
if (atlasShift == 0) {
for (int dx = -1; dx <= 1; dx++) {
for (int dy = -1; dy <= 1; dy++) {
for (int dz = -1; dz <= 1; dz++) {
......@@ -85,6 +86,34 @@ predictGeometryOccupancyIntra(
// todo(df): remove unnecessary checks
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) {
for (int i = 0; i < 8; i++)
score[i] += LUT1[p[i]];
......@@ -99,6 +128,7 @@ predictGeometryOccupancyIntra(
}
}
}
}
if (numOccupied <= 8) {
*occupancyIsPredicted = 0;
......
......@@ -47,6 +47,7 @@ namespace pcc {
void predictGeometryOccupancyIntra(
const MortonMap3D& occupancyAtlas,
Vec3<uint32_t> pos,
const int atlasShift,
int* occupacyIsPredIntra,
int* occupacyPredIntra);
......
......@@ -114,6 +114,18 @@ void decodeGeometryOctree(
EntropyDecoder* arithmeticDecoder,
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)
{
return sizeLog2[0] <= 0 && sizeLog2[1] <= 0 && sizeLog2[2] <= 0;
}
//---------------------------------------------------------------------------
// Determine if direct coding is permitted.
// If tool is enabled:
......@@ -206,4 +218,88 @@ CtxMapOctreeOccupancy::evolve(bool bit, uint8_t* ctxIdx)
//---------------------------------------------------------------------------
inline Vec3<int>
implicitQtBtDecision(
Vec3<int> nodeSizeLog2,
int maxNumImplicitQtbtBeforeOt,
int minDepthImplicitQtbt)
{
int nodeMinDimLog2 =
std::min({nodeSizeLog2[0], nodeSizeLog2[1], nodeSizeLog2[2]});
if (maxNumImplicitQtbtBeforeOt || nodeMinDimLog2 == minDepthImplicitQtbt) {
// implicit qt bt
int nodeMaxDimLog2 =
std::max({nodeSizeLog2[0], nodeSizeLog2[1], nodeSizeLog2[2]});
for (int k = 0; k < 3; k++) {
if (nodeSizeLog2[k] == nodeMaxDimLog2)
nodeSizeLog2[k]--;
}
} else // octree partition
nodeSizeLog2 = nodeSizeLog2 - 1;
return nodeSizeLog2;
}
//---------------------------------------------------------------------------
inline void
updateImplicitQtBtParameters(
const Vec3<int>& nodeSizeLog2,
int trisoup_node_size_log2,
int* maxNumImplicitQtbtBeforeOt,
int* minSizeImplicitQtbt)
{
int nodeMinDimLog2 =
std::min({nodeSizeLog2[0], nodeSizeLog2[1], nodeSizeLog2[2]});
int nodeMaxDimLog2 =
std::max({nodeSizeLog2[0], nodeSizeLog2[1], nodeSizeLog2[2]});
// max number of implicit qtbt before ot is bounded by difference between
// max and min node size
if (*maxNumImplicitQtbtBeforeOt > (nodeMaxDimLog2 - nodeMinDimLog2))
*maxNumImplicitQtbtBeforeOt = nodeMaxDimLog2 - nodeMinDimLog2;
// min depth of implicit qtbt is bounded by min node size
if (*minSizeImplicitQtbt > nodeMinDimLog2)
*minSizeImplicitQtbt = nodeMinDimLog2;
// if all dimensions have same size, min depth of implicit qtbt should be 0
if (nodeMaxDimLog2 == nodeMinDimLog2) {
*minSizeImplicitQtbt = 0;
}
// if trisoup is enabled, perform qtbt first before ot
if (trisoup_node_size_log2 != 0) {
*maxNumImplicitQtbtBeforeOt = nodeMaxDimLog2 - nodeMinDimLog2;
*minSizeImplicitQtbt = 0;
}
}
//---------------------------------------------------------------------------
inline Vec3<int>
qtBtChildSize(const Vec3<int>& nodeSizeLog2, const Vec3<int>& childSizeLog2)
{
Vec3<int> bitpos = 0;
for (int k = 0; k < 3; k++) {
if (childSizeLog2[k] != nodeSizeLog2[k])
bitpos[k] = 1 << childSizeLog2[k];
}
return bitpos;
}
//---------------------------------------------------------------------------
inline int
nonSplitQtBtAxes(const Vec3<int>& nodeSizeLog2, const Vec3<int>& childSizeLog2)
{
int indicator = 0;
for (int k = 0; k < 3; k++) {
indicator <<= 1;
indicator |= nodeSizeLog2[k] == childSizeLog2[k];
}
return indicator;
}
//---------------------------------------------------------------------------
} // namespace pcc
......@@ -61,7 +61,8 @@ public:
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1,
int mappedOccAdjUnocc);
int mappedOccAdjUnocc,
int occupancySkip);
int decodeOccupancyNeighNZ(
int neighPattern,
......@@ -69,7 +70,8 @@ public:
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1,
int mappedOccAdjUnocc);
int mappedOccAdjUnocc,
int occupancySkip);
int decodeOccupancyBitwise(
int neighPattern,
......@@ -77,7 +79,8 @@ public:
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1,
int mappedOccAdjUnocc);
int mappedOccAdjUnocc,
int occupancySkip);
int decodeOccupancyBytewise(int neighPattern);
......@@ -87,15 +90,18 @@ public:
int occupancyPrediction,
int occupancyAdjGt0,
int occupancyAdjGt1,
int occupancyAdjUncc);
int occupancyAdjUncc,
int occupancySkip);
Vec3<uint32_t> decodePointPosition(int nodeSizeLog2);
Vec3<uint32_t> decodePointPosition(const Vec3<int>& nodeSizeLog2);
int decodeQpOffset();
template<class OutputIt>
int decodeDirectPosition(
int nodeSizeLog2, const PCCOctree3Node& node, OutputIt outputPoints);
const Vec3<int>& nodeSizeLog2,
const PCCOctree3Node& node,
OutputIt outputPoints);
private:
// selects between the bitwise and bytewise occupancy coders
......@@ -174,13 +180,27 @@ GeometryOctreeDecoder::decodeOccupancyNeighZ(
int mappedOccPrediction,
int mappedOccAdjGt0,
int mappedOccAdjGt1,
int mappedOccAdjUnocc)
int mappedOccAdjUnocc,
int occupancySkip)
{
int minOccupied = 2;
int numOccupiedAcc = 0;
int occupancy = 0;
int numCoded = 0;