Commit 8a13140f authored by David Flynn's avatar David Flynn
Browse files

m43387/hls: encode attribute bitdepth

This commit allows the attribute codec to be parametrised by attribute
bitdepth.  The attribute bitdepth is signalled in the attribute's sequence
parameter set description.  The specified bitdepth affects cliping in the
attribute prediction and reconstruction process.
parent 9af74b63
......@@ -17,6 +17,7 @@ categories:
r02: 16
r03: 8
r04: 4
- bitdepth: 8
- attribute: color
# geomstepsize -> default
# translation -> default
......
......@@ -22,6 +22,7 @@ categories:
r04: 8
r05: 4
r06: 1
- bitdepth: 8
- attribute: color
# geomstepsize -> default
# translation -> default
......
......@@ -32,16 +32,19 @@ categories:
- dist2: 134217728 33554432 8388608 2097152 524288 131072 32768 8192 0
- quantizationStepsLuma: 0 0 0 0 0 0 0 0 0
- quantizationStepsChroma: 0 0 0 0 0 0 0 0 0
- bitdepth: 8
- attribute: color
overpass_q1mm:
encflags:
- *mitsubishiLosslessAttrs
- bitdepth: 8
- attribute: color
tollbooth_q1mm:
encflags:
- *mitsubishiLosslessAttrs
- bitdepth: 8
- attribute: color
##
......@@ -65,16 +68,19 @@ categories:
citytunnel_q1mm:
encflags:
- *mitsubishiLosslessAttrs
- bitdepth: 16
- attribute: reflectance
overpass_q1mm:
encflags:
- *mitsubishiLosslessAttrs
- bitdepth: 16
- attribute: reflectance
tollbooth_q1mm:
encflags:
- *mitsubishiLosslessAttrs
- bitdepth: 16
- attribute: reflectance
ford_03_q1mm:
......@@ -84,14 +90,17 @@ categories:
- levelOfDetailCount: 6
- dist2: 4194301 1048582 262149 65534 16383 0
- quantizationStepsLuma: 0 0 0 0 0 0
- bitdepth: 8
- attribute: reflectance
ford_02_q1mm:
encflags:
- *fordLosslessAttrs
- bitdepth: 8
- attribute: reflectance
ford_01_q1mm:
encflags:
- *fordLosslessAttrs
- bitdepth: 8
- attribute: reflectance
......@@ -45,6 +45,7 @@ categories:
r04: 1 2 4 8 8 8 16 16 16
r05: 1 2 4 4 4 4 4 8 8
r06: 0 1 1 1 2 2 2 2 2
- bitdepth: 8
- attribute: color
tollbooth_q1mm:
......@@ -64,6 +65,7 @@ categories:
r04: 1 2 4 8 8 8 8 10 16
r05: 1 2 4 4 4 4 4 4 6
r06: 0 0 0 0 0 0 1 1 2
- bitdepth: 8
- attribute: color
##
......@@ -95,6 +97,7 @@ categories:
r04: 10 20 40 80 160 320 640 1280 2560
r05: 2 5 10 20 40 80 160 320 640
r06: 0 1 2 4 8 16 16 32 32
- bitdepth: 16
- attribute: reflectance
tollbooth_q1mm:
......@@ -107,4 +110,5 @@ categories:
r04: 17 33 67 133 267 533 1067 2133 4267
r05: 4 8 16 32 64 128 256 512 1024
r06: 1 2 4 8 16 32 32 32 32
- bitdepth: 16
- attribute: reflectance
......@@ -43,16 +43,19 @@ categories:
r03: 8 8 8 8 8 8 8 8 8
r04: 16 16 16 16 16 16 16 16 16
r05: 32 32 32 32 32 32 32 32 32
- bitdepth: 8
- attribute: color
overpass_q1mm:
encflags:
- *mitsubishiNearlosslessAttrs
- bitdepth: 8
- attribute: color
tollbooth_q1mm:
encflags:
- *mitsubishiNearlosslessAttrs
- bitdepth: 8
- attribute: color
##
......@@ -77,16 +80,19 @@ categories:
citytunnel_q1mm:
encflags:
- *mitsubishiNearlosslessAttrs
- bitdepth: 16
- attribute: reflectance
overpass_q1mm:
encflags:
- *mitsubishiNearlosslessAttrs
- bitdepth: 16
- attribute: reflectance
tollbooth_q1mm:
encflags:
- *mitsubishiNearlosslessAttrs
- bitdepth: 16
- attribute: reflectance
ford_03_q1mm:
......@@ -101,14 +107,17 @@ categories:
r03: 8 8 8 8 8 8
r04: 16 16 16 16 16 16
r05: 32 32 32 32 32 32
- bitdepth: 8
- attribute: reflectance
ford_02_q1mm:
encflags:
- *fordNearlosslessAttrs
- bitdepth: 8
- attribute: reflectance
ford_01_q1mm:
encflags:
- *fordNearlosslessAttrs
- bitdepth: 8
- attribute: reflectance
......@@ -47,6 +47,7 @@ categories:
r04: 0 1 2 4 4 4
r05: 0 1 2 4 4 4
r06: 0 1 2 4 4 4
- bitdepth: 8
- attribute: reflectance
ford_02_q1mm:
......
......@@ -141,29 +141,29 @@ AttributeDecoder::decode(
if (attr_desc.attr_count == 1) {
switch (attr_aps.attr_encoding) {
case AttributeEncoding::kRAHTransform:
decodeReflectancesRaht(attr_aps, decoder, pointCloud);
decodeReflectancesRaht(attr_desc, attr_aps, decoder, pointCloud);
break;
case AttributeEncoding::kPredictingTransform:
decodeReflectancesPred(attr_aps, decoder, pointCloud);
decodeReflectancesPred(attr_desc, attr_aps, decoder, pointCloud);
break;
case AttributeEncoding::kLiftingTransform:
decodeReflectancesLift(attr_aps, decoder, pointCloud);
decodeReflectancesLift(attr_desc, attr_aps, decoder, pointCloud);
break;
}
} else if (attr_desc.attr_count == 3) {
switch (attr_aps.attr_encoding) {
case AttributeEncoding::kRAHTransform:
decodeColorsRaht(attr_aps, decoder, pointCloud);
decodeColorsRaht(attr_desc, attr_aps, decoder, pointCloud);
break;
case AttributeEncoding::kPredictingTransform:
decodeColorsPred(attr_aps, decoder, pointCloud);
decodeColorsPred(attr_desc, attr_aps, decoder, pointCloud);
break;
case AttributeEncoding::kLiftingTransform:
decodeColorsLift(attr_aps, decoder, pointCloud);
decodeColorsLift(attr_desc, attr_aps, decoder, pointCloud);
break;
}
} else {
......@@ -213,6 +213,7 @@ computeReflectancePredictionWeights(
void
AttributeDecoder::decodeReflectancesPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud)
......@@ -227,8 +228,8 @@ AttributeDecoder::decodeReflectancesPred(
pointCloud, numberOfPointsPerLOD, indexesLOD,
aps.num_pred_nearest_neighbours, predictors);
const size_t pointCount = pointCloud.getPointCount();
const int64_t threshold = 16384;
const int64_t maxReflectance = std::numeric_limits<uint16_t>::max();
const int64_t maxReflectance = (1ll << desc.attr_bitdepth) - 1;
const int64_t threshold = 1ll << (desc.attr_bitdepth - 2);
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
auto& predictor = predictors[predictorIndex];
......@@ -292,6 +293,7 @@ AttributeDecoder::computeColorPredictionWeights(
void
AttributeDecoder::decodeColorsPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud)
......@@ -305,7 +307,7 @@ AttributeDecoder::decodeColorsPred(
PCCComputePredictors2(
pointCloud, numberOfPointsPerLOD, indexesLOD,
aps.num_pred_nearest_neighbours, predictors);
const int64_t threshold = 64;
const int64_t threshold = 1ll << (desc.attr_bitdepth - 2);
const size_t pointCount = pointCloud.getPointCount();
uint32_t values[3];
for (size_t predictorIndex = 0; predictorIndex < pointCount;
......@@ -326,15 +328,17 @@ AttributeDecoder::decodeColorsPred(
const int64_t delta =
PCCInverseQuantization(o3dgc::UIntToInt(values[0]), qs);
const int64_t reconstructedQuantAttValue = quantPredAttValue + delta;
int64_t clipMax = (1 << desc.attr_bitdepth) - 1;
color[0] =
uint8_t(PCCClip(reconstructedQuantAttValue, int64_t(0), int64_t(255)));
uint8_t(PCCClip(reconstructedQuantAttValue, int64_t(0), clipMax));
for (size_t k = 1; k < 3; ++k) {
const int64_t quantPredAttValue = predictedColor[k];
const int64_t delta =
PCCInverseQuantization(o3dgc::UIntToInt(values[k]), qs2);
const int64_t reconstructedQuantAttValue = quantPredAttValue + delta;
color[k] =
uint8_t(PCCClip(reconstructedQuantAttValue, int64_t(0), int64_t(255)));
uint8_t(PCCClip(reconstructedQuantAttValue, int64_t(0), clipMax));
}
}
}
......@@ -343,6 +347,7 @@ AttributeDecoder::decodeColorsPred(
void
AttributeDecoder::decodeReflectancesRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud)
......@@ -409,7 +414,7 @@ AttributeDecoder::decodeReflectancesRaht(
regionAdaptiveHierarchicalInverseTransform(
mortonCode, attributes, 1, voxelCount, aps.raht_depth);
const int maxReflectance = std::numeric_limits<uint16_t>::max();
const int maxReflectance = (1 << desc.attr_bitdepth) - 1;
const int minReflectance = 0;
for (int n = 0; n < voxelCount; n++) {
const int reflectance =
......@@ -430,6 +435,7 @@ AttributeDecoder::decodeReflectancesRaht(
void
AttributeDecoder::decodeColorsRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud)
......@@ -515,14 +521,15 @@ AttributeDecoder::decodeColorsRaht(
regionAdaptiveHierarchicalInverseTransform(
mortonCode, attributes, attribCount, voxelCount, aps.raht_depth);
const int clipMax = (1 << desc.attr_bitdepth) - 1;
for (int n = 0; n < voxelCount; n++) {
const int r = (int)round(attributes[attribCount * n]);
const int g = (int)round(attributes[attribCount * n + 1]);
const int b = (int)round(attributes[attribCount * n + 2]);
PCCColor3B color;
color[0] = uint8_t(PCCClip(r, 0, 255));
color[1] = uint8_t(PCCClip(g, 0, 255));
color[2] = uint8_t(PCCClip(b, 0, 255));
color[0] = uint8_t(PCCClip(r, 0, clipMax));
color[1] = uint8_t(PCCClip(g, 0, clipMax));
color[2] = uint8_t(PCCClip(b, 0, clipMax));
pointCloud.setColor(packedVoxel[n].index, color);
}
......@@ -539,6 +546,7 @@ AttributeDecoder::decodeColorsRaht(
void
AttributeDecoder::decodeColorsLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud)
......@@ -591,11 +599,13 @@ AttributeDecoder::decodeColorsLift(
PCCLiftUpdate(predictors, weights, startIndex, endIndex, false, colors);
PCCLiftPredict(predictors, startIndex, endIndex, false, colors);
}
const double clipMax = (1 << desc.attr_bitdepth) - 1;
for (size_t f = 0; f < pointCount; ++f) {
const auto& predictor = predictors[f];
PCCColor3B color;
for (size_t d = 0; d < 3; ++d) {
color[d] = uint8_t(PCCClip(std::round(colors[f][d]), 0.0, 255.0));
color[d] = uint8_t(PCCClip(std::round(colors[f][d]), 0.0, clipMax));
}
pointCloud.setColor(predictor.index, color);
}
......@@ -605,6 +615,7 @@ AttributeDecoder::decodeColorsLift(
void
AttributeDecoder::decodeReflectancesLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud)
......@@ -657,7 +668,7 @@ AttributeDecoder::decodeReflectancesLift(
predictors, weights, startIndex, endIndex, false, reflectances);
PCCLiftPredict(predictors, startIndex, endIndex, false, reflectances);
}
const double maxReflectance = std::numeric_limits<uint16_t>::max();
const double maxReflectance = (1 << desc.attr_bitdepth) - 1;
for (size_t f = 0; f < pointCount; ++f) {
pointCloud.setReflectance(
predictors[f].index,
......
......@@ -65,31 +65,37 @@ protected:
// todo(df): consider alternative encapsulation
void decodeReflectancesLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud);
void decodeColorsLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud);
void decodeReflectancesPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud);
void decodeColorsPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud);
void decodeReflectancesRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud);
void decodeColorsRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCResidualsDecoder& decoder,
PCCPointSet3& pointCloud);
......
......@@ -262,7 +262,7 @@ PCCResidualsEntropyEstimator::update(
void
AttributeEncoder::encode(
const AttributeDescription& attr_desc,
const AttributeDescription& desc,
const AttributeParameterSet& attr_aps,
PCCPointSet3& pointCloud,
PayloadBuffer* payload)
......@@ -271,36 +271,36 @@ AttributeEncoder::encode(
const uint32_t alphabetSize = 64;
encoder.start(int(pointCloud.getPointCount()), alphabetSize);
if (attr_desc.attr_count == 1) {
if (desc.attr_count == 1) {
switch (attr_aps.attr_encoding) {
case AttributeEncoding::kRAHTransform:
encodeReflectancesTransformRaht(attr_aps, pointCloud, encoder);
encodeReflectancesTransformRaht(desc, attr_aps, pointCloud, encoder);
break;
case AttributeEncoding::kPredictingTransform:
encodeReflectancesPred(attr_aps, pointCloud, encoder);
encodeReflectancesPred(desc, attr_aps, pointCloud, encoder);
break;
case AttributeEncoding::kLiftingTransform:
encodeReflectancesLift(attr_aps, pointCloud, encoder);
encodeReflectancesLift(desc, attr_aps, pointCloud, encoder);
break;
}
} else if (attr_desc.attr_count == 3) {
} else if (desc.attr_count == 3) {
switch (attr_aps.attr_encoding) {
case AttributeEncoding::kRAHTransform:
encodeColorsTransformRaht(attr_aps, pointCloud, encoder);
encodeColorsTransformRaht(desc, attr_aps, pointCloud, encoder);
break;
case AttributeEncoding::kPredictingTransform:
encodeColorsPred(attr_aps, pointCloud, encoder);
encodeColorsPred(desc, attr_aps, pointCloud, encoder);
break;
case AttributeEncoding::kLiftingTransform:
encodeColorsLift(attr_aps, pointCloud, encoder);
encodeColorsLift(desc, attr_aps, pointCloud, encoder);
break;
}
} else {
assert(attr_desc.attr_count == 1 || attr_desc.attr_count == 3);
assert(desc.attr_count == 1 || desc.attr_count == 3);
}
uint32_t acDataLen = encoder.stop();
......@@ -379,6 +379,7 @@ AttributeEncoder::computeReflectancePredictionWeights(
void
AttributeEncoder::encodeReflectancesPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder)
......@@ -393,7 +394,10 @@ AttributeEncoder::encodeReflectancesPred(
PCCComputePredictors2(
pointCloud, numberOfPointsPerLOD, indexesLOD,
aps.num_pred_nearest_neighbours, predictors);
const int64_t threshold = 16384;
// todo(??): what about attr_bitdepth < 2?
const int64_t threshold = 1ll << (desc.attr_bitdepth - 2);
const int64_t clipMax = (1ll << desc.attr_bitdepth) - 1;
PCCResidualsEntropyEstimator context;
for (size_t predictorIndex = 0; predictorIndex < pointCount;
++predictorIndex) {
......@@ -414,9 +418,9 @@ AttributeEncoder::encodeReflectancesPred(
const int64_t reconstructedDelta = PCCInverseQuantization(delta, qs);
const int64_t reconstructedQuantAttValue =
quantPredAttValue + reconstructedDelta;
const uint16_t reconstructedReflectance = uint16_t(PCCClip(
reconstructedQuantAttValue, int64_t(0),
int64_t(std::numeric_limits<uint16_t>::max())));
const uint16_t reconstructedReflectance =
uint16_t(PCCClip(reconstructedQuantAttValue, int64_t(0), clipMax));
encoder.encode0(attValue0);
pointCloud.setReflectance(predictor.index, reconstructedReflectance);
}
......@@ -508,6 +512,7 @@ AttributeEncoder::computeColorPredictionWeights(
void
AttributeEncoder::encodeColorsPred(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder)
......@@ -522,7 +527,10 @@ AttributeEncoder::encodeColorsPred(
PCCComputePredictors2(
pointCloud, numberOfPointsPerLOD, indexesLOD,
aps.num_pred_nearest_neighbours, predictors);
const int64_t threshold = 64;
// todo(??): what about attr_bitdepth < 2?
const int64_t threshold = 1ll << (desc.attr_bitdepth - 2);
const int64_t clipMax = (1ll << desc.attr_bitdepth) - 1;
uint32_t values[3];
PCCResidualsEntropyEstimator context;
for (size_t predictorIndex = 0; predictorIndex < pointCount;
......@@ -546,7 +554,7 @@ AttributeEncoder::encodeColorsPred(
values[0] = uint32_t(o3dgc::IntToUInt(long(delta)));
PCCColor3B reconstructedColor;
reconstructedColor[0] =
uint8_t(PCCClip(reconstructedQuantAttValue, int64_t(0), int64_t(255)));
uint8_t(PCCClip(reconstructedQuantAttValue, int64_t(0), clipMax));
for (size_t k = 1; k < 3; ++k) {
const int64_t quantAttValue = color[k];
const int64_t quantPredAttValue = predictedColor[k];
......@@ -557,7 +565,7 @@ AttributeEncoder::encodeColorsPred(
quantPredAttValue + reconstructedDelta;
values[k] = uint32_t(o3dgc::IntToUInt(long(delta)));
reconstructedColor[k] =
uint8_t(PCCClip(reconstructedQuantAttValue, int64_t(0), int64_t(255)));
uint8_t(PCCClip(reconstructedQuantAttValue, int64_t(0), clipMax));
}
pointCloud.setColor(predictor.index, reconstructedColor);
encoder.encode0(values[0]);
......@@ -570,6 +578,7 @@ AttributeEncoder::encodeColorsPred(
void
AttributeEncoder::encodeReflectancesTransformRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder)
......@@ -660,7 +669,7 @@ AttributeEncoder::encodeReflectancesTransformRaht(
regionAdaptiveHierarchicalInverseTransform(
mortonCode, attributes, 1, voxelCount, aps.raht_depth);
const int maxReflectance = std::numeric_limits<uint16_t>::max();
const int maxReflectance = (1 << desc.attr_bitdepth) - 1;
const int minReflectance = 0;
for (int n = 0; n < voxelCount; n++) {
const int reflectance =
......@@ -681,6 +690,7 @@ AttributeEncoder::encodeReflectancesTransformRaht(
void
AttributeEncoder::encodeColorsTransformRaht(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder)
......@@ -800,14 +810,16 @@ AttributeEncoder::encodeColorsTransformRaht(
regionAdaptiveHierarchicalInverseTransform(
mortonCode, attributes, attribCount, voxelCount, aps.raht_depth);
const int clipMax = (1 << desc.attr_bitdepth) - 1;
for (size_t n = 0; n < voxelCount; n++) {
const int r = (int)round(attributes[attribCount * n]);
const int g = (int)round(attributes[attribCount * n + 1]);
const int b = (int)round(attributes[attribCount * n + 2]);
PCCColor3B color;
color[0] = uint8_t(PCCClip(r, 0, 255));
color[1] = uint8_t(PCCClip(g, 0, 255));
color[2] = uint8_t(PCCClip(b, 0, 255));
color[0] = uint8_t(PCCClip(r, 0, clipMax));
color[1] = uint8_t(PCCClip(g, 0, clipMax));
color[2] = uint8_t(PCCClip(b, 0, clipMax));
pointCloud.setColor(packedVoxel[n].index, color);
}
......@@ -824,6 +836,7 @@ AttributeEncoder::encodeColorsTransformRaht(
void
AttributeEncoder::encodeColorsLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder)
......@@ -899,11 +912,13 @@ AttributeEncoder::encodeColorsLift(
PCCLiftUpdate(predictors, weights, startIndex, endIndex, false, colors);
PCCLiftPredict(predictors, startIndex, endIndex, false, colors);
}
const double clipMax = (1 << desc.attr_bitdepth) - 1;
for (size_t f = 0; f < pointCount; ++f) {
const auto& predictor = predictors[f];
PCCColor3B color;
for (size_t d = 0; d < 3; ++d) {
color[d] = uint8_t(PCCClip(std::round(colors[f][d]), 0.0, 255.0));
color[d] = uint8_t(PCCClip(std::round(colors[f][d]), 0.0, clipMax));
}
pointCloud.setColor(predictor.index, color);
}
......@@ -913,6 +928,7 @@ AttributeEncoder::encodeColorsLift(
void
AttributeEncoder::encodeReflectancesLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder)
......@@ -973,7 +989,7 @@ AttributeEncoder::encodeReflectancesLift(
predictors, weights, startIndex, endIndex, false, reflectances);
PCCLiftPredict(predictors, startIndex, endIndex, false, reflectances);
}
const double maxReflectance = std::numeric_limits<uint16_t>::max();
const double maxReflectance = (1 << desc.attr_bitdepth) - 1;
for (size_t f = 0; f < pointCount; ++f) {
pointCloud.setReflectance(
predictors[f].index,
......
......@@ -58,7 +58,7 @@ struct PCCResidualsEntropyEstimator;
class AttributeEncoder {
public:
void encode(
const AttributeDescription& attr_desc,
const AttributeDescription& desc,
const AttributeParameterSet& attr_aps,
PCCPointSet3& pointCloud,
PayloadBuffer* payload);
......@@ -67,31 +67,37 @@ protected:
// todo(df): consider alternative encapsulation
void encodeReflectancesLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCPointSet3& pointCloud,
PCCResidualsEncoder& encoder);
void encodeColorsLift(
const AttributeDescription& desc,
const AttributeParameterSet& aps,
PCCPointSet3& pointCloud,