Skip to content

Commit

Permalink
[softwares] Handle feature extraction occlusion image masks that cann…
Browse files Browse the repository at this point in the history
…ot be read. openMVG#998, openMVG#1005

- If a feature mask cannot be read a message is displayed and the
feature extraction stops.
- The global mask.png is now read into the input image directory.

- If the extracted features regions cannot be saved a message is
displayed and the feature extraction stops.
  • Loading branch information
pmoulon committed Aug 11, 2017
1 parent 03cf646 commit 2f8c9f0
Show file tree
Hide file tree
Showing 4 changed files with 114 additions and 53 deletions.
6 changes: 3 additions & 3 deletions docs/sphinx/rst/software/SfM/ComputeFeatures.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ Arguments description:
The black areas on a mask denote the "bad parts", *i.e.* the areas to be masked and for which descriptors are not computed. A point is kept if the mask value at the point position is different than 0.
In openMVG_main_ComputeFeatures, the association of a mask and an image is implicit. It uses the following conventions:

- It tries to load a global mask.png file from directory where the the SfM container file (sfm_data.*) is stored.
- It tries to load an individual <image_name>_mask.png from directory where the current image is stored
- It tries to load a global mask.png file from where the images are stored.
- It tries to load an individual <image_name>_mask.png from directory where the current image is stored.

The individual mask **always** takes precedence over the global one
The individual mask **always** takes precedence over the global one.

Once openMVG_main_ComputeFeatures is done you can compute the Matches between the computed description.

Expand Down
2 changes: 1 addition & 1 deletion src/openMVG/image/image_io.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
#include "openMVG/image/image_container.hpp"
#include "openMVG/image/image_converter.hpp"

#include <stdio.h>
#include <cstdio>
#include <vector>

namespace openMVG
Expand Down
81 changes: 53 additions & 28 deletions src/software/SfM/main_ComputeFeatures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@

#include <cereal/details/helpers.hpp>

