added tree structure to organize file paths

pull/249/head
edgarriba 2015-12-10 11:01:41 +00:00
rodzic 23eb0acc7f
commit c65d2b51b3
12 zmienionych plików z 454 dodań i 241 usunięć

Wyświetl plik

@ -1,7 +1,7 @@
import argparse import argparse
# parse arguments # parse arguments
processopts = ['resize', 'opensfm', 'pmvs', processopts = ['resize', 'opensfm', 'cmvs', 'pmvs',
'odm_meshing', 'odm_texturing', 'odm_georeferencing', 'odm_meshing', 'odm_texturing', 'odm_georeferencing',
'odm_orthophoto'] 'odm_orthophoto']
@ -28,7 +28,7 @@ parser.add_argument('--end-with', '-e',
choices=processopts, choices=processopts,
help=('Can be one of:' + ' | '.join(processopts))) help=('Can be one of:' + ' | '.join(processopts)))
parser.add_argument('--run-only', parser.add_argument('--rerun', '-r'
metavar='<string>', metavar='<string>',
choices=processopts, choices=processopts,
help=('Can be one of:' + ' | '.join(processopts))) help=('Can be one of:' + ' | '.join(processopts)))
@ -143,6 +143,13 @@ parser.add_argument('--pmvs-minImageNum',
'minImageNum images for being reconstructed. 3 is ' 'minImageNum images for being reconstructed. 3 is '
'suggested in general.')) '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', parser.add_argument('--odm_meshing-maxVertexCount',
metavar='<positive integer>', metavar='<positive integer>',
default=100000, default=100000,
@ -211,10 +218,4 @@ parser.add_argument('--zip-results',
default=False, default=False,
help='compress the results using gunzip') 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()) args = vars(parser.parse_args())

Wyświetl plik

@ -51,7 +51,7 @@ class ODMPhoto:
metadata.read() metadata.read()
# loop over image tags # loop over image tags
for key in metadata: 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: '' # ValueError: invalid literal for int() with base 10: ''
try: try:
val = metadata[key].value val = metadata[key].value
@ -84,7 +84,7 @@ class ODMPhoto:
# TODO: finish this class # TODO: finish this class
class ODMReconstruction(object): class ODMTree(object):
def __init__(self, root_path): def __init__(self, root_path):
### root path to the project ### root path to the project
self.root_path = io.absolute_path_file(root_path) 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 # order to keep track all files al directories during the
# whole reconstruction process. # whole reconstruction process.
self.dataset_raw = io.join_paths(self.root_path, 'images') 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.opensfm = io.join_paths(self.root_path, 'opensfm')
self.pmvs = io.join_paths(self.root_path, 'pmvs') self.pmvs = io.join_paths(self.root_path, 'pmvs')
self.odm_meshing = io.join_paths(self.root_path, 'odm_meshing') 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_bundle_list = io.join_paths(self.opensfm, 'list_r000.out')
self.opensfm_image_list = io.join_paths(self.opensfm, 'image_list.txt') self.opensfm_image_list = io.join_paths(self.opensfm, 'image_list.txt')
self.opensfm_reconstruction = io.join_paths(self.opensfm, 'reconstruction.json') self.opensfm_reconstruction = io.join_paths(self.opensfm, 'reconstruction.json')
# pmvs # pmvs
self.pmvs_options = io.join_paths(self.pmvs, 'recon0/pmvs_options.txt') self.pmvs_rec_path = io.join_paths(self.pmvs, 'recon0')
self.pmvs_model = io.join_paths(self.pmvs, 'models/pmvs_options.txt.ply') 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 # odm_meshing
self.mesh = io.join_paths(self.odm_meshing, 'odm_mesh.ply') self.odm_mesh = io.join_paths(self.odm_meshing, 'odm_mesh.ply')
# odm_texturing && odm_georeferencing self.odm_meshing_log = io.join_paths(self.odm_meshing, 'odm_meshing_log.txt')
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') # odm_texturing
self.textured_model_mtl = io.join_paths(self.odm_texturing, 'odm_textured_model.mtl') self.odm_textured_model_obj = io.join_paths(
self.textured_model_obj_geo = io.join_paths(self.odm_texturing, 'odm_textured_model_geo.obj') self.odm_texturing, 'odm_textured_model.obj')
self.textured_model_mtl_geo = io.join_paths(self.odm_texturing, 'odm_textured_model_geo.mtl') 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 # 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')

56
scripts/cmvs.py 100644
Wyświetl plik

@ -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

Wyświetl plik

@ -12,8 +12,9 @@ class ODMLoadDatasetCell(ecto.Cell):
pass pass
def declare_io(self, params, inputs, outputs): def declare_io(self, params, inputs, outputs):
inputs.declare("tree", "Struct with paths", [])
inputs.declare("args", "The application arguments.", {}) 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): def process(self, inputs, outputs):
# check if the extension is sopported # check if the extension is sopported
@ -23,17 +24,19 @@ class ODMLoadDatasetCell(ecto.Cell):
log.ODM_INFO('Running ODM Load Dataset Cell') log.ODM_INFO('Running ODM Load Dataset Cell')
# get parameters # get inputs
args = self.inputs.args args = self.inputs.args
project_path = io.absolute_path_file(args['project_path']) tree = self.inputs.tree
images_dir = io.join_paths(project_path, 'images_resize')
# set images directory
images_dir = tree.dataset_resize
# check if we rerun cell or not # check if we rerun cell or not
rerun_cell = args['run_only'] is not None \ rerun_cell = args['rerun'] is not None \
and args['run_only'] == 'resize' and args['rerun'] == 'resize'
if not io.dir_exists(images_dir) or rerun_cell: 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): if not io.dir_exists(images_dir):
log.ODM_ERROR("You must put your pictures into an <images> directory") log.ODM_ERROR("You must put your pictures into an <images> directory")
return ecto.QUIT return ecto.QUIT
@ -44,7 +47,6 @@ class ODMLoadDatasetCell(ecto.Cell):
files = io.get_files_list(images_dir) files = io.get_files_list(images_dir)
# filter images for its extension type # filter images for its extension type
# by now only 'jpg' and 'jpeg are supported
files = [f for f in files if supported_extension(f)] files = [f for f in files if supported_extension(f)]
if files: if files:

Wyświetl plik

@ -1,11 +1,14 @@
import ecto import ecto
from opendm import context from opendm import context
from opendm import types
from opendm import config
from dataset import ODMLoadDatasetCell from dataset import ODMLoadDatasetCell
from resize import ODMResizeCell from resize import ODMResizeCell
from opensfm import ODMOpenSfMCell from opensfm import ODMOpenSfMCell
from pmvs import ODMPmvsCell from pmvs import ODMPmvsCell
from cmvs import ODMCmvsCell
from odm_meshing import ODMeshingCell from odm_meshing import ODMeshingCell
from odm_texturing import ODMTexturingCell from odm_texturing import ODMTexturingCell
from odm_georeferencing import ODMGeoreferencingCell from odm_georeferencing import ODMGeoreferencingCell
@ -23,67 +26,127 @@ class ODMApp(ecto.BlackBox):
@staticmethod @staticmethod
def declare_cells(p): def declare_cells(p):
print p.args
""" """
Implement the virtual function from the base class Implement the virtual function from the base class
Only cells from which something is forwarded have to be declared Only cells from which something is forwarded have to be declared
""" """
cells = { 'args': ecto.Constant(value=p.args), cells = { 'args': ecto.Constant(value=p.args),
'load_dataset': ODMLoadDatasetCell(), 'dataset': ODMLoadDatasetCell(),
'resize': ODMResizeCell(), 'resize': ODMResizeCell(),
'opensfm': ODMOpenSfMCell(use_exif_size=False, 'opensfm': ODMOpenSfMCell(use_exif_size=False,
feature_process_size=p.args['resize_to'], feature_process_size=p.args['resize_to'],
feature_min_frames=p.args['min_num_features'], feature_min_frames=p.args['min_num_features'],
processes=context.num_cores, processes=context.num_cores,
matching_gps_neighbors=p.args['matcher_k']), matching_gps_neighbors=p.args['matcher_k']),
'pmvs': ODMPmvsCell(), 'cmvs': ODMCmvsCell(max_images=p.args['cmvs_maxImages']),
'meshing': ODMeshingCell(), 'pmvs': ODMPmvsCell(level=p.args['pmvs_level'],
'texturing': ODMTexturingCell(), csize=p.args['pmvs_csize'],
'georeferencing': ODMGeoreferencingCell(), thresh=p.args['pmvs_threshold'],
'orthophoto': ODMOrthoPhotoCell() 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 return cells
def connections(self, _p): def configure(self, p, _i, _o):
# define initial and final tasks tree = types.ODMTree(p.args['project_path'])
# TODO: not sure how to manage that self.tree = ecto.Constant(value=tree)
initial_task = _p.args['start_with']
final_task = _p.args['end_with']
run_only = _p.args['run_only']
# 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 = [] connections = []
# load the dataset ## load the dataset
connections = [ self.args[:] >> self.load_dataset['args'] ] connections = [ self.tree[:] >> self.dataset['tree'],
self.args[:] >> self.dataset['args'] ]
# resize images ## check we want to start with resize task
connections += [ self.args[:] >> self.resize['args'], if initial_task_id <= config.processopts.index('resize'):
self.load_dataset['photos'] >> self.resize['photos'] ]
# run opensfm # resize images
connections += [ self.args[:] >> self.opensfm['args'], connections += [ self.tree[:] >> self.resize['tree'],
self.load_dataset['photos'] >> self.opensfm['photos'] ] self.args[:] >> self.resize['args'],
self.dataset['photos'] >> self.resize['photos'] ]
# run cmvs # forward opensfm variables
connections += [ self.args[:] >> self.pmvs['args'], connections += [ self.tree[:] >> self.opensfm['tree'],
self.opensfm['reconstruction_path'] >> self.args[:] >> self.opensfm['args'] ]
self.pmvs['reconstruction_path'] ]
# create odm mesh ## check we want to start with opensfm task
connections += [ self.args[:] >> self.meshing['args'], if initial_task_id <= config.processopts.index('opensfm'):
self.pmvs['model_path'] >> self.meshing['model_path'] ] # 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 ## check we want to start with cmvs task
connections += [ self.args[:] >> self.texturing['args'], if initial_task_id <= config.processopts.index('cmvs'):
self.meshing['mesh_path'] >> self.texturing['model_path'] ]
# create odm georeference # run cmvs
connections += [ self.args[:] >> self.georeferencing['args'] ] connections += [ self.tree[:] >> self.cmvs['tree'],
self.args[:] >> self.cmvs['args'],
self.opensfm['reconstruction'] >> self.cmvs['reconstruction'] ]
# create odm orthophoto ## check we want to start with cmvs task
connections += [ self.args[:] >> self.orthophoto['args'] ] 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 return connections

Wyświetl plik

@ -6,10 +6,20 @@ from opendm import system
from opendm import context from opendm import context
class ODMGeoreferencingCell(ecto.Cell): 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): def declare_io(self, params, inputs, outputs):
inputs.declare("tree", "Struct with paths", [])
inputs.declare("args", "The application arguments.", {}) 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): def process(self, inputs, outputs):
@ -17,80 +27,82 @@ class ODMGeoreferencingCell(ecto.Cell):
# get inputs # get inputs
args = self.inputs.args args = self.inputs.args
project_path = io.absolute_path_file(args['project_path']) tree = self.inputs.tree
# define paths and create working directories # define paths and create working directories
odm_texturing = io.join_paths(project_path, 'odm_texturing') system.mkdir_p(tree.odm_georeferencing)
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')
# in case a gcp file it's not provided, let's try to generate it using # in case a gcp file it's not provided, let's try to generate it using
# images metadata. Internally calls jhead. # 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. ' \ log.ODM_WARNING('Warning: No coordinates file. ' \
'Generating coordinates file in: %s' % coords_file) 'Generating coordinates file in: %s' % tree.odm_georeferencing_coords)
try: 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: except Exception, e:
log.ODM_ERROR('Could not generate GCP file from images metadata.' \ log.ODM_ERROR('Could not generate GCP file from images metadata.' \
'Consider rerunning with argument --odm_georeferencing-useGcp'\ 'Consider rerunning with argument --odm_georeferencing-useGcp' \
' and provide a proper GCP file') ' and provide a proper GCP file')
log.ODM_ERROR(str(e)) log.ODM_ERROR(e)
return ecto.QUIT 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 # check if we rerun cell or not
rerun_cell = args['run_only'] is not None \ rerun_cell = args['rerun'] is not None \
and args['run_only'] == 'odm_georeferencing' and args['rerun'] == 'odm_georeferencing'
if not io.file_exists(model_geo) or \ if not io.file_exists(tree.odm_textured_model_obj_geo) or \
not io.file_exists(pointcloud_geo) or rerun_cell: not io.file_exists(tree.odm_textured_model_ply_geo) or rerun_cell:
# odm_georeference definitions # odm_georeference definitions
kwargs = { kwargs = {
'bin': context.odm_modules_path, 'bin': context.odm_modules_path,
'bundle': io.join_paths(project_path,'opensfm/bundle_r000.out'), 'bundle': tree.opensfm_bundle,
'gcp': io.join_paths(project_path, args['odm_georeferencing_gcpFile']), 'imgs': tree.dataset_resize,
'imgs': io.join_paths(project_path, 'images_resize'), 'imgs_list': tree.opensfm_bundle_list,
'imgs_list': io.join_paths(project_path, 'opensfm/list_r000.out'), 'model': tree.odm_textured_model_obj,
'size': str(args['resize_to']), 'pc': tree.pmvs_model,
'model': io.join_paths(project_path, 'odm_texturing/odm_textured_model.obj'), 'log': tree.odm_georeferencing_log,
'pc': io.join_paths(project_path, 'pmvs/recon0/models/option-0000.ply'), 'coords': tree.odm_georeferencing_coords,
'log': io.join_paths(odm_georeferencing, 'odm_texturing_log.txt'), 'pc_geo': tree.odm_textured_model_ply_geo,
'coords': io.join_paths(odm_georeferencing, 'coords.txt'), 'geo_sys': tree.odm_textured_model_txt_geo,
'pc_geo': pointcloud_geo, 'model_geo': tree.odm_textured_model_obj_geo,
'geo_sys': system_geo, 'size': self.params.img_size,
'model_geo': model_geo, 'gcp': io.join_paths(tree.root_path, self.params.gcp_file),
} }
# run odm_georeference if self.params.use_gcp and \
system.run('{bin}/odm_georef -bundleFile {bundle} -inputCoordFile {coords} ' \ io.file_exists(tree.odm_georeferencing_coords):
'-bundleResizedTo {size} -inputFile {model} -outputFile {model_geo} ' \
'-inputPointCloudFile {pc} -outputPointCloudFile {pc_geo} ' \ system.run('{bin}/odm_georef -bundleFile {bundle} -inputCoordFile {coords} ' \
'-logFile {log} -georefFileOutputPath {geo_sys}'.format(**kwargs)) '-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: 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') log.ODM_INFO('Running OMD Georeferencing Cell - Finished')

Wyświetl plik

@ -7,10 +7,24 @@ from opendm import context
class ODMeshingCell(ecto.Cell): 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): def declare_io(self, params, inputs, outputs):
inputs.declare("tree", "Struct with paths", [])
inputs.declare("args", "The application arguments.", {}) inputs.declare("args", "The application arguments.", {})
inputs.declare("model_path", "Clusters output. list of reconstructions", []) inputs.declare("reconstruction", "Clusters output. list of ODMReconstructions", [])
outputs.declare("mesh_path", "Clusters output. list of reconstructions", []) outputs.declare("reconstruction", "Clusters output. list of ODMReconstructions", [])
def process(self, inputs, outputs): def process(self, inputs, outputs):
@ -18,36 +32,37 @@ class ODMeshingCell(ecto.Cell):
# get inputs # get inputs
args = self.inputs.args args = self.inputs.args
model_path = self.inputs.model_path tree = self.inputs.tree
project_path = io.absolute_path_file(args['project_path'])
# define paths and create working directories # define paths and create working directories
odm_meshing = io.join_paths(project_path, 'odm_meshing') system.mkdir_p(tree.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
# check if we rerun cell or not # check if we rerun cell or not
rerun_cell = args['run_only'] is not None \ rerun_cell = args['rerun'] is not None \
and args['run_only'] == 'odm_meshing' and args['rerun'] == 'odm_meshing'
if not io.file_exists(output_file) or rerun_cell: if not io.file_exists(tree.odm_mesh) or rerun_cell:
log.ODM_DEBUG('Writting odm mesh file in: %s' % output_file) 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 # run meshing binary
system.run('%s/odm_meshing -inputFile %s -outputFile %s ' \ system.run('{bin}/odm_meshing -inputFile {infile} ' \
'-logFile %s -maxVertexCount %s -octreeDepth %s ' \ '-outputFile {outfile} -logFile {log} ' \
'-samplesPerNode %s -solverDivide %s' % \ '-maxVertexCount {max_vertex} -octreeDepth {oct_tree} ' \
(context.odm_modules_path, model_path, output_file, log_file, \ '-samplesPerNode {samples} -solverDivide {solver}'.format(**kwargs))
str(args['odm_meshing_maxVertexCount']), \
str(args['odm_meshing_octreeDepth']), \
str(args['odm_meshing_samplesPerNode']), \
str(args['odm_meshing_solverDivide'])))
else: else:
log.ODM_WARNING('Found a valid odm mesh file in: %s' % log.ODM_WARNING('Found a valid ODM Mesh file in: %s' %
(output_file)) (tree.odm_mesh))
log.ODM_INFO('Running OMD Meshing Cell - Finished') log.ODM_INFO('Running OMD Meshing Cell - Finished')
return ecto.OK if args['end_with'] != 'odm_meshing' else ecto.QUIT return ecto.OK if args['end_with'] != 'odm_meshing' else ecto.QUIT

Wyświetl plik

@ -6,9 +6,13 @@ from opendm import system
from opendm import context from opendm import context
class ODMOrthoPhotoCell(ecto.Cell): 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): def declare_io(self, params, inputs, outputs):
inputs.declare("tree", "Struct with paths", [])
inputs.declare("args", "The application arguments.", {}) inputs.declare("args", "The application arguments.", {})
inputs.declare("reconstruction", "list of ODMReconstructions", [])
def process(self, inputs, outputs): def process(self, inputs, outputs):
@ -16,33 +20,32 @@ class ODMOrthoPhotoCell(ecto.Cell):
# get inputs # get inputs
args = self.inputs.args args = self.inputs.args
project_path = io.absolute_path_file(args['project_path']) tree = self.inputs.tree
# define paths and create working directories # define paths and create working directories
odm_texturing = io.join_paths(project_path, 'odm_texturing') system.mkdir_p(tree.odm_orthophoto)
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)
}
# check if we rerun cell or not # check if we rerun cell or not
rerun_cell = args['run_only'] is not None \ rerun_cell = args['rerun'] is not None \
and args['run_only'] == 'odm_orthophoto' 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 # run odm_georeference
system.run('{bin}/odm_orthophoto -inputFile {model_geo} -logFile {log} ' \ system.run('{bin}/odm_orthophoto -inputFile {model_geo} -logFile {log} ' \
'-outputFile {ortho} -resolution {res} -outputCornerFile {corners}'.format(**kwargs)) '-outputFile {ortho} -resolution {res} -outputCornerFile {corners}'.format(**kwargs))
else: 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') log.ODM_INFO('Running OMD OrthoPhoto Cell - Finished')
return ecto.OK if args['end_with'] != 'odm_orthophoto' else ecto.QUIT return ecto.OK if args['end_with'] != 'odm_orthophoto' else ecto.QUIT

Wyświetl plik

@ -7,10 +7,18 @@ from opendm import context
class ODMTexturingCell(ecto.Cell): 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): def declare_io(self, params, inputs, outputs):
inputs.declare("tree", "Struct with paths", [])
inputs.declare("args", "The application arguments.", {}) inputs.declare("args", "The application arguments.", {})
inputs.declare("model_path", "Clusters output. list of reconstructions", []) inputs.declare("reconstruction", "Clusters output. list of ODMReconstructions", [])
outputs.declare("texture_path", "Clusters output. list of reconstructions", []) outputs.declare("reconstruction", "Clusters output. list of ODMReconstructions", [])
def process(self, inputs, outputs): def process(self, inputs, outputs):
@ -18,47 +26,42 @@ class ODMTexturingCell(ecto.Cell):
# get inputs # get inputs
args = self.inputs.args args = self.inputs.args
input_model_path = self.inputs.model_path tree = self.inputs.tree
project_path = io.absolute_path_file(args['project_path'])
# define paths and create working directories # define paths and create working directories
odm_meshing = io.join_paths(project_path, 'odm_meshing') system.mkdir_p(tree.odm_texturing)
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')
# check if we rerun cell or not # check if we rerun cell or not
rerun_cell = args['run_only'] is not None \ rerun_cell = args['rerun'] is not None \
and args['run_only'] == 'odm_texturing' and args['rerun'] == 'odm_texturing'
if not io.file_exists(output_file) or rerun_cell: if not io.file_exists(tree.odm_textured_model_obj) or rerun_cell:
log.ODM_DEBUG('Writting odm textured file in: %s' % output_file) log.ODM_DEBUG('Writting ODM Textured file in: %s' \
% tree.odm_textured_model_obj)
# odm_texturing definitions # odm_texturing definitions
kwargs = { kwargs = {
'bin': context.odm_modules_path, 'bin': context.odm_modules_path,
'out_dir': odm_texturing, 'out_dir': tree.odm_texturing,
'bundle': io.join_paths(project_path,'opensfm/bundle_r000.out'), 'bundle': tree.opensfm_bundle,
'imgs_path': io.join_paths(project_path, 'images_resize'), 'imgs_path': tree.dataset_resize,
'imgs_list': io.join_paths(project_path, 'opensfm/list_r000.out'), 'imgs_list': tree.opensfm_bundle_list,
'model': io.join_paths(odm_meshing, 'odm_mesh.ply'), 'model': tree.odm_mesh,
'log': io.join_paths(odm_texturing, 'odm_texturing_log.txt'), 'log': tree.odm_texuring_log,
'bsize': str(args['resize_to']), 'resize': self.params.resize,
'res': str(args['odm_texturing_textureResolution']), 'resolution': self.params.resolution,
'wsize': str(args['odm_texturing_textureWithSize']) 'size': self.params.size
} }
# run texturing binary # run texturing binary
system.run('{bin}/odm_texturing -bundleFile {bundle} ' \ system.run('{bin}/odm_texturing -bundleFile {bundle} ' \
'-imagesPath {imgs_path} -imagesListPath {imgs_list} ' \ '-imagesPath {imgs_path} -imagesListPath {imgs_list} ' \
'-inputModelPath {model} -outputFolder {out_dir}/ ' \ '-inputModelPath {model} -outputFolder {out_dir}/ ' \
'-textureResolution {res} -bundleResizedTo {bsize} ' \ '-textureResolution {resolution} -bundleResizedTo {resize} ' \
'-textureWithSize {wsize} -logFile {log}'.format(**kwargs)) '-textureWithSize {size} -logFile {log}'.format(**kwargs))
else: else:
log.ODM_WARNING('Found a valid odm texture file in: %s' % output_file) log.ODM_WARNING('Found a valid ODM Texture file in: %s' \
% tree.odm_textured_model_obj)
self.outputs.texture_path = output_file
log.ODM_INFO('Running OMD Texturing Cell - Finished') log.ODM_INFO('Running OMD Texturing Cell - Finished')
return ecto.OK if args['end_with'] != 'odm_texturing' else ecto.QUIT return ecto.OK if args['end_with'] != 'odm_texturing' else ecto.QUIT

Wyświetl plik

@ -6,6 +6,8 @@ from opendm import system
from opendm import context from opendm import context
class ODMOpenSfMCell(ecto.Cell): class ODMOpenSfMCell(ecto.Cell):
def declare_params(self, params):
pass
def declare_params(self, params): def declare_params(self, params):
params.declare("use_exif_size", "The application arguments.", False) 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) params.declare("matching_gps_neighbors", "The application arguments.", 0)
def declare_io(self, params, inputs, outputs): def declare_io(self, params, inputs, outputs):
inputs.declare("tree", "Struct with paths", [])
inputs.declare("args", "The application arguments.", {}) inputs.declare("args", "The application arguments.", {})
inputs.declare("photos", "Clusters output. list of ODMPhoto's", []) inputs.declare("photos", "list of ODMPhoto's", [])
outputs.declare("reconstructions", "Clusters output. list of reconstructions", []) outputs.declare("reconstruction", "list of ODMReconstructions", [])
outputs.declare("reconstruction_path", "The directory to the images to load.", "")
def process(self, inputs, outputs): def process(self, inputs, outputs):
log.ODM_INFO('Running OMD OpenSfm Cell') log.ODM_INFO('Running OMD OpenSfm Cell')
# get inputs # get inputs
tree = self.inputs.tree
args = self.inputs.args args = self.inputs.args
photos = self.inputs.photos photos = self.inputs.photos
project_path = io.absolute_path_file(args['project_path'])
if not photos: if not photos:
log.ODM_ERROR('Not enough photos in photos array to start OpenSfm') log.ODM_ERROR('Not enough photos in photos array to start OpenSfm')
return ecto.QUIT return ecto.QUIT
# create working directories # create working directories
opensfm_path = io.join_paths(project_path, 'opensfm') system.mkdir_p(tree.opensfm)
pmvs_path = io.join_paths(project_path, 'pmvs') system.mkdir_p(tree.pmvs)
system.mkdir_p(opensfm_path)
system.mkdir_p(pmvs_path)
# check if we rerun cell or not # check if we rerun cell or not
rerun_cell = args['run_only'] is not None \ rerun_cell = args['rerun'] is not None \
and args['run_only'] == 'opensfm' and args['rerun'] == 'opensfm'
### check if reconstruction was done before ### 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 # 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: with open(list_path, 'w') as fout:
for photo in photos: for photo in photos:
fout.write('%s\n' % photo.path_file) fout.write('%s\n' % photo.path_file)
@ -63,40 +63,37 @@ class ODMOpenSfMCell(ecto.Cell):
] ]
# write config file # 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: with open(config_filename, 'w') as fout:
fout.write("\n".join(config)) fout.write("\n".join(config))
# run OpenSfM reconstruction # run OpenSfM reconstruction
system.run('PYTHONPATH=%s %s/bin/run_all %s' % 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: else:
log.ODM_WARNING('Found a valid reconstruction file in: %s' % log.ODM_WARNING('Found a valid OpenSfm file in: %s' %
(reconstruction_file)) (tree.opensfm_reconstruction))
### check if reconstruction was exported to bundler before ### 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 # convert back to bundler's format
system.run('PYTHONPATH=%s %s/bin/export_bundler %s' % 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: else:
log.ODM_WARNING('Found a valid bundle file in: %s' % log.ODM_WARNING('Found a valid Bundler file in: %s' %
(reconstruction_file)) (tree.opensfm_reconstruction))
### check if reconstruction was exported to pmvs before ### 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 # run PMVS converter
system.run('PYTHONPATH=%s %s/bin/export_pmvs %s --output %s' % 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: else:
log.ODM_WARNING('Found a valid PMVS file in: %s' % pmvs_file) log.ODM_WARNING('Found a valid CMVS file in: %s' % tree.pmvs_visdat)
# append biggest reconstruction path to output
self.outputs.reconstruction_path = io.join_paths(pmvs_path, 'recon0')
log.ODM_INFO('Running OMD OpenSfm Cell - Finished') log.ODM_INFO('Running OMD OpenSfm Cell - Finished')
return ecto.OK if args['end_with'] != 'opensfm' else ecto.QUIT return ecto.OK if args['end_with'] != 'opensfm' else ecto.QUIT

Wyświetl plik

@ -7,10 +7,30 @@ from opendm import context
class ODMPmvsCell(ecto.Cell): 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): def declare_io(self, params, inputs, outputs):
inputs.declare("tree", "Struct with paths", [])
inputs.declare("args", "The application arguments.", {}) inputs.declare("args", "The application arguments.", {})
inputs.declare("reconstruction_path", "Clusters output. list of reconstructions", []) inputs.declare("reconstruction", "list of ODMReconstructions", [])
outputs.declare("model_path", "Clusters output. list of reconstructions", []) outputs.declare("reconstruction", "list of ODMReconstructions", [])
def process(self, inputs, outputs): def process(self, inputs, outputs):
@ -18,24 +38,36 @@ class ODMPmvsCell(ecto.Cell):
# get inputs # get inputs
args = self.inputs.args args = self.inputs.args
rec_path = self.inputs.reconstruction_path tree = self.inputs.tree
# 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
# check if we rerun cell or not # check if we rerun cell or not
rerun_cell = args['run_only'] is not None \ rerun_cell = args['rerun'] is not None \
and args['run_only'] == 'pmvs' and args['rerun'] == 'pmvs'
if not io.file_exists(model_path) or rerun_cell: if not io.file_exists(tree.pmvs_model) or rerun_cell:
log.ODM_DEBUG('Creating dense pointcloud in: %s' % model_path) 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 # 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: 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') log.ODM_INFO('Running OMD PMVS Cell - Finished')
return ecto.OK if args['end_with'] != 'pmvs' else ecto.QUIT return ecto.OK if args['end_with'] != 'pmvs' else ecto.QUIT

Wyświetl plik

@ -12,6 +12,7 @@ class ODMResizeCell(ecto.Cell):
pass pass
def declare_io(self, params, inputs, outputs): def declare_io(self, params, inputs, outputs):
inputs.declare("tree", "Struct with paths", [])
inputs.declare("args", "The application arguments.", []) inputs.declare("args", "The application arguments.", [])
inputs.declare("photos", "Clusters inputs. list of ODMPhoto's", []) inputs.declare("photos", "Clusters inputs. list of ODMPhoto's", [])
outputs.declare("photos", "Clusters output. list of ODMPhoto's", []) outputs.declare("photos", "Clusters output. list of ODMPhoto's", [])
@ -22,29 +23,28 @@ class ODMResizeCell(ecto.Cell):
# get inputs # get inputs
args = self.inputs.args args = self.inputs.args
tree = self.inputs.tree
photos = self.inputs.photos photos = self.inputs.photos
project_path = io.absolute_path_file(args['project_path'])
if not photos: if not photos:
log.ODM_ERROR('Not enough photos in photos to resize') log.ODM_ERROR('Not enough photos in photos to resize')
return ecto.QUIT return ecto.QUIT
# create working directory # create working directory
resizing_dir = io.join_paths(project_path, 'images_resize') system.mkdir_p(tree.dataset_resize)
system.mkdir_p(resizing_dir)
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 # check if we rerun cell or not
rerun_cell = args['run_only'] is not None \ rerun_cell = args['rerun'] is not None \
and args['run_only'] == 'resize' and args['rerun'] == 'resize'
# loop over photos # loop over photos
for photo in photos: for photo in photos:
# TODO(edgar): check if resize is needed, else copy img. # TODO(edgar): check if resize is needed, else copy img.
# Try to avoid oversampling! # 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: if not io.file_exists(new_path_file) or rerun_cell:
# open and resize image with opencv # open and resize image with opencv