Commit 05526a18 authored by Toshiyasu Sugio's avatar Toshiyasu Sugio Committed by David Flynn
Browse files

attr/m46108: implement coefficient zero run length coding

This commit introduces zero run length coding for attribute residual
value along with an eq1 flag which indicates if residual value is equal
to 1 based on the current residual coding specification. In zero run
length coding, the number of zeros prior to each residual value is
counted as zerorun, and then zerorun is encoded instead of encoding
sequence of 0s
parent cc990c49
......@@ -53,11 +53,14 @@ struct PCCResidualsDecoder {
AdaptiveBitModel binaryModelDiff[7];
AdaptiveBitModel binaryModelIsZero[7];
AdaptiveBitModel ctxPredMode[2];
AdaptiveBitModel ctxZeroCnt[3];
AdaptiveBitModel binaryModelIsOne[7];
DualLutCoder<false> symbolCoder[2];
void start(const char* buf, int buf_len);
void stop();
int decodePredMode(int max);
int decodeZeroCnt(int max);
uint32_t decodeSymbol(int k1, int k2);
void decode(uint32_t values[3]);
uint32_t decode();
......@@ -103,21 +106,42 @@ PCCResidualsDecoder::decodePredMode(int maxMode)
//----------------------------------------------------------------------------
int
PCCResidualsDecoder::decodeZeroCnt(int maxMode)
{
int mode = 0;
if (maxMode == 0)
return mode;
int ctxIdx = 0;
while (arithmeticDecoder.decode(ctxZeroCnt[ctxIdx])) {
ctxIdx = (ctxIdx == 0 ? 1 : 2);
mode++;
if (mode == maxMode)
break;
}
return mode;
}
//----------------------------------------------------------------------------
uint32_t
PCCResidualsDecoder::decodeSymbol(int k1, int k2)
{
if (arithmeticDecoder.decode(binaryModelIsZero[k1])) {
if (arithmeticDecoder.decode(binaryModelIsZero[k1]))
return 0u;
}
if (arithmeticDecoder.decode(binaryModelIsOne[k1]))
return 1u;
uint32_t value = symbolCoder[k2].decode(&arithmeticDecoder);
if (value == kAttributeResidualAlphabetSize) {
value +=
arithmeticDecoder.decodeExpGolomb(0, binaryModel0, binaryModelDiff[k1]);
}
++value;
return value;
return value + 2;
}
//----------------------------------------------------------------------------
......@@ -130,6 +154,11 @@ PCCResidualsDecoder::decode(uint32_t value[3])
value[1] = decodeSymbol(1 + b0, 1);
int b1 = value[1] == 0;
value[2] = decodeSymbol(3 + (b0 << 1) + b1, 1);
int d = (value[0] == value[1] && value[0] == value[2]);
for (int k = 0; k < 3; k++) {
value[k] += d;
}
}
//----------------------------------------------------------------------------
......@@ -137,7 +166,7 @@ PCCResidualsDecoder::decode(uint32_t value[3])
uint32_t
PCCResidualsDecoder::decode()
{
return decodeSymbol(0, 0);
return decodeSymbol(0, 0) + 1;
}
//============================================================================
......@@ -260,6 +289,7 @@ AttributeDecoder::decodeReflectancesPred(
}
const int64_t maxReflectance = (1ll << desc.attr_bitdepth) - 1;
int zero_cnt = decoder.decodeZeroCnt(pointCount);
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
auto& predictor = predictors[predictorIndex];
......@@ -268,7 +298,13 @@ AttributeDecoder::decodeReflectancesPred(
aps, pointCloud, indexesLOD, predictor, decoder);
const uint32_t pointIndex = indexesLOD[predictorIndex];
uint16_t& reflectance = pointCloud.getReflectance(pointIndex);
const uint32_t attValue0 = decoder.decode();
uint32_t attValue0 = 0;
if (zero_cnt > 0) {
zero_cnt--;
} else {
attValue0 = decoder.decode();
zero_cnt = decoder.decodeZeroCnt(pointCount);
}
const int64_t quantPredAttValue =
predictor.predictReflectance(pointCloud, indexesLOD);
const int64_t delta =
......@@ -349,6 +385,7 @@ AttributeDecoder::decodeColorsPred(
}
uint32_t values[3];
int zero_cnt = decoder.decodeZeroCnt(pointCount);
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
auto& predictor = predictors[predictorIndex];
......@@ -356,7 +393,13 @@ AttributeDecoder::decodeColorsPred(
const int64_t qs2 = qstep[1];
computeColorPredictionWeights(
aps, pointCloud, indexesLOD, predictor, decoder);
if (zero_cnt > 0) {
values[0] = values[1] = values[2] = 0;
zero_cnt--;
} else {
decoder.decode(values);
zero_cnt = decoder.decodeZeroCnt(pointCount);
}
const uint32_t pointIndex = indexesLOD[predictorIndex];
Vec3<uint8_t>& color = pointCloud.getColor(pointIndex);
const Vec3<uint8_t> predictedColor =
......@@ -408,10 +451,16 @@ AttributeDecoder::decodeReflectancesRaht(
// Entropy decode
const int attribCount = 1;
uint32_t value;
int* integerizedAttributes = new int[attribCount * voxelCount];
int zero_cnt = decoder.decodeZeroCnt(voxelCount);
for (int n = 0; n < voxelCount; ++n) {
uint32_t value = 0;
if (zero_cnt > 0) {
zero_cnt--;
} else {
value = decoder.decode();
zero_cnt = decoder.decodeZeroCnt(voxelCount);
}
integerizedAttributes[n] = UIntToInt(value);
}
......@@ -467,11 +516,18 @@ AttributeDecoder::decodeColorsRaht(
// Entropy decode
const int attribCount = 3;
uint32_t values[3];
int zero_cnt = decoder.decodeZeroCnt(voxelCount);
int* integerizedAttributes = new int[attribCount * voxelCount];
for (int n = 0; n < voxelCount; ++n) {
uint32_t values[3];
if (zero_cnt > 0) {
values[0] = values[1] = values[2] = 0;
zero_cnt--;
} else {
decoder.decode(values);
zero_cnt = decoder.decodeZeroCnt(voxelCount);
}
for (int d = 0; d < attribCount; ++d) {
integerizedAttributes[voxelCount * d + n] = UIntToInt(values[d]);
}
......@@ -540,10 +596,17 @@ AttributeDecoder::decodeColorsLift(
std::vector<Vec3<int64_t>> colors;
colors.resize(pointCount);
// decompress
int zero_cnt = decoder.decodeZeroCnt(pointCount);
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
uint32_t values[3];
if (zero_cnt > 0) {
values[0] = values[1] = values[2] = 0;
zero_cnt--;
} else {
decoder.decode(values);
zero_cnt = decoder.decodeZeroCnt(pointCount);
}
const int64_t qs = qstep[0] << (kFixedPointWeightShift / 2);
const int64_t qs2 = qstep[1] << (kFixedPointWeightShift / 2);
// + kFixedPointAttributeShift ???
......@@ -617,9 +680,16 @@ AttributeDecoder::decodeReflectancesLift(
reflectances.resize(pointCount);
// decompress
int zero_cnt = decoder.decodeZeroCnt(pointCount);
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
const int64_t detail = decoder.decode();
int64_t detail = 0;
if (zero_cnt > 0) {
zero_cnt--;
} else {
detail = decoder.decode();
zero_cnt = decoder.decodeZeroCnt(pointCount);
}
const int64_t qs = qstep[0] << (kFixedPointWeightShift / 2);
const int64_t quantWeight = weights[predictorIndex];
auto& reflectance = reflectances[predictorIndex];
......
......@@ -57,11 +57,14 @@ struct PCCResidualsEncoder {
AdaptiveBitModel binaryModelDiff[7];
AdaptiveBitModel binaryModelIsZero[7];
AdaptiveBitModel ctxPredMode[2];
AdaptiveBitModel ctxZeroCnt[3];
AdaptiveBitModel binaryModelIsOne[7];
DualLutCoder<false> symbolCoder[2];
void start(int numPoints);
int stop();
void encodePredMode(int value, int max);
void encodeZeroCnt(int value, int max);
void encodeSymbol(uint32_t value, int k1, int k2);
void encode(uint32_t value0, uint32_t value1, uint32_t value2);
void encode(uint32_t value);
......@@ -108,6 +111,26 @@ PCCResidualsEncoder::encodePredMode(int mode, int maxMode)
//----------------------------------------------------------------------------
void
PCCResidualsEncoder::encodeZeroCnt(int mode, int maxMode)
{
// max = 0 => no direct predictors are used
if (maxMode == 0)
return;
int ctxIdx = 0;
for (int i = 0; i < mode; i++) {
arithmeticEncoder.encode(1, ctxZeroCnt[ctxIdx]);
ctxIdx = (ctxIdx == 0 ? 1 : 2);
}
// Truncated unary
if (mode != maxMode)
arithmeticEncoder.encode(0, ctxZeroCnt[ctxIdx]);
}
//----------------------------------------------------------------------------
void
PCCResidualsEncoder::encodeSymbol(uint32_t value, int k1, int k2)
{
......@@ -116,7 +139,14 @@ PCCResidualsEncoder::encodeSymbol(uint32_t value, int k1, int k2)
if (isZero) {
return;
}
--value;
bool isOne = value == 1;
arithmeticEncoder.encode(isOne, binaryModelIsOne[k1]);
if (isOne) {
return;
}
value -= 2;
if (value < kAttributeResidualAlphabetSize) {
symbolCoder[k2].encode(value, &arithmeticEncoder);
} else {
......@@ -132,6 +162,12 @@ PCCResidualsEncoder::encodeSymbol(uint32_t value, int k1, int k2)
void
PCCResidualsEncoder::encode(uint32_t value0, uint32_t value1, uint32_t value2)
{
if (value0 == value1 && value0 == value2) {
value0--;
value1--;
value2--;
}
int b0 = value0 == 0;
int b1 = value1 == 0;
encodeSymbol(value0, 0, 0);
......@@ -144,7 +180,7 @@ PCCResidualsEncoder::encode(uint32_t value0, uint32_t value1, uint32_t value2)
void
PCCResidualsEncoder::encode(uint32_t value)
{
encodeSymbol(value, 0, 0);
encodeSymbol(value - 1, 0, 0);
}
//============================================================================
......@@ -371,6 +407,7 @@ AttributeEncoder::computeReflectancePredictionWeights(
const int64_t qs)
{
predictor.computeWeights();
predictor.maxDiff = -1;
if (predictor.neighborCount > 1) {
int64_t minValue = 0;
int64_t maxValue = 0;
......@@ -385,6 +422,7 @@ AttributeEncoder::computeReflectancePredictionWeights(
}
}
const int64_t maxDiff = maxValue - minValue;
predictor.maxDiff = maxDiff;
if (maxDiff > aps.adaptive_prediction_threshold) {
uint64_t attrValue =
pointCloud.getReflectance(indexesLOD[predictorIndex]);
......@@ -418,9 +456,6 @@ AttributeEncoder::computeReflectancePredictionWeights(
// with reconstruction.
}
}
encoder.encodePredMode(
predictor.predMode, aps.max_num_direct_predictors);
}
}
}
......@@ -460,6 +495,12 @@ AttributeEncoder::encodeReflectancesPred(
const int64_t clipMax = (1ll << desc.attr_bitdepth) - 1;
PCCResidualsEntropyEstimator context;
int zero_cnt = 0;
std::vector<int> zerorun;
zerorun.reserve(pointCount);
std::vector<uint32_t> residual;
residual.resize(pointCount);
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
auto& predictor = predictors[predictorIndex];
......@@ -483,9 +524,37 @@ AttributeEncoder::encodeReflectancesPred(
const uint16_t reconstructedReflectance =
uint16_t(PCCClip(reconstructedQuantAttValue, int64_t(0), clipMax));
encoder.encode(attValue0);
if (!attValue0)
++zero_cnt;
else {
zerorun.push_back(zero_cnt);
zero_cnt = 0;
}
residual[predictorIndex] = attValue0;
pointCloud.setReflectance(pointIndex, reconstructedReflectance);
}
zerorun.push_back(zero_cnt);
int run_index = 0;
encoder.encodeZeroCnt(zerorun[run_index], pointCount);
zero_cnt = zerorun[run_index++];
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
auto& predictor = predictors[predictorIndex];
if (predictor.maxDiff > aps.adaptive_prediction_threshold) {
encoder.encodePredMode(
predictor.predMode, aps.max_num_direct_predictors);
}
if (zero_cnt > 0)
zero_cnt--;
else {
encoder.encode(residual[predictorIndex]);
if (predictorIndex != pointCount - 1)
encoder.encodeZeroCnt(zerorun[run_index], pointCount);
zero_cnt = zerorun[run_index++];
}
}
}
//----------------------------------------------------------------------------
......@@ -528,6 +597,7 @@ AttributeEncoder::computeColorPredictionWeights(
const int64_t qs2)
{
predictor.computeWeights();
predictor.maxDiff = -1;
if (predictor.neighborCount > 1) {
int64_t minValue[3] = {0, 0, 0};
int64_t maxValue[3] = {0, 0, 0};
......@@ -546,6 +616,8 @@ AttributeEncoder::computeColorPredictionWeights(
const int64_t maxDiff = (std::max)(
maxValue[2] - minValue[2],
(std::max)(maxValue[0] - minValue[0], maxValue[1] - minValue[1]));
predictor.maxDiff = maxDiff;
if (maxDiff > aps.adaptive_prediction_threshold) {
Vec3<uint8_t> attrValue =
pointCloud.getColor(indexesLOD[predictorIndex]);
......@@ -581,9 +653,6 @@ AttributeEncoder::computeColorPredictionWeights(
// with reconstruction.
}
}
encoder.encodePredMode(
predictor.predMode, aps.max_num_direct_predictors);
}
}
}
......@@ -624,6 +693,14 @@ AttributeEncoder::encodeColorsPred(
const int64_t clipMax = (1ll << desc.attr_bitdepth) - 1;
uint32_t values[3];
PCCResidualsEntropyEstimator context;
int zero_cnt = 0;
std::vector<int> zerorun;
std::vector<uint32_t> residual[3];
for (int i = 0; i < 3; i++) {
residual[i].resize(pointCount);
}
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
auto& predictor = predictors[predictorIndex];
......@@ -661,7 +738,41 @@ AttributeEncoder::encodeColorsPred(
uint8_t(PCCClip(reconstructedQuantAttValue, int64_t(0), clipMax));
}
pointCloud.setColor(pointIndex, reconstructedColor);
if (!values[0] && !values[1] && !values[2]) {
++zero_cnt;
} else {
zerorun.push_back(zero_cnt);
zero_cnt = 0;
}
for (int i = 0; i < 3; i++) {
residual[i][predictorIndex] = values[i];
}
}
zerorun.push_back(zero_cnt);
int run_index = 0;
encoder.encodeZeroCnt(zerorun[run_index], pointCount);
zero_cnt = zerorun[run_index++];
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
auto& predictor = predictors[predictorIndex];
if (predictor.maxDiff > aps.adaptive_prediction_threshold) {
encoder.encodePredMode(
predictor.predMode, aps.max_num_direct_predictors);
}
if (zero_cnt > 0)
zero_cnt--;
else {
for (size_t k = 0; k < 3; k++)
values[k] = residual[k][predictorIndex];
encoder.encode(values[0], values[1], values[2]);
if (predictorIndex != pointCount - 1)
encoder.encodeZeroCnt(zerorun[run_index], pointCount);
zero_cnt = zerorun[run_index++];
}
}
}
......@@ -705,13 +816,21 @@ AttributeEncoder::encodeReflectancesTransformRaht(
attribCount, voxelCount, integerizedAttributes);
// Entropy encode.
int zero_cnt = 0;
uint32_t value;
for (int n = 0; n < voxelCount; ++n) {
const int64_t detail = IntToUInt(integerizedAttributes[n]);
assert(detail < std::numeric_limits<uint32_t>::max());
value = uint32_t(detail);
if (!value)
++zero_cnt;
else {
encoder.encodeZeroCnt(zero_cnt, voxelCount);
encoder.encode(value);
zero_cnt = 0;
}
}
encoder.encodeZeroCnt(zero_cnt, voxelCount);
// local decode
std::fill_n(attributes, attribCount * voxelCount, FixedPoint(0));
......@@ -784,6 +903,7 @@ AttributeEncoder::encodeColorsTransformRaht(
// Entropy encode.
uint32_t values[attribCount];
int zero_cnt = 0;
for (int n = 0; n < voxelCount; ++n) {
for (int d = 0; d < attribCount; ++d) {
const int64_t detail =
......@@ -791,9 +911,17 @@ AttributeEncoder::encodeColorsTransformRaht(
assert(detail < std::numeric_limits<uint32_t>::max());
values[d] = uint32_t(detail);
}
if (!values[0] && !values[1] && !values[2])
++zero_cnt;
else {
encoder.encodeZeroCnt(zero_cnt, voxelCount);
encoder.encode(values[0], values[1], values[2]);
zero_cnt = 0;
}
}
encoder.encodeZeroCnt(zero_cnt, voxelCount);
// local decode
std::fill_n(attributes, attribCount * voxelCount, FixedPoint(0));
for (int n = 0; n < voxelCount; n++) {
......@@ -824,7 +952,6 @@ AttributeEncoder::encodeColorsTransformRaht(
delete[] integerizedAttributes;
delete[] weight;
}
//----------------------------------------------------------------------------
void
......@@ -878,6 +1005,7 @@ AttributeEncoder::encodeColorsLift(
}
// compress
int zero_cnt = 0;
const int64_t qs = qstep[0] << (kFixedPointWeightShift / 2);
const size_t qs2 = qstep[1] << (kFixedPointWeightShift / 2);
for (size_t predictorIndex = 0; predictorIndex < pointCount;
......@@ -899,8 +1027,15 @@ AttributeEncoder::encodeColorsLift(
color[d] = reconstructedDelta / quantWeight;
values[d] = uint32_t(detail);
}
if (!values[0] && !values[1] && !values[2])
++zero_cnt;
else {
encoder.encodeZeroCnt(zero_cnt, pointCount);
encoder.encode(values[0], values[1], values[2]);
zero_cnt = 0;
}
}
encoder.encodeZeroCnt(zero_cnt, pointCount);
// reconstruct
for (size_t lodIndex = 1; lodIndex < lodCount; ++lodIndex) {
......@@ -975,6 +1110,7 @@ AttributeEncoder::encodeReflectancesLift(
}
// compress
int zero_cnt = 0;
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
const int64_t qs = qstep[0] << (kFixedPointWeightShift / 2);
......@@ -985,8 +1121,15 @@ AttributeEncoder::encodeReflectancesLift(
assert(detail < std::numeric_limits<uint32_t>::max());
const int64_t reconstructedDelta = PCCInverseQuantization(delta, qs);
reflectance = reconstructedDelta / quantWeight;
if (!detail)
++zero_cnt;
else {
encoder.encodeZeroCnt(zero_cnt, pointCount);
encoder.encode(detail);
zero_cnt = 0;
}
}
encoder.encodeZeroCnt(zero_cnt, pointCount);
// reconstruct
for (size_t lodIndex = 1; lodIndex < lodCount; ++lodIndex) {
......
......@@ -101,6 +101,7 @@ struct PCCPredictor {
uint32_t neighborCount;
PCCNeighborInfo neighbors[kAttributePredictionMaxNeighbourCount];
int8_t predMode;
int64_t maxDiff;
Vec3<uint8_t> predictColor(
const PCCPointSet3& pointCloud, const std::vector<uint32_t>& indexes) const
......
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