#include <atomic>
#include <cstdlib>
#include <fstream>
#include <string>
Expand Down Expand Up @@ -244,22 +245,13 @@ int main(int argc, char **argv)
// - if no file, compute features
{
system::Timer timer;
Image<unsigned char> imageGray, globalMask;
Image<unsigned char> imageGray;

const std::string sGlobalMask_filename = stlplus::create_filespec(sOutDir, "mask.png");
if (stlplus::file_exists(sGlobalMask_filename))
{
if (ReadImage(sGlobalMask_filename.c_str(), &globalMask))
{
std::cout
<< "Feature extraction will use a GLOBAL MASK:\n"
<< sGlobalMask_filename << std::endl;
}
}

C_Progress_display my_progress_bar( sfm_data.GetViews().size(),
C_Progress_display my_progress_bar(sfm_data.GetViews().size(),
std::cout, "\n- EXTRACT FEATURES -\n" );

// Use a boolean to track if we must stop feature extraction
std::atomic<bool> preemptive_exit(false);
#ifdef OPENMVG_USE_OPENMP
const unsigned int nb_max_thread = omp_get_max_threads();

Expand All @@ -281,32 +273,65 @@ int main(int argc, char **argv)
sFeat = stlplus::create_filespec(sOutDir, stlplus::basename_part(sView_filename), "feat"),
sDesc = stlplus::create_filespec(sOutDir, stlplus::basename_part(sView_filename), "desc");

//If features or descriptors file are missing, compute them
if (bForce || !stlplus::file_exists(sFeat) || !stlplus::file_exists(sDesc))
// If features or descriptors file are missing, compute them
if (!preemptive_exit && (bForce || !stlplus::file_exists(sFeat) || !stlplus::file_exists(sDesc)))
{
if (!ReadImage(sView_filename.c_str(), &imageGray))
continue;

//
// Look if there is occlusion feature mask
//
Image<unsigned char> * mask = nullptr; // The mask is null by default

const std::string sImageMask_filename =
stlplus::create_filespec(sfm_data.s_root_path,
stlplus::basename_part(sView_filename) + "_mask", "png");
const std::string
mask_filename_local =
stlplus::create_filespec(sfm_data.s_root_path,
stlplus::basename_part(sView_filename) + "_mask", "png"),
mask__filename_global =
stlplus::create_filespec(sfm_data.s_root_path, "mask", "png");

Image<unsigned char> imageMask;
if (stlplus::file_exists(sImageMask_filename))
ReadImage(sImageMask_filename.c_str(), &imageMask);

// The mask point to the globalMask, if a valid one exists for the current image
if (globalMask.Width() == imageGray.Width() && globalMask.Height() == imageGray.Height())
mask = &globalMask;
// The mask point to the imageMask (individual mask) if a valid one exists for the current image
if (imageMask.Width() == imageGray.Width() && imageMask.Height() == imageGray.Height())
mask = &imageMask;
// Try to read the local mask
if (stlplus::file_exists(mask_filename_local))
{
if (!ReadImage(mask_filename_local.c_str(), &imageMask))
{
std::cerr << "Invalid mask: " << mask_filename_local << std::endl
<< "Stopping feature extraction." << std::endl;
preemptive_exit = true;
continue;
}
// Use the local mask only if it fits the current image size
if (imageMask.Width() == imageGray.Width() && imageMask.Height() == imageGray.Height())
mask = &imageMask;
}
else
{
// Try to read the global mask
if (stlplus::file_exists(mask__filename_global))
{
if (!ReadImage(mask__filename_global.c_str(), &imageMask))
{
std::cerr << "Invalid mask: " << mask__filename_global << std::endl
<< "Stopping feature extraction." << std::endl;
preemptive_exit = true;
continue;
}
// Use the global mask only if it fits the current image size
if (imageMask.Width() == imageGray.Width() && imageMask.Height() == imageGray.Height())
mask = &imageMask;
}
}

// Compute features and descriptors and export them to files
auto regions = image_describer->Describe(imageGray, mask);
image_describer->Save(regions.get(), sFeat, sDesc);
if (regions && !image_describer->Save(regions.get(), sFeat, sDesc)) {
std::cerr << "Cannot save regions for images: " << sView_filename << std::endl
<< "Stopping feature extraction." << std::endl;
preemptive_exit = true;
continue;
}
}
++my_progress_bar;
}
Expand Down
78 changes: 57 additions & 21 deletions src/software/SfM/main_ComputeFeatures_OpenCV.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,12 @@
// The <cereal/archives> headers are special and must be included first.
#include <cereal/archives/json.hpp>

#include "openMVG/features/regions_factory_io.hpp"
#include "openMVG/image/image_io.hpp"
#include "openMVG/sfm/sfm.hpp"
#include "openMVG/system/timer.hpp"


#include "third_party/cmdLine/cmdLine.h"
#include "third_party/stlplus3/filesystemSimplified/file_system.hpp"
#include "third_party/progress/progress.hpp"
Expand Down Expand Up @@ -396,17 +398,16 @@ int main(int argc, char **argv)
// - if no file, compute features
{
system::Timer timer;
Image<unsigned char> imageGray, globalMask, imageMask;

const std::string sGlobalMask_filename = stlplus::create_filespec(sOutDir, "mask.png");
if (stlplus::file_exists(sGlobalMask_filename))
ReadImage(sGlobalMask_filename.c_str(), &globalMask);
Image<unsigned char> imageGray;

C_Progress_display my_progress_bar( sfm_data.GetViews().size(),
std::cout, "\n- EXTRACT FEATURES -\n" );

// Use a boolean to track if we must stop feature extraction
bool preemptive_exit(false);
for (auto iterViews = sfm_data.views.cbegin();
iterViews != sfm_data.views.cend();
++iterViews, ++my_progress_bar)
iterViews != sfm_data.views.cend() && !preemptive_exit;
++iterViews)
{
const View * view = iterViews->second.get();
const std::string
Expand All @@ -420,25 +421,60 @@ int main(int argc, char **argv)
if (!ReadImage(sView_filename.c_str(), &imageGray))
continue;

//
// Look if there is occlusion feature mask
//
Image<unsigned char> * mask = nullptr; // The mask is null by default

const std::string sImageMask_filename =
stlplus::create_filespec(sfm_data.s_root_path,
stlplus::basename_part(sView_filename) + "_mask", "png");

if (stlplus::file_exists(sImageMask_filename))
ReadImage(sImageMask_filename.c_str(), &imageMask);

// The mask point to the globalMask, if a valid one exists for the current image
if (globalMask.Width() == imageGray.Width() && globalMask.Height() == imageGray.Height())
mask = &globalMask;
// The mask point to the imageMask (individual mask) if a valid one exists for the current image
if (imageMask.Width() == imageGray.Width() && imageMask.Height() == imageGray.Height())
mask = &imageMask;
const std::string
mask_filename_local =
stlplus::create_filespec(sfm_data.s_root_path,
stlplus::basename_part(sView_filename) + "_mask", "png"),
mask__filename_global =
stlplus::create_filespec(sfm_data.s_root_path, "mask", "png");

Image<unsigned char> imageMask;
// Try to read the local mask
if (stlplus::file_exists(mask_filename_local))
{
if (!ReadImage(mask_filename_local.c_str(), &imageMask))
{
std::cerr << "Invalid mask: " << mask_filename_local << std::endl
<< "Stopping feature extraction." << std::endl;
preemptive_exit = true;
continue;
}
// Use the local mask only if it fits the current image size
if (imageMask.Width() == imageGray.Width() && imageMask.Height() == imageGray.Height())
mask = &imageMask;
}
else
{
// Try to read the global mask
if (stlplus::file_exists(mask__filename_global))
{
if (!ReadImage(mask__filename_global.c_str(), &imageMask))
{
std::cerr << "Invalid mask: " << mask__filename_global << std::endl
<< "Stopping feature extraction." << std::endl;
preemptive_exit = true;
continue;
}
// Use the global mask only if it fits the current image size
if (imageMask.Width() == imageGray.Width() && imageMask.Height() == imageGray.Height())
mask = &imageMask;
}
}

// Compute features and descriptors and export them to files
auto regions = image_describer->Describe(imageGray, mask);
image_describer->Save(regions.get(), sFeat, sDesc);
if (regions && !image_describer->Save(regions.get(), sFeat, sDesc)) {
std::cerr << "Cannot save regions for images: " << sView_filename << std::endl
<< "Stopping feature extraction." << std::endl;
preemptive_exit = true;
continue;
}
++my_progress_bar;
}
}
std::cout << "Task done in (s): " << timer.elapsed() << std::endl;
Expand Down

0 comments on commit 2f8c9f0

Please sign in to comment.