Commit 098e25ab authored by Khaled Mammou's avatar Khaled Mammou
Browse files

update codec to work with unquantized point clouds

git-svn-id: http://wg11.sc29.org/svn/repos/MPEG-I/Part5-PointCloudCompression/TM/TMC3/trunk@1231 94298a81-5874-47c9-aab8-bfb24faeed7f
parent 0cf8cc46
......@@ -231,9 +231,16 @@ class PCCPointSet3 {
}
}
fout << "element vertex " << pointCount << std::endl;
fout << "property float64 x" << std::endl;
fout << "property float64 y" << std::endl;
fout << "property float64 z" << std::endl;
if (asAscii) {
fout << "property float x" << std::endl;
fout << "property float y" << std::endl;
fout << "property float z" << std::endl;
} else {
fout << "property float64 x" << std::endl;
fout << "property float64 y" << std::endl;
fout << "property float64 z" << std::endl;
}
if (hasColors()) {
fout << "property uchar red" << std::endl;
fout << "property uchar green" << std::endl;
......@@ -246,7 +253,8 @@ class PCCPointSet3 {
fout << "property list uint8 int32 vertex_index" << std::endl;
fout << "end_header" << std::endl;
if (asAscii) {
fout << std::setprecision(std::numeric_limits<double>::max_digits10);
// fout << std::setprecision(std::numeric_limits<double>::max_digits10);
fout << std::fixed << std::setprecision(5);
for (size_t i = 0; i < pointCount; ++i) {
const PCCPoint3D &position = (*this)[i];
fout << position.x() << " " << position.y() << " " << position.z();
......
......@@ -141,7 +141,7 @@ inline int64_t PCCInverseQuantization(const int64_t value, const int64_t qs, int
inline void PCCBuildPredictors(const PCCPointSet3 &pointCloud,
const size_t numberOfNearestNeighborsInPrediction,
const size_t levelOfDetailCount, const std::vector<size_t> &dist2,
std::vector<PCCPredictor> &predictors,
const double dist2Scale, std::vector<PCCPredictor> &predictors,
std::vector<uint32_t> &numberOfPointsPerLOD,
std::vector<uint32_t> &indexes) {
const size_t pointCount = pointCloud.getPointCount();
......@@ -164,7 +164,7 @@ inline void PCCBuildPredictors(const PCCPointSet3 &pointCloud,
for (size_t lodIndex = 0; lodIndex < levelOfDetailCount && indexes.size() < pointCount;
++lodIndex) {
const bool filterByDistance = (lodIndex + 1) != levelOfDetailCount;
const double minDist2 = double(dist2[lodIndex]);
const double minDist2 = dist2[lodIndex] * dist2Scale;
nNQuery.radius = minDist2;
size_t balanceTargetPointCount = initialBalanceTargetPointCount;
for (uint32_t current = 0; current < pointCount; ++current) {
......
......@@ -69,7 +69,63 @@ class PCCTMC3Decoder3 {
quantizationDeadZoneSizes.clear();
predictors.clear();
}
int decompressWithLosslessGeometry(PCCBitstream &bitstream, PCCPointSet3 &pointCloud) {
init();
uint32_t magicNumber = 0;
uint32_t formatVersion = 0;
PCCReadFromBuffer<uint32_t>(bitstream.buffer, magicNumber, bitstream.size);
if (magicNumber != PCCTMC3MagicNumber) {
std::cout << "Error: corrupted bistream!" << std::endl;
return -1;
}
PCCReadFromBuffer<uint32_t>(bitstream.buffer, formatVersion, bitstream.size);
if (formatVersion != PCCTMC3FormatVersion) {
std::cout << "Error: bistream version not supported!" << std::endl;
return -1;
}
uint8_t hasColors = 0;
PCCReadFromBuffer<uint8_t>(bitstream.buffer, hasColors, bitstream.size);
uint8_t hasReflectances = 0;
PCCReadFromBuffer<uint8_t>(bitstream.buffer, hasReflectances, bitstream.size);
if (hasColors) {
pointCloud.addColors();
} else {
pointCloud.removeColors();
}
if (hasReflectances) {
pointCloud.addReflectances();
} else {
pointCloud.removeReflectances();
}
if (pointCloud.hasColors()) {
uint64_t colorsSize = bitstream.size;
if (int ret = decodeAttributeHeader("color", bitstream)) {
return ret;
}
buildPredictors(pointCloud, 0.001);
if (int ret = decodeColors(bitstream, pointCloud)) {
return ret;
}
colorsSize = bitstream.size - colorsSize;
std::cout << "colors bitstream size " << colorsSize << " B" << std::endl;
std::cout << std::endl;
}
if (pointCloud.hasReflectances()) {
uint64_t reflectancesSize = bitstream.size;
if (int ret = decodeAttributeHeader("reflectance", bitstream)) {
return ret;
}
buildPredictors(pointCloud, 0.001);
if (int ret = decodeReflectances(bitstream, pointCloud)) {
return ret;
}
reflectancesSize = bitstream.size - reflectancesSize;
std::cout << "reflectances bitstream size " << reflectancesSize << " B" << std::endl;
}
return 0;
}
int decompress(PCCBitstream &bitstream, PCCPointSet3 &pointCloud) {
init();
uint32_t magicNumber = 0;
......@@ -312,11 +368,11 @@ class PCCTMC3Decoder3 {
bitstream.size += compressedBitstreamSize;
return 0;
}
void buildPredictors(const PCCPointSet3 &pointCloud) {
void buildPredictors(const PCCPointSet3 &pointCloud, const double dist2Scale = 1.0) {
std::vector<uint32_t> numberOfPointsPerLOD;
std::vector<uint32_t> indexes;
PCCBuildPredictors(pointCloud, numberOfNearestNeighborsInPrediction, levelOfDetailCount, dist2,
predictors, numberOfPointsPerLOD, indexes);
dist2Scale, predictors, numberOfPointsPerLOD, indexes);
}
int decodeAttributeHeader(const std::string &attributeName, PCCBitstream &bitstream) {
......
......@@ -125,6 +125,69 @@ class PCCTMC3Encoder3 {
return bitstreamSize;
}
int compressWithLosslessGeometry(const PCCPointSet3 &inputPointCloud,
const PCCTMC3Encoder3Parameters &params, PCCBitstream &bitstream,
PCCPointSet3 *reconstructedCloud = nullptr) {
init();
pointCloud = inputPointCloud;
const bool compressColors =
inputPointCloud.hasColors() &&
params.attributeEncodeParameters.find("color") != params.attributeEncodeParameters.end();
if (!compressColors) {
pointCloud.removeColors();
}
const bool compressReflectances = inputPointCloud.hasReflectances() &&
params.attributeEncodeParameters.find("reflectance") !=
params.attributeEncodeParameters.end();
if (!compressReflectances) {
pointCloud.removeReflectances();
}
PCCWriteToBuffer<uint32_t>(PCCTMC3MagicNumber, bitstream.buffer, bitstream.size);
PCCWriteToBuffer<uint32_t>(PCCTMC3FormatVersion, bitstream.buffer, bitstream.size);
PCCWriteToBuffer<uint8_t>(uint8_t(pointCloud.hasColors()), bitstream.buffer, bitstream.size);
PCCWriteToBuffer<uint8_t>(uint8_t(pointCloud.hasReflectances()), bitstream.buffer,
bitstream.size);
if (pointCloud.hasColors()) {
const auto &colorParams = params.attributeEncodeParameters.find("color")->second;
uint64_t colorsSize = bitstream.size;
if (int ret = encodeAttributeHeader(colorParams, "color", bitstream)) {
return ret;
}
buildPredictors(colorParams, 0.001);
computeColorPredictionWeights(colorParams);
if (int ret = encodeColors(colorParams, bitstream)) {
return ret;
}
colorsSize = bitstream.size - colorsSize;
std::cout << "colors bitstream size " << colorsSize << " B ("
<< (8.0 * colorsSize) / inputPointCloud.getPointCount() << " bpp)" << std::endl;
}
if (pointCloud.hasReflectances()) {
const auto &reflectanceParams = params.attributeEncodeParameters.find("reflectance")->second;
uint64_t reflectancesSize = bitstream.size;
if (int ret = encodeAttributeHeader(reflectanceParams, "reflectance", bitstream)) {
return ret;
}
buildPredictors(reflectanceParams, 0.001);
computeReflectancePredictionWeights(reflectanceParams);
if (int ret = encodeReflectances(reflectanceParams, bitstream)) {
return ret;
}
reflectancesSize = bitstream.size - reflectancesSize;
std::cout << "reflectances bitstream size " << reflectancesSize << " B ("
<< (8.0 * reflectancesSize) / inputPointCloud.getPointCount() << " bpp)"
<< std::endl;
}
if (reconstructedCloud) {
(*reconstructedCloud) = pointCloud;
}
return 0;
}
int compress(const PCCPointSet3 &inputPointCloud, const PCCTMC3Encoder3Parameters &params,
PCCBitstream &bitstream, PCCPointSet3 *reconstructedCloud = nullptr) {
init();
......@@ -282,7 +345,7 @@ class PCCTMC3Encoder3 {
const int64_t quantAttValue = pointCloud.getReflectance(predictor.index);
const int64_t quantPredAttValue = predictor.predictReflectance(pointCloud);
const int64_t delta = PCCQuantization(quantAttValue - quantPredAttValue, qs, dz);
const uint32_t attValue0 = o3dgc::IntToUInt(long(delta));
const uint32_t attValue0 = uint32_t(o3dgc::IntToUInt(long(delta)));
encodeDiff0UInt32(attValue0, maxAttributeValueDiff0, adaptiveDataModelAlphabetSizeDiff0,
arithmeticEncoder, multiSymbolModelDiff0, binaryModelDiff0, binaryModel0);
......@@ -407,7 +470,7 @@ class PCCTMC3Encoder3 {
const int64_t quantAttValue = color[0];
const int64_t quantPredAttValue = predictedColor[0];
const int64_t delta = PCCQuantization(quantAttValue - quantPredAttValue, qs, dz);
const uint32_t attValue0 = o3dgc::IntToUInt(long(delta));
const uint32_t attValue0 = uint32_t(o3dgc::IntToUInt(long(delta)));
const uint32_t modelIndex = (attValue0 < PCCTMC3Diff1AdaptiveDataModelCount)
? attValue0
: PCCTMC3Diff1AdaptiveDataModelCount - 1;
......@@ -425,7 +488,7 @@ class PCCTMC3Encoder3 {
const int64_t delta = PCCQuantization(quantAttValue - quantPredAttValue, qs, dz);
const int64_t reconstructedDelta = PCCInverseQuantization(delta, qs, dz);
const int64_t reconstructedQuantAttValue = quantPredAttValue + reconstructedDelta;
const uint32_t attValue1 = o3dgc::IntToUInt(long(delta));
const uint32_t attValue1 = uint32_t(o3dgc::IntToUInt(long(delta)));
encodeDiff1UInt32(attValue1, modelIndex, maxAttributeValueDiff1,
adaptiveDataModelAlphabetSizeDiff1, arithmeticEncoder,
multiSymbolModelDiff1, binaryModelDiff1, binaryModel0);
......@@ -464,7 +527,7 @@ class PCCTMC3Encoder3 {
PCCQuantization(quantAttValue - quantPredAttValue,
int64_t(attributeParams.quantizationSteps[lodIndex]),
int64_t(attributeParams.quantizationDeadZoneSizes[lodIndex]));
const uint32_t delta1 = o3dgc::IntToUInt(long(delta0));
const uint32_t delta1 = uint32_t(o3dgc::IntToUInt(long(delta0)));
cost += delta1;
}
}
......@@ -500,9 +563,10 @@ class PCCTMC3Encoder3 {
const int64_t delta0 = PCCQuantization(
quantAttValue - quantPredAttValue, int64_t(attributeParams.quantizationSteps[lodIndex]),
int64_t(attributeParams.quantizationDeadZoneSizes[lodIndex]));
const uint32_t delta1 = o3dgc::IntToUInt(long(delta0));
const uint32_t delta1 = uint32_t(o3dgc::IntToUInt(long(delta0)));
cost += delta1;
}
if (cost < bestCost) {
bestCost = cost;
bestNeighborCount = neighborCount;
......@@ -517,12 +581,13 @@ class PCCTMC3Encoder3 {
}
}
void buildPredictors(const PCCAttributeEncodeParamaters &attributeParams) {
void buildPredictors(const PCCAttributeEncodeParamaters &attributeParams,
const double dist2Scale = 1.0) {
std::vector<uint32_t> numberOfPointsPerLOD;
std::vector<uint32_t> indexes;
PCCBuildPredictors(pointCloud, attributeParams.numberOfNearestNeighborsInPrediction,
attributeParams.levelOfDetailCount, attributeParams.dist2, predictors,
numberOfPointsPerLOD, indexes);
attributeParams.levelOfDetailCount, attributeParams.dist2, dist2Scale,
predictors, numberOfPointsPerLOD, indexes);
}
void reconstructedPointCloud(const PCCTMC3Encoder3Parameters &params,
PCCPointSet3 *reconstructedCloud) {
......@@ -740,7 +805,7 @@ class PCCTMC3Encoder3 {
pointCloud.resize(retainedPoints.size());
const double invScale = 1.0 / params.positionQuantizationScale;
size_t pointCounter = 0;
for (const auto quantizedPoint : retainedPoints) {
for (const auto &quantizedPoint : retainedPoints) {
auto &point = pointCloud[pointCounter++];
for (size_t k = 0; k < 3; ++k) {
point[k] = double(quantizedPoint[k]) * invScale + minPositions[k];
......@@ -767,7 +832,7 @@ class PCCTMC3Encoder3 {
// compute quantized coordinates
pointCounter = 0;
for (const auto quantizedPoint : retainedPoints) {
for (const auto &quantizedPoint : retainedPoints) {
auto &point = pointCloud[pointCounter++];
for (size_t k = 0; k < 3; ++k) {
point[k] = double(quantizedPoint[k]);
......
......@@ -49,7 +49,7 @@ int main(int argc, char *argv[]) {
}
const auto start = std::chrono::high_resolution_clock::now();
int ret = 0;
if (params.mode == CODEC_MODE_ENCODE) {
if (params.mode == CODEC_MODE_ENCODE || params.mode == CODEC_MODE_ENCODE_LOSSLESS_GEOMETRY) {
ret = Compress(params);
} else {
ret = Decompress(params);
......@@ -103,6 +103,7 @@ bool ParseParameters(int argc, char *argv[], Parameters &params) {
attributeEncodeParams.quantizationSteps.resize(attributeEncodeParams.levelOfDetailCount);
attributeEncodeParams.quantizationDeadZoneSizes.resize(
attributeEncodeParams.levelOfDetailCount);
attributeEncodeParams.dist2.resize(attributeEncodeParams.levelOfDetailCount);
}
} else if (!strcmp(argv[i], "--quantizationSteps")) {
for (size_t k = 0; k < attributeEncodeParams.levelOfDetailCount; ++k) {
......@@ -123,18 +124,28 @@ bool ParseParameters(int argc, char *argv[], Parameters &params) {
} else if (!strcmp(argv[i], "--positionQuantizationScale")) {
if (++i < argc) params.encodeParameters.positionQuantizationScale = atof(argv[i]);
} else if (!strcmp(argv[i], "--mergeDuplicatedPoints")) {
if (++i < argc) params.encodeParameters.mergeDuplicatedPoints = argv[i] != 0;
if (++i < argc) params.encodeParameters.mergeDuplicatedPoints = atoi(argv[i]) != 0;
}
}
const bool encode =
(params.mode == CODEC_MODE_ENCODE || params.mode == CODEC_MODE_ENCODE_LOSSLESS_GEOMETRY);
cout << "+ Parameters" << endl;
cout << "\t mode "
<< ((params.mode == CODEC_MODE_ENCODE) ? "encode" : "decode") << endl;
cout << "\t mode ";
if (params.mode == CODEC_MODE_ENCODE) {
cout << "encode" << endl;
} else if (params.mode == CODEC_MODE_ENCODE_LOSSLESS_GEOMETRY) {
cout << "encode with lossless geometry" << endl;
} else if (params.mode == CODEC_MODE_DECODE) {
cout << "decode" << endl;
} else if (params.mode == CODEC_MODE_DECODE_LOSSLESS_GEOMETRY) {
cout << "decode with lossless geometry" << endl;
}
cout << "\t uncompressedDataPath " << params.uncompressedDataPath << endl;
cout << "\t compressedStreamPath " << params.compressedStreamPath << endl;
cout << "\t reconstructedDataPath " << params.reconstructedDataPath << endl;
cout << "\t colorTransform " << params.colorTransform << endl;
if (params.mode == CODEC_MODE_ENCODE) {
if (encode) {
cout << "\t mergeDuplicatedPoints " << params.encodeParameters.mergeDuplicatedPoints
<< endl;
cout << "\t positionQuantizationScale " << params.encodeParameters.positionQuantizationScale
......@@ -166,11 +177,13 @@ bool ParseParameters(int argc, char *argv[], Parameters &params) {
cout << endl;
}
const bool test1 = (params.mode == CODEC_MODE_ENCODE) &&
(params.uncompressedDataPath.empty() || params.compressedStreamPath.empty());
const bool test2 = params.mode == CODEC_MODE_DECODE &&
(params.reconstructedDataPath.empty() || params.compressedStreamPath.empty());
if (test1 || test2) {
const bool test1 =
encode && (params.uncompressedDataPath.empty() || params.compressedStreamPath.empty());
const bool test2 =
!encode && (params.reconstructedDataPath.empty() || params.compressedStreamPath.empty());
const bool test3 =
params.mode == CODEC_MODE_DECODE_LOSSLESS_GEOMETRY && params.uncompressedDataPath.empty();
if (test1 || test2 || test3) {
return false;
}
return true;
......@@ -199,11 +212,16 @@ int Compress(const Parameters &params) {
reconstructedPointCloud.reset(new PCCPointSet3);
}
if (encoder.compress(pointCloud, params.encodeParameters, bitstream,
reconstructedPointCloud.get())) {
if ((params.mode == CODEC_MODE_ENCODE &&
encoder.compress(pointCloud, params.encodeParameters, bitstream,
reconstructedPointCloud.get())) ||
(params.mode == CODEC_MODE_ENCODE_LOSSLESS_GEOMETRY &&
encoder.compressWithLosslessGeometry(pointCloud, params.encodeParameters, bitstream,
reconstructedPointCloud.get()))) {
cout << "Error: can't compress point cloud!" << endl;
return -1;
}
assert(bitstream.size <= bitstream.capacity);
std::cout << "Total bitstream size " << bitstream.size << " B" << std::endl;
ofstream fout(params.compressedStreamPath, ios::binary);
......@@ -243,7 +261,18 @@ int Decompress(const Parameters &params) {
PCCTMC3Decoder3 decoder;
PCCPointSet3 pointCloud;
if (decoder.decompress(bitstream, pointCloud)) {
if (params.mode == CODEC_MODE_DECODE_LOSSLESS_GEOMETRY) { // read geometry from input file
if (!pointCloud.read(params.uncompressedDataPath) || pointCloud.getPointCount() == 0) {
cout << "Error: can't open input file!" << endl;
return -1;
}
pointCloud.removeReflectances();
pointCloud.removeColors();
}
if ((params.mode == CODEC_MODE_DECODE && decoder.decompress(bitstream, pointCloud)) ||
(params.mode == CODEC_MODE_DECODE_LOSSLESS_GEOMETRY &&
decoder.decompressWithLosslessGeometry(bitstream, pointCloud))) {
cout << "Error: can't decompress point cloud!" << endl;
return -1;
}
......
......@@ -58,7 +58,12 @@
enum ColorTransform { COLOR_TRANSFORM_NONE = 0, COLOR_TRANSFORM_RGB_TO_YCBCR = 1 };
enum CodecMode { CODEC_MODE_ENCODE = 0, CODEC_MODE_DECODE = 1 };
enum CodecMode {
CODEC_MODE_ENCODE = 0,
CODEC_MODE_DECODE = 1,
CODEC_MODE_ENCODE_LOSSLESS_GEOMETRY = 2,
CODEC_MODE_DECODE_LOSSLESS_GEOMETRY = 3,
};
struct Parameters {
std::string uncompressedDataPath;
......
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