Commit 5529c24e authored by David Flynn's avatar David Flynn
Browse files

use program-options-lite for command-line and config handling

This commit replaces the previous command-line argument parsing with
program-options-lite, which additionally serves as a simple config-file
parser.

A table based configuration of options provides in a single place
option naming, help text, and default values.

Side effects of this change are to:

 - adds further error checking for unknown arguments (warning only), parse
   failures, required options.

 - replace the default constructor of Parameters,
   PCCAttributeEncodeParamaters, and PCCAttributeEncodeParamaters
   with defaults in args handler

 - updates the type of Parameters::mode & ...::colorTransform to be more
   more descriptive.



git-svn-id: http://wg11.sc29.org/svn/repos/MPEG-I/Part5-PointCloudCompression/TM/TMC3/trunk@1318 94298a81-5874-47c9-aab8-bfb24faeed7f
parent 5e0c0f91
...@@ -13,9 +13,19 @@ configure_file ( ...@@ -13,9 +13,19 @@ configure_file (
) )
file(GLOB PROJECT_IN_FILES "*.in") file(GLOB PROJECT_IN_FILES "*.in")
file(GLOB PROJECT_INC_FILES "*.h" "../dependencies/nanoflann/*.hpp" "../dependencies/nanoflann/*.h" "../dependencies/arithmetic-coding/inc/*.h") file(GLOB PROJECT_INC_FILES
"*.h"
"../dependencies/nanoflann/*.hpp"
"../dependencies/nanoflann/*.h"
"../dependencies/arithmetic-coding/inc/*.h"
"../dependencies/program-options-lite/*.h"
)
file(GLOB PROJECT_INL_FILES "*.inl") file(GLOB PROJECT_INL_FILES "*.inl")
file(GLOB PROJECT_CPP_FILES "*.cpp" "../dependencies/arithmetic-coding/src/*.cpp") file(GLOB PROJECT_CPP_FILES
"*.cpp"
"../dependencies/arithmetic-coding/src/*.cpp"
"../dependencies/program-options-lite/*.cpp"
)
file(GLOB PROJECT_C_FILES "*.c") file(GLOB PROJECT_C_FILES "*.c")
file(GLOB PROJECT_CL_FILES "*.cl") file(GLOB PROJECT_CL_FILES "*.cl")
source_group (inc FILES ${PROJECT_INC_FILES}) source_group (inc FILES ${PROJECT_INC_FILES})
...@@ -25,7 +35,13 @@ source_group (cpp FILES ${PROJECT_CPP_FILES}) ...@@ -25,7 +35,13 @@ source_group (cpp FILES ${PROJECT_CPP_FILES})
source_group (c FILES ${PROJECT_C_FILES}) source_group (c FILES ${PROJECT_C_FILES})
source_group (cl FILES ${PROJECT_CL_FILES}) source_group (cl FILES ${PROJECT_CL_FILES})
include_directories("${PROJECT_BINARY_DIR}/tmc3" "${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/nanoflann" "${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/tbb/include" "${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/arithmetic-coding/inc") include_directories(
"${PROJECT_BINARY_DIR}/tmc3"
"${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/nanoflann"
"${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/tbb/include"
"${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/arithmetic-coding/inc"
"${CMAKE_CURRENT_SOURCE_DIR}/../dependencies/program-options-lite"
)
add_executable(tmc3 ${PROJECT_CPP_FILES} ${PROJECT_C_FILES} ${PROJECT_CL_FILES} ${PROJECT_PUB_FILES} ${PROJECT_INC_FILES} ${PROJECT_IN_FILES} ${PROJECT_INL_FILES}) add_executable(tmc3 ${PROJECT_CPP_FILES} ${PROJECT_C_FILES} ${PROJECT_CL_FILES} ${PROJECT_PUB_FILES} ${PROJECT_INC_FILES} ${PROJECT_IN_FILES} ${PROJECT_INL_FILES})
target_link_libraries (tmc3 tbb_static) target_link_libraries (tmc3 tbb_static)
......
...@@ -60,44 +60,12 @@ struct PCCAttributeEncodeParamaters { ...@@ -60,44 +60,12 @@ struct PCCAttributeEncodeParamaters {
std::vector<size_t> dist2; std::vector<size_t> dist2;
std::vector<size_t> quantizationSteps; std::vector<size_t> quantizationSteps;
std::vector<size_t> quantizationDeadZoneSizes; std::vector<size_t> quantizationDeadZoneSizes;
PCCAttributeEncodeParamaters() {
searchRange = 2;
numberOfNearestNeighborsInPrediction = 8;
levelOfDetailCount = 6;
dist2.reserve(levelOfDetailCount);
dist2.push_back(576);
dist2.push_back(144);
dist2.push_back(36);
dist2.push_back(9);
dist2.push_back(2);
dist2.push_back(0);
quantizationSteps.reserve(levelOfDetailCount);
quantizationSteps.push_back(1);
quantizationSteps.push_back(2);
quantizationSteps.push_back(4);
quantizationSteps.push_back(8);
quantizationSteps.push_back(12);
quantizationSteps.push_back(16);
assert(quantizationSteps.size() == levelOfDetailCount);
quantizationDeadZoneSizes.reserve(levelOfDetailCount);
quantizationDeadZoneSizes.push_back(1);
quantizationDeadZoneSizes.push_back(2);
quantizationDeadZoneSizes.push_back(4);
quantizationDeadZoneSizes.push_back(8);
quantizationDeadZoneSizes.push_back(12);
quantizationDeadZoneSizes.push_back(16);
assert(quantizationDeadZoneSizes.size() == levelOfDetailCount);
}
}; };
struct PCCTMC3Encoder3Parameters { struct PCCTMC3Encoder3Parameters {
double positionQuantizationScale; double positionQuantizationScale;
bool mergeDuplicatedPoints; bool mergeDuplicatedPoints;
std::map<std::string, PCCAttributeEncodeParamaters> attributeEncodeParameters; std::map<std::string, PCCAttributeEncodeParamaters> attributeEncodeParameters;
PCCTMC3Encoder3Parameters() {
positionQuantizationScale = 1.0;
mergeDuplicatedPoints = true;
}
}; };
class PCCTMC3Encoder3 { class PCCTMC3Encoder3 {
......
...@@ -36,15 +36,17 @@ ...@@ -36,15 +36,17 @@
*/ */
#include "TMC3.h" #include "TMC3.h"
#include "program_options_lite.h"
using namespace std; using namespace std;
using namespace pcc; using namespace pcc;
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
std::cout << "tmc3 v" << TMC3_VERSION_MAJOR << "." << TMC3_VERSION_MAJOR << std::endl
<< std::endl;
Parameters params; Parameters params;
Usage();
if (!ParseParameters(argc, argv, params)) { if (!ParseParameters(argc, argv, params)) {
std::cout << "Error: missing parameters!" << std::endl;
return -1; return -1;
} }
const auto start = std::chrono::high_resolution_clock::now(); const auto start = std::chrono::high_resolution_clock::now();
...@@ -61,77 +63,188 @@ int main(int argc, char *argv[]) { ...@@ -61,77 +63,188 @@ int main(int argc, char *argv[]) {
<< std::endl; << std::endl;
return ret; return ret;
} }
void Usage() {
std::cout << "tmc3 v" << TMC3_VERSION_MAJOR << "." << TMC3_VERSION_MAJOR << std::endl
<< std::endl;
std::cout << "+ Usage" << std::endl; //---------------------------------------------------------------------------
std::cout << "\t Encode example: \n tmc3 --mode 0 --mergeDuplicatedPoints 1 " // :: Command line / config parsing helpers
"--uncompressedDataPath Ford_01-0100.ply --compressedStreamPath compressed.bin "
"--colorTransform 1 --numberOfNearestNeighborsInPrediction 8 " template <typename T>
"--positionQuantizationScale 500.0 --levelOfDetailCount 6 --dist2 16777216 4194304 " static std::istream& readUInt(std::istream &in, T &val) {
"1048576 262144 65536 0 --quantizationSteps 1 1 1 2 2 2 --quantizationDeadZoneSizes " unsigned int tmp;
"1 1 1 2 2 2 --searchRange 2 --attribute color --attribute reflectance" in >> tmp;
<< std::endl val = T(tmp);
<< std::endl; return in;
std::cout << "\t Decode example: \n tmc3 --mode 1 --compressedStreamPath compressed.bin " }
"--reconstructedDataPath reconstructed_dec.ply --colorTransform 1"
<< std::endl static std::istream& operator>>(std::istream &in, CodecMode &val) {
<< std::endl; return readUInt(in, val);
std::cout << std::endl;
} }
static std::istream& operator>>(std::istream &in, ColorTransform &val) {
return readUInt(in, val);
}
//---------------------------------------------------------------------------
// :: Command line / config parsing
bool ParseParameters(int argc, char *argv[], Parameters &params) { bool ParseParameters(int argc, char *argv[], Parameters &params) {
PCCAttributeEncodeParamaters attributeEncodeParams;
for (int i = 1; i < argc; ++i) { namespace po = df::program_options_lite;
if (!strcmp(argv[i], "--mode")) {
if (++i < argc) params.mode = atoi(argv[i]); PCCAttributeEncodeParamaters params_attr;
} else if (!strcmp(argv[i], "--reconstructedDataPath")) { bool print_help = false;
if (++i < argc) params.reconstructedDataPath = argv[i];
} else if (!strcmp(argv[i], "--uncompressedDataPath")) { // a helper to set the attribute
if (++i < argc) params.uncompressedDataPath = argv[i]; std::function<po::OptionFunc::Func> attribute_setter =
} else if (!strcmp(argv[i], "--compressedStreamPath")) { [&](po::Options&, const std::string& name, po::ErrorReporter) {
if (++i < argc) params.compressedStreamPath = argv[i]; // copy the current state of parsed attribute parameters
} else if (!strcmp(argv[i], "--attribute")) { //
if (++i < argc) // NB: this does not cause the default values of attr to be restored
params.encodeParameters.attributeEncodeParameters[argv[i]] = attributeEncodeParams; // for the next attribute block. A side-effect of this is that the
} else if (!strcmp(argv[i], "--numberOfNearestNeighborsInPrediction")) { // following is allowed leading to attribute foo having both X=1 and
if (++i < argc) attributeEncodeParams.numberOfNearestNeighborsInPrediction = atoi(argv[i]); // Y=2:
} else if (!strcmp(argv[i], "--levelOfDetailCount")) { // "--attr.X=1 --attribute foo --attr.Y=2 --attribute foo"
if (++i < argc) { //
attributeEncodeParams.levelOfDetailCount = atoi(argv[i]); params.encodeParameters.attributeEncodeParameters[name] = params_attr;
attributeEncodeParams.quantizationSteps.resize(attributeEncodeParams.levelOfDetailCount); };
attributeEncodeParams.quantizationDeadZoneSizes.resize(
attributeEncodeParams.levelOfDetailCount); // The definition of the program/config options, along with default values.
attributeEncodeParams.dist2.resize(attributeEncodeParams.levelOfDetailCount); //
} // NB: when updating the following tables:
} else if (!strcmp(argv[i], "--quantizationSteps")) { // (a) please keep to 80-columns for easier reading at a glance,
for (size_t k = 0; k < attributeEncodeParams.levelOfDetailCount; ++k) { // (b) do not vertically align values -- it breaks quickly
if (++i < argc) attributeEncodeParams.quantizationSteps[k] = atoi(argv[i]); //
po::Options opts;
opts.addOptions()
("help", print_help, false, "this help text")
("config,c", po::parseConfigFile, "configuration file name")
("mode", params.mode, CODEC_MODE_ENCODE,
"The encoding/decoding mode:\n"
" 0: encode\n"
" 1: decode\n"
" 2: encode with lossless geometry\n"
" 3: decode with lossless geometry")
// i/o parameters
("reconstructedDataPath",
params.reconstructedDataPath, {},
"The ouput reconstructed pointcloud file path (decoder only)")
("uncompressedDataPath",
params.uncompressedDataPath, {},
"The input pointcloud file path")
("compressedStreamPath",
params.compressedStreamPath, {},
"The compressed bitstream path (encoder=output, decoder=input)")
// general
("colorTransform",
params.colorTransform, COLOR_TRANSFORM_RGB_TO_YCBCR,
"The colour transform to be applied:\n"
" 0: none\n"
" 1: RGB to YCbCr (Rec.709)")
("positionQuantizationScale",
params.encodeParameters.positionQuantizationScale, 1.,
"Scale factor to be applied to point positions during quantization process")
("mergeDuplicatedPoints",
params.encodeParameters.mergeDuplicatedPoints, true,
"Enables removal of duplicated points")
("roundOutputPositions",
params.roundOutputPositions, false,
"todo(kmammou)")
// attribute processing
// NB: Attribute options are special in the way they are applied (see above)
("attribute",
attribute_setter,
"Encode the given attribute (NB, must appear after the"
"following attribute parameters)")
("searchRange",
params_attr.searchRange, size_t(2),
"Attribute's todo(kmammou)")
("numberOfNearestNeighborsInPrediction",
params_attr.numberOfNearestNeighborsInPrediction, size_t(8),
"Attribute's maximum number of nearest neighbors to be used for prediction")
("levelOfDetailCount",
params_attr.levelOfDetailCount, size_t(6),
"Attribute's number of levels of detail")
("quantizationSteps",
params_attr.quantizationSteps, {},
"Attribute's list of quantization step sizes (one for each LoD)")
("quantizationDeadZoneSizes",
params_attr.quantizationDeadZoneSizes, {},
"Attribute's list of dead-zone sizes (one for each LoD)")
("dist2", params_attr.dist2, {},
"Attribute's list of squared distances (one for each LoD)")
;
po::setDefaults(opts);
po::ErrorReporter err;
const list<const char*>& argv_unhandled =
po::scanArgv(opts, argc, (const char**)argv, err);
for (const auto arg : argv_unhandled) {
err.warn() << "Unhandled argument ignored: " << arg << "\n";
}
if (argc == 1 || print_help) {
po::doHelp(std::cout, opts, 78);
return false;
}
// sanity checks
// - validate that quantizationSteps, quantizationDeadZoneSizes, dist2
// of each attribute contain levelOfDetailCount elements.
for (const auto &attr : params.encodeParameters.attributeEncodeParameters) {
int lod = attr.second.levelOfDetailCount;
if (attr.second.dist2.size() != lod) {
err.error() << attr.first << ".dist2 does not have " << lod << " entries\n";
} }
} else if (!strcmp(argv[i], "--quantizationDeadZoneSizes")) { if (attr.second.quantizationSteps.size() != lod) {
for (size_t k = 0; k < attributeEncodeParams.levelOfDetailCount; ++k) { err.error() << attr.first << ".quantizationSteps does not have " << lod << " entries\n";
if (++i < argc) attributeEncodeParams.quantizationDeadZoneSizes[k] = atoi(argv[i]);
} }
} else if (!strcmp(argv[i], "--dist2")) { if (attr.second.quantizationDeadZoneSizes.size() != lod) {
for (size_t k = 0; k < attributeEncodeParams.levelOfDetailCount; ++k) { err.error() << attr.first << ".quantizationDeadZoneSizes does not have " << lod << " entries\n";
if (++i < argc) attributeEncodeParams.dist2[k] = atoi(argv[i]);
} }
} else if (!strcmp(argv[i], "--searchRange")) {
if (++i < argc) attributeEncodeParams.searchRange = atoi(argv[i]);
} else if (!strcmp(argv[i], "--colorTransform")) {
if (++i < argc) params.colorTransform = static_cast<ColorTransform>(atoi(argv[i]));
} 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 = atoi(argv[i]) != 0;
} else if (!strcmp(argv[i], "--roundOutputPositions")) {
if (++i < argc) params.roundOutputPositions = atoi(argv[i]) != 0;
}
} }
// check required arguments are specified
const bool encode = const bool encode =
(params.mode == CODEC_MODE_ENCODE || params.mode == CODEC_MODE_ENCODE_LOSSLESS_GEOMETRY); params.mode == CODEC_MODE_ENCODE
|| params.mode == CODEC_MODE_ENCODE_LOSSLESS_GEOMETRY;
if (encode && params.uncompressedDataPath.empty())
err.error() << "uncompressedDataPath not set\n";
if (!encode && params.reconstructedDataPath.empty())
err.error() << "reconstructedDataPath not set\n";
if (params.compressedStreamPath.empty())
err.error() << "compressedStreamPath not set\n";
// currently the attributes with lossless geometry require the source data
// todo(?): remove this dependency by improving reporting
if (params.mode == CODEC_MODE_DECODE_LOSSLESS_GEOMETRY
&& params.uncompressedDataPath.empty())
err.error() << "uncompressedDataPath not set\n";
// report the current configuration (only in the absence of errors so
// that errors/warnings are more obvious and in the same place).
if (err.is_errored)
return false;
cout << "+ Parameters" << endl; cout << "+ Parameters" << endl;
cout << "\t mode "; cout << "\t mode ";
if (params.mode == CODEC_MODE_ENCODE) { if (params.mode == CODEC_MODE_ENCODE) {
...@@ -181,17 +294,9 @@ bool ParseParameters(int argc, char *argv[], Parameters &params) { ...@@ -181,17 +294,9 @@ bool ParseParameters(int argc, char *argv[], Parameters &params) {
cout << "\t roundOutputPositions " << params.roundOutputPositions << endl; cout << "\t roundOutputPositions " << params.roundOutputPositions << endl;
} }
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; return true;
} }
int Compress(const Parameters &params) { int Compress(const Parameters &params) {
PCCPointSet3 pointCloud; PCCPointSet3 pointCloud;
if (!pointCloud.read(params.uncompressedDataPath) || pointCloud.getPointCount() == 0) { if (!pointCloud.read(params.uncompressedDataPath) || pointCloud.getPointCount() == 0) {
......
...@@ -69,20 +69,13 @@ struct Parameters { ...@@ -69,20 +69,13 @@ struct Parameters {
std::string uncompressedDataPath; std::string uncompressedDataPath;
std::string compressedStreamPath; std::string compressedStreamPath;
std::string reconstructedDataPath; std::string reconstructedDataPath;
size_t colorTransform; ColorTransform colorTransform;
size_t mode; CodecMode mode;
bool roundOutputPositions; bool roundOutputPositions;
pcc::PCCTMC3Encoder3Parameters encodeParameters; pcc::PCCTMC3Encoder3Parameters encodeParameters;
Parameters(void) {
mode = CODEC_MODE_ENCODE;
colorTransform = COLOR_TRANSFORM_RGB_TO_YCBCR;
roundOutputPositions = false;
}
}; };
bool ParseParameters(int argc, char *argv[], Parameters &params); bool ParseParameters(int argc, char *argv[], Parameters &params);
void Usage();
int Compress(const Parameters &params); int Compress(const Parameters &params);
int Decompress(const Parameters &params); int Decompress(const Parameters &params);
......
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