Commit d96e5851 authored by David Flynn's avatar David Flynn
Browse files

hls/m51027: signal geometry axis order

This adoption permits encoding the geometry positions in an order other
than {x,y,z}.  The --geometry_axis_order option causes the encoder to
load data from the ply file in a different order.  The order is
signalled in the SPS and the decoder will label the output axis as
appropriate.
parent 31d57093
......@@ -150,6 +150,22 @@ Controls the ability to code duplicate points. When duplicate point
merging is enabled, bitstream syntax related to duplicate points is
disabled and a pre-filtering process is used to remove co-located points.
### `--geometry_axis_order=INT-VALUE`
Configures the order in which axes are internally coded. Changing
the axis order does not change the orientation of the reconstructed
point cloud.
| Value | Coding order |
|:-----:| -------------|
| 0 | z, y, x |
| 1 | x, y, z |
| 2 | x, z, y |
| 3 | y, z, x |
| 4 | z, y, x |
| 5 | z, x, y |
| 6 | y, x, z |
| 7 | x, y, z |
### `--disableAttributeCoding=0|1`
This option instructs the encoder to ignore all options relating to
attribute coding, as if they had never been configured.
......
......@@ -128,7 +128,8 @@ private:
class PCCTMC3Decoder3::Callbacks {
public:
virtual void onOutputCloud(const PCCPointSet3&) = 0;
virtual void
onOutputCloud(const SequenceParameterSet&, const PCCPointSet3&) = 0;
};
//============================================================================
......
......@@ -104,6 +104,8 @@ protected:
void onPostRecolour(const PCCPointSet3& cloud) override;
private:
ply::PropertyNameMap _plyAttrNames;
Parameters* params;
PCCTMC3Encoder3 encoder;
......@@ -122,7 +124,9 @@ public:
int decompress(Stopwatch* clock);
protected:
void onOutputCloud(const PCCPointSet3& decodedPointCloud) override;
void onOutputCloud(
const SequenceParameterSet& sps,
const PCCPointSet3& decodedPointCloud) override;
private:
const Parameters* params;
......@@ -170,6 +174,19 @@ main(int argc, char* argv[])
return ret;
}
//---------------------------------------------------------------------------
std::array<const char*, 3>
axisOrderToPropertyNames(AxisOrder order)
{
static const std::array<const char*, 3> kAxisOrderToPropertyNames[] = {
{"z", "y", "x"}, {"x", "y", "z"}, {"x", "z", "y"}, {"y", "z", "x"},
{"z", "y", "x"}, {"z", "x", "y"}, {"y", "x", "z"}, {"x", "y", "z"},
};
return kAxisOrderToPropertyNames[int(order)];
}
//---------------------------------------------------------------------------
// :: Command line / config parsing helpers
......@@ -183,6 +200,14 @@ readUInt(std::istream& in, T& val)
return in;
}
namespace pcc {
static std::istream&
operator>>(std::istream& in, AxisOrder& val)
{
return readUInt(in, val);
}
} // namespace pcc
static std::istream&
operator>>(std::istream& in, ColorTransform& val)
{
......@@ -205,6 +230,24 @@ operator>>(std::istream& in, PartitionMethod& val)
}
} // namespace pcc
namespace pcc {
static std::ostream&
operator<<(std::ostream& out, const AxisOrder& val)
{
switch (val) {
case AxisOrder::kZYX: out << "0 (zyx)"; break;
case AxisOrder::kXYZ: out << "1 (xyz)"; break;
case AxisOrder::kXZY: out << "2 (xzy)"; break;
case AxisOrder::kYZX: out << "3 (yzx)"; break;
case AxisOrder::kZYX_4: out << "4 (zyx)"; break;
case AxisOrder::kZXY: out << "5 (zxy)"; break;
case AxisOrder::kYXZ: out << "6 (yxz)"; break;
case AxisOrder::kXYZ_7: out << "7 (xyz)"; break;
}
return out;
}
} // namespace pcc
namespace pcc {
static std::ostream&
operator<<(std::ostream& out, const AttributeEncoding& val)
......@@ -371,6 +414,13 @@ ParseParameters(int argc, char* argv[], Parameters& params)
(po::Section("Encoder"))
("geometry_axis_order",
params.encoder.sps.geometry_axis_order, AxisOrder::kXYZ,
"Sets the geometry axis coding order:\n"
" 0: (zyx)\n 1: (xyz)\n 2: (xzy)\n"
" 3: (yzx)\n 4: (zyx)\n 5: (zxy)\n"
" 6: (yxz)\n 7: (xyz)")
("seq_bounding_box_xyz0",
params.encoder.sps.seq_bounding_box_xyz0, {0},
"seq_bounding_box_xyz0. NB: seq_bounding_box_whd must be set for this "
......@@ -847,7 +897,11 @@ ParseParameters(int argc, char* argv[], Parameters& params)
//============================================================================
SequenceEncoder::SequenceEncoder(Parameters* params) : params(params)
{}
{
// determine the naming (ordering) of ply properties
_plyAttrNames.position =
axisOrderToPropertyNames(params->encoder.sps.geometry_axis_order);
}
//----------------------------------------------------------------------------
......@@ -878,7 +932,9 @@ SequenceEncoder::compressOneFrame(Stopwatch* clock)
{
std::string srcName{expandNum(params->uncompressedDataPath, frameNum)};
PCCPointSet3 pointCloud;
if (!ply::read(srcName, pointCloud) || pointCloud.getPointCount() == 0) {
if (
!ply::read(srcName, _plyAttrNames, pointCloud)
|| pointCloud.getPointCount() == 0) {
cout << "Error: can't open input file!" << endl;
return -1;
}
......@@ -946,7 +1002,8 @@ SequenceEncoder::compressOneFrame(Stopwatch* clock)
}
std::string recName{expandNum(params->reconstructedDataPath, frameNum)};
ply::write(*reconPointCloud, recName, !params->outputBinaryPly);
ply::write(
*reconPointCloud, _plyAttrNames, recName, !params->outputBinaryPly);
}
return 0;
......@@ -973,13 +1030,13 @@ SequenceEncoder::onPostRecolour(const PCCPointSet3& cloud)
// todo(df): stop the clock
if (params->colorTransform != COLOR_TRANSFORM_RGB_TO_YCBCR) {
ply::write(cloud, plyName, !params->outputBinaryPly);
ply::write(cloud, _plyAttrNames, plyName, !params->outputBinaryPly);
return;
}
PCCPointSet3 tmpCloud(cloud);
tmpCloud.convertYUVToRGB();
ply::write(tmpCloud, plyName, !params->outputBinaryPly);
ply::write(tmpCloud, _plyAttrNames, plyName, !params->outputBinaryPly);
}
//============================================================================
......@@ -1034,7 +1091,8 @@ SequenceDecoder::decompress(Stopwatch* clock)
//----------------------------------------------------------------------------
void
SequenceDecoder::onOutputCloud(const PCCPointSet3& decodedPointCloud)
SequenceDecoder::onOutputCloud(
const SequenceParameterSet& sps, const PCCPointSet3& decodedPointCloud)
{
// copy the point cloud in order to modify it according to the output options
PCCPointSet3 pointCloud(decodedPointCloud);
......@@ -1051,10 +1109,16 @@ SequenceDecoder::onOutputCloud(const PCCPointSet3& decodedPointCloud)
}
}
// the order of the property names must be determined from the sps
ply::PropertyNameMap attrNames;
attrNames.position = axisOrderToPropertyNames(sps.geometry_axis_order);
// Dump the decoded colour using the pre inverse scaled geometry
if (!params->preInvScalePath.empty()) {
std::string filename{expandNum(params->preInvScalePath, frameNum)};
ply::write(pointCloud, params->preInvScalePath, !params->outputBinaryPly);
ply::write(
pointCloud, attrNames, params->preInvScalePath,
!params->outputBinaryPly);
}
decoder.inverseQuantization(pointCloud);
......@@ -1062,7 +1126,7 @@ SequenceDecoder::onOutputCloud(const PCCPointSet3& decodedPointCloud)
clock->stop();
std::string decName{expandNum(params->reconstructedDataPath, frameNum)};
if (!ply::write(pointCloud, decName, !params->outputBinaryPly)) {
if (!ply::write(pointCloud, attrNames, decName, !params->outputBinaryPly)) {
cout << "Error: can't open output file!" << endl;
}
......
......@@ -90,7 +90,7 @@ PCCTMC3Decoder3::decompress(
if (!buf) {
// flush decoder, output pending cloud if any
callback->onOutputCloud(_accumCloud);
callback->onOutputCloud(*_sps, _accumCloud);
_accumCloud.clear();
return 0;
}
......@@ -106,7 +106,8 @@ PCCTMC3Decoder3::decompress(
// NB: frame counter is reset to avoid outputing a runt point cloud
// on the next slice.
case PayloadType::kFrameBoundaryMarker:
callback->onOutputCloud(_accumCloud);
// todo(df): if no sps is activated ...
callback->onOutputCloud(*_sps, _accumCloud);
_accumCloud.clear();
_currentFrameIdx = -1;
return 0;
......@@ -114,7 +115,7 @@ PCCTMC3Decoder3::decompress(
case PayloadType::kGeometryBrick:
activateParameterSets(parseGbhIds(*buf));
if (frameIdxChanged(parseGbh(*_sps, *_gps, *buf, nullptr))) {
callback->onOutputCloud(_accumCloud);
callback->onOutputCloud(*_sps, _accumCloud);
_accumCloud.clear();
}
return decodeGeometryBrick(*buf);
......
......@@ -121,6 +121,20 @@ enum class AttributeEncoding
//============================================================================
enum class AxisOrder
{
kZYX = 0,
kXYZ = 1,
kXZY = 2,
kYZX = 3,
kZYX_4 = 4,
kZXY = 5,
kYXZ = 6,
kXYZ_7 = 7,
};
//============================================================================
// invariant properties
struct AttributeDescription {
int attr_num_dimensions;
......@@ -162,6 +176,9 @@ struct SequenceParameterSet {
// The number of bits to use for frame_idx
int log2_max_frame_idx;
// Defines the ordering of the position components (eg, xyz vs zyx)
AxisOrder geometry_axis_order;
// Controls whether bypass bins are written to a seperate sub-stream, or
// encoded as ep bins via CABAC.
bool cabac_bypass_stream_enabled_flag;
......
......@@ -112,6 +112,7 @@ write(const SequenceParameterSet& sps)
}
bs.writeUn(5, sps.log2_max_frame_idx);
bs.writeUn(3, sps.geometry_axis_order);
bs.write(sps.cabac_bypass_stream_enabled_flag);
bool sps_extension_flag = false;
......@@ -173,6 +174,7 @@ parseSps(const PayloadBuffer& buf)
}
bs.readUn(5, &sps.log2_max_frame_idx);
bs.readUn(3, &sps.geometry_axis_order);
bs.read(&sps.cabac_bypass_stream_enabled_flag);
bool sps_extension_flag = bs.read();
......
......@@ -87,7 +87,10 @@ getTokens(
bool
ply::write(
const PCCPointSet3& cloud, const std::string& fileName, bool asAscii)
const PCCPointSet3& cloud,
const PropertyNameMap& attributeNames,
const std::string& fileName,
bool asAscii)
{
std::ofstream fout(fileName, std::ofstream::out);
if (!fout.is_open()) {
......@@ -109,13 +112,13 @@ ply::write(
}
fout << "element vertex " << pointCount << std::endl;
if (asAscii) {
fout << "property float x" << std::endl;
fout << "property float y" << std::endl;
fout << "property float z" << std::endl;
fout << "property float " << attributeNames.position[0] << std::endl;
fout << "property float " << attributeNames.position[1] << std::endl;
fout << "property float " << attributeNames.position[2] << std::endl;
} else {
fout << "property float64 x" << std::endl;
fout << "property float64 y" << std::endl;
fout << "property float64 z" << std::endl;
fout << "property float64 " << attributeNames.position[0] << std::endl;
fout << "property float64 " << attributeNames.position[1] << std::endl;
fout << "property float64 " << attributeNames.position[2] << std::endl;
}
if (cloud.hasColors()) {
......@@ -182,7 +185,10 @@ ply::write(
//============================================================================
bool
ply::read(const std::string& fileName, PCCPointSet3& cloud)
ply::read(
const std::string& fileName,
const PropertyNameMap& attributeNames,
PCCPointSet3& cloud)
{
std::ifstream ifs(fileName, std::ifstream::in | std::ifstream::binary);
if (!ifs.is_open()) {
......@@ -317,15 +323,15 @@ ply::read(const std::string& fileName, PCCPointSet3& cloud)
for (size_t a = 0; a < attributeCount; ++a) {
const auto& attributeInfo = attributesInfo[a];
if (
attributeInfo.name == "x"
attributeInfo.name == attributeNames.position[0]
&& (attributeInfo.byteCount == 8 || attributeInfo.byteCount == 4)) {
indexX = a;
} else if (
attributeInfo.name == "y"
attributeInfo.name == attributeNames.position[1]
&& (attributeInfo.byteCount == 8 || attributeInfo.byteCount == 4)) {
indexY = a;
} else if (
attributeInfo.name == "z"
attributeInfo.name == attributeNames.position[2]
&& (attributeInfo.byteCount == 8 || attributeInfo.byteCount == 4)) {
indexZ = a;
} else if (attributeInfo.name == "red" && attributeInfo.byteCount == 1) {
......
......@@ -35,6 +35,7 @@
#pragma once
#include <array>
#include <string>
#include "PCCPointSet.h"
......@@ -43,10 +44,26 @@ namespace pcc {
namespace ply {
//============================================================================
// This defines the the attribute names to be used when reading/writing ply
// files. The order of the names define the ordering used in the internal
// point cloud representation.
bool
write(const PCCPointSet3& cloud, const std::string& fileName, bool asAscii);
bool read(const std::string& fileName, PCCPointSet3& cloud);
struct PropertyNameMap {
// The names of the position attributes, typically {"x", "y", "z"}
std::array<const char*, 3> position;
};
//============================================================================
bool write(
const PCCPointSet3& cloud,
const PropertyNameMap& propertyNames,
const std::string& fileName,
bool asAscii);
bool read(
const std::string& fileName,
const PropertyNameMap& propertyNames,
PCCPointSet3& cloud);
//============================================================================
......
......@@ -219,6 +219,9 @@ parseParameters(int argc, char* argv[], Options& params)
void
runMerge(const Options& opts)
{
ply::PropertyNameMap propNames;
propNames.position = {"x", "y", "z"};
// iterate over all input frames in groups
int outFrameNum = opts.firstOutputFrameNum;
for (int i = 0; i < opts.frameCount; outFrameNum++) {
......@@ -232,7 +235,9 @@ runMerge(const Options& opts)
srcClouds.emplace_back();
auto& srcCloud = srcClouds.back();
if (!ply::read(srcName, srcCloud) || srcCloud.getPointCount() == 0) {
if (
!ply::read(srcName, propNames, srcCloud)
|| srcCloud.getPointCount() == 0) {
throw runtime_error("failed to read input file: " + srcName);
}
}
......@@ -268,7 +273,7 @@ runMerge(const Options& opts)
}
string outName{expandNum(opts.outPath, outFrameNum)};
if (!ply::write(outCloud, outName, !opts.outputBinaryPly))
if (!ply::write(outCloud, propNames, outName, !opts.outputBinaryPly))
throw runtime_error("failed to write output file: " + outName);
cout << outName << endl;
}
......@@ -281,6 +286,9 @@ runMerge(const Options& opts)
void
runSplit(const Options& opts)
{
ply::PropertyNameMap propNames;
propNames.position = {"x", "y", "z"};
int outFrameNum = opts.firstOutputFrameNum;
int srcFrameNum = opts.firstFrameNum;
......@@ -288,7 +296,9 @@ runSplit(const Options& opts)
string srcName{expandNum(opts.srcPath, srcFrameNum)};
PCCPointSet3 srcCloud;
if (!ply::read(srcName, srcCloud) || srcCloud.getPointCount() == 0) {
if (
!ply::read(srcName, propNames, srcCloud)
|| srcCloud.getPointCount() == 0) {
throw runtime_error("failed to read input file: " + srcName);
}
......@@ -331,7 +341,7 @@ runSplit(const Options& opts)
string outName{expandNum(opts.outPath, outFrameNum)};
if (outCloud.getPointCount() > 0)
if (!ply::write(outCloud, outName, !opts.outputBinaryPly))
if (!ply::write(outCloud, propNames, outName, !opts.outputBinaryPly))
throw runtime_error("failed to write output file: " + outName);
cout << outName << endl;
......
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