diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index b43e80e9..173129c5 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,9 +1,5 @@ # The examples need a few additional dependencies (e.g. boost filesystem, program_options, and OpenCV highgui): find_package(OpenCV 4 CONFIG REQUIRED core imgproc imgcodecs) - -set(Boost_NO_WARN_NEW_VERSIONS ON) # Supress "New Boost version may have incorrect dependencies or import targets" warning -find_package(Boost 1.71.0 REQUIRED COMPONENTS program_options) - find_package(cxxopts CONFIG REQUIRED) # Simple model fitting (orthographic camera & shape to landmarks) example: @@ -14,13 +10,13 @@ target_compile_options(fit-model-simple PRIVATE "$<$:/bigo # Model fitting example that fits orthographic camera, shape, blendshapes, and contours: add_executable(fit-model fit-model.cpp) -target_link_libraries(fit-model PRIVATE eos opencv_core opencv_imgproc opencv_imgcodecs Boost::program_options) +target_link_libraries(fit-model PRIVATE cxxopts::cxxopts eos opencv_core opencv_imgproc opencv_imgcodecs) target_link_libraries(fit-model PRIVATE "$<$:-pthread>$<$:-pthreads>") target_compile_options(fit-model PRIVATE "$<$:/bigobj>") # Model fitting example that fits orthographic camera, shape, blendshapes, and contours to multiple images: add_executable(fit-model-multi fit-model-multi.cpp) -target_link_libraries(fit-model-multi PRIVATE eos opencv_core opencv_imgproc opencv_imgcodecs Boost::program_options) +target_link_libraries(fit-model-multi PRIVATE cxxopts::cxxopts eos opencv_core opencv_imgproc opencv_imgcodecs) target_link_libraries(fit-model-multi PRIVATE "$<$:-pthread>$<$:-pthreads>") target_compile_options(fit-model-multi PRIVATE "$<$:/bigobj>") @@ -42,7 +38,7 @@ if(EOS_BUILD_CERES_EXAMPLE) # Single and multi-image non-linear model fitting with Ceres example: add_executable(fit-model-ceres fit-model-ceres.cpp) - target_link_libraries(fit-model-ceres PRIVATE eos Ceres::ceres opencv_core opencv_imgproc opencv_imgcodecs Boost::program_options) + target_link_libraries(fit-model-ceres PRIVATE cxxopts::cxxopts eos Ceres::ceres opencv_core opencv_imgproc opencv_imgcodecs) target_compile_options(fit-model-ceres PRIVATE "$<$:/bigobj>") install(TARGETS fit-model-ceres DESTINATION bin) endif() diff --git a/examples/fit-model-ceres.cpp b/examples/fit-model-ceres.cpp index 0cd0245d..e8b54351 100644 --- a/examples/fit-model-ceres.cpp +++ b/examples/fit-model-ceres.cpp @@ -39,7 +39,7 @@ #include "opencv2/imgproc.hpp" #include "opencv2/imgcodecs.hpp" -#include "boost/program_options.hpp" +#include #include #include @@ -48,15 +48,12 @@ using namespace eos; using namespace ceres; -namespace po = boost::program_options; using eos::core::Landmark; using eos::core::LandmarkCollection; using cv::Mat; using Eigen::Vector2f; using std::cout; using std::endl; -using std::string; -using std::vector; // print a vector: template @@ -84,42 +81,51 @@ std::ostream& operator<<(std::ostream& out, const std::vector& v) */ int main(int argc, char* argv[]) { + using std::vector; + using std::string; + cxxopts::Options options("fit-model-ceres", + "A simple example of fitting a 3D Morphable Model using Ceres Solver."); + // clang-format off + options.add_options() + ("h,help", "display the help message") + ("m,model", "a Morphable Model, containing a shape and albedo model, stored as cereal BinaryArchive", + cxxopts::value()->default_value("../share/sfm_3448.bin"), "filename") + ("b,blendshapes", "file with blendshapes", + cxxopts::value()->default_value("../share/expression_blendshapes_3448.bin"), "filename") + ("i,image", "an input image", + cxxopts::value()->default_value("data/image_0010.png"), "filename") + ("l,landmarks", "2D landmarks for the image, in ibug .pts format", + cxxopts::value()->default_value("data/image_0010.pts"), "filename") + ("p,mapping", "landmark identifier to model vertex number mapping", + cxxopts::value()->default_value("../share/ibug_to_sfm.txt"), "filename") + ("c,model-contour", "file with model contour indices", + cxxopts::value()->default_value("../share/sfm_model_contours.json"), "filename") + ("o,output", "basename for the output obj file", + cxxopts::value()->default_value("out"), "basename"); + // clang-format on + using std::filesystem::path; path modelfile, imagefile, landmarksfile, mappingsfile, contourfile, blendshapesfile, outputfile; try { - po::options_description desc("Allowed options"); - // clang-format off - desc.add_options() - ("help,h", "display the help message") - ("model,m", po::value(&modelfile)->required()->default_value("../share/sfm_3448.bin"), - "a Morphable Model, containing a shape and albedo model, stored as cereal BinaryArchive") - ("blendshapes,b", po::value(&blendshapesfile)->required()->default_value("../share/expression_blendshapes_3448.bin"), - "file with blendshapes") - ("image,i", po::value(&imagefile)->required()->default_value("data/image_0010.png"), - "an input image") - ("landmarks,l", po::value(&landmarksfile)->required()->default_value("data/image_0010.pts"), - "2D landmarks for the image, in ibug .pts format") - ("mapping,p", po::value(&mappingsfile)->required()->default_value("../share/ibug_to_sfm.txt"), - "landmark identifier to model vertex number mapping") - ("model-contour,c", po::value(&contourfile)->required()->default_value("../share/sfm_model_contours.json"), - "file with model contour indices") - ("output,o", po::value(&outputfile)->required()->default_value("out"), - "basename for the output obj file"); - // clang-format on - po::variables_map vm; - po::store(po::command_line_parser(argc, argv).options(desc).run(), vm); - if (vm.count("help")) + const auto result = options.parse(argc, argv); + if (result.count("help")) { - cout << "Usage: fit-model-ceres [options]" << endl; - cout << desc; + std::cout << options.help() << std::endl; return EXIT_SUCCESS; } - po::notify(vm); - } catch (const po::error& e) + + modelfile = result["model"].as(); // required (with default) + blendshapesfile = result["blendshapes"].as(); // required (with default) + imagefile = result["image"].as(); // required (with default) + landmarksfile = result["landmarks"].as(); // required (with default) + mappingsfile = result["mapping"].as(); // required (with default) + contourfile = result["model-contour"].as(); // required (with default) + outputfile = result["output"].as(); // required (with default) + } catch (const std::exception& e) { - cout << "Error while parsing command-line arguments: " << e.what() << endl; - cout << "Use --help to display a list of options." << endl; + std::cout << "Error while parsing command-line arguments: " << e.what() << std::endl; + std::cout << "Use --help to display a list of options." << std::endl; return EXIT_FAILURE; } diff --git a/examples/fit-model-multi.cpp b/examples/fit-model-multi.cpp index ba1fd236..b3ed2212 100644 --- a/examples/fit-model-multi.cpp +++ b/examples/fit-model-multi.cpp @@ -35,7 +35,7 @@ #include "opencv2/imgproc.hpp" #include "opencv2/imgcodecs.hpp" -#include "boost/program_options.hpp" +#include #include #include @@ -45,14 +45,11 @@ #include using namespace eos; -namespace po = boost::program_options; using eos::core::Landmark; using eos::core::LandmarkCollection; using cv::Mat; using std::cout; using std::endl; -using std::vector; -using std::string; /** * @brief Merges isomaps from a live video with a weighted averaging, based @@ -137,56 +134,82 @@ class WeightedIsomapAveraging */ int main(int argc, char *argv[]) { + using std::vector; + using std::string; + cxxopts::Options options( + "fit-model-multi", + "A simple example of fitting a 3DMM shape model to 2D landmarks of multiple images."); + // clang-format off + options.add_options() + ("h,help", "display the help message") + ("m,model", "a Morphable Model stored as cereal BinaryArchive", + cxxopts::value()->default_value("../share/sfm_shape_3448.bin"), "filename") + ("i,image", "An input image. Repeat this option to input multiple images.", + cxxopts::value>(), "filename") + ("l,landmarks", "2D landmarks for the given images, in ibug .pts format. " + "Repeat this option to provide landmarks for multiple images, and make sure to us the same order as the input images.", + cxxopts::value>(), "filename") + ("p,mapping", "landmark identifier to model vertex number mapping", + cxxopts::value()->default_value("../share/ibug_to_sfm.txt"), "filename") + ("c,model-contour", "file with model contour indices", + cxxopts::value()->default_value("../share/sfm_model_contours.json"), "filename") + ("e,edge-topology", "file with model's precomputed edge topology", + cxxopts::value()->default_value("../share/sfm_3448_edge_topology.json"), "filename") + ("b,blendshapes", "file with blendshapes", + cxxopts::value()->default_value("../share/expression_blendshapes_3448.bin"), "filename") + ("o,output", "basename for the output rendering and obj files", + cxxopts::value()->default_value("out"), "basename"); + // clang-format on + using std::filesystem::path; path modelfile, mappingsfile, contourfile, edgetopologyfile, blendshapesfile, outputfilebase; vector imagefiles, landmarksfiles; try { - po::options_description desc("Allowed options"); - // clang-format off - desc.add_options() - ("help,h", "display the help message") - ("model,m", po::value(&modelfile)->required()->default_value("../share/sfm_shape_3448.bin"), - "a Morphable Model stored as cereal BinaryArchive") - ("image,i", po::value>(&imagefiles)->multitoken(), - "an input image") - ("landmarks,l", po::value>(&landmarksfiles)->multitoken(), - "2D landmarks for the image, in ibug .pts format") - ("mapping,p", po::value(&mappingsfile)->required()->default_value("../share/ibug_to_sfm.txt"), - "landmark identifier to model vertex number mapping") - ("model-contour,c", po::value(&contourfile)->required()->default_value("../share/model_contours.json"), - "file with model contour indices") - ("edge-topology,e", po::value(&edgetopologyfile)->required()->default_value("../share/sfm_3448_edge_topology.json"), - "file with model's precomputed edge topology") - ("blendshapes,b", po::value(&blendshapesfile)->required()->default_value("../share/expression_blendshapes_3448.bin"), - "file with blendshapes") - ("output,o", po::value(&outputfilebase)->required()->default_value("out"), - "basename for the output rendering and obj files"); - // clang-format on - po::variables_map vm; - po::store(po::command_line_parser(argc, argv).options(desc).run(), vm); - if (vm.count("help")) + const auto result = options.parse(argc, argv); + if (result.count("help")) { - cout << "Usage: fit-model-multi [options]" << endl; - cout << desc; + std::cout << options.help() << std::endl; return EXIT_SUCCESS; } - po::notify(vm); - } catch (const po::error& e) + + modelfile = result["model"].as(); // required (with default) + { + const auto imagefiles_str = + result["image"].as>(); // required + for (const auto& imagefile : imagefiles_str) + { + imagefiles.push_back(imagefile); + } + } + { + const auto landmarksfiles_str = + result["landmarks"].as>(); // required + for (const auto& landmarksfile : landmarksfiles_str) + { + landmarksfiles.push_back(landmarksfile); + } + } + mappingsfile = result["mapping"].as(); // required (with default) + contourfile = result["model-contour"].as(); // required (with default) + edgetopologyfile = result["edge-topology"].as(); // required (with default) + blendshapesfile = result["blendshapes"].as(); // required (with default) + outputfilebase = result["output"].as(); // required (with default) + } catch (const std::exception& e) { - cout << "Error while parsing command-line arguments: " << e.what() << endl; - cout << "Use --help to display a list of options." << endl; + std::cout << "Error while parsing command-line arguments: " << e.what() << std::endl; + std::cout << "Use --help to display a list of options." << std::endl; return EXIT_FAILURE; } if (landmarksfiles.size() != imagefiles.size()) { - cout << "Number of landmarks files not equal to number of images given: " << landmarksfiles.size() - << "!=" << imagefiles.size() << endl; + cout << "Number of landmarks files not equal to number of images given. Image files: " + << imagefiles.size() << ", landmark files: " << landmarksfiles.size() << endl; return EXIT_FAILURE; } if (landmarksfiles.empty()) { - cout << "Please give at least 1 image and landmark file." << endl; + cout << "Please input at least 1 image and landmark file." << endl; return EXIT_FAILURE; } // Load the image, landmarks, LandmarkMapper and the Morphable Model: diff --git a/examples/fit-model-simple.cpp b/examples/fit-model-simple.cpp index bdd89f27..f07b200d 100644 --- a/examples/fit-model-simple.cpp +++ b/examples/fit-model-simple.cpp @@ -49,7 +49,6 @@ using Eigen::Vector4f; using cv::Mat; using std::cout; using std::endl; -using std::string; using std::vector; /** @@ -63,26 +62,26 @@ using std::vector; */ int main(int argc, char* argv[]) { + using std::string; cxxopts::Options options("fit-model-simple", "A simple example of fitting a 3DMM shape model to 2D landmarks."); // clang-format off options.add_options() ("h,help", "display the help message") ("m,model", "a Morphable Model stored as cereal BinaryArchive", - cxxopts::value()->default_value("../share/sfm_shape_3448.bin"), "filename") + cxxopts::value()->default_value("../share/sfm_shape_3448.bin"), "filename") ("i,image", "an input image", - cxxopts::value()->default_value("data/image_0010.png"), "filename") + cxxopts::value()->default_value("data/image_0010.png"), "filename") ("l,landmarks", "2D landmarks for the image, in ibug .pts format", - cxxopts::value()->default_value("data/image_0010.pts"), "filename") + cxxopts::value()->default_value("data/image_0010.pts"), "filename") ("p,mapping", "landmark identifier to model vertex number mapping", - cxxopts::value()->default_value("../share/ibug_to_sfm.txt"), "filename") + cxxopts::value()->default_value("../share/ibug_to_sfm.txt"), "filename") ("o,output", "basename for the output rendering and obj files", - cxxopts::value()->default_value("out"), "basename"); + cxxopts::value()->default_value("out"), "basename"); // clang-format on using std::filesystem::path; path modelfile, imagefile, landmarksfile, mappingsfile, outputbasename; - try { const auto result = options.parse(argc, argv); @@ -92,11 +91,11 @@ int main(int argc, char* argv[]) return EXIT_SUCCESS; } - modelfile = result["model"].as(); // required (with default) - imagefile = result["image"].as(); // required (with default) - landmarksfile = result["landmarks"].as(); // required (with default) - mappingsfile = result["mapping"].as(); // required (with default) - outputbasename = result["output"].as(); // required (with default) + modelfile = result["model"].as(); // required (with default) + imagefile = result["image"].as(); // required (with default) + landmarksfile = result["landmarks"].as(); // required (with default) + mappingsfile = result["mapping"].as(); // required (with default) + outputbasename = result["output"].as(); // required (with default) } catch (const std::exception& e) { std::cout << "Error while parsing command-line arguments: " << e.what() << std::endl; diff --git a/examples/fit-model.cpp b/examples/fit-model.cpp index b2e9d945..060c6160 100644 --- a/examples/fit-model.cpp +++ b/examples/fit-model.cpp @@ -31,7 +31,7 @@ #include "Eigen/Core" -#include "boost/program_options.hpp" +#include #include "opencv2/core.hpp" #include "opencv2/imgproc.hpp" @@ -43,14 +43,11 @@ #include using namespace eos; -namespace po = boost::program_options; using eos::core::Landmark; using eos::core::LandmarkCollection; using cv::Mat; using std::cout; using std::endl; -using std::string; -using std::vector; /** * This app demonstrates estimation of the camera and fitting of the shape @@ -63,45 +60,55 @@ using std::vector; */ int main(int argc, char* argv[]) { + using std::vector; + using std::string; + cxxopts::Options options("fit-model", "An example of fitting a 3DMM shape model to 2D landmarks, " + "including expression and contour fitting."); + // clang-format off + options.add_options() + ("h,help", "display the help message") + ("m,model", "a Morphable Model stored as cereal BinaryArchive", + cxxopts::value()->default_value("../share/sfm_shape_3448.bin"), "filename") + ("i,image", "an input image", + cxxopts::value()->default_value("data/image_0010.png"), "filename") + ("l,landmarks", "2D landmarks for the image, in ibug .pts format", + cxxopts::value()->default_value("data/image_0010.pts"), "filename") + ("p,mapping", "landmark identifier to model vertex number mapping", + cxxopts::value()->default_value("../share/ibug_to_sfm.txt"), "filename") + ("c,model-contour", "file with model contour indices", + cxxopts::value()->default_value("../share/sfm_model_contours.json"), "filename") + ("e,edge-topology", "file with model's precomputed edge topology", + cxxopts::value()->default_value("../share/sfm_3448_edge_topology.json"), "filename") + ("b,blendshapes", "file with blendshapes", + cxxopts::value()->default_value("../share/expression_blendshapes_3448.bin"), "filename") + ("o,output", "basename for the output rendering and obj files", + cxxopts::value()->default_value("out"), "basename"); + // clang-format on + using std::filesystem::path; path modelfile, imagefile, landmarksfile, mappingsfile, contourfile, edgetopologyfile, blendshapesfile, outputbasename; try { - po::options_description desc("Allowed options"); - // clang-format off - desc.add_options() - ("help,h", "display the help message") - ("model,m", po::value(&modelfile)->required()->default_value("../share/sfm_shape_3448.bin"), - "a Morphable Model stored as cereal BinaryArchive") - ("image,i", po::value(&imagefile)->required()->default_value("data/image_0010.png"), - "an input image") - ("landmarks,l", po::value(&landmarksfile)->required()->default_value("data/image_0010.pts"), - "2D landmarks for the image, in ibug .pts format") - ("mapping,p", po::value(&mappingsfile)->required()->default_value("../share/ibug_to_sfm.txt"), - "landmark identifier to model vertex number mapping") - ("model-contour,c", po::value(&contourfile)->required()->default_value("../share/sfm_model_contours.json"), - "file with model contour indices") - ("edge-topology,e", po::value(&edgetopologyfile)->required()->default_value("../share/sfm_3448_edge_topology.json"), - "file with model's precomputed edge topology") - ("blendshapes,b", po::value(&blendshapesfile)->required()->default_value("../share/expression_blendshapes_3448.bin"), - "file with blendshapes") - ("output,o", po::value(&outputbasename)->required()->default_value("out"), - "basename for the output rendering and obj files"); - // clang-format on - po::variables_map vm; - po::store(po::command_line_parser(argc, argv).options(desc).run(), vm); - if (vm.count("help")) + const auto result = options.parse(argc, argv); + if (result.count("help")) { - cout << "Usage: fit-model [options]" << endl; - cout << desc; + std::cout << options.help() << std::endl; return EXIT_SUCCESS; } - po::notify(vm); - } catch (const po::error& e) + + modelfile = result["model"].as(); // required (with default) + imagefile = result["image"].as(); // required (with default) + landmarksfile = result["landmarks"].as(); // required (with default) + mappingsfile = result["mapping"].as(); // required (with default) + contourfile = result["model-contour"].as(); // required (with default) + edgetopologyfile = result["edge-topology"].as(); // required (with default) + blendshapesfile = result["blendshapes"].as(); // required (with default) + outputbasename = result["output"].as(); // required (with default) + } catch (const std::exception& e) { - cout << "Error while parsing command-line arguments: " << e.what() << endl; - cout << "Use --help to display a list of options." << endl; + std::cout << "Error while parsing command-line arguments: " << e.what() << std::endl; + std::cout << "Use --help to display a list of options." << std::endl; return EXIT_FAILURE; } diff --git a/utils/scm-to-cereal.cpp b/utils/scm-to-cereal.cpp index 9228794f..6e0ecac3 100644 --- a/utils/scm-to-cereal.cpp +++ b/utils/scm-to-cereal.cpp @@ -50,7 +50,6 @@ int main(int argc, char* argv[]) std::filesystem::path scmmodelfile, outputfile; std::optional isomapfile; bool save_shape_only; - try { const auto result = options.parse(argc, argv);