kopia lustrzana https://github.com/OpenDroneMap/ODM
Add smvs as default dense reconstruction
rodzic
f09b42ec81
commit
a18e989c58
|
@ -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 ""
|
||||
)
|
||||
|
|
|
@ -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"
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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):
|
||||
|
|
|
@ -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')
|
||||
|
|
|
@ -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'],
|
||||
|
|
|
@ -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')
|
||||
|
||||
|
|
|
@ -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\'' %
|
||||
|
|
|
@ -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
|
Ładowanie…
Reference in New Issue