kopia lustrzana https://github.com/OpenDroneMap/ODM
added tree structure to organize file paths
rodzic
23eb0acc7f
commit
c65d2b51b3
|
@ -1,7 +1,7 @@
|
|||
import argparse
|
||||
|
||||
# parse arguments
|
||||
processopts = ['resize', 'opensfm', 'pmvs',
|
||||
processopts = ['resize', 'opensfm', 'cmvs', 'pmvs',
|
||||
'odm_meshing', 'odm_texturing', 'odm_georeferencing',
|
||||
'odm_orthophoto']
|
||||
|
||||
|
@ -28,7 +28,7 @@ parser.add_argument('--end-with', '-e',
|
|||
choices=processopts,
|
||||
help=('Can be one of:' + ' | '.join(processopts)))
|
||||
|
||||
parser.add_argument('--run-only',
|
||||
parser.add_argument('--rerun', '-r'
|
||||
metavar='<string>',
|
||||
choices=processopts,
|
||||
help=('Can be one of:' + ' | '.join(processopts)))
|
||||
|
@ -143,6 +143,13 @@ parser.add_argument('--pmvs-minImageNum',
|
|||
'minImageNum images for being reconstructed. 3 is '
|
||||
'suggested in general.'))
|
||||
|
||||
parser.add_argument('--pmvs-num-cores',
|
||||
metavar='<positive integer>',
|
||||
default=1,
|
||||
type=int,
|
||||
help=('The maximum number of cores to use in dense '
|
||||
'reconstruction.'))
|
||||
|
||||
parser.add_argument('--odm_meshing-maxVertexCount',
|
||||
metavar='<positive integer>',
|
||||
default=100000,
|
||||
|
@ -211,10 +218,4 @@ parser.add_argument('--zip-results',
|
|||
default=False,
|
||||
help='compress the results using gunzip')
|
||||
|
||||
parser.add_argument('--use-opensfm',
|
||||
type=bool,
|
||||
default=True,
|
||||
help='use OpenSfM instead of Bundler to find the camera positions '
|
||||
'(replaces getKeypoints, match and bundler steps)')
|
||||
|
||||
args = vars(parser.parse_args())
|
|
@ -51,7 +51,7 @@ class ODMPhoto:
|
|||
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: ''
|
||||
try:
|
||||
val = metadata[key].value
|
||||
|
@ -84,7 +84,7 @@ class ODMPhoto:
|
|||
|
||||
|
||||
# TODO: finish this class
|
||||
class ODMReconstruction(object):
|
||||
class ODMTree(object):
|
||||
def __init__(self, root_path):
|
||||
### root path to the project
|
||||
self.root_path = io.absolute_path_file(root_path)
|
||||
|
@ -95,7 +95,7 @@ class ODMReconstruction(object):
|
|||
# order to keep track all files al directories during the
|
||||
# whole reconstruction process.
|
||||
self.dataset_raw = io.join_paths(self.root_path, 'images')
|
||||
self.dataset_resized = io.join_paths(self.root_path, 'images_resized')
|
||||
self.dataset_resize = io.join_paths(self.root_path, 'images_resize')
|
||||
self.opensfm = io.join_paths(self.root_path, 'opensfm')
|
||||
self.pmvs = io.join_paths(self.root_path, 'pmvs')
|
||||
self.odm_meshing = io.join_paths(self.root_path, 'odm_meshing')
|
||||
|
@ -110,19 +110,48 @@ class ODMReconstruction(object):
|
|||
self.opensfm_bundle_list = io.join_paths(self.opensfm, 'list_r000.out')
|
||||
self.opensfm_image_list = io.join_paths(self.opensfm, 'image_list.txt')
|
||||
self.opensfm_reconstruction = io.join_paths(self.opensfm, 'reconstruction.json')
|
||||
|
||||
# pmvs
|
||||
self.pmvs_options = io.join_paths(self.pmvs, 'recon0/pmvs_options.txt')
|
||||
self.pmvs_model = io.join_paths(self.pmvs, 'models/pmvs_options.txt.ply')
|
||||
self.pmvs_rec_path = io.join_paths(self.pmvs, 'recon0')
|
||||
self.pmvs_bundle = io.join_paths(self.pmvs_rec_path, 'bundle.rd.out')
|
||||
self.pmvs_visdat = io.join_paths(self.pmvs_rec_path, 'vis.dat')
|
||||
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')
|
||||
|
||||
# odm_meshing
|
||||
self.mesh = io.join_paths(self.odm_meshing, 'odm_mesh.ply')
|
||||
# odm_texturing && odm_georeferencing
|
||||
self.textured_model = io.join_paths(self.odm_texturing, 'odm_textured_model_geo.ply')
|
||||
self.textured_model_obj = io.join_paths(self.odm_texturing, 'odm_textured_model.obj')
|
||||
self.textured_model_mtl = io.join_paths(self.odm_texturing, 'odm_textured_model.mtl')
|
||||
self.textured_model_obj_geo = io.join_paths(self.odm_texturing, 'odm_textured_model_geo.obj')
|
||||
self.textured_model_mtl_geo = io.join_paths(self.odm_texturing, 'odm_textured_model_geo.mtl')
|
||||
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')
|
||||
|
||||
# odm_texturing
|
||||
self.odm_textured_model_obj = io.join_paths(
|
||||
self.odm_texturing, 'odm_textured_model.obj')
|
||||
self.odm_textured_model_mtl = io.join_paths(
|
||||
self.odm_texturing, 'odm_textured_model.mtl')
|
||||
self.odm_textured_model_txt_geo = io.join_paths(
|
||||
self.odm_texturing, 'odm_textured_model_geo.txt')
|
||||
self.odm_textured_model_ply_geo = io.join_paths(
|
||||
self.odm_texturing, 'odm_textured_model_geo.ply')
|
||||
self.odm_textured_model_obj_geo = io.join_paths(
|
||||
self.odm_texturing, 'odm_textured_model_geo.obj')
|
||||
self.odm_textured_model_mtl_geo = io.join_paths(
|
||||
self.odm_texturing, 'odm_textured_model_geo.mtl')
|
||||
self.odm_texuring_log = io.join_paths(
|
||||
self.odm_texturing, 'odm_texturing_log.txt')
|
||||
|
||||
# odm_georeferencing
|
||||
self.odm_georeferencing_coords = io.join_paths(
|
||||
self.odm_georeferencing, 'coords.txt')
|
||||
self.odm_georeferencing_gcp = io.join_paths(
|
||||
self.odm_georeferencing, 'gcp_list.txt')
|
||||
self.odm_georeferencing_utm_log = io.join_paths(
|
||||
self.odm_georeferencing, 'odm_georeferencing_utm_log.txt')
|
||||
self.odm_georeferencing_log = io.join_paths(
|
||||
self.odm_georeferencing, 'odm_georeferencing_log.txt')
|
||||
|
||||
# odm_orthophoto
|
||||
self.orthophoto = io.join_paths(self.odm_orthophoto, 'odm_orthophoto.png')
|
||||
self.odm_orthophoto_file = io.join_paths(self.odm_orthophoto, 'odm_orthophoto.png')
|
||||
self.odm_orthophoto_corners = io.join_paths(self.odm_orthophoto, 'odm_orthphoto_corners.txt')
|
||||
self.odm_orthophoto_log = io.join_paths(self.odm_orthophoto, 'odm_orthophoto_log.txt')
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
import ecto
|
||||
|
||||
from opendm import io
|
||||
from opendm import log
|
||||
from opendm import system
|
||||
from opendm import context
|
||||
|
||||
class ODMCmvsCell(ecto.Cell):
|
||||
|
||||
def declare_params(self, params):
|
||||
params.declare("max_images", 'The maximum number of images '
|
||||
'per cluster', 500)
|
||||
params.declare("cores", 'The maximum number of cores to use '
|
||||
'in dense reconstruction.', context.num_cores)
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("tree", "Struct with paths", [])
|
||||
inputs.declare("args", "Struct with paths", [])
|
||||
inputs.declare("reconstruction", "list of ODMReconstructions", [])
|
||||
outputs.declare("reconstruction", "list of ODMReconstructions", [])
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
|
||||
log.ODM_INFO('Running OMD CMVS Cell')
|
||||
|
||||
# get inputs
|
||||
args = self.inputs.args
|
||||
tree = self.inputs.tree
|
||||
|
||||
# check if we rerun cell or not
|
||||
rerun_cell = args['rerun'] is not None \
|
||||
and args['rerun'] == 'cmvs'
|
||||
|
||||
if not io.file_exists(tree.pmvs_bundle) or rerun_cell:
|
||||
log.ODM_DEBUG('Writting CMVS vis in: %s' % tree.pmvs_bundle)
|
||||
|
||||
# copy bundle file to pmvs dir
|
||||
from shutil import copyfile
|
||||
copyfile(tree.opensfm_bundle,
|
||||
tree.pmvs_bundle)
|
||||
|
||||
kwargs = {
|
||||
'bin': context.cmvs_path,
|
||||
'prefix': self.inputs.tree.pmvs_rec_path,
|
||||
'max_images': self.params.max_images,
|
||||
'cores': self.params.cores
|
||||
}
|
||||
|
||||
# run cmvs
|
||||
system.run('{bin} {prefix}/ {max_images} {cores}'.format(**kwargs))
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid CMVS file in: %s' %
|
||||
(tree.pmvs_bundle))
|
||||
|
||||
log.ODM_INFO('Running OMD CMVS Cell - Finished')
|
||||
return ecto.OK if args['end_with'] != 'cmvs' else ecto.QUIT
|
|
@ -12,8 +12,9 @@ class ODMLoadDatasetCell(ecto.Cell):
|
|||
pass
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("tree", "Struct with paths", [])
|
||||
inputs.declare("args", "The application arguments.", {})
|
||||
outputs.declare("photos", "Clusters output. list of ODMPhoto's", [])
|
||||
outputs.declare("photos", "list of ODMPhoto's", [])
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
# check if the extension is sopported
|
||||
|
@ -23,17 +24,19 @@ class ODMLoadDatasetCell(ecto.Cell):
|
|||
|
||||
log.ODM_INFO('Running ODM Load Dataset Cell')
|
||||
|
||||
# get parameters
|
||||
# get inputs
|
||||
args = self.inputs.args
|
||||
project_path = io.absolute_path_file(args['project_path'])
|
||||
images_dir = io.join_paths(project_path, 'images_resize')
|
||||
tree = self.inputs.tree
|
||||
|
||||
# set images directory
|
||||
images_dir = tree.dataset_resize
|
||||
|
||||
# check if we rerun cell or not
|
||||
rerun_cell = args['run_only'] is not None \
|
||||
and args['run_only'] == 'resize'
|
||||
rerun_cell = args['rerun'] is not None \
|
||||
and args['rerun'] == 'resize'
|
||||
|
||||
if not io.dir_exists(images_dir) or rerun_cell:
|
||||
images_dir = io.join_paths(project_path, 'images')
|
||||
images_dir = tree.dataset_raw
|
||||
if not io.dir_exists(images_dir):
|
||||
log.ODM_ERROR("You must put your pictures into an <images> directory")
|
||||
return ecto.QUIT
|
||||
|
@ -44,7 +47,6 @@ class ODMLoadDatasetCell(ecto.Cell):
|
|||
files = io.get_files_list(images_dir)
|
||||
|
||||
# filter images for its extension type
|
||||
# by now only 'jpg' and 'jpeg are supported
|
||||
files = [f for f in files if supported_extension(f)]
|
||||
|
||||
if files:
|
||||
|
|
|
@ -1,11 +1,14 @@
|
|||
import ecto
|
||||
|
||||
from opendm import context
|
||||
from opendm import types
|
||||
from opendm import config
|
||||
|
||||
from dataset import ODMLoadDatasetCell
|
||||
from resize import ODMResizeCell
|
||||
from opensfm import ODMOpenSfMCell
|
||||
from pmvs import ODMPmvsCell
|
||||
from cmvs import ODMCmvsCell
|
||||
from odm_meshing import ODMeshingCell
|
||||
from odm_texturing import ODMTexturingCell
|
||||
from odm_georeferencing import ODMGeoreferencingCell
|
||||
|
@ -23,67 +26,127 @@ class ODMApp(ecto.BlackBox):
|
|||
|
||||
@staticmethod
|
||||
def declare_cells(p):
|
||||
print p.args
|
||||
"""
|
||||
Implement the virtual function from the base class
|
||||
Only cells from which something is forwarded have to be declared
|
||||
"""
|
||||
cells = { 'args': ecto.Constant(value=p.args),
|
||||
'load_dataset': ODMLoadDatasetCell(),
|
||||
'dataset': ODMLoadDatasetCell(),
|
||||
'resize': ODMResizeCell(),
|
||||
'opensfm': ODMOpenSfMCell(use_exif_size=False,
|
||||
feature_process_size=p.args['resize_to'],
|
||||
feature_min_frames=p.args['min_num_features'],
|
||||
processes=context.num_cores,
|
||||
matching_gps_neighbors=p.args['matcher_k']),
|
||||
'pmvs': ODMPmvsCell(),
|
||||
'meshing': ODMeshingCell(),
|
||||
'texturing': ODMTexturingCell(),
|
||||
'georeferencing': ODMGeoreferencingCell(),
|
||||
'orthophoto': ODMOrthoPhotoCell()
|
||||
'cmvs': ODMCmvsCell(max_images=p.args['cmvs_maxImages']),
|
||||
'pmvs': ODMPmvsCell(level=p.args['pmvs_level'],
|
||||
csize=p.args['pmvs_csize'],
|
||||
thresh=p.args['pmvs_threshold'],
|
||||
wsize=p.args['pmvs_wsize'],
|
||||
min_imgs=p.args['pmvs_minImageNum'],
|
||||
cores=p.args['pmvs_num_cores']),
|
||||
'meshing': ODMeshingCell(max_vertex=p.args['odm_meshing_maxVertexCount'],
|
||||
oct_tree=p.args['odm_meshing_octreeDepth'],
|
||||
samples=p.args['odm_meshing_samplesPerNode'],
|
||||
solver=p.args['odm_meshing_solverDivide']),
|
||||
'texturing': ODMTexturingCell(resize=p.args['resize_to'],
|
||||
resolution=p.args['odm_texturing_textureResolution'],
|
||||
size=p.args['odm_texturing_textureWithSize']),
|
||||
'georeferencing': ODMGeoreferencingCell(img_size=p.args['resize_to'],
|
||||
gcp_file=p.args['odm_georeferencing_gcpFile'],
|
||||
use_gcp=p.args['odm_georeferencing_useGcp']),
|
||||
'orthophoto': ODMOrthoPhotoCell(resolution=p.args['odm_orthophoto_resolution'])
|
||||
|
||||
}
|
||||
|
||||
return cells
|
||||
|
||||
def connections(self, _p):
|
||||
# define initial and final tasks
|
||||
# TODO: not sure how to manage that
|
||||
initial_task = _p.args['start_with']
|
||||
final_task = _p.args['end_with']
|
||||
run_only = _p.args['run_only']
|
||||
def configure(self, p, _i, _o):
|
||||
tree = types.ODMTree(p.args['project_path'])
|
||||
self.tree = ecto.Constant(value=tree)
|
||||
|
||||
# define the connections like you would for the plasm
|
||||
|
||||
def connections(self, _p):
|
||||
# define initial task
|
||||
initial_task = _p.args['start_with']
|
||||
initial_task_id = config.processopts.index(initial_task)
|
||||
|
||||
print _p.args['rerun']
|
||||
|
||||
## define the connections like you would for the plasm
|
||||
connections = []
|
||||
|
||||
# load the dataset
|
||||
connections = [ self.args[:] >> self.load_dataset['args'] ]
|
||||
## load the dataset
|
||||
connections = [ self.tree[:] >> self.dataset['tree'],
|
||||
self.args[:] >> self.dataset['args'] ]
|
||||
|
||||
# resize images
|
||||
connections += [ self.args[:] >> self.resize['args'],
|
||||
self.load_dataset['photos'] >> self.resize['photos'] ]
|
||||
## check we want to start with resize task
|
||||
if initial_task_id <= config.processopts.index('resize'):
|
||||
|
||||
# run opensfm
|
||||
connections += [ self.args[:] >> self.opensfm['args'],
|
||||
self.load_dataset['photos'] >> self.opensfm['photos'] ]
|
||||
# resize images
|
||||
connections += [ self.tree[:] >> self.resize['tree'],
|
||||
self.args[:] >> self.resize['args'],
|
||||
self.dataset['photos'] >> self.resize['photos'] ]
|
||||
|
||||
# run cmvs
|
||||
connections += [ self.args[:] >> self.pmvs['args'],
|
||||
self.opensfm['reconstruction_path'] >>
|
||||
self.pmvs['reconstruction_path'] ]
|
||||
# forward opensfm variables
|
||||
connections += [ self.tree[:] >> self.opensfm['tree'],
|
||||
self.args[:] >> self.opensfm['args'] ]
|
||||
|
||||
# create odm mesh
|
||||
connections += [ self.args[:] >> self.meshing['args'],
|
||||
self.pmvs['model_path'] >> self.meshing['model_path'] ]
|
||||
## check we want to start with opensfm task
|
||||
if initial_task_id <= config.processopts.index('opensfm'):
|
||||
# run opensfm with images from load dataset
|
||||
connections += [ self.dataset['photos'] >> self.opensfm['photos'] ]
|
||||
else:
|
||||
# run opensfm with images from resize
|
||||
connections += [ self.resize['photos'] >> self.opensfm['photos'] ]
|
||||
|
||||
# create odm texture
|
||||
connections += [ self.args[:] >> self.texturing['args'],
|
||||
self.meshing['mesh_path'] >> self.texturing['model_path'] ]
|
||||
## check we want to start with cmvs task
|
||||
if initial_task_id <= config.processopts.index('cmvs'):
|
||||
|
||||
# create odm georeference
|
||||
connections += [ self.args[:] >> self.georeferencing['args'] ]
|
||||
# run cmvs
|
||||
connections += [ self.tree[:] >> self.cmvs['tree'],
|
||||
self.args[:] >> self.cmvs['args'],
|
||||
self.opensfm['reconstruction'] >> self.cmvs['reconstruction'] ]
|
||||
|
||||
# create odm orthophoto
|
||||
connections += [ self.args[:] >> self.orthophoto['args'] ]
|
||||
## check we want to start with cmvs task
|
||||
if initial_task_id <= config.processopts.index('pmvs'):
|
||||
|
||||
# run pmvs
|
||||
connections += [ self.tree[:] >> self.pmvs['tree'],
|
||||
self.args[:] >> self.pmvs['args'],
|
||||
self.cmvs['reconstruction'] >> self.pmvs['reconstruction'] ]
|
||||
|
||||
## check we want to start with odm_meshing task
|
||||
if initial_task_id <= config.processopts.index('odm_meshing'):
|
||||
|
||||
# create odm mesh
|
||||
connections += [ self.tree[:] >> self.meshing['tree'],
|
||||
self.args[:] >> self.meshing['args'],
|
||||
self.pmvs['reconstruction'] >> self.meshing['reconstruction'] ]
|
||||
|
||||
## check we want to start with odm_texturing task
|
||||
if initial_task_id <= config.processopts.index('odm_texturing'):
|
||||
|
||||
# create odm texture
|
||||
connections += [ self.tree[:] >> self.texturing['tree'],
|
||||
self.args[:] >> self.texturing['args'],
|
||||
self.meshing['reconstruction'] >> self.texturing['reconstruction'] ]
|
||||
|
||||
## check we want to start with odm_georeferencing task
|
||||
if initial_task_id <= config.processopts.index('odm_georeferencing'):
|
||||
|
||||
# create odm georeference
|
||||
connections += [ self.tree[:] >> self.georeferencing['tree'],
|
||||
self.args[:] >> self.georeferencing['args'],
|
||||
self.dataset['photos'] >> self.georeferencing['photos'],
|
||||
self.texturing['reconstruction'] >> self.georeferencing['reconstruction'] ]
|
||||
|
||||
## check we want to start with odm_orthophoto task
|
||||
if initial_task_id <= config.processopts.index('odm_orthophoto'):
|
||||
|
||||
## create odm orthophoto
|
||||
connections += [ self.tree[:] >> self.orthophoto['tree'],
|
||||
self.args[:] >> self.orthophoto['args'],
|
||||
self.georeferencing['reconstruction'] >> self.orthophoto['reconstruction'] ]
|
||||
|
||||
return connections
|
|
@ -6,10 +6,20 @@ from opendm import system
|
|||
from opendm import context
|
||||
|
||||
class ODMGeoreferencingCell(ecto.Cell):
|
||||
def declare_params(self, params):
|
||||
params.declare("gcp_file", 'path to the file containing the ground control '
|
||||
'points used for georeferencing.The file needs to '
|
||||
'be on the following line format: \neasting '
|
||||
'northing height pixelrow pixelcol imagename', 'gcp_list.txt')
|
||||
params.declare("use_gcp", 'set to true for enabling GCPs from the file above', False)
|
||||
params.declare("img_size", 'image size used in calibration', 2400)
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("tree", "Struct with paths", [])
|
||||
inputs.declare("args", "The application arguments.", {})
|
||||
inputs.declare("texture_path", "The application arguments.", {})
|
||||
inputs.declare("photos", "list of ODMPhoto's", [])
|
||||
inputs.declare("reconstruction", "list of ODMReconstructions", [])
|
||||
outputs.declare("reconstruction", "list of ODMReconstructions", [])
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
|
||||
|
@ -17,80 +27,82 @@ class ODMGeoreferencingCell(ecto.Cell):
|
|||
|
||||
# get inputs
|
||||
args = self.inputs.args
|
||||
project_path = io.absolute_path_file(args['project_path'])
|
||||
tree = self.inputs.tree
|
||||
|
||||
# define paths and create working directories
|
||||
odm_texturing = io.join_paths(project_path, 'odm_texturing')
|
||||
odm_georeferencing = io.join_paths(project_path, 'odm_georeferencing')
|
||||
system.mkdir_p(odm_georeferencing)
|
||||
|
||||
images_path = io.join_paths(project_path, 'images_resize')
|
||||
images_list_file = io.join_paths(project_path, 'opensfm/list_r000.out')
|
||||
|
||||
# define gcp file path, we'll assume that's placed in the project root
|
||||
gcp_file = io.join_paths(project_path, args['odm_georeferencing_gcpFile'])
|
||||
coords_file = io.join_paths(odm_georeferencing, 'coords.txt')
|
||||
system.mkdir_p(tree.odm_georeferencing)
|
||||
|
||||
# in case a gcp file it's not provided, let's try to generate it using
|
||||
# images metadata. Internally calls jhead.
|
||||
if not args['odm_georeferencing_useGcp'] and not io.file_exists(coords_file):
|
||||
if not self.params.use_gcp and \
|
||||
not io.file_exists(tree.odm_georeferencing_coords):
|
||||
|
||||
log.ODM_WARNING('Warning: No coordinates file. ' \
|
||||
'Generating coordinates file in: %s' % coords_file)
|
||||
'Generating coordinates file in: %s' % tree.odm_georeferencing_coords)
|
||||
try:
|
||||
log_file = io.join_paths(odm_georeferencing, 'odm_texturing_utm_log.txt')
|
||||
# odm_georeference definitions
|
||||
kwargs = {
|
||||
'bin': context.odm_modules_path,
|
||||
'imgs': tree.dataset_resize,
|
||||
'imgs_list': tree.opensfm_bundle_list,
|
||||
'coords': tree.odm_georeferencing_coords,
|
||||
'log': tree.odm_georeferencing_utm_log
|
||||
}
|
||||
|
||||
# run UTM extraction binary
|
||||
system.run('{bin}/odm_extract_utm -imagesPath {imgs}/ ' \
|
||||
'-imageListFile {imgs_list} -outputCoordFile {coords} ' \
|
||||
'-logFile {log}'.format(**kwargs))
|
||||
|
||||
system.run('%s/odm_extract_utm -imagesPath %s/ ' \
|
||||
'-imageListFile %s -outputCoordFile %s ' \
|
||||
'-logFile %s' % \
|
||||
(context.odm_modules_path, images_path, \
|
||||
images_list_file, coords_file, log_file))
|
||||
except Exception, e:
|
||||
log.ODM_ERROR('Could not generate GCP file from images metadata.' \
|
||||
'Consider rerunning with argument --odm_georeferencing-useGcp'\
|
||||
' and provide a proper GCP file')
|
||||
log.ODM_ERROR(str(e))
|
||||
log.ODM_ERROR('Could not generate GCP file from images metadata.' \
|
||||
'Consider rerunning with argument --odm_georeferencing-useGcp' \
|
||||
' and provide a proper GCP file')
|
||||
log.ODM_ERROR(e)
|
||||
return ecto.QUIT
|
||||
elif io.file_exists(coords_file):
|
||||
log.ODM_WARNING('Found a valid coordinates file in: %s' % coords_file)
|
||||
|
||||
# define odm georeferencing outputs
|
||||
# for convenience we'll put all data into odm_texturing
|
||||
model_geo = io.join_paths(odm_texturing, 'odm_textured_model_geo.obj')
|
||||
pointcloud_geo = io.join_paths(odm_texturing, 'odm_textured_model_geo.ply')
|
||||
system_geo = io.join_paths(odm_texturing, 'odm_textured_model_geo.txt')
|
||||
|
||||
# check if we rerun cell or not
|
||||
rerun_cell = args['run_only'] is not None \
|
||||
and args['run_only'] == 'odm_georeferencing'
|
||||
rerun_cell = args['rerun'] is not None \
|
||||
and args['rerun'] == 'odm_georeferencing'
|
||||
|
||||
if not io.file_exists(model_geo) or \
|
||||
not io.file_exists(pointcloud_geo) or rerun_cell:
|
||||
if not io.file_exists(tree.odm_textured_model_obj_geo) or \
|
||||
not io.file_exists(tree.odm_textured_model_ply_geo) or rerun_cell:
|
||||
|
||||
# odm_georeference definitions
|
||||
kwargs = {
|
||||
'bin': context.odm_modules_path,
|
||||
'bundle': io.join_paths(project_path,'opensfm/bundle_r000.out'),
|
||||
'gcp': io.join_paths(project_path, args['odm_georeferencing_gcpFile']),
|
||||
'imgs': io.join_paths(project_path, 'images_resize'),
|
||||
'imgs_list': io.join_paths(project_path, 'opensfm/list_r000.out'),
|
||||
'size': str(args['resize_to']),
|
||||
'model': io.join_paths(project_path, 'odm_texturing/odm_textured_model.obj'),
|
||||
'pc': io.join_paths(project_path, 'pmvs/recon0/models/option-0000.ply'),
|
||||
'log': io.join_paths(odm_georeferencing, 'odm_texturing_log.txt'),
|
||||
'coords': io.join_paths(odm_georeferencing, 'coords.txt'),
|
||||
'pc_geo': pointcloud_geo,
|
||||
'geo_sys': system_geo,
|
||||
'model_geo': model_geo,
|
||||
'bundle': tree.opensfm_bundle,
|
||||
'imgs': tree.dataset_resize,
|
||||
'imgs_list': tree.opensfm_bundle_list,
|
||||
'model': tree.odm_textured_model_obj,
|
||||
'pc': tree.pmvs_model,
|
||||
'log': tree.odm_georeferencing_log,
|
||||
'coords': tree.odm_georeferencing_coords,
|
||||
'pc_geo': tree.odm_textured_model_ply_geo,
|
||||
'geo_sys': tree.odm_textured_model_txt_geo,
|
||||
'model_geo': tree.odm_textured_model_obj_geo,
|
||||
'size': self.params.img_size,
|
||||
'gcp': io.join_paths(tree.root_path, self.params.gcp_file),
|
||||
|
||||
}
|
||||
|
||||
# run odm_georeference
|
||||
system.run('{bin}/odm_georef -bundleFile {bundle} -inputCoordFile {coords} ' \
|
||||
'-bundleResizedTo {size} -inputFile {model} -outputFile {model_geo} ' \
|
||||
'-inputPointCloudFile {pc} -outputPointCloudFile {pc_geo} ' \
|
||||
'-logFile {log} -georefFileOutputPath {geo_sys}'.format(**kwargs))
|
||||
if self.params.use_gcp and \
|
||||
io.file_exists(tree.odm_georeferencing_coords):
|
||||
|
||||
system.run('{bin}/odm_georef -bundleFile {bundle} -inputCoordFile {coords} ' \
|
||||
'-bundleResizedTo {size} -inputFile {model} -outputFile {model_geo} ' \
|
||||
'-inputPointCloudFile {pc} -outputPointCloudFile {pc_geo} ' \
|
||||
'-logFile {log} -georefFileOutputPath {geo_sys} -gcpFile {gcp} ' \
|
||||
'-outputCoordFile {coords}'.format(**kwargs))
|
||||
else:
|
||||
system.run('{bin}/odm_georef -bundleFile {bundle} -inputCoordFile {coords} ' \
|
||||
'-inputFile {model} -outputFile {model_geo} ' \
|
||||
'-inputPointCloudFile {pc} -outputPointCloudFile {pc_geo} ' \
|
||||
'-logFile {log} -georefFileOutputPath {geo_sys}'.format(**kwargs))
|
||||
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid georeferenced model in: %s' % pointcloud_geo)
|
||||
log.ODM_WARNING('Found a valid georeferenced model in: %s' \
|
||||
% tree.odm_textured_model_ply_geo)
|
||||
|
||||
|
||||
log.ODM_INFO('Running OMD Georeferencing Cell - Finished')
|
||||
|
|
|
@ -7,10 +7,24 @@ from opendm import context
|
|||
|
||||
class ODMeshingCell(ecto.Cell):
|
||||
|
||||
def declare_params(self, params):
|
||||
params.declare("max_vertex", 'The maximum vertex count of the output '
|
||||
'mesh', 100000)
|
||||
params.declare("oct_tree", 'Oct-tree depth used in the mesh reconstruction, '
|
||||
'increase to get more vertices, recommended '
|
||||
'values are 8-12', 9)
|
||||
params.declare("samples", 'Number of points per octree node, recommended '
|
||||
'value: 1.0', 1)
|
||||
params.declare("solver", 'Oct-tree depth at which the Laplacian equation '
|
||||
'is solved in the surface reconstruction step. '
|
||||
'Increasing this value increases computation '
|
||||
'times slightly but helps reduce memory usage.', 9)
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("tree", "Struct with paths", [])
|
||||
inputs.declare("args", "The application arguments.", {})
|
||||
inputs.declare("model_path", "Clusters output. list of reconstructions", [])
|
||||
outputs.declare("mesh_path", "Clusters output. list of reconstructions", [])
|
||||
inputs.declare("reconstruction", "Clusters output. list of ODMReconstructions", [])
|
||||
outputs.declare("reconstruction", "Clusters output. list of ODMReconstructions", [])
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
|
||||
|
@ -18,36 +32,37 @@ class ODMeshingCell(ecto.Cell):
|
|||
|
||||
# get inputs
|
||||
args = self.inputs.args
|
||||
model_path = self.inputs.model_path
|
||||
project_path = io.absolute_path_file(args['project_path'])
|
||||
tree = self.inputs.tree
|
||||
|
||||
# define paths and create working directories
|
||||
odm_meshing = io.join_paths(project_path, 'odm_meshing')
|
||||
system.mkdir_p(odm_meshing)
|
||||
output_file = io.join_paths(odm_meshing, 'odm_mesh.ply')
|
||||
log_file = io.join_paths(odm_meshing, 'odm_meshing_log.txt')
|
||||
|
||||
self.outputs.mesh_path = output_file
|
||||
system.mkdir_p(tree.odm_meshing)
|
||||
|
||||
# check if we rerun cell or not
|
||||
rerun_cell = args['run_only'] is not None \
|
||||
and args['run_only'] == 'odm_meshing'
|
||||
rerun_cell = args['rerun'] is not None \
|
||||
and args['rerun'] == 'odm_meshing'
|
||||
|
||||
if not io.file_exists(output_file) or rerun_cell:
|
||||
log.ODM_DEBUG('Writting odm mesh file in: %s' % output_file)
|
||||
if not io.file_exists(tree.odm_mesh) or rerun_cell:
|
||||
log.ODM_DEBUG('Writting ODM Mesh file in: %s' % tree.odm_mesh)
|
||||
|
||||
kwargs = {
|
||||
'bin': context.odm_modules_path,
|
||||
'infile': tree.pmvs_model,
|
||||
'outfile': tree.odm_mesh,
|
||||
'log': tree.odm_meshing_log,
|
||||
'max_vertex': self.params.max_vertex,
|
||||
'oct_tree': self.params.oct_tree,
|
||||
'samples': self.params.samples,
|
||||
'solver':self.params.solver
|
||||
}
|
||||
|
||||
# run meshing binary
|
||||
system.run('%s/odm_meshing -inputFile %s -outputFile %s ' \
|
||||
'-logFile %s -maxVertexCount %s -octreeDepth %s ' \
|
||||
'-samplesPerNode %s -solverDivide %s' % \
|
||||
(context.odm_modules_path, model_path, output_file, log_file, \
|
||||
str(args['odm_meshing_maxVertexCount']), \
|
||||
str(args['odm_meshing_octreeDepth']), \
|
||||
str(args['odm_meshing_samplesPerNode']), \
|
||||
str(args['odm_meshing_solverDivide'])))
|
||||
system.run('{bin}/odm_meshing -inputFile {infile} ' \
|
||||
'-outputFile {outfile} -logFile {log} ' \
|
||||
'-maxVertexCount {max_vertex} -octreeDepth {oct_tree} ' \
|
||||
'-samplesPerNode {samples} -solverDivide {solver}'.format(**kwargs))
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid odm mesh file in: %s' %
|
||||
(output_file))
|
||||
log.ODM_WARNING('Found a valid ODM Mesh file in: %s' %
|
||||
(tree.odm_mesh))
|
||||
|
||||
log.ODM_INFO('Running OMD Meshing Cell - Finished')
|
||||
return ecto.OK if args['end_with'] != 'odm_meshing' else ecto.QUIT
|
|
@ -6,9 +6,13 @@ from opendm import system
|
|||
from opendm import context
|
||||
|
||||
class ODMOrthoPhotoCell(ecto.Cell):
|
||||
def declare_params(self, params):
|
||||
params.declare("resolution", 'Orthophoto ground resolution in pixels/meter', 20)
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("tree", "Struct with paths", [])
|
||||
inputs.declare("args", "The application arguments.", {})
|
||||
inputs.declare("reconstruction", "list of ODMReconstructions", [])
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
|
||||
|
@ -16,33 +20,32 @@ class ODMOrthoPhotoCell(ecto.Cell):
|
|||
|
||||
# get inputs
|
||||
args = self.inputs.args
|
||||
project_path = io.absolute_path_file(args['project_path'])
|
||||
tree = self.inputs.tree
|
||||
|
||||
# define paths and create working directories
|
||||
odm_texturing = io.join_paths(project_path, 'odm_texturing')
|
||||
odm_orthophoto = io.join_paths(project_path, 'odm_orthophoto')
|
||||
system.mkdir_p(odm_orthophoto)
|
||||
|
||||
# odm_georeference definitions
|
||||
kwargs = {
|
||||
'bin': context.odm_modules_path,
|
||||
'model_geo': io.join_paths(odm_texturing, 'odm_textured_model_geo.obj'),
|
||||
'log': io.join_paths(odm_orthophoto, 'odm_orthophoto_log.txt'),
|
||||
'ortho': io.join_paths(odm_orthophoto, 'odm_orthphoto.png'),
|
||||
'corners': io.join_paths(odm_orthophoto, 'odm_orthphoto_corners.txt'),
|
||||
'res': str(20.0)
|
||||
}
|
||||
system.mkdir_p(tree.odm_orthophoto)
|
||||
|
||||
# check if we rerun cell or not
|
||||
rerun_cell = args['run_only'] is not None \
|
||||
and args['run_only'] == 'odm_orthophoto'
|
||||
rerun_cell = args['rerun'] is not None \
|
||||
and args['rerun'] == 'odm_orthophoto'
|
||||
|
||||
if not io.file_exists(tree.odm_orthophoto_file) or rerun_cell:
|
||||
|
||||
# odm_georeference definitions
|
||||
kwargs = {
|
||||
'bin': context.odm_modules_path,
|
||||
'model_geo': tree.odm_textured_model_obj_geo,
|
||||
'log': tree.odm_orthophoto_log,
|
||||
'ortho': tree.odm_orthophoto_file,
|
||||
'corners': tree.odm_orthophoto_corners,
|
||||
'res': self.params.resolution
|
||||
}
|
||||
|
||||
if not io.file_exists(kwargs['ortho']) or rerun_cell:
|
||||
# run odm_georeference
|
||||
system.run('{bin}/odm_orthophoto -inputFile {model_geo} -logFile {log} ' \
|
||||
'-outputFile {ortho} -resolution {res} -outputCornerFile {corners}'.format(**kwargs))
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid orthophoto in: %s' % kwargs['ortho'])
|
||||
log.ODM_WARNING('Found a valid orthophoto in: %s' % tree.odm_orthophoto_file)
|
||||
|
||||
log.ODM_INFO('Running OMD OrthoPhoto Cell - Finished')
|
||||
return ecto.OK if args['end_with'] != 'odm_orthophoto' else ecto.QUIT
|
||||
|
|
|
@ -7,10 +7,18 @@ from opendm import context
|
|||
|
||||
class ODMTexturingCell(ecto.Cell):
|
||||
|
||||
def declare_params(self, params):
|
||||
params.declare("resize", 'resizes images by the largest side', 2400)
|
||||
params.declare("resolution", 'The resolution of the output textures. Must be '
|
||||
'greater than textureWithSize.', 4096)
|
||||
params.declare("size", 'The resolution to rescale the images performing '
|
||||
'the texturing.', 3600)
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("tree", "Struct with paths", [])
|
||||
inputs.declare("args", "The application arguments.", {})
|
||||
inputs.declare("model_path", "Clusters output. list of reconstructions", [])
|
||||
outputs.declare("texture_path", "Clusters output. list of reconstructions", [])
|
||||
inputs.declare("reconstruction", "Clusters output. list of ODMReconstructions", [])
|
||||
outputs.declare("reconstruction", "Clusters output. list of ODMReconstructions", [])
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
|
||||
|
@ -18,47 +26,42 @@ class ODMTexturingCell(ecto.Cell):
|
|||
|
||||
# get inputs
|
||||
args = self.inputs.args
|
||||
input_model_path = self.inputs.model_path
|
||||
project_path = io.absolute_path_file(args['project_path'])
|
||||
tree = self.inputs.tree
|
||||
|
||||
# define paths and create working directories
|
||||
odm_meshing = io.join_paths(project_path, 'odm_meshing')
|
||||
odm_texturing = io.join_paths(project_path, 'odm_texturing')
|
||||
system.mkdir_p(odm_texturing)
|
||||
|
||||
output_file = io.join_paths(odm_texturing, 'odm_textured_model.obj')
|
||||
system.mkdir_p(tree.odm_texturing)
|
||||
|
||||
# check if we rerun cell or not
|
||||
rerun_cell = args['run_only'] is not None \
|
||||
and args['run_only'] == 'odm_texturing'
|
||||
rerun_cell = args['rerun'] is not None \
|
||||
and args['rerun'] == 'odm_texturing'
|
||||
|
||||
if not io.file_exists(output_file) or rerun_cell:
|
||||
log.ODM_DEBUG('Writting odm textured file in: %s' % output_file)
|
||||
if not io.file_exists(tree.odm_textured_model_obj) or rerun_cell:
|
||||
log.ODM_DEBUG('Writting ODM Textured file in: %s' \
|
||||
% tree.odm_textured_model_obj)
|
||||
|
||||
# odm_texturing definitions
|
||||
kwargs = {
|
||||
'bin': context.odm_modules_path,
|
||||
'out_dir': odm_texturing,
|
||||
'bundle': io.join_paths(project_path,'opensfm/bundle_r000.out'),
|
||||
'imgs_path': io.join_paths(project_path, 'images_resize'),
|
||||
'imgs_list': io.join_paths(project_path, 'opensfm/list_r000.out'),
|
||||
'model': io.join_paths(odm_meshing, 'odm_mesh.ply'),
|
||||
'log': io.join_paths(odm_texturing, 'odm_texturing_log.txt'),
|
||||
'bsize': str(args['resize_to']),
|
||||
'res': str(args['odm_texturing_textureResolution']),
|
||||
'wsize': str(args['odm_texturing_textureWithSize'])
|
||||
'out_dir': tree.odm_texturing,
|
||||
'bundle': tree.opensfm_bundle,
|
||||
'imgs_path': tree.dataset_resize,
|
||||
'imgs_list': tree.opensfm_bundle_list,
|
||||
'model': tree.odm_mesh,
|
||||
'log': tree.odm_texuring_log,
|
||||
'resize': self.params.resize,
|
||||
'resolution': self.params.resolution,
|
||||
'size': self.params.size
|
||||
}
|
||||
|
||||
# run texturing binary
|
||||
system.run('{bin}/odm_texturing -bundleFile {bundle} ' \
|
||||
'-imagesPath {imgs_path} -imagesListPath {imgs_list} ' \
|
||||
'-inputModelPath {model} -outputFolder {out_dir}/ ' \
|
||||
'-textureResolution {res} -bundleResizedTo {bsize} ' \
|
||||
'-textureWithSize {wsize} -logFile {log}'.format(**kwargs))
|
||||
'-textureResolution {resolution} -bundleResizedTo {resize} ' \
|
||||
'-textureWithSize {size} -logFile {log}'.format(**kwargs))
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid odm texture file in: %s' % output_file)
|
||||
|
||||
self.outputs.texture_path = output_file
|
||||
log.ODM_WARNING('Found a valid ODM Texture file in: %s' \
|
||||
% tree.odm_textured_model_obj)
|
||||
|
||||
log.ODM_INFO('Running OMD Texturing Cell - Finished')
|
||||
return ecto.OK if args['end_with'] != 'odm_texturing' else ecto.QUIT
|
|
@ -6,6 +6,8 @@ from opendm import system
|
|||
from opendm import context
|
||||
|
||||
class ODMOpenSfMCell(ecto.Cell):
|
||||
def declare_params(self, params):
|
||||
pass
|
||||
|
||||
def declare_params(self, params):
|
||||
params.declare("use_exif_size", "The application arguments.", False)
|
||||
|
@ -15,40 +17,38 @@ class ODMOpenSfMCell(ecto.Cell):
|
|||
params.declare("matching_gps_neighbors", "The application arguments.", 0)
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("tree", "Struct with paths", [])
|
||||
inputs.declare("args", "The application arguments.", {})
|
||||
inputs.declare("photos", "Clusters output. list of ODMPhoto's", [])
|
||||
outputs.declare("reconstructions", "Clusters output. list of reconstructions", [])
|
||||
outputs.declare("reconstruction_path", "The directory to the images to load.", "")
|
||||
inputs.declare("photos", "list of ODMPhoto's", [])
|
||||
outputs.declare("reconstruction", "list of ODMReconstructions", [])
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
|
||||
log.ODM_INFO('Running OMD OpenSfm Cell')
|
||||
|
||||
# get inputs
|
||||
tree = self.inputs.tree
|
||||
args = self.inputs.args
|
||||
photos = self.inputs.photos
|
||||
project_path = io.absolute_path_file(args['project_path'])
|
||||
|
||||
if not photos:
|
||||
log.ODM_ERROR('Not enough photos in photos array to start OpenSfm')
|
||||
return ecto.QUIT
|
||||
|
||||
# create working directories
|
||||
opensfm_path = io.join_paths(project_path, 'opensfm')
|
||||
pmvs_path = io.join_paths(project_path, 'pmvs')
|
||||
system.mkdir_p(opensfm_path)
|
||||
system.mkdir_p(pmvs_path)
|
||||
system.mkdir_p(tree.opensfm)
|
||||
system.mkdir_p(tree.pmvs)
|
||||
|
||||
# check if we rerun cell or not
|
||||
rerun_cell = args['run_only'] is not None \
|
||||
and args['run_only'] == 'opensfm'
|
||||
rerun_cell = args['rerun'] is not None \
|
||||
and args['rerun'] == 'opensfm'
|
||||
|
||||
|
||||
### check if reconstruction was done before
|
||||
reconstruction_file = io.join_paths(opensfm_path, 'reconstruction.json')
|
||||
|
||||
if not io.file_exists(reconstruction_file) or rerun_cell:
|
||||
if not io.file_exists(tree.opensfm_reconstruction) or rerun_cell:
|
||||
# create file list
|
||||
list_path = io.join_paths(opensfm_path, 'image_list.txt')
|
||||
list_path = io.join_paths(tree.opensfm, 'image_list.txt')
|
||||
with open(list_path, 'w') as fout:
|
||||
for photo in photos:
|
||||
fout.write('%s\n' % photo.path_file)
|
||||
|
@ -63,40 +63,37 @@ class ODMOpenSfMCell(ecto.Cell):
|
|||
]
|
||||
|
||||
# write config file
|
||||
config_filename = io.join_paths(opensfm_path, 'config.yaml')
|
||||
config_filename = io.join_paths(tree.opensfm, 'config.yaml')
|
||||
with open(config_filename, 'w') as fout:
|
||||
fout.write("\n".join(config))
|
||||
|
||||
# run OpenSfM reconstruction
|
||||
system.run('PYTHONPATH=%s %s/bin/run_all %s' %
|
||||
(context.pyopencv_path, context.opensfm_path, opensfm_path))
|
||||
(context.pyopencv_path, context.opensfm_path, tree.opensfm))
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid reconstruction file in: %s' %
|
||||
(reconstruction_file))
|
||||
log.ODM_WARNING('Found a valid OpenSfm file in: %s' %
|
||||
(tree.opensfm_reconstruction))
|
||||
|
||||
|
||||
### check if reconstruction was exported to bundler before
|
||||
bundler_file = io.join_paths(opensfm_path, 'bundle_r000.out')
|
||||
|
||||
if not io.file_exists(bundler_file) or rerun_cell:
|
||||
if not io.file_exists(tree.opensfm_bundle_list) or rerun_cell:
|
||||
# convert back to bundler's format
|
||||
system.run('PYTHONPATH=%s %s/bin/export_bundler %s' %
|
||||
(context.pyopencv_path, context.opensfm_path, opensfm_path))
|
||||
(context.pyopencv_path, context.opensfm_path, tree.opensfm))
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid bundle file in: %s' %
|
||||
(reconstruction_file))
|
||||
log.ODM_WARNING('Found a valid Bundler file in: %s' %
|
||||
(tree.opensfm_reconstruction))
|
||||
|
||||
|
||||
### check if reconstruction was exported to pmvs before
|
||||
pmvs_file = io.join_paths(pmvs_path, 'recon0/pmvs_options.txt')
|
||||
|
||||
if not io.file_exists(pmvs_file) or rerun_cell:
|
||||
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, opensfm_path, pmvs_path))
|
||||
(context.pyopencv_path, context.opensfm_path, tree.opensfm, tree.pmvs))
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid PMVS file in: %s' % pmvs_file)
|
||||
|
||||
# append biggest reconstruction path to output
|
||||
self.outputs.reconstruction_path = io.join_paths(pmvs_path, 'recon0')
|
||||
log.ODM_WARNING('Found a valid CMVS file in: %s' % tree.pmvs_visdat)
|
||||
|
||||
log.ODM_INFO('Running OMD OpenSfm Cell - Finished')
|
||||
return ecto.OK if args['end_with'] != 'opensfm' else ecto.QUIT
|
|
@ -7,10 +7,30 @@ from opendm import context
|
|||
|
||||
class ODMPmvsCell(ecto.Cell):
|
||||
|
||||
def declare_params(self, params):
|
||||
params.declare("level", 'The level in the image pyramid that is used '
|
||||
'for the computation', 1)
|
||||
params.declare("csize", 'Cell size controls the density of reconstructions', 2)
|
||||
params.declare("thresh", 'A patch reconstruction is accepted as a success '
|
||||
'and kept, if its associcated photometric consistency '
|
||||
'measure is above this threshold.', 0.7)
|
||||
params.declare("wsize", 'pmvs samples wsize x wsize pixel colors from '
|
||||
'each image to compute photometric consistency '
|
||||
'score. For example, when wsize=7, 7x7=49 pixel '
|
||||
'colors are sampled in each image. Increasing the '
|
||||
'value leads to more stable reconstructions, but '
|
||||
'the program becomes slower.', 7)
|
||||
params.declare("min_imgs", 'Each 3D point must be visible in at least '
|
||||
'minImageNum images for being reconstructed. 3 is '
|
||||
'suggested in general.', 3)
|
||||
params.declare("cores", 'The maximum number of cores to use in dense '
|
||||
' reconstruction.', context.num_cores)
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("tree", "Struct with paths", [])
|
||||
inputs.declare("args", "The application arguments.", {})
|
||||
inputs.declare("reconstruction_path", "Clusters output. list of reconstructions", [])
|
||||
outputs.declare("model_path", "Clusters output. list of reconstructions", [])
|
||||
inputs.declare("reconstruction", "list of ODMReconstructions", [])
|
||||
outputs.declare("reconstruction", "list of ODMReconstructions", [])
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
|
||||
|
@ -18,24 +38,36 @@ class ODMPmvsCell(ecto.Cell):
|
|||
|
||||
# get inputs
|
||||
args = self.inputs.args
|
||||
rec_path = self.inputs.reconstruction_path
|
||||
|
||||
# the path to create the model
|
||||
model_path = io.join_paths(rec_path, 'models/pmvs_options.txt.ply')
|
||||
# attach created model to output
|
||||
self.outputs.model_path = model_path
|
||||
tree = self.inputs.tree
|
||||
|
||||
# check if we rerun cell or not
|
||||
rerun_cell = args['run_only'] is not None \
|
||||
and args['run_only'] == 'pmvs'
|
||||
rerun_cell = args['rerun'] is not None \
|
||||
and args['rerun'] == 'pmvs'
|
||||
|
||||
if not io.file_exists(model_path) or rerun_cell:
|
||||
log.ODM_DEBUG('Creating dense pointcloud in: %s' % model_path)
|
||||
if not io.file_exists(tree.pmvs_model) or rerun_cell:
|
||||
log.ODM_DEBUG('Creating dense pointcloud in: %s' % tree.pmvs_model)
|
||||
|
||||
kwargs = {
|
||||
'bin': context.cmvs_opts_path,
|
||||
'prefix': tree.pmvs_rec_path,
|
||||
'level': self.params.level,
|
||||
'csize': self.params.csize,
|
||||
'thresh': self.params.thresh,
|
||||
'wsize': self.params.wsize,
|
||||
'min_imgs': self.params.min_imgs,
|
||||
'cores': self.params.cores
|
||||
}
|
||||
|
||||
# generate pmvs2 options
|
||||
system.run('{bin} {prefix}/ {level} {csize} {thresh} {wsize} ' \
|
||||
'{min_imgs} {cores}'.format(**kwargs))
|
||||
|
||||
# run pmvs2
|
||||
system.run('%s %s/ pmvs_options.txt ' % (context.pmvs2_path, rec_path))
|
||||
system.run('%s %s/ option-0000' % \
|
||||
(context.pmvs2_path, tree.pmvs_rec_path))
|
||||
|
||||
else:
|
||||
log.ODM_WARNING('Found a valid PMVS file in %s' % model_path)
|
||||
log.ODM_WARNING('Found a valid PMVS file in %s' % tree.pmvs_model)
|
||||
|
||||
log.ODM_INFO('Running OMD PMVS Cell - Finished')
|
||||
return ecto.OK if args['end_with'] != 'pmvs' else ecto.QUIT
|
||||
|
|
|
@ -12,6 +12,7 @@ class ODMResizeCell(ecto.Cell):
|
|||
pass
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("tree", "Struct with paths", [])
|
||||
inputs.declare("args", "The application arguments.", [])
|
||||
inputs.declare("photos", "Clusters inputs. list of ODMPhoto's", [])
|
||||
outputs.declare("photos", "Clusters output. list of ODMPhoto's", [])
|
||||
|
@ -22,29 +23,28 @@ class ODMResizeCell(ecto.Cell):
|
|||
|
||||
# get inputs
|
||||
args = self.inputs.args
|
||||
tree = self.inputs.tree
|
||||
photos = self.inputs.photos
|
||||
project_path = io.absolute_path_file(args['project_path'])
|
||||
|
||||
if not photos:
|
||||
log.ODM_ERROR('Not enough photos in photos to resize')
|
||||
return ecto.QUIT
|
||||
|
||||
# create working directory
|
||||
resizing_dir = io.join_paths(project_path, 'images_resize')
|
||||
system.mkdir_p(resizing_dir)
|
||||
system.mkdir_p(tree.dataset_resize)
|
||||
|
||||
log.ODM_DEBUG('Resizing dataset to: %s' % resizing_dir)
|
||||
log.ODM_DEBUG('Resizing dataset to: %s' % tree.dataset_resize)
|
||||
|
||||
# check if we rerun cell or not
|
||||
rerun_cell = args['run_only'] is not None \
|
||||
and args['run_only'] == 'resize'
|
||||
rerun_cell = args['rerun'] is not None \
|
||||
and args['rerun'] == 'resize'
|
||||
|
||||
# loop over photos
|
||||
for photo in photos:
|
||||
|
||||
# TODO(edgar): check if resize is needed, else copy img.
|
||||
# Try to avoid oversampling!
|
||||
new_path_file = io.join_paths(resizing_dir, photo.filename)
|
||||
new_path_file = io.join_paths(tree.dataset_resize, photo.filename)
|
||||
|
||||
if not io.file_exists(new_path_file) or rerun_cell:
|
||||
# open and resize image with opencv
|
||||
|
|
Ładowanie…
Reference in New Issue