From 5e2b5b42335da0fbc1ca8de31507a962e751cd52 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Candice=20Bent=C3=A9jac?= Date: Wed, 7 Jun 2023 16:26:51 +0200 Subject: [PATCH 1/3] [software] PrepareDenseScene: Formatting: Use 4-space based indentation --- .../pipeline/main_prepareDenseScene.cpp | 562 +++++++++--------- 1 file changed, 281 insertions(+), 281 deletions(-) diff --git a/src/software/pipeline/main_prepareDenseScene.cpp b/src/software/pipeline/main_prepareDenseScene.cpp index a9c67fb202..dc1d063c1f 100644 --- a/src/software/pipeline/main_prepareDenseScene.cpp +++ b/src/software/pipeline/main_prepareDenseScene.cpp @@ -44,34 +44,34 @@ namespace fs = boost::filesystem; template void process(const std::string &dstColorImage, const IntrinsicBase* cam, const oiio::ParamValueList & metadata, const std::string & srcImage, bool evCorrection, float exposureCompensation, MaskFuncT && maskFunc) { - ImageT image, image_ud; - readImage(srcImage, image, image::EImageColorSpace::LINEAR); - - //exposure correction - if(evCorrection) - { - for(int pix = 0; pix < image.Width() * image.Height(); ++pix) - { - image(pix) = image(pix) * exposureCompensation; - } - } - - // mask - maskFunc(image); - - // undistort - if(cam->isValid() && cam->hasDistortion()) - { - // undistort the image and save it - using Pix = typename ImageT::Tpixel; - Pix pixZero(Pix::Zero()); - UndistortImage(image, cam, image_ud, pixZero); - writeImage(dstColorImage, image_ud, image::ImageWriteOptions(), metadata); - } - else - { - writeImage(dstColorImage, image, image::ImageWriteOptions(), metadata); - } + ImageT image, image_ud; + readImage(srcImage, image, image::EImageColorSpace::LINEAR); + + // exposure correction + if(evCorrection) + { + for(int pix = 0; pix < image.Width() * image.Height(); ++pix) + { + image(pix) = image(pix) * exposureCompensation; + } + } + + // mask + maskFunc(image); + + // undistort + if(cam->isValid() && cam->hasDistortion()) + { + // undistort the image and save it + using Pix = typename ImageT::Tpixel; + Pix pixZero(Pix::Zero()); + UndistortImage(image, cam, image_ud, pixZero); + writeImage(dstColorImage, image_ud, image::ImageWriteOptions(), metadata); + } + else + { + writeImage(dstColorImage, image, image::ImageWriteOptions(), metadata); + } } bool prepareDenseScene(const SfMData& sfmData, @@ -85,287 +85,287 @@ bool prepareDenseScene(const SfMData& sfmData, bool saveMatricesFiles, bool evCorrection) { - // defined view Ids - std::set viewIds; + // defined view Ids + std::set viewIds; - sfmData::Views::const_iterator itViewBegin = sfmData.getViews().begin(); - sfmData::Views::const_iterator itViewEnd = sfmData.getViews().end(); + sfmData::Views::const_iterator itViewBegin = sfmData.getViews().begin(); + sfmData::Views::const_iterator itViewEnd = sfmData.getViews().end(); - if(endIndex > 0) - { - itViewEnd = itViewBegin; - std::advance(itViewEnd, endIndex); - } - - std::advance(itViewBegin, (beginIndex < 0) ? 0 : beginIndex); + if(endIndex > 0) + { + itViewEnd = itViewBegin; + std::advance(itViewEnd, endIndex); + } - // export valid views as projective cameras - for(auto it = itViewBegin; it != itViewEnd; ++it) - { - const View* view = it->second.get(); - if (!sfmData.isPoseAndIntrinsicDefined(view)) - continue; - viewIds.insert(view->getViewId()); - } + std::advance(itViewBegin, (beginIndex < 0) ? 0 : beginIndex); - if((outputFileType != image::EImageFileType::EXR) && saveMetadata) - ALICEVISION_LOG_WARNING("Cannot save informations in images metadata.\n" - "Choose '.exr' file type if you want AliceVision custom metadata"); + // export valid views as projective cameras + for(auto it = itViewBegin; it != itViewEnd; ++it) + { + const View* view = it->second.get(); + if (!sfmData.isPoseAndIntrinsicDefined(view)) + continue; + viewIds.insert(view->getViewId()); + } - // export data - auto progressDisplay = system::createConsoleProgressDisplay(viewIds.size(), std::cout, - "Exporting Scene Undistorted Images\n"); + if((outputFileType != image::EImageFileType::EXR) && saveMetadata) + ALICEVISION_LOG_WARNING("Cannot save informations in images metadata.\n" + "Choose '.exr' file type if you want AliceVision custom metadata"); - // for exposure correction - const double medianCameraExposure = sfmData.getMedianCameraExposureSetting().getExposure(); - ALICEVISION_LOG_INFO("Median Camera Exposure: " << medianCameraExposure << ", Median EV: " << std::log2(1.0/medianCameraExposure)); + // export data + auto progressDisplay = system::createConsoleProgressDisplay(viewIds.size(), std::cout, + "Exporting Scene Undistorted Images\n"); -#pragma omp parallel for num_threads(3) - for(int i = 0; i < viewIds.size(); ++i) - { - auto itView = viewIds.begin(); - std::advance(itView, i); + // for exposure correction + const double medianCameraExposure = sfmData.getMedianCameraExposureSetting().getExposure(); + ALICEVISION_LOG_INFO("Median Camera Exposure: " << medianCameraExposure << ", Median EV: " << std::log2(1.0/medianCameraExposure)); - const IndexT viewId = *itView; - const View* view = sfmData.getViews().at(viewId).get(); + #pragma omp parallel for num_threads(3) + for(int i = 0; i < viewIds.size(); ++i) + { + auto itView = viewIds.begin(); + std::advance(itView, i); - Intrinsics::const_iterator iterIntrinsic = sfmData.getIntrinsics().find(view->getIntrinsicId()); + const IndexT viewId = *itView; + const View* view = sfmData.getViews().at(viewId).get(); - //we have a valid view with a corresponding camera & pose - const std::string baseFilename = std::to_string(viewId); + Intrinsics::const_iterator iterIntrinsic = sfmData.getIntrinsics().find(view->getIntrinsicId()); - // get metadata from source image to be sure we get all metadata. We don't use the metadatas from the Views inside the SfMData to avoid type conversion problems with string maps. - std::string srcImage = view->getImagePath(); - oiio::ParamValueList metadata = image::readImageMetadata(srcImage); + // we have a valid view with a corresponding camera & pose + const std::string baseFilename = std::to_string(viewId); - // export camera - if(saveMetadata || saveMatricesFiles) - { - // get camera pose / projection - const Pose3 pose = sfmData.getPose(*view).getTransform(); - - std::shared_ptr cam = iterIntrinsic->second; - std::shared_ptr camPinHole = std::dynamic_pointer_cast(cam); - if (!camPinHole) { - ALICEVISION_LOG_ERROR("Camera is not pinhole in filter"); - continue; - } - - Mat34 P = camPinHole->getProjectiveEquivalent(pose); - - // get camera intrinsics matrices - const Mat3 K = dynamic_cast(sfmData.getIntrinsicPtr(view->getIntrinsicId()))->K(); - const Mat3& R = pose.rotation(); - const Vec3& t = pose.translation(); - - if(saveMatricesFiles) - { - std::ofstream fileP((fs::path(outFolder) / (baseFilename + "_P.txt")).string()); - fileP << std::setprecision(10) - << P(0, 0) << " " << P(0, 1) << " " << P(0, 2) << " " << P(0, 3) << "\n" - << P(1, 0) << " " << P(1, 1) << " " << P(1, 2) << " " << P(1, 3) << "\n" - << P(2, 0) << " " << P(2, 1) << " " << P(2, 2) << " " << P(2, 3) << "\n"; - fileP.close(); - - std::ofstream fileKRt((fs::path(outFolder) / (baseFilename + "_KRt.txt")).string()); - fileKRt << std::setprecision(10) - << K(0, 0) << " " << K(0, 1) << " " << K(0, 2) << "\n" - << K(1, 0) << " " << K(1, 1) << " " << K(1, 2) << "\n" - << K(2, 0) << " " << K(2, 1) << " " << K(2, 2) << "\n" - << "\n" - << R(0, 0) << " " << R(0, 1) << " " << R(0, 2) << "\n" - << R(1, 0) << " " << R(1, 1) << " " << R(1, 2) << "\n" - << R(2, 0) << " " << R(2, 1) << " " << R(2, 2) << "\n" - << "\n" - << t(0) << " " << t(1) << " " << t(2) << "\n"; - fileKRt.close(); - } - - if(saveMetadata) - { - // convert to 44 matix - Mat4 projectionMatrix; - projectionMatrix << P(0, 0), P(0, 1), P(0, 2), P(0, 3), - P(1, 0), P(1, 1), P(1, 2), P(1, 3), - P(2, 0), P(2, 1), P(2, 2), P(2, 3), - 0, 0, 0, 1; - - // convert matrices to rowMajor - std::vector vP(projectionMatrix.size()); - std::vector vK(K.size()); - std::vector vR(R.size()); - - typedef Eigen::Matrix RowMatrixXd; - Eigen::Map(vP.data(), projectionMatrix.rows(), projectionMatrix.cols()) = projectionMatrix; - Eigen::Map(vK.data(), K.rows(), K.cols()) = K; - Eigen::Map(vR.data(), R.rows(), R.cols()) = R; - - // add metadata - metadata.push_back(oiio::ParamValue("AliceVision:downscale", 1)); - metadata.push_back(oiio::ParamValue("AliceVision:P", oiio::TypeDesc(oiio::TypeDesc::DOUBLE, oiio::TypeDesc::MATRIX44), 1, vP.data())); - metadata.push_back(oiio::ParamValue("AliceVision:K", oiio::TypeDesc(oiio::TypeDesc::DOUBLE, oiio::TypeDesc::MATRIX33), 1, vK.data())); - metadata.push_back(oiio::ParamValue("AliceVision:R", oiio::TypeDesc(oiio::TypeDesc::DOUBLE, oiio::TypeDesc::MATRIX33), 1, vR.data())); - metadata.push_back(oiio::ParamValue("AliceVision:t", oiio::TypeDesc(oiio::TypeDesc::DOUBLE, oiio::TypeDesc::VEC3), 1, t.data())); - } - } + // get metadata from source image to be sure we get all metadata. We don't use the metadatas from the Views inside the SfMData to avoid type conversion problems with string maps. + std::string srcImage = view->getImagePath(); + oiio::ParamValueList metadata = image::readImageMetadata(srcImage); - // export undistort image - { - if(!imagesFolders.empty()) - { - std::vector paths = sfmDataIO::viewPathsFromFolders(*view, imagesFolders); - - // if path was not found - if(paths.empty()) - { - throw std::runtime_error("Cannot find view '" + std::to_string(view->getViewId()) + "' image file in given folder(s)"); - } - else if(paths.size() > 1) - { - throw std::runtime_error( "Ambiguous case: Multiple source image files found in given folder(s) for the view '" + - std::to_string(view->getViewId()) + "'."); - } - - srcImage = paths[0]; - } - const std::string dstColorImage = (fs::path(outFolder) / (baseFilename + "." + image::EImageFileType_enumToString(outputFileType))).string(); - const IntrinsicBase* cam = iterIntrinsic->second.get(); - - // add exposure values to images metadata - const double cameraExposure = view->getCameraExposureSetting().getExposure(); - const double ev = std::log2(1.0 / cameraExposure); - const float exposureCompensation = float(medianCameraExposure / cameraExposure); - metadata.push_back(oiio::ParamValue("AliceVision:EV", float(ev))); - metadata.push_back(oiio::ParamValue("AliceVision:EVComp", exposureCompensation)); - - if(evCorrection) - { - ALICEVISION_LOG_INFO("image " << viewId << ", exposure: " << cameraExposure << ", Ev " << ev << " Ev compensation: " + std::to_string(exposureCompensation)); - } - - image::Image mask; - if(tryLoadMask(&mask, masksFolders, viewId, srcImage)) - { - process>(dstColorImage, cam, metadata, srcImage, evCorrection, exposureCompensation, [&mask] (Image & image) + // export camera + if(saveMetadata || saveMatricesFiles) { - if(image.Width() * image.Height() != mask.Width() * mask.Height()) - { - ALICEVISION_LOG_WARNING("Invalid image mask size: mask is ignored."); - return; - } - - for(int pix = 0; pix < image.Width() * image.Height(); ++pix) - { - const bool masked = (mask(pix) == 0); - image(pix).a() = masked ? 0.f : 1.f; - } - }); - } - else - { - const auto noMaskingFunc = [] (Image & image) {}; - process>(dstColorImage, cam, metadata, srcImage, evCorrection, exposureCompensation, noMaskingFunc); - } + // get camera pose / projection + const Pose3 pose = sfmData.getPose(*view).getTransform(); + + std::shared_ptr cam = iterIntrinsic->second; + std::shared_ptr camPinHole = std::dynamic_pointer_cast(cam); + if (!camPinHole) { + ALICEVISION_LOG_ERROR("Camera is not pinhole in filter"); + continue; + } + + Mat34 P = camPinHole->getProjectiveEquivalent(pose); + + // get camera intrinsics matrices + const Mat3 K = dynamic_cast(sfmData.getIntrinsicPtr(view->getIntrinsicId()))->K(); + const Mat3& R = pose.rotation(); + const Vec3& t = pose.translation(); + + if(saveMatricesFiles) + { + std::ofstream fileP((fs::path(outFolder) / (baseFilename + "_P.txt")).string()); + fileP << std::setprecision(10) + << P(0, 0) << " " << P(0, 1) << " " << P(0, 2) << " " << P(0, 3) << "\n" + << P(1, 0) << " " << P(1, 1) << " " << P(1, 2) << " " << P(1, 3) << "\n" + << P(2, 0) << " " << P(2, 1) << " " << P(2, 2) << " " << P(2, 3) << "\n"; + fileP.close(); + + std::ofstream fileKRt((fs::path(outFolder) / (baseFilename + "_KRt.txt")).string()); + fileKRt << std::setprecision(10) + << K(0, 0) << " " << K(0, 1) << " " << K(0, 2) << "\n" + << K(1, 0) << " " << K(1, 1) << " " << K(1, 2) << "\n" + << K(2, 0) << " " << K(2, 1) << " " << K(2, 2) << "\n" + << "\n" + << R(0, 0) << " " << R(0, 1) << " " << R(0, 2) << "\n" + << R(1, 0) << " " << R(1, 1) << " " << R(1, 2) << "\n" + << R(2, 0) << " " << R(2, 1) << " " << R(2, 2) << "\n" + << "\n" + << t(0) << " " << t(1) << " " << t(2) << "\n"; + fileKRt.close(); + } + + if(saveMetadata) + { + // convert to 44 matix + Mat4 projectionMatrix; + projectionMatrix << P(0, 0), P(0, 1), P(0, 2), P(0, 3), + P(1, 0), P(1, 1), P(1, 2), P(1, 3), + P(2, 0), P(2, 1), P(2, 2), P(2, 3), + 0, 0, 0, 1; + + // convert matrices to rowMajor + std::vector vP(projectionMatrix.size()); + std::vector vK(K.size()); + std::vector vR(R.size()); + + typedef Eigen::Matrix RowMatrixXd; + Eigen::Map(vP.data(), projectionMatrix.rows(), projectionMatrix.cols()) = projectionMatrix; + Eigen::Map(vK.data(), K.rows(), K.cols()) = K; + Eigen::Map(vR.data(), R.rows(), R.cols()) = R; + + // add metadata + metadata.push_back(oiio::ParamValue("AliceVision:downscale", 1)); + metadata.push_back(oiio::ParamValue("AliceVision:P", oiio::TypeDesc(oiio::TypeDesc::DOUBLE, oiio::TypeDesc::MATRIX44), 1, vP.data())); + metadata.push_back(oiio::ParamValue("AliceVision:K", oiio::TypeDesc(oiio::TypeDesc::DOUBLE, oiio::TypeDesc::MATRIX33), 1, vK.data())); + metadata.push_back(oiio::ParamValue("AliceVision:R", oiio::TypeDesc(oiio::TypeDesc::DOUBLE, oiio::TypeDesc::MATRIX33), 1, vR.data())); + metadata.push_back(oiio::ParamValue("AliceVision:t", oiio::TypeDesc(oiio::TypeDesc::DOUBLE, oiio::TypeDesc::VEC3), 1, t.data())); + } + } + + // export undistort image + { + if(!imagesFolders.empty()) + { + std::vector paths = sfmDataIO::viewPathsFromFolders(*view, imagesFolders); + + // if path was not found + if(paths.empty()) + { + throw std::runtime_error("Cannot find view '" + std::to_string(view->getViewId()) + "' image file in given folder(s)"); + } + else if(paths.size() > 1) + { + throw std::runtime_error( "Ambiguous case: Multiple source image files found in given folder(s) for the view '" + + std::to_string(view->getViewId()) + "'."); + } + + srcImage = paths[0]; + } + const std::string dstColorImage = (fs::path(outFolder) / (baseFilename + "." + image::EImageFileType_enumToString(outputFileType))).string(); + const IntrinsicBase* cam = iterIntrinsic->second.get(); + + // add exposure values to images metadata + const double cameraExposure = view->getCameraExposureSetting().getExposure(); + const double ev = std::log2(1.0 / cameraExposure); + const float exposureCompensation = float(medianCameraExposure / cameraExposure); + metadata.push_back(oiio::ParamValue("AliceVision:EV", float(ev))); + metadata.push_back(oiio::ParamValue("AliceVision:EVComp", exposureCompensation)); + + if(evCorrection) + { + ALICEVISION_LOG_INFO("image " << viewId << ", exposure: " << cameraExposure << ", Ev " << ev << " Ev compensation: " + std::to_string(exposureCompensation)); + } + + image::Image mask; + if(tryLoadMask(&mask, masksFolders, viewId, srcImage)) + { + process>(dstColorImage, cam, metadata, srcImage, evCorrection, exposureCompensation, [&mask] (Image & image) + { + if(image.Width() * image.Height() != mask.Width() * mask.Height()) + { + ALICEVISION_LOG_WARNING("Invalid image mask size: mask is ignored."); + return; + } + + for(int pix = 0; pix < image.Width() * image.Height(); ++pix) + { + const bool masked = (mask(pix) == 0); + image(pix).a() = masked ? 0.f : 1.f; + } + }); + } + else + { + const auto noMaskingFunc = [] (Image & image) {}; + process>(dstColorImage, cam, metadata, srcImage, evCorrection, exposureCompensation, noMaskingFunc); + } + } + + ++progressDisplay; } - ++progressDisplay; - } - - return true; + return true; } int aliceVision_main(int argc, char *argv[]) { - // command-line parameters - - std::string verboseLevel = system::EVerboseLevel_enumToString(system::Logger::getDefaultVerboseLevel()); - std::string sfmDataFilename; - std::string outFolder; - std::string outImageFileTypeName = image::EImageFileType_enumToString(image::EImageFileType::EXR); - std::vector imagesFolders; - std::vector masksFolders; - int rangeStart = -1; - int rangeSize = 1; - bool saveMetadata = true; - bool saveMatricesTxtFiles = false; - bool evCorrection = false; - - po::options_description requiredParams("Required parameters"); - requiredParams.add_options() - ("input,i", po::value(&sfmDataFilename)->required(), - "SfMData file.") - ("output,o", po::value(&outFolder)->required(), - "Output folder."); - - po::options_description optionalParams("Optional parameters"); - optionalParams.add_options() - ("imagesFolders", po::value>(&imagesFolders)->multitoken(), - "Use images from specific folder(s) instead of those specify in the SfMData file.\n" - "Filename should be the same or the image uid.") - ("masksFolders", po::value>(&masksFolders)->multitoken(), - "Use masks from specific folder(s).\n" - "Filename should be the same or the image uid.") - ("outputFileType", po::value(&outImageFileTypeName)->default_value(outImageFileTypeName), - image::EImageFileType_informations().c_str()) - ("saveMetadata", po::value(&saveMetadata)->default_value(saveMetadata), - "Save projections and intrinsics information in images metadata.") - ("saveMatricesTxtFiles", po::value(&saveMatricesTxtFiles)->default_value(saveMatricesTxtFiles), - "Save projections and intrinsics information in text files.") - ("rangeStart", po::value(&rangeStart)->default_value(rangeStart), - "Range image index start.") - ("rangeSize", po::value(&rangeSize)->default_value(rangeSize), - "Range size.") - ("evCorrection", po::value(&evCorrection)->default_value(evCorrection), - "Correct exposure value."); - - CmdLine cmdline("AliceVision prepareDenseScene"); - cmdline.add(requiredParams); - cmdline.add(optionalParams); - if (!cmdline.execute(argc, argv)) - { - return EXIT_FAILURE; - } + // command-line parameters + + std::string verboseLevel = system::EVerboseLevel_enumToString(system::Logger::getDefaultVerboseLevel()); + std::string sfmDataFilename; + std::string outFolder; + std::string outImageFileTypeName = image::EImageFileType_enumToString(image::EImageFileType::EXR); + std::vector imagesFolders; + std::vector masksFolders; + int rangeStart = -1; + int rangeSize = 1; + bool saveMetadata = true; + bool saveMatricesTxtFiles = false; + bool evCorrection = false; + + po::options_description requiredParams("Required parameters"); + requiredParams.add_options() + ("input,i", po::value(&sfmDataFilename)->required(), + "SfMData file.") + ("output,o", po::value(&outFolder)->required(), + "Output folder."); + + po::options_description optionalParams("Optional parameters"); + optionalParams.add_options() + ("imagesFolders", po::value>(&imagesFolders)->multitoken(), + "Use images from specific folder(s) instead of those specify in the SfMData file.\n" + "Filename should be the same or the image uid.") + ("masksFolders", po::value>(&masksFolders)->multitoken(), + "Use masks from specific folder(s).\n" + "Filename should be the same or the image uid.") + ("outputFileType", po::value(&outImageFileTypeName)->default_value(outImageFileTypeName), + image::EImageFileType_informations().c_str()) + ("saveMetadata", po::value(&saveMetadata)->default_value(saveMetadata), + "Save projections and intrinsics information in images metadata.") + ("saveMatricesTxtFiles", po::value(&saveMatricesTxtFiles)->default_value(saveMatricesTxtFiles), + "Save projections and intrinsics information in text files.") + ("rangeStart", po::value(&rangeStart)->default_value(rangeStart), + "Range image index start.") + ("rangeSize", po::value(&rangeSize)->default_value(rangeSize), + "Range size.") + ("evCorrection", po::value(&evCorrection)->default_value(evCorrection), + "Correct exposure value."); + + CmdLine cmdline("AliceVision prepareDenseScene"); + cmdline.add(requiredParams); + cmdline.add(optionalParams); + if (!cmdline.execute(argc, argv)) + { + return EXIT_FAILURE; + } - // set output file type - image::EImageFileType outputFileType = image::EImageFileType_stringToEnum(outImageFileTypeName); + // set output file type + image::EImageFileType outputFileType = image::EImageFileType_stringToEnum(outImageFileTypeName); - // Create output dir - if(!fs::exists(outFolder)) - fs::create_directory(outFolder); + // Create output dir + if(!fs::exists(outFolder)) + fs::create_directory(outFolder); - // Read the input SfM scene - SfMData sfmData; - if(!sfmDataIO::Load(sfmData, sfmDataFilename, sfmDataIO::ESfMData::ALL)) - { - ALICEVISION_LOG_ERROR("The input SfMData file '" << sfmDataFilename << "' cannot be read."); - return EXIT_FAILURE; - } + // Read the input SfM scene + SfMData sfmData; + if(!sfmDataIO::Load(sfmData, sfmDataFilename, sfmDataIO::ESfMData::ALL)) + { + ALICEVISION_LOG_ERROR("The input SfMData file '" << sfmDataFilename << "' cannot be read."); + return EXIT_FAILURE; + } - int rangeEnd = sfmData.getViews().size(); + int rangeEnd = sfmData.getViews().size(); - // set range - if(rangeStart != -1) - { - if(rangeStart < 0 || rangeSize < 0 || - rangeStart > sfmData.getViews().size()) + // set range + if(rangeStart != -1) { - ALICEVISION_LOG_ERROR("Range is incorrect"); - return EXIT_FAILURE; - } + if(rangeStart < 0 || rangeSize < 0 || + rangeStart > sfmData.getViews().size()) + { + ALICEVISION_LOG_ERROR("Range is incorrect"); + return EXIT_FAILURE; + } - if(rangeStart + rangeSize > sfmData.views.size()) - rangeSize = sfmData.views.size() - rangeStart; + if(rangeStart + rangeSize > sfmData.views.size()) + rangeSize = sfmData.views.size() - rangeStart; - rangeEnd = rangeStart + rangeSize; - } - else - { - rangeStart = 0; - } + rangeEnd = rangeStart + rangeSize; + } + else + { + rangeStart = 0; + } - // export - if(prepareDenseScene(sfmData, imagesFolders, masksFolders, rangeStart, rangeEnd, outFolder, outputFileType, saveMetadata, saveMatricesTxtFiles, evCorrection)) - return EXIT_SUCCESS; + // export + if(prepareDenseScene(sfmData, imagesFolders, masksFolders, rangeStart, rangeEnd, outFolder, outputFileType, saveMetadata, saveMatricesTxtFiles, evCorrection)) + return EXIT_SUCCESS; - return EXIT_FAILURE; + return EXIT_FAILURE; } From 6e3d3cabcb615bf9f6abdeb82360ab9ff352dcff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Candice=20Bent=C3=A9jac?= Date: Wed, 7 Jun 2023 17:46:59 +0200 Subject: [PATCH 2/3] [software] FeatureExtraction: Formatting: Use 4-space based indentation --- .../pipeline/main_featureExtraction.cpp | 235 +++++++++--------- 1 file changed, 118 insertions(+), 117 deletions(-) diff --git a/src/software/pipeline/main_featureExtraction.cpp b/src/software/pipeline/main_featureExtraction.cpp index 97570e2225..f82ea5483e 100644 --- a/src/software/pipeline/main_featureExtraction.cpp +++ b/src/software/pipeline/main_featureExtraction.cpp @@ -43,143 +43,144 @@ namespace fs = boost::filesystem; /// - Export computed data int aliceVision_main(int argc, char **argv) { - // command-line parameters - std::string sfmDataFilename; - std::string masksFolder; - std::string outputFolder; - - // user optional parameters - - std::string describerTypesName = feature::EImageDescriberType_enumToString(feature::EImageDescriberType::SIFT); - feature::ConfigurationPreset featDescConfig; - int rangeStart = -1; - int rangeSize = 1; - int maxThreads = 0; - bool forceCpuExtraction = false; - - po::options_description requiredParams("Required parameters"); - requiredParams.add_options() - ("input,i", po::value(&sfmDataFilename)->required(), - "SfMData file.") - ("output,o", po::value(&outputFolder)->required(), - "Output path for the features and descriptors files (*.feat, *.desc)."); - - po::options_description optionalParams("Optional parameters"); - optionalParams.add_options() - ("describerTypes,d", po::value(&describerTypesName)->default_value(describerTypesName), - feature::EImageDescriberType_informations().c_str()) - ("describerPreset,p", po::value(&featDescConfig.descPreset)->default_value(featDescConfig.descPreset), - "Control the ImageDescriber configuration (low, medium, normal, high, ultra).\n" - "Configuration 'ultra' can take long time !") - ("describerQuality", po::value(&featDescConfig.quality)->default_value(featDescConfig.quality), - feature::EFeatureQuality_information().c_str()) - ("gridFiltering", po::value(&featDescConfig.gridFiltering)->default_value(featDescConfig.gridFiltering), - "Enable grid filtering. Highly recommended to ensure usable number of features.") - ("maxNbFeatures", po::value(&featDescConfig.maxNbFeatures)->default_value(featDescConfig.maxNbFeatures), - "Max number of features extracted (0 means default value based on describerPreset).") - ("contrastFiltering", po::value(&featDescConfig.contrastFiltering)->default_value(featDescConfig.contrastFiltering), - feature::EFeatureConstrastFiltering_information().c_str()) - ("relativePeakThreshold", po::value(&featDescConfig.relativePeakThreshold)->default_value(featDescConfig.relativePeakThreshold), - "Peak Threshold relative to median of gradiants.") - ("forceCpuExtraction", po::value(&forceCpuExtraction)->default_value(forceCpuExtraction), - "Use only CPU feature extraction methods.") - ("masksFolder", po::value(&masksFolder), - "Masks folder.") - ("rangeStart", po::value(&rangeStart)->default_value(rangeStart), - "Range image index start.") - ("rangeSize", po::value(&rangeSize)->default_value(rangeSize), - "Range size.") - ("maxThreads", po::value(&maxThreads)->default_value(maxThreads), - "Specifies the maximum number of threads to run simultaneously (0 for automatic mode)."); - - CmdLine cmdline("AliceVision featureExtraction"); - cmdline.add(requiredParams); - cmdline.add(optionalParams); - if (!cmdline.execute(argc, argv)) - { - return EXIT_FAILURE; - } - - if(describerTypesName.empty()) - { - ALICEVISION_LOG_ERROR("--describerTypes option is empty."); - return EXIT_FAILURE; - } - - // create output folder - if(!fs::exists(outputFolder)) - { - if(!fs::create_directory(outputFolder)) + // command-line parameters + std::string sfmDataFilename; + std::string masksFolder; + std::string outputFolder; + + // user optional parameters + + std::string describerTypesName = feature::EImageDescriberType_enumToString(feature::EImageDescriberType::SIFT); + feature::ConfigurationPreset featDescConfig; + int rangeStart = -1; + int rangeSize = 1; + int maxThreads = 0; + bool forceCpuExtraction = false; + + po::options_description requiredParams("Required parameters"); + requiredParams.add_options() + ("input,i", po::value(&sfmDataFilename)->required(), + "SfMData file.") + ("output,o", po::value(&outputFolder)->required(), + "Output path for the features and descriptors files (*.feat, *.desc)."); + + po::options_description optionalParams("Optional parameters"); + optionalParams.add_options() + ("describerTypes,d", po::value(&describerTypesName)->default_value(describerTypesName), + feature::EImageDescriberType_informations().c_str()) + ("describerPreset,p", po::value(&featDescConfig.descPreset)->default_value(featDescConfig.descPreset), + "Control the ImageDescriber configuration (low, medium, normal, high, ultra).\n" + "Configuration 'ultra' can take long time !") + ("describerQuality", po::value(&featDescConfig.quality)->default_value(featDescConfig.quality), + feature::EFeatureQuality_information().c_str()) + ("gridFiltering", po::value(&featDescConfig.gridFiltering)->default_value(featDescConfig.gridFiltering), + "Enable grid filtering. Highly recommended to ensure usable number of features.") + ("maxNbFeatures", po::value(&featDescConfig.maxNbFeatures)->default_value(featDescConfig.maxNbFeatures), + "Max number of features extracted (0 means default value based on describerPreset).") + ("contrastFiltering", po::value(&featDescConfig.contrastFiltering)->default_value(featDescConfig.contrastFiltering), + feature::EFeatureConstrastFiltering_information().c_str()) + ("relativePeakThreshold", po::value(&featDescConfig.relativePeakThreshold)->default_value(featDescConfig.relativePeakThreshold), + "Peak Threshold relative to median of gradiants.") + ("forceCpuExtraction", po::value(&forceCpuExtraction)->default_value(forceCpuExtraction), + "Use only CPU feature extraction methods.") + ("masksFolder", po::value(&masksFolder), + "Masks folder.") + ("rangeStart", po::value(&rangeStart)->default_value(rangeStart), + "Range image index start.") + ("rangeSize", po::value(&rangeSize)->default_value(rangeSize), + "Range size.") + ("maxThreads", po::value(&maxThreads)->default_value(maxThreads), + "Specifies the maximum number of threads to run simultaneously (0 for automatic mode)."); + + CmdLine cmdline("AliceVision featureExtraction"); + cmdline.add(requiredParams); + cmdline.add(optionalParams); + if (!cmdline.execute(argc, argv)) { - ALICEVISION_LOG_ERROR("Cannot create output folder"); - return EXIT_FAILURE; + return EXIT_FAILURE; + } + + if(describerTypesName.empty()) + { + ALICEVISION_LOG_ERROR("--describerTypes option is empty."); + return EXIT_FAILURE; + } + + // create output folder + if(!fs::exists(outputFolder)) + { + if(!fs::create_directory(outputFolder)) + { + ALICEVISION_LOG_ERROR("Cannot create output folder"); + return EXIT_FAILURE; + } } - } #ifdef ALICEVISION_HAVE_GPU_FEATURES - // Print GPU Information - ALICEVISION_LOG_INFO(gpu::gpuInformationCUDA()); + // Print GPU Information + ALICEVISION_LOG_INFO(gpu::gpuInformationCUDA()); #endif - // load input scene - sfmData::SfMData sfmData; - std::cout << sfmData.getViews().size() << std::endl; - if(!sfmDataIO::Load(sfmData, sfmDataFilename, sfmDataIO::ESfMData(sfmDataIO::VIEWS|sfmDataIO::INTRINSICS))) - { - ALICEVISION_LOG_ERROR("The input file '" + sfmDataFilename + "' cannot be read"); - return EXIT_FAILURE; - } - - // create feature extractor - feature::FeatureExtractor extractor(sfmData); - extractor.setMasksFolder(masksFolder); - extractor.setOutputFolder(outputFolder); - - // set maxThreads - HardwareContext hwc = cmdline.getHardwareContext(); - hwc.setUserCoresLimit(maxThreads); - - // set extraction range - if(rangeStart != -1) - { - if(rangeStart < 0 || rangeSize < 0 || - rangeStart > sfmData.getViews().size()) + // load input scene + sfmData::SfMData sfmData; + std::cout << sfmData.getViews().size() << std::endl; + if(!sfmDataIO::Load(sfmData, sfmDataFilename, sfmDataIO::ESfMData(sfmDataIO::VIEWS|sfmDataIO::INTRINSICS))) { - ALICEVISION_LOG_ERROR("Range is incorrect"); - return EXIT_FAILURE; + ALICEVISION_LOG_ERROR("The input file '" + sfmDataFilename + "' cannot be read"); + return EXIT_FAILURE; } - if(rangeStart + rangeSize > sfmData.views.size()) - rangeSize = sfmData.views.size() - rangeStart; + // create feature extractor + feature::FeatureExtractor extractor(sfmData); + extractor.setMasksFolder(masksFolder); + extractor.setOutputFolder(outputFolder); + + // set maxThreads + HardwareContext hwc = cmdline.getHardwareContext(); + hwc.setUserCoresLimit(maxThreads); - extractor.setRange(rangeStart, rangeSize); - } + // set extraction range + if(rangeStart != -1) + { + if(rangeStart < 0 || rangeSize < 0 || + rangeStart > sfmData.getViews().size()) + { + ALICEVISION_LOG_ERROR("Range is incorrect"); + return EXIT_FAILURE; + } + + if(rangeStart + rangeSize > sfmData.views.size()) + rangeSize = sfmData.views.size() - rangeStart; - // initialize feature extractor imageDescribers - { - std::vector imageDescriberTypes = feature::EImageDescriberType_stringToEnums(describerTypesName); - for(const auto& imageDescriberType: imageDescriberTypes) + extractor.setRange(rangeStart, rangeSize); + } + + // initialize feature extractor imageDescribers { - std::shared_ptr imageDescriber = feature::createImageDescriber(imageDescriberType); - imageDescriber->setConfigurationPreset(featDescConfig); - if(forceCpuExtraction) - imageDescriber->setUseCuda(false); + std::vector imageDescriberTypes = feature::EImageDescriberType_stringToEnums(describerTypesName); - extractor.addImageDescriber(imageDescriber); + for(const auto& imageDescriberType: imageDescriberTypes) + { + std::shared_ptr imageDescriber = feature::createImageDescriber(imageDescriberType); + imageDescriber->setConfigurationPreset(featDescConfig); + if(forceCpuExtraction) + imageDescriber->setUseCuda(false); + + extractor.addImageDescriber(imageDescriber); + } } - } // feature extraction routines // for each View of the SfMData container: // - if regions file exist continue, // - if no file, compute features - { - system::Timer timer; + { + system::Timer timer; - extractor.process(hwc); + extractor.process(hwc); - ALICEVISION_LOG_INFO("Task done in (s): " + std::to_string(timer.elapsed())); - } - return EXIT_SUCCESS; + ALICEVISION_LOG_INFO("Task done in (s): " + std::to_string(timer.elapsed())); + } + return EXIT_SUCCESS; } From 222b020a2267fc7b6521b60246c9dc9f74a04fc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Candice=20Bent=C3=A9jac?= Date: Thu, 8 Jun 2023 09:28:27 +0200 Subject: [PATCH 3/3] [software] Do not fail if range start is larger than the number of views For cases where a node declares a size that is bigger than it actually is, the start of ranges might exceed the number of views in the SfMData. Instead of causing an EXIT_FAILURE, we detect that the size of the range is incorrect to proceed with computations, and return EXIT_SUCCESS. This allows to use nodes such as the `KeyframeSelection`, for which the number of outputs can rarely be known before the end of the computations: if the number of chunks for `PrepareDenseScene` and `FeatureExtraction` is too large for the actual size of `KeyframeSelection`, then we keep on going through the pipeline instead of failing. --- src/software/pipeline/main_featureExtraction.cpp | 8 ++++++-- src/software/pipeline/main_prepareDenseScene.cpp | 14 ++++++++++---- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/software/pipeline/main_featureExtraction.cpp b/src/software/pipeline/main_featureExtraction.cpp index f82ea5483e..8fefd38385 100644 --- a/src/software/pipeline/main_featureExtraction.cpp +++ b/src/software/pipeline/main_featureExtraction.cpp @@ -142,8 +142,7 @@ int aliceVision_main(int argc, char **argv) // set extraction range if(rangeStart != -1) { - if(rangeStart < 0 || rangeSize < 0 || - rangeStart > sfmData.getViews().size()) + if(rangeStart < 0 || rangeSize < 0) { ALICEVISION_LOG_ERROR("Range is incorrect"); return EXIT_FAILURE; @@ -152,6 +151,11 @@ int aliceVision_main(int argc, char **argv) if(rangeStart + rangeSize > sfmData.views.size()) rangeSize = sfmData.views.size() - rangeStart; + if(rangeSize <= 0) + { + ALICEVISION_LOG_WARNING("Nothing to compute."); + return EXIT_SUCCESS; + } extractor.setRange(rangeStart, rangeSize); } diff --git a/src/software/pipeline/main_prepareDenseScene.cpp b/src/software/pipeline/main_prepareDenseScene.cpp index dc1d063c1f..2451037e49 100644 --- a/src/software/pipeline/main_prepareDenseScene.cpp +++ b/src/software/pipeline/main_prepareDenseScene.cpp @@ -188,7 +188,7 @@ bool prepareDenseScene(const SfMData& sfmData, projectionMatrix << P(0, 0), P(0, 1), P(0, 2), P(0, 3), P(1, 0), P(1, 1), P(1, 2), P(1, 3), P(2, 0), P(2, 1), P(2, 2), P(2, 3), - 0, 0, 0, 1; + 0, 0, 0, 1; // convert matrices to rowMajor std::vector vP(projectionMatrix.size()); @@ -346,8 +346,7 @@ int aliceVision_main(int argc, char *argv[]) // set range if(rangeStart != -1) { - if(rangeStart < 0 || rangeSize < 0 || - rangeStart > sfmData.getViews().size()) + if(rangeStart < 0 || rangeSize < 0) { ALICEVISION_LOG_ERROR("Range is incorrect"); return EXIT_FAILURE; @@ -357,6 +356,12 @@ int aliceVision_main(int argc, char *argv[]) rangeSize = sfmData.views.size() - rangeStart; rangeEnd = rangeStart + rangeSize; + + if(rangeSize <= 0) + { + ALICEVISION_LOG_WARNING("Nothing to compute."); + return EXIT_SUCCESS; + } } else { @@ -364,7 +369,8 @@ int aliceVision_main(int argc, char *argv[]) } // export - if(prepareDenseScene(sfmData, imagesFolders, masksFolders, rangeStart, rangeEnd, outFolder, outputFileType, saveMetadata, saveMatricesTxtFiles, evCorrection)) + if(prepareDenseScene(sfmData, imagesFolders, masksFolders, rangeStart, rangeEnd, + outFolder, outputFileType, saveMetadata, saveMatricesTxtFiles, evCorrection)) return EXIT_SUCCESS; return EXIT_FAILURE;