Add smvs as default dense reconstruction

pull/889/head
Dakota Benjamin 2018-06-27 14:32:49 -04:00
rodzic f09b42ec81
commit a18e989c58
10 zmienionych plików z 164 dodań i 36 usunięć

Wyświetl plik

@ -98,7 +98,7 @@ SETUP_EXTERNAL_PROJECT(Ceres ${ODM_Ceres_Version} ${ODM_BUILD_Ceres})
# ---------------------------------------------------------------------------------------------
# VTK7
# We need to build VTK from sources because Debian packages
# are built with DVTK_SMP_IMPLEMENTATION_TYPE set to
# are built with DVTK_SMP_IMPLEMENTATION_TYPE set to
# "Sequential" which means no multithread support.
set(ODM_VTK7_Version 7.1.1)
@ -139,3 +139,24 @@ foreach(lib ${custom_libs})
SETUP_EXTERNAL_PROJECT_CUSTOM(${lib})
endforeach()
## Add smvs Build
externalproject_add(smvs
GIT_REPOSITORY https://github.com/flanggut/smvs.git
UPDATE_COMMAND ""
SOURCE_DIR ${SB_SOURCE_DIR}/elibs/smvs
CONFIGURE_COMMAND ""
BUILD_IN_SOURCE 1
BUILD_COMMAND make
INSTALL_COMMAND ""
)
externalproject_add(mve
GIT_REPOSITORY https://github.com/simonfuhrmann/mve.git
UPDATE_COMMAND ""
SOURCE_DIR ${SB_SOURCE_DIR}/elibs/mve
CONFIGURE_COMMAND ""
BUILD_IN_SOURCE 1
BUILD_COMMAND make
INSTALL_COMMAND ""
)

Wyświetl plik

@ -102,6 +102,7 @@ install() {
pip install -U gippy psutil
echo "Compiling SuperBuild"
cd ${RUNPATH}/SuperBuild
mkdir -p build && cd build
@ -112,6 +113,12 @@ install() {
mkdir -p build && cd build
cmake .. && make -j$processes
# echo "Compiling mve and smvs"
# git clone https://github.com/simonfuhrmann/mve.git
# git clone https://github.com/flanggut/smvs.git
# make -C mve -j$processes
# make -C smvs -j$processes
echo "Configuration Finished"
}

Wyświetl plik

@ -7,7 +7,7 @@ from appsettings import SettingsParser
import sys
# parse arguments
processopts = ['dataset', 'opensfm', 'slam', 'cmvs', 'pmvs',
processopts = ['dataset', 'opensfm', 'slam', 'cmvs', 'pmvs', 'smvs',
'odm_meshing', 'odm_25dmeshing', 'mvs_texturing', 'odm_georeferencing',
'odm_dem', 'odm_orthophoto']
@ -192,10 +192,18 @@ def config():
default=False,
help='Use a 2.5D mesh to compute the orthophoto. This option tends to provide better results for planar surfaces. Experimental.')
parser.add_argument('--use-pmvs',
parser.add_argument('--use-opensfm-dense',
action='store_true',
default=False,
help='Use pmvs to compute point cloud alternatively')
help='Use opensfm to compute dense point cloud alternatively')
parser.add_argument('--smvs-scale',
metavar='<non-negative integer>',
default=1,
type=int,
help='Scales the input images, which affects the output'
' density. 0 is original scale but takes longer '
'to process. 2 is 1/4 scale. Default: %(default)s')
parser.add_argument('--cmvs-maxImages',
metavar='<integer>',
@ -285,7 +293,7 @@ def config():
'Increasing this value increases computation '
'times slightly but helps reduce memory usage. '
'Default: %(default)s'))
parser.add_argument('--mesh-neighbors',
metavar='<positive integer>',
default=24,

Wyświetl plik

@ -28,6 +28,10 @@ cmvs_path = os.path.join(superbuild_path, "install/bin/cmvs")
cmvs_opts_path = os.path.join(superbuild_path, "install/bin/genOption")
pmvs2_path = os.path.join(superbuild_path, "install/bin/pmvs2")
# define smvs join_paths
makescene_path = os.path.join(superbuild_path, 'src', 'elibs', 'mve', 'apps', 'makescene', 'makescene') #TODO: don't install in source
smvs_path = os.path.join(superbuild_path, 'src', 'elibs', 'smvs', 'app', 'smvsrecon')
# define mvstex path
mvstex_path = os.path.join(superbuild_path, "install/bin/texrecon")
@ -44,5 +48,5 @@ settings_path = os.path.join(root_path, 'settings.yaml')
# Define supported image extensions
supported_extensions = {'.jpg','.jpeg','.png'}
# Define the number of cores
# Define the number of cores
num_cores = multiprocessing.cpu_count()

Wyświetl plik

@ -34,13 +34,18 @@ def dir_exists(dirname):
def copy(src, dst):
try:
try:
shutil.copytree(src, dst)
except OSError as e:
if e.errno == errno.ENOTDIR:
shutil.copy(src, dst)
else: raise
def rename_file(src, dst):
try:
os.rename(src, dst)
except OSError as e:
raise
# find a file in the root directory
def find(filename, folder):

Wyświetl plik

@ -61,7 +61,7 @@ class ODM_Photo:
metadata.read()
# loop over image tags
for key in metadata:
# try/catch tag value due to weird bug in pyexiv2
# try/catch tag value due to weird bug in pyexiv2
# ValueError: invalid literal for int() with base 10: ''
GPS = 'Exif.GPSInfo.GPS'
try:
@ -272,7 +272,7 @@ class ODM_GeoRef(object):
with open(json_file, 'w') as f:
f.write(pipeline)
# call pdal
# call pdal
system.run('{bin}/pdal pipeline -i {json} --readers.ply.filename={f_in} '
'--writers.las.filename={f_out}'.format(**kwargs))
@ -388,7 +388,7 @@ class ODM_GeoRef(object):
# Create a nested list for the transformation matrix
with open(_file) as f:
for line in f:
# Handle matrix formats that either
# Handle matrix formats that either
# have leading or trailing brakets or just plain numbers.
line = re.sub(r"[\[\],]", "", line).strip()
self.transform += [[float(i) for i in line.split()]]
@ -413,6 +413,7 @@ class ODM_Tree(object):
# whole reconstruction process.
self.dataset_raw = io.join_paths(self.root_path, 'images')
self.opensfm = io.join_paths(self.root_path, 'opensfm')
self.smvs = io.join_paths(self.root_path, 'smvs')
self.pmvs = io.join_paths(self.root_path, 'pmvs')
self.odm_meshing = io.join_paths(self.root_path, 'odm_meshing')
self.odm_texturing = io.join_paths(self.root_path, 'odm_texturing')
@ -445,6 +446,12 @@ class ODM_Tree(object):
self.pmvs_options = io.join_paths(self.pmvs_rec_path, 'pmvs_options.txt')
self.pmvs_model = io.join_paths(self.pmvs_rec_path, 'models/option-0000.ply')
# smvs
self.smvs_model = io.join_paths(self.smvs, 'smvs_dense_point_cloud.ply')
self.mve_path = io.join_paths(self.opensfm, 'mve')
self.mve_image_list = io.join_paths(self.mve_path, 'list.txt')
self.mve_bundle = io.join_paths(self.mve_path, 'bundle/bundle.out')
# odm_meshing
self.odm_mesh = io.join_paths(self.odm_meshing, 'odm_mesh.ply')
self.odm_meshing_log = io.join_paths(self.odm_meshing, 'odm_meshing_log.txt')

Wyświetl plik

@ -8,6 +8,7 @@ from opendm import system
from dataset import ODMLoadDatasetCell
from run_opensfm import ODMOpenSfMCell
from smvs import ODMSmvsCell
from odm_slam import ODMSlamCell
from pmvs import ODMPmvsCell
from cmvs import ODMCmvsCell
@ -57,6 +58,7 @@ class ODMApp(ecto.BlackBox):
wsize=p.args.pmvs_wsize,
min_imgs=p.args.pmvs_min_images,
cores=p.args.pmvs_num_cores),
'smvs': ODMSmvsCell(scale=p.args.smvs_scale), #TODO: add more options
'meshing': ODMeshingCell(max_vertex=p.args.mesh_size,
oct_tree=p.args.mesh_octree_depth,
samples=p.args.mesh_samples,
@ -116,26 +118,21 @@ class ODMApp(ecto.BlackBox):
self.args[:] >> self.opensfm['args'],
self.dataset['reconstruction'] >> self.opensfm['reconstruction']]
if not p.args.use_pmvs:
if p.args.use_opensfm_dense:
# create odm mesh from opensfm point cloud
connections += [self.tree[:] >> self.meshing['tree'],
self.args[:] >> self.meshing['args'],
self.opensfm['reconstruction'] >> self.meshing['reconstruction']]
else:
# run cmvs
connections += [self.tree[:] >> self.cmvs['tree'],
self.args[:] >> self.cmvs['args'],
self.opensfm['reconstruction'] >> self.cmvs['reconstruction']]
# run pmvs
connections += [self.tree[:] >> self.pmvs['tree'],
self.args[:] >> self.pmvs['args'],
self.cmvs['reconstruction'] >> self.pmvs['reconstruction']]
# run smvs
connections += [self.tree[:] >> self.smvs['tree'],
self.args[:] >> self.smvs['args'],
self.opensfm['reconstruction'] >> self.smvs['reconstruction']]
# create odm mesh from pmvs point cloud
connections += [self.tree[:] >> self.meshing['tree'],
self.args[:] >> self.meshing['args'],
self.pmvs['reconstruction'] >> self.meshing['reconstruction']]
self.smvs['reconstruction'] >> self.meshing['reconstruction']]
# create odm texture
connections += [self.tree[:] >> self.texturing['tree'],

Wyświetl plik

@ -50,9 +50,9 @@ class ODMeshingCell(ecto.Cell):
(args.rerun_from is not None and
'odm_meshing' in args.rerun_from)
infile = tree.opensfm_model
if args.use_pmvs:
infile = tree.pmvs_model
infile = tree.smvs_model
if args.use_opensfm_dense:
infile = ttree.opensfm_model
elif args.fast_orthophoto:
infile = os.path.join(tree.opensfm, 'reconstruction.ply')

Wyświetl plik

@ -40,7 +40,7 @@ class ODMOpenSfMCell(ecto.Cell):
log.ODM_ERROR('Not enough photos in photos array to start OpenSfM')
return ecto.QUIT
# create working directories
# create working directories
system.mkdir_p(tree.opensfm)
system.mkdir_p(tree.pmvs)
@ -51,7 +51,7 @@ class ODMOpenSfMCell(ecto.Cell):
(args.rerun_from is not None and
'opensfm' in args.rerun_from)
if not args.use_pmvs:
if args.use_opensfm_dense:
output_file = tree.opensfm_model
if args.fast_orthophoto:
output_file = io.join_paths(tree.opensfm, 'reconstruction.ply')
@ -136,7 +136,7 @@ class ODMOpenSfMCell(ecto.Cell):
log.ODM_WARNING('Found a valid OpenSfM reconstruction file in: %s' %
tree.opensfm_reconstruction)
if not args.use_pmvs:
if args.use_opensfm_dense:
if not io.file_exists(tree.opensfm_reconstruction_nvm) or rerun_cell:
system.run('PYTHONPATH=%s %s/bin/opensfm export_visualsfm %s' %
(context.pyopencv_path, context.opensfm_path, tree.opensfm))
@ -146,7 +146,7 @@ class ODMOpenSfMCell(ecto.Cell):
system.run('PYTHONPATH=%s %s/bin/opensfm undistort %s' %
(context.pyopencv_path, context.opensfm_path, tree.opensfm))
# Skip dense reconstruction if necessary and export
# sparse reconstruction instead
if args.fast_orthophoto:
@ -169,14 +169,14 @@ class ODMOpenSfMCell(ecto.Cell):
log.ODM_WARNING('Found a valid Bundler file in: %s' %
tree.opensfm_reconstruction)
if args.use_pmvs:
# check if reconstruction was exported to pmvs before
if not io.file_exists(tree.pmvs_visdat) or rerun_cell:
# run PMVS converter
system.run('PYTHONPATH=%s %s/bin/export_pmvs %s --output %s' %
(context.pyopencv_path, context.opensfm_path, tree.opensfm, tree.pmvs))
else:
log.ODM_WARNING('Found a valid CMVS file in: %s' % tree.pmvs_visdat)
# if args.use_pmvs:
# # check if reconstruction was exported to pmvs before
# if not io.file_exists(tree.pmvs_visdat) or rerun_cell:
# # run PMVS converter
# system.run('PYTHONPATH=%s %s/bin/export_pmvs %s --output %s' %
# (context.pyopencv_path, context.opensfm_path, tree.opensfm, tree.pmvs))
# else:
# log.ODM_WARNING('Found a valid CMVS file in: %s' % tree.pmvs_visdat)
if reconstruction.georef:
system.run('PYTHONPATH=%s %s/bin/opensfm export_geocoords %s --transformation --proj \'%s\'' %

79
scripts/smvs.py 100644
Wyświetl plik

@ -0,0 +1,79 @@
import ecto
from opendm import log
from opendm import io
from opendm import system
from opendm import context
class ODMSmvsCell(ecto.Cell):
def declare_params(self, params):
params.declare("scale", "input scale", 1)
def declare_io(self, params, inputs, outputs):
inputs.declare("tree", "Struct with paths", [])
inputs.declare("args", "The application arguments.", {})
inputs.declare("reconstruction", "ODMReconstruction", [])
outputs.declare("reconstruction", "list of ODMReconstructions", [])
def process(self, inputs, outputs):
# Benchmarking
start_time = system.now_raw()
log.ODM_INFO('Running SMVS Cell')
# get inputs
tree = inputs.tree
args = inputs.args
reconstruction = inputs.reconstruction
photos = reconstruction.photos
if not photos:
log.ODM_ERROR('Not enough photos in photos array to start SMVS')
return ecto.QUIT
# create working directories
system.mkdir_p(tree.smvs)
# check if we rerun cell or not
rerun_cell = (args.rerun is not None and
args.rerun == 'smvs') or \
(args.rerun_all) or \
(args.rerun_from is not None and
'smvs' in args.rerun_from)
# check if reconstruction was done before
if not io.file_exists(tree.smvs_model) or rerun_cell:
# make bundle directory
if not io.file_exists(tree.mve_bundle):
system.mkdir_p(tree.mve_path) #TODO: check permissions/what happens when rerun
system.mkdir_p(io.join_paths(tree.mve_path, 'bundle'))
io.copy(tree.opensfm_image_list, tree.mve_image_list)
io.copy(tree.opensfm_bundle, tree.mve_bundle)
# config
config = [
"-s%s" % self.params.scale
]
# run mve makescene
system.run('%s %s %s' % (context.makescene_path, tree.mve_path, tree.smvs))
# run smvs
system.run('%s %s %s' % (context.smvs_path, ' '.join(config), tree.smvs))
# rename the file for simplicity
io.rename_file(io.join_paths(tree.smvs, 'smvs-B%s.ply' % self.params.scale), tree.smvs_model)
else:
log.ODM_WARNING('Found a valid SMVS reconstruction file in: %s' %
tree.smvs_model)
outputs.reconstruction = reconstruction
if args.time:
system.benchmark(start_time, tree.benchmarking, 'SMVS')
log.ODM_INFO('Running ODM SMVS Cell - Finished')
return ecto.OK if args.end_with != 'smvs' else ecto.QUIT