Refactor python code to comply with PEP8

pull/263/head
Dakota Benjamin 2016-02-26 13:50:12 -05:00
rodzic 70675e7b6c
commit 0515166832
16 zmienionych plików z 412 dodań i 457 usunięć

Wyświetl plik

@ -6,13 +6,14 @@ processopts = ['resize', 'opensfm', 'cmvs', 'pmvs',
'odm_meshing', 'odm_texturing', 'odm_georeferencing',
'odm_orthophoto']
class RerunFrom(argparse.Action):
def __call__(self, parser, namespace, values, option_string=None):
setattr(namespace, self.dest, processopts[processopts.index(values):])
parser = argparse.ArgumentParser(description='OpenDroneMap')
parser.add_argument('--project-path',
parser.add_argument('--project-path',
metavar='<string>',
help='Path to the project to process')
@ -56,7 +57,7 @@ parser.add_argument('--force-focal',
metavar='<positive float>',
type=float,
help=('Override the focal length information for the '
'images'))
'images'))
parser.add_argument('--force-ccd',
metavar='<positive float>',
@ -76,160 +77,160 @@ parser.add_argument('--matcher-threshold',
default=2.0,
type=float,
help=('Ignore matched keypoints if the two images share '
'less than <float> percent of keypoints. Default:'
' $(default)s'))
'less than <float> percent of keypoints. Default:'
' $(default)s'))
parser.add_argument('--matcher-ratio',
metavar='<float>',
default=0.6,
type=float,
help=('Ratio of the distance to the next best matched '
'keypoint. Default: %(default)s'))
'keypoint. Default: %(default)s'))
parser.add_argument('--matcher-neighbors',
type=int,
metavar='<integer>',
default=8,
help='Number of nearest images to pre-match based on GPS '
'exif data. Set to 0 to skip pre-matching. '
'Neighbors works together with Distance parameter, '
'set both to 0 to not use pre-matching. OpenSFM '
'uses both parameters at the same time, Bundler '
'uses only one which has value, prefering the '
'Neighbors parameter. Default: %(default)s')
'exif data. Set to 0 to skip pre-matching. '
'Neighbors works together with Distance parameter, '
'set both to 0 to not use pre-matching. OpenSFM '
'uses both parameters at the same time, Bundler '
'uses only one which has value, prefering the '
'Neighbors parameter. Default: %(default)s')
parser.add_argument('--matcher-distance',
metavar='<integer>',
default=0,
type=int,
help='Distance threshold in meters to find pre-matching '
'images based on GPS exif data. Set to 0 to skip '
'pre-matching. Default: %(default)s')
'images based on GPS exif data. Set to 0 to skip '
'pre-matching. Default: %(default)s')
parser.add_argument('--cmvs-maxImages',
metavar='<integer>',
default=500,
type=int,
help='The maximum number of images per cluster. '
'Default: %(default)s')
'Default: %(default)s')
parser.add_argument('--pmvs-level',
metavar='<positive integer>',
default=1,
type=int,
help=('The level in the image pyramid that is used '
'for the computation. see '
'http://www.di.ens.fr/pmvs/documentation.html for '
'more pmvs documentation. Default: %(default)s'))
'for the computation. see '
'http://www.di.ens.fr/pmvs/documentation.html for '
'more pmvs documentation. Default: %(default)s'))
parser.add_argument('--pmvs-csize',
metavar='< positive integer>',
default=2,
type=int,
help='Cell size controls the density of reconstructions'
'Default: %(default)s')
'Default: %(default)s')
parser.add_argument('--pmvs-threshold',
metavar='<float: -1.0 <= x <= 1.0>',
default=0.7,
type=float,
help=('A patch reconstruction is accepted as a success '
'and kept if its associated photometric consistency '
'measure is above this threshold. Default: %(default)s'))
'and kept if its associated photometric consistency '
'measure is above this threshold. Default: %(default)s'))
parser.add_argument('--pmvs-wsize',
metavar='<positive integer>',
default=7,
type=int,
help='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. Default: %(default)s')
'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. Default: %(default)s')
parser.add_argument('--pmvs-minImageNum',
metavar='<positive integer>',
default=3,
type=int,
help=('Each 3D point must be visible in at least '
'minImageNum images for being reconstructed. 3 is '
'suggested in general. Default: %(default)s'))
'minImageNum images for being reconstructed. 3 is '
'suggested in general. Default: %(default)s'))
parser.add_argument('--pmvs-num-cores',
metavar='<positive integer>',
default=context.num_cores,
type=int,
help=('The maximum number of cores to use in dense '
'reconstruction. Default: %(default)s'))
'reconstruction. Default: %(default)s'))
parser.add_argument('--odm_meshing-maxVertexCount',
metavar='<positive integer>',
default=100000,
type=int,
help=('The maximum vertex count of the output mesh '
'Default: %(default)s'))
'Default: %(default)s'))
parser.add_argument('--odm_meshing-octreeDepth',
metavar='<positive integer>',
default=9,
type=int,
help=('Oct-tree depth used in the mesh reconstruction, '
'increase to get more vertices, recommended '
'values are 8-12. Default: %(default)s'))
'increase to get more vertices, recommended '
'values are 8-12. Default: %(default)s'))
parser.add_argument('--odm_meshing-samplesPerNode',
metavar='<float >= 1.0>',
default=1.0,
type=float,
help=('Number of points per octree node, recommended '
'and default value: %(default)s'))
'and default value: %(default)s'))
parser.add_argument('--odm_meshing-solverDivide',
metavar='<positive integer>',
default=9,
type=int,
help=('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. '
'Default: %(default)s'))
'is solved in the surface reconstruction step. '
'Increasing this value increases computation '
'times slightly but helps reduce memory usage. '
'Default: %(default)s'))
parser.add_argument('--odm_texturing-textureResolution',
metavar='<positive integer>',
default=4096,
type=int,
help=('The resolution of the output textures. Must be '
'greater than textureWithSize. Default: %(default)s'))
'greater than textureWithSize. Default: %(default)s'))
parser.add_argument('--odm_texturing-textureWithSize',
metavar='<positive integer>',
default=3600,
type=int,
help=('The resolution to rescale the images performing '
'the texturing. Default: %(default)s'))
'the texturing. Default: %(default)s'))
parser.add_argument('--odm_georeferencing-gcpFile',
metavar='<path string>',
default='gcp_list.txt',
help=('path to the file containing the ground control '
'points used for georeferencing. Default: '
'%(default)s. The file needs to '
'be on the following line format: \neasting '
'northing height pixelrow pixelcol imagename'))
'points used for georeferencing. Default: '
'%(default)s. The file needs to '
'be on the following line format: \neasting '
'northing height pixelrow pixelcol imagename'))
parser.add_argument('--odm_georeferencing-useGcp',
action = 'store_true',
default = False,
help = 'Enabling GCPs from the file above. The GCP file '
'is not used by default.')
action='store_true',
default=False,
help='Enabling GCPs from the file above. The GCP file '
'is not used by default.')
parser.add_argument('--odm_orthophoto-resolution',
metavar='<float > 0.0>',
default=20.0,
type=float,
help=('Orthophoto ground resolution in pixels/meter'
'Default: %(default)s'))
'Default: %(default)s'))
parser.add_argument('--zip-results',
action='store_true',
@ -240,6 +241,6 @@ parser.add_argument('--time',
action='store_true',
default=False,
help='Generates a benchmark file with runtime info\n'
'Default: %(default)s')
'Default: %(default)s')
args = vars(parser.parse_args())

Wyświetl plik

@ -1,25 +1,32 @@
import os
def get_files_list(path_dir):
return os.listdir(path_dir)
def absolute_path_file(path_file):
return os.path.abspath(path_file)
def extract_file_from_path_file(path_file):
path, file = os.path.split(path_file)
return file
def extract_path_from_file(file):
path_file = os.path.abspath(os.path.dirname(file))
path, file = os.path.split(path_file)
return path
def join_paths(path1, path2):
return os.path.join(path1, path2)
def file_exists(path_file):
return os.path.isfile(path_file)
return os.path.isfile(path_file)
def dir_exists(dirname):
return os.path.isdir(dirname)
return os.path.isdir(dirname)

Wyświetl plik

@ -5,14 +5,18 @@ WARNING = '\033[93m'
FAIL = '\033[91m'
ENDC = '\033[0m'
def ODM_INFO(str):
print OKBLUE + '[INFO] ' + str + ENDC
print OKBLUE + '[INFO] ' + str + ENDC
def ODM_WARNING(str):
print WARNING + '[WARNING] ' + str + ENDC
print WARNING + '[WARNING] ' + str + ENDC
def ODM_ERROR(str):
print FAIL + '[ERROR] ' + str + ENDC
print FAIL + '[ERROR] ' + str + ENDC
def ODM_DEBUG(str):
print OKGREEN + '[DEBUG] ' + str + ENDC
print OKGREEN + '[DEBUG] ' + str + ENDC

Wyświetl plik

@ -8,11 +8,13 @@ import subprocess
from opendm import context
from opendm import log
def get_ccd_widths():
"""Return the CCD Width of the camera listed in the JSON defs file."""
with open(context.ccd_widths_path) as jsonFile:
return json.load(jsonFile)
def run(cmd):
"""Run a system command"""
log.ODM_DEBUG('running %s' % cmd)
@ -23,10 +25,12 @@ def run(cmd):
sys.exit("\nquitting cause: \n\t" + cmd + "\nreturned with code " +
str(returnCode) + ".\n")
def now():
"""Return the current time"""
return datetime.datetime.now().strftime('%a %b %d %H:%M:%S %Z %Y')
def run_and_return(cmdSrc, cmdDest=None):
"""Run a system command and return the output"""
process = subprocess.Popen(cmdSrc, stdout=subprocess.PIPE, shell=True)
@ -35,8 +39,8 @@ def run_and_return(cmdSrc, cmdDest=None):
def mkdir_p(path):
'''Make a directory including parent directories.
'''
"""Make a directory including parent directories.
"""
try:
os.makedirs(path)
except os.error as exc:
@ -50,26 +54,3 @@ def calculate_EPSG(utmZone, south):
return 32700 + utmZone
else:
return 32600 + utmZone
def parse_coordinate_system():
"""Write attributes to jobOptions from coord file"""
if os.path.isfile(jobOptions['jobDir'] +
'/odm_georeferencing/coordFile.txt'):
with open(jobOptions['jobDir'] + '/odm_georeferencing/coordFile.txt') as f:
for lineNumber, line in enumerate(f):
if lineNumber == 0:
tokens = line.split(' ')
if len(tokens) == 3:
utmZoneString = tokens[2][0:len(tokens[2])-2].strip()
utmSouthBool = (tokens[2][len(tokens[2])-2].strip() == 'S')
jobOptions['csString'] = '+datum=WGS84 +proj=utm +zone=' \
+ utmZoneString + (' +south' if utmSouthBool else '')
jobOptions['epsg'] = calculate_EPSG(int(utmZoneString), utmSouthBool)
elif lineNumber == 1:
tokens = line.split(' ')
if len(tokens) == 2:
jobOptions['utmEastOffset'] = int(tokens[0].strip())
jobOptions['utmNorthOffset'] = int(tokens[1].strip())
else:
break

Wyświetl plik

@ -8,143 +8,144 @@ from scripts.resize import resize
from scripts.opensfm import opensfm
# Define pipeline tasks
tasks_dict = { '1': 'resize',
'2': 'opensfm',
'3': 'cmvs',
'4': 'pmvs',
'5': 'odm_meshing',
'6': 'odm_texturing',
'7': 'odm_georeferencing',
'8': 'odm_orthophoto',
'9': 'zip_results' }
tasks_dict = {'1': 'resize',
'2': 'opensfm',
'3': 'cmvs',
'4': 'pmvs',
'5': 'odm_meshing',
'6': 'odm_texturing',
'7': 'odm_georeferencing',
'8': 'odm_orthophoto',
'9': 'zip_results'}
class ODMTaskManager(object):
"""docstring for ODMTaskManager"""
def __init__(self, odm_app):
self.odm_app = odm_app
self.initial_task_id = 0
self.current_task_id = 0
self.final_task_id = len(tasks_dict)
self.tasks = self.init_tasks(tasks_dict, self.odm_app)
"""docstring for ODMTaskManager"""
def init_tasks(self, _tasks_dict, _odm_app):
# dict to store tasks objects
tasks = {}
# loop over tasks dict
for key, in _tasks_dict:
# instantiate and append ODMTask
task_name = _tasks_dict[key]
tasks[key] = ODMTask(key, task_name)
def __init__(self, odm_app):
self.odm_app = odm_app
self.initial_task_id = 0
self.current_task_id = 0
self.final_task_id = len(tasks_dict)
self.tasks = self.init_tasks(tasks_dict, self.odm_app)
# setup tasks
if task_name == 'resize':
# setup this task
command = resize
inputs = { 'project_path': _odm_app.project_path,
'args': _odm_app.args,
'photos': _odm_app.photos }
def init_tasks(self, _tasks_dict, _odm_app):
# dict to store tasks objects
tasks = {}
# loop over tasks dict
for key, in _tasks_dict:
# instantiate and append ODMTask
task_name = _tasks_dict[key]
tasks[key] = ODMTask(key, task_name)
elif task_name == 'opensfm':
# setup this task
command = opensfm
inputs = { 'project_path': _odm_app.project_path,
'args': _odm_app.args,
'photos': _odm_app.photos }
# setup tasks
if task_name == 'resize':
# setup this task
command = resize
inputs = {'project_path': _odm_app.project_path,
'args': _odm_app.args,
'photos': _odm_app.photos}
elif task_name == 'cmvs':
# setup this task
command = None
inputs = {}
elif task_name == 'opensfm':
# setup this task
command = opensfm
inputs = {'project_path': _odm_app.project_path,
'args': _odm_app.args,
'photos': _odm_app.photos}
elif task_name == 'pmvs':
# setup this task
command = None
inputs = {}
elif task_name == 'cmvs':
# setup this task
command = None
inputs = {}
elif task_name == 'odm_meshing':
# setup this task
command = None
inputs = {}
elif task_name == 'pmvs':
# setup this task
command = None
inputs = {}
elif task_name == 'odm_texturing':
# setup this task
command = None
inputs = {}
elif task_name == 'odm_meshing':
# setup this task
command = None
inputs = {}
elif task_name == 'odm_georeferencing':
# setup this task
command = None
inputs = {}
elif task_name == 'odm_texturing':
# setup this task
command = None
inputs = {}
elif task_name == 'odm_orthophoto':
# setup this task
command = None
inputs = {}
elif task_name == 'odm_georeferencing':
# setup this task
command = None
inputs = {}
elif task_name == 'zip_results':
# setup this task
command = None
inputs = {}
elif task_name == 'odm_orthophoto':
# setup this task
command = None
inputs = {}
else:
log.ODM_ERROR('task_name %s is not valid' % task_name)
elif task_name == 'zip_results':
# setup this task
command = None
inputs = {}
# setup task configuration
task = tasks[key]
task.command = command
task.inputs = inputs
else:
log.ODM_ERROR('task_name %s is not valid' % task_name)
return tasks
# setup task configuration
task = tasks[key]
task.command = command
task.inputs = inputs
def run_tasks(self):
return tasks
#curr_task = self.tasks['resize']
def run_tasks(self):
#self.tasks['resize']
# curr_task = self.tasks['resize']
for id in range(self.initial_task_id, self.final_task_id + 1):
# catch task with current id
task = self.tasks[str(id)]
# update task tracking
log.ODM_INFO('Running task %s: %s' % (task.id, task.name))
self.current_task_id = task.id
# run task
task.state = task.run()
if task.state == 2:
log.ODM_INFO('Succeeded task %s: %s - %s' % (task.id, task.name, system.now()))
else:
log.ODM_ERROR('Aborted task %s: %s' % (task.id, task.name))
# self.tasks['resize']
for id in range(self.initial_task_id, self.final_task_id + 1):
# catch task with current id
task = self.tasks[str(id)]
# update task tracking
log.ODM_INFO('Running task %s: %s' % (task.id, task.name))
self.current_task_id = task.id
# run task
task.state = task.run()
if task.state == 2:
log.ODM_INFO('Succeeded task %s: %s - %s' % (task.id, task.name, system.now()))
else:
log.ODM_ERROR('Aborted task %s: %s' % (task.id, task.name))
class ODMTask(object):
"""docstring for ODMTask"""
def __init__(self, id, name):
# task definition
self.id = id
self.name = name
# task i/o
self.command = None
self.inputs = {}
# Current task state (0:waiting, 1:running, 2:succeded: 3:failed)
# By default we set a task in waiting state
self.state = 0
"""docstring for ODMTask"""
# Launch task
def run(self):
# while doing something
self.state = 1
return self.launch_command()
def __init__(self, id, name):
# task definition
self.id = id
self.name = name
# task i/o
self.command = None
self.inputs = {}
# Current task state (0:waiting, 1:running, 2:succeded: 3:failed)
# By default we set a task in waiting state
self.state = 0
def launch_command(self):
if self.command is None:
log.ODM_ERROR('Call method for task %s not defined' % self.name)
return 3 # failed
# run conmmand
try:
succeed = self.command(**self.inputs)
return 2 if succeed else 3 # 2:succeed, 3:failed
except Exception, e:
log.ODM_ERROR(str(e))
return 3 # failed
# Launch task
def run(self):
# while doing something
self.state = 1
return self.launch_command()
def launch_command(self):
if self.command is None:
log.ODM_ERROR('Call method for task %s not defined' % self.name)
return 3 # failed
# run conmmand
try:
succeed = self.command(**self.inputs)
return 2 if succeed else 3 # 2:succeed, 3:failed
except Exception, e:
log.ODM_ERROR(str(e))
return 3 # failed

Wyświetl plik

@ -1,7 +1,5 @@
import os
import cv2
import pyexiv2
import subprocess
import re
from fractions import Fraction
@ -10,9 +8,11 @@ import io
import system
import context
class ODM_Photo:
""" ODMPhoto - a class for ODMPhotos
"""
def __init__(self, path_file, force_focal, force_ccd):
# general purpose
self.path_file = path_file
@ -28,12 +28,12 @@ class ODM_Photo:
self.camera_model = None
# parse values from metadata
self.parse_pyexiv2_values(self.path_file, force_focal, force_ccd)
# compute focal lenght into pixels
# compute focal length into pixels
self.update_focal()
# print log message
log.ODM_DEBUG('Loaded %s | dimensions: %s x %s | focal: %s | ccd: %s' % \
(self.filename, self.width, self.height, self.focal_length, self.ccd_width))
log.ODM_DEBUG('Loaded %s | dimensions: %s x %s | focal: %s | ccd: %s' %
(self.filename, self.width, self.height, self.focal_length, self.ccd_width))
def update_focal(self):
# compute focal length in pixels
@ -59,12 +59,15 @@ class ODM_Photo:
try:
val = metadata[key].value
# parse tag names
if key == 'Exif.Image.Make': self.camera_make = val
elif key == 'Exif.Image.Model': self.camera_model = val
elif key == 'Exif.Photo.FocalLength': self.focal_length = float(val)
if key == 'Exif.Image.Make':
self.camera_make = val
elif key == 'Exif.Image.Model':
self.camera_model = val
elif key == 'Exif.Photo.FocalLength':
self.focal_length = float(val)
except Exception, e:
pass
# needed to do that since sometimes metadata contains wrong data
img = cv2.imread(_path_file)
self.width = img.shape[1]
@ -81,7 +84,8 @@ class ODM_Photo:
# search ccd by camera model
key = [x for x in ccd_widths.keys() if self.camera_model in x]
# convert to float if found
if key: self.ccd_width = float(ccd_widths[key[0]])
if key:
self.ccd_width = float(ccd_widths[key[0]])
# else:
# log.ODM_ERROR('Could not find ccd_width in file')
@ -89,6 +93,7 @@ class ODM_Photo:
# TODO: finish this class
class ODM_Reconstruction(object):
"""docstring for ODMReconstruction"""
def __init__(self, arg):
super(ODMReconstruction, self).__init__()
self.arg = arg
@ -96,6 +101,7 @@ class ODM_Reconstruction(object):
class ODM_GCPoint(object):
"""docstring for ODMPoint"""
def __init__(self, x, y, z):
self.x = x
self.y = y
@ -104,6 +110,7 @@ class ODM_GCPoint(object):
class ODM_GeoRef(object):
"""docstring for ODMUtmZone"""
def __init__(self):
self.datum = 'WGS84'
self.epsg = None
@ -129,13 +136,13 @@ class ODM_GeoRef(object):
log.ODM_ERROR('Empty EPSG: Could not convert to LAS')
return
kwargs = { 'bin': context.pdal_path,
'f_in': _file,
'f_out': _file + '.las',
'east': self.utm_east_offset,
'north': self.utm_north_offset,
'epsg': self.epsg,
'xml': pdalXML}
kwargs = {'bin': context.pdal_path,
'f_in': _file,
'f_out': _file + '.las',
'east': self.utm_east_offset,
'north': self.utm_north_offset,
'epsg': self.epsg,
'xml': pdalXML}
# call txt2las
# system.run('{bin}/txt2las -i {f_in} -o {f_out} -skip 30 -parse xyzRGBssss ' \
@ -143,7 +150,7 @@ class ODM_GeoRef(object):
# '-translate_xyz 0 -epsg {epsg}'.format(**kwargs))
#
# create pipeline file transform.xml to enable transformation
pipelineXml = '<?xml version=\"1.0\" encoding=\"utf-8\"?>'
pipelineXml = '<?xml version=\"1.0\" encoding=\"utf-8\"?>'
pipelineXml += '<Pipeline version=\"1.0\">'
pipelineXml += ' <Writer type=\"writers.las\">'
pipelineXml += ' <Option name=\"filename\">'
@ -176,16 +183,16 @@ class ODM_GeoRef(object):
gcp = self.gcps[idx]
kwargs = { 'datum': self.datum,
'zone': self.utm_zone,
'file': _file,
'x': gcp.x + self.utm_east_offset,
'y': gcp.y + self.utm_north_offset,
'z': gcp.z }
kwargs = {'datum': self.datum,
'zone': self.utm_zone,
'file': _file,
'x': gcp.x + self.utm_east_offset,
'y': gcp.y + self.utm_north_offset,
'z': gcp.z}
latlon = system.run_and_return('echo {x} {y} | cs2cs +proj=utm '
'+datum={datum} +ellps={datum} +zone={zone} +units=m +to '
'+proj=latlon +ellps={datum}'.format(**kwargs)).split()
'+datum={datum} +ellps={datum} +zone={zone} +units=m +to '
'+proj=latlon +ellps={datum}'.format(**kwargs)).split()
# Example: 83d18'16.285"W
# Example: 41d2'11.789"N
@ -198,7 +205,7 @@ class ODM_GeoRef(object):
alt_str = ''
else:
log.ODM_ERROR('Something went wrong %s' % latlon)
tokens = re.split("[d '\"]+", lon_str)
if len(tokens) >= 4:
lon_deg, lon_min, lon_sec = tokens[:3]
@ -226,7 +233,7 @@ class ODM_GeoRef(object):
metadata = pyexiv2.ImageMetadata(_photo.path_file)
metadata.read()
## set values
# set values
# GPS latitude
key = 'Exif.GPSInfo.GPSLatitude'
@ -256,10 +263,9 @@ class ODM_GeoRef(object):
key = 'Exif.GPSInfo.GPSAltitudeRef'
metadata[key] = pyexiv2.ExifTag(key, '0')
## write values
# write values
metadata.write()
def parse_coordinate_system(self, _file):
"""Write attributes to jobOptions from coord file"""
# check for coordinate file existence
@ -273,8 +279,8 @@ class ODM_GeoRef(object):
# 'WGS84 UTM 17N'
line = f.readline().split(' ')
self.datum = line[0]
self.utm_pole = line[2][len(line)-1]
self.utm_zone = int(line[2][:len(line)-1])
self.utm_pole = line[2][len(line) - 1]
self.utm_zone = int(line[2][:len(line) - 1])
# extract east and west offsets from second line.
# We will assume the following format:
# '440143 4588391'
@ -293,10 +299,10 @@ class ODM_GeoRef(object):
class ODM_Tree(object):
def __init__(self, root_path):
### root path to the project
# root path to the project
self.root_path = io.absolute_path_file(root_path)
### modules paths
# modules paths
# here are defined where all modules should be located in
# order to keep track all files al directories during the
@ -311,8 +317,8 @@ class ODM_Tree(object):
self.odm_orthophoto = io.join_paths(self.root_path, 'odm_orthophoto')
self.odm_pdal = io.join_paths(self.root_path, 'pdal')
### important files paths
# important files paths
# opensfm
self.opensfm_bundle = io.join_paths(self.opensfm, 'bundle_r000.out')
self.opensfm_bundle_list = io.join_paths(self.opensfm, 'list_r000.out')
@ -325,11 +331,11 @@ class ODM_Tree(object):
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.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')
@ -368,4 +374,3 @@ class ODM_Tree(object):
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')
self.odm_orthophoto_tif_log = io.join_paths(self.odm_orthophoto, 'gdal_translate_log.txt')

36
run.py
Wyświetl plik

@ -9,28 +9,30 @@ import ecto
from scripts.odm_app import ODMApp
def usage():
log.ODM_ERROR('USAGE: %s --project-path [project_path]' % sys.argv[0])
log.ODM_ERROR('OpenDroneMap app finished - %s' % system.now())
sys.exit(0)
log.ODM_ERROR('USAGE: %s --project-path [project_path]' % sys.argv[0])
log.ODM_ERROR('OpenDroneMap app finished - %s' % system.now())
sys.exit(0)
if __name__ == '__main__':
log.ODM_INFO('Initializing OpenDroneMap app - %s' % system.now())
log.ODM_INFO('Initializing OpenDroneMap app - %s' % system.now())
# Force to provide the images path
if config.args.get('project_path') is None:
usage()
# Force to provide the images path
if config.args.get('project_path') is None:
usage()
# create an instance of my App BlackBox
# internally configure all tasks
app = ODMApp(args=config.args)
# create an instance of my App BlackBox
# internally configure all tasks
app = ODMApp(args=config.args)
# create a plasm that only contains the BlackBox
plasm = ecto.Plasm()
plasm.insert(app)
# create a plasm that only contains the BlackBox
plasm = ecto.Plasm()
plasm.insert(app)
# execute the plasm
plasm.execute(niter=1)
# execute the plasm
plasm.execute(niter=1)
log.ODM_INFO('OpenDroneMap app finished - %s' % system.now())
log.ODM_INFO('OpenDroneMap app finished - %s' % system.now())

Wyświetl plik

@ -5,6 +5,7 @@ from opendm import log
from opendm import system
from opendm import context
class ODMCmvsCell(ecto.Cell):
def declare_params(self, params):
@ -53,7 +54,7 @@ class ODMCmvsCell(ecto.Cell):
system.run('{bin} {prefix}/ {max_images} {cores}'.format(**kwargs))
else:
log.ODM_WARNING('Found a valid CMVS file in: %s' %
(tree.pmvs_bundle))
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

@ -6,13 +6,14 @@ from opendm import io
from opendm import types
from opendm import log
class ODMLoadDatasetCell(ecto.Cell):
def declare_params(self, params):
params.declare("force_focal", 'Override the focal length information for the '
'images', None)
'images', None)
params.declare("force_ccd", 'Override the ccd widht information for the '
'images', None)
'images', None)
def declare_io(self, params, inputs, outputs):
inputs.declare("tree", "Struct with paths", [])
@ -65,4 +66,4 @@ class ODMLoadDatasetCell(ecto.Cell):
outputs.photos = photos
log.ODM_INFO('Running ODM Load Dataset Cell - Finished')
return ecto.OK
return ecto.OK

Wyświetl plik

@ -14,11 +14,14 @@ from odm_texturing import ODMTexturingCell
from odm_georeferencing import ODMGeoreferencingCell
from odm_orthophoto import ODMOrthoPhotoCell
class ODMApp(ecto.BlackBox):
''' ODMApp - a class for ODM Activities
'''
"""ODMApp - a class for ODM Activities
"""
def __init__(self, *args, **kwargs):
ecto.BlackBox.__init__(self, *args, **kwargs)
self.tree = None
@staticmethod
def declare_direct_params(p):
@ -30,38 +33,38 @@ class ODMApp(ecto.BlackBox):
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),
'dataset': ODMLoadDatasetCell(force_focal=p.args['force_focal'],
force_ccd=p.args['force_ccd']),
'resize': ODMResizeCell(resize_to=p.args['resize_to']),
'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_neighbors'],
matching_gps_distance=p.args['matcher_distance']),
'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'])
cells = {'args': ecto.Constant(value=p.args),
'dataset': ODMLoadDatasetCell(force_focal=p.args['force_focal'],
force_ccd=p.args['force_ccd']),
'resize': ODMResizeCell(resize_to=p.args['resize_to']),
'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_neighbors'],
matching_gps_distance=p.args['matcher_distance']),
'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
return cells
def configure(self, p, _i, _o):
tree = types.ODM_Tree(p.args['project_path'])
@ -69,54 +72,55 @@ class ODMApp(ecto.BlackBox):
def connections(self, _p):
# define initial task
initial_task = _p.args['start_with']
initial_task_id = config.processopts.index(initial_task)
# TODO: What is this?
# initial_task = _p.args['start_with']
# initial_task_id = config.processopts.index(initial_task)
## define the connections like you would for the plasm
connections = []
# define the connections like you would for the plasm
# connections = []
## load the dataset
connections = [ self.tree[:] >> self.dataset['tree'] ]
# load the dataset
connections = [self.tree[:] >> self.dataset['tree']]
# run resize cell
connections += [ self.tree[:] >> self.resize['tree'],
self.args[:] >> self.resize['args'],
self.dataset['photos'] >> self.resize['photos'] ]
connections += [self.tree[:] >> self.resize['tree'],
self.args[:] >> self.resize['args'],
self.dataset['photos'] >> self.resize['photos']]
# run opensfm with images from load dataset
connections += [ self.tree[:] >> self.opensfm['tree'],
self.args[:] >> self.opensfm['args'],
self.resize['photos'] >> self.opensfm['photos'] ]
# run cmvs
connections += [ self.tree[:] >> self.cmvs['tree'],
self.args[:] >> self.cmvs['args'],
self.opensfm['reconstruction'] >> self.cmvs['reconstruction'] ]
# run pmvs
connections += [ self.tree[:] >> self.pmvs['tree'],
self.args[:] >> self.pmvs['args'],
self.cmvs['reconstruction'] >> self.pmvs['reconstruction'] ]
# create odm mesh
connections += [ self.tree[:] >> self.meshing['tree'],
self.args[:] >> self.meshing['args'],
self.pmvs['reconstruction'] >> self.meshing['reconstruction'] ]
# create odm texture
connections += [ self.tree[:] >> self.texturing['tree'],
self.args[:] >> self.texturing['args'],
self.meshing['reconstruction'] >> self.texturing['reconstruction'] ]
# 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'] ]
connections += [self.tree[:] >> self.opensfm['tree'],
self.args[:] >> self.opensfm['args'],
self.resize['photos'] >> self.opensfm['photos']]
## create odm orthophoto
connections += [ self.tree[:] >> self.orthophoto['tree'],
self.args[:] >> self.orthophoto['args'],
self.georeferencing['reconstruction'] >> self.orthophoto['reconstruction'] ]
# run cmvs
connections += [self.tree[:] >> self.cmvs['tree'],
self.args[:] >> self.cmvs['args'],
self.opensfm['reconstruction'] >> self.cmvs['reconstruction']]
# run pmvs
connections += [self.tree[:] >> self.pmvs['tree'],
self.args[:] >> self.pmvs['args'],
self.cmvs['reconstruction'] >> self.pmvs['reconstruction']]
# create odm mesh
connections += [self.tree[:] >> self.meshing['tree'],
self.args[:] >> self.meshing['args'],
self.pmvs['reconstruction'] >> self.meshing['reconstruction']]
# create odm texture
connections += [self.tree[:] >> self.texturing['tree'],
self.args[:] >> self.texturing['args'],
self.meshing['reconstruction'] >> self.texturing['reconstruction']]
# 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']]
# create odm orthophoto
connections += [self.tree[:] >> self.orthophoto['tree'],
self.args[:] >> self.orthophoto['args'],
self.georeferencing['reconstruction'] >> self.orthophoto['reconstruction']]
return connections

Wyświetl plik

@ -5,20 +5,20 @@ from opendm import io
from opendm import system
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)
'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)
'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)
'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)
'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", [])
@ -27,7 +27,7 @@ class ODMeshingCell(ecto.Cell):
outputs.declare("reconstruction", "Clusters output. list of ODMReconstructions", [])
def process(self, inputs, outputs):
log.ODM_INFO('Running OMD Meshing Cell')
# get inputs
@ -55,17 +55,17 @@ class ODMeshingCell(ecto.Cell):
'max_vertex': self.params.max_vertex,
'oct_tree': self.params.oct_tree,
'samples': self.params.samples,
'solver':self.params.solver
'solver': self.params.solver
}
# run meshing binary
system.run('{bin}/odm_meshing -inputFile {infile} ' \
'-outputFile {outfile} -logFile {log} ' \
'-maxVertexCount {max_vertex} -octreeDepth {oct_tree} ' \
'-samplesPerNode {samples} -solverDivide {solver}'.format(**kwargs))
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' %
(tree.odm_mesh))
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
return ecto.OK if args['end_with'] != 'odm_meshing' else ecto.QUIT

Wyświetl plik

@ -47,17 +47,17 @@ class ODMOrthoPhotoCell(ecto.Cell):
}
# run odm_orthophoto
system.run('{bin}/odm_orthophoto -inputFile {model_geo} ' \
'-logFile {log} -outputFile {ortho} -resolution {res} ' \
'-outputCornerFile {corners}'.format(**kwargs))
system.run('{bin}/odm_orthophoto -inputFile {model_geo} '
'-logFile {log} -outputFile {ortho} -resolution {res} '
'-outputCornerFile {corners}'.format(**kwargs))
# Create georeferenced GeoTiff
geoTiffCreated = False
geotiffcreated = False
georef = types.ODM_GeoRef()
# creates the coord refs # TODO I don't want to have to do this twice- after odm_georef
georef.parse_coordinate_system(tree.odm_georeferencing_coords)
if (georef.epsg and georef.utm_east_offset and georef.utm_north_offset):
if georef.epsg and georef.utm_east_offset and georef.utm_north_offset:
ulx = uly = lrx = lry = 0.0
with open(tree.odm_orthophoto_corners) as f:
for lineNumber, line in enumerate(f):
@ -87,8 +87,8 @@ class ODMOrthoPhotoCell(ecto.Cell):
system.run('gdal_translate -a_ullr {ulx} {uly} {lrx} {lry} '
'-a_srs \"EPSG:{epsg}\" {png} {tiff} > {log}'.format(**kwargs))
geoTiffCreated = True
if not geoTiffCreated:
geotiffcreated = True
if not geotiffcreated:
log.ODM_WARNING('No geo-referenced orthophoto created due '
'to missing geo-referencing or corner coordinates.')
@ -97,54 +97,3 @@ class ODMOrthoPhotoCell(ecto.Cell):
log.ODM_INFO('Running OMD OrthoPhoto Cell - Finished')
return ecto.OK if args['end_with'] != 'odm_orthophoto' else ecto.QUIT
def odm_orthophoto():
"""Run odm_orthophoto"""
print "\n - running orthophoto generation - " + system.now()
os.chdir(jobOptions["jobDir"])
try:
os.mkdir(jobOptions["jobDir"] + "/odm_orthophoto")
except:
pass
run("\"" + BIN_PATH + "/odm_orthophoto\" -inputFile " + jobOptions["jobDir"] + \
"-results/odm_texturing/odm_textured_model_geo.obj -logFile " + jobOptions["jobDir"] \
+ "/odm_orthophoto/odm_orthophoto_log.txt -outputFile " + jobOptions["jobDir"] \
+ "-results/odm_orthphoto.png -resolution 20.0 -outputCornerFile " + jobOptions["jobDir"] \
+ "/odm_orthphoto_corners.txt")
if "csString" not in jobOptions:
parse_coordinate_system() # Writes the coord string to the jobOptions object
geoTiffCreated = False
if ("csString" in jobOptions and
"utmEastOffset" in jobOptions and "utmNorthOffset" in jobOptions):
ulx = uly = lrx = lry = 0.0
with open(jobOptions["jobDir"] +
"/odm_orthphoto_corners.txt") as f: # Open tree.odm_orthophoto_corners
for lineNumber, line in enumerate(f):
if lineNumber == 0:
tokens = line.split(' ')
if len(tokens) == 4:
ulx = float(tokens[0]) + \
float(jobOptions["utmEastOffset"])
lry = float(tokens[1]) + \
float(jobOptions["utmNorthOffset"])
lrx = float(tokens[2]) + \
float(jobOptions["utmEastOffset"])
uly = float(tokens[3]) + \
float(jobOptions["utmNorthOffset"])
print(" Creating GeoTIFF...")
sys.stdout.write(" ")
run("gdal_translate -a_ullr " + str(ulx) + " " + str(uly) + " " +
str(lrx) + " " + str(lry) + " -a_srs \"" + jobOptions["csString"] +
"\" " + jobOptions["jobDir"] + "-results/odm_orthphoto.png " +
jobOptions["jobDir"] + "-results/odm_orthphoto.tif")
geoTiffCreated = True
if not geoTiffCreated:
print " Warning: No geo-referenced orthophoto created due to missing geo-referencing or corner coordinates."

Wyświetl plik

@ -5,14 +5,14 @@ from opendm import io
from opendm import system
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)
'greater than textureWithSize.', 4096)
params.declare("size", 'The resolution to rescale the images performing '
'the texturing.', 3600)
'the texturing.', 3600)
def declare_io(self, params, inputs, outputs):
inputs.declare("tree", "Struct with paths", [])
@ -21,7 +21,7 @@ class ODMTexturingCell(ecto.Cell):
outputs.declare("reconstruction", "Clusters output. list of ODMReconstructions", [])
def process(self, inputs, outputs):
log.ODM_INFO('Running OMD Texturing Cell')
# get inputs
@ -39,8 +39,8 @@ class ODMTexturingCell(ecto.Cell):
'odm_texturing' in args['rerun_from'])
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)
log.ODM_DEBUG('Writing ODM Textured file in: %s'
% tree.odm_textured_model_obj)
# odm_texturing definitions
kwargs = {
@ -57,14 +57,14 @@ class ODMTexturingCell(ecto.Cell):
}
# run texturing binary
system.run('{bin}/odm_texturing -bundleFile {bundle} ' \
'-imagesPath {imgs_path} -imagesListPath {imgs_list} ' \
'-inputModelPath {model} -outputFolder {out_dir}/ ' \
'-textureResolution {resolution} -bundleResizedTo {resize} ' \
'-textureWithSize {size} -logFile {log}'.format(**kwargs))
system.run('{bin}/odm_texturing -bundleFile {bundle} '
'-imagesPath {imgs_path} -imagesListPath {imgs_list} '
'-inputModelPath {model} -outputFolder {out_dir}/ '
'-textureResolution {resolution} -bundleResizedTo {resize} '
'-textureWithSize {size} -logFile {log}'.format(**kwargs))
else:
log.ODM_WARNING('Found a valid ODM Texture file in: %s' \
% tree.odm_textured_model_obj)
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
return ecto.OK if args['end_with'] != 'odm_texturing' else ecto.QUIT

Wyświetl plik

@ -5,6 +5,7 @@ from opendm import io
from opendm import system
from opendm import context
class ODMOpenSfMCell(ecto.Cell):
def declare_params(self, params):
params.declare("use_exif_size", "The application arguments.", False)
@ -44,8 +45,7 @@ class ODMOpenSfMCell(ecto.Cell):
(args['rerun_from'] is not None and
'opensfm' in args['rerun_from'])
### check if reconstruction was done before
# check if reconstruction was done before
if not io.file_exists(tree.opensfm_reconstruction) or rerun_cell:
# create file list
@ -63,7 +63,7 @@ class ODMOpenSfMCell(ecto.Cell):
"matching_gps_neighbors: %s" % self.params.matching_gps_neighbors
]
if args['matcher_distance']>0:
if args['matcher_distance'] > 0:
config.append("matching_gps_distance: %s" % self.params.matching_gps_distance)
# write config file
@ -72,30 +72,28 @@ class ODMOpenSfMCell(ecto.Cell):
fout.write("\n".join(config))
# run OpenSfM reconstruction
system.run('PYTHONPATH=%s %s/bin/run_all %s' %
(context.pyopencv_path, context.opensfm_path, tree.opensfm))
system.run('PYTHONPATH=%s %s/bin/run_all %s' %
(context.pyopencv_path, context.opensfm_path, tree.opensfm))
else:
log.ODM_WARNING('Found a valid OpenSfm file in: %s' %
(tree.opensfm_reconstruction))
log.ODM_WARNING('Found a valid OpenSfm file in: %s' %
tree.opensfm_reconstruction)
### check if reconstruction was exported to bundler before
# check if reconstruction was exported to bundler before
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, tree.opensfm))
(context.pyopencv_path, context.opensfm_path, tree.opensfm))
else:
log.ODM_WARNING('Found a valid Bundler file in: %s' %
(tree.opensfm_reconstruction))
log.ODM_WARNING('Found a valid Bundler file in: %s' %
tree.opensfm_reconstruction)
### check if reconstruction was exported to pmvs before
# check if reconstruction was exported to pmvs before
if not io.file_exists(tree.pmvs_visdat) or rerun_cell:
# run PMVS converter
system.run('PYTHONPATH=%s %s/bin/export_pmvs %s --output %s' %
(context.pyopencv_path, context.opensfm_path, tree.opensfm, tree.pmvs))
system.run('PYTHONPATH=%s %s/bin/export_pmvs %s --output %s' %
(context.pyopencv_path, context.opensfm_path, tree.opensfm, tree.pmvs))
else:
log.ODM_WARNING('Found a valid CMVS file in: %s' % tree.pmvs_visdat)

Wyświetl plik

@ -5,26 +5,26 @@ from opendm import log
from opendm import system
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)
'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)
'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)
'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)
' reconstruction.', context.num_cores)
def declare_io(self, params, inputs, outputs):
inputs.declare("tree", "Struct with paths", [])
@ -33,7 +33,7 @@ class ODMPmvsCell(ecto.Cell):
outputs.declare("reconstruction", "list of ODMReconstructions", [])
def process(self, inputs, outputs):
log.ODM_INFO('Running OMD PMVS Cell')
# get inputs
@ -62,12 +62,12 @@ class ODMPmvsCell(ecto.Cell):
}
# generate pmvs2 options
system.run('{bin} {prefix}/ {level} {csize} {thresh} {wsize} ' \
system.run('{bin} {prefix}/ {level} {csize} {thresh} {wsize} '
'{min_imgs} {cores}'.format(**kwargs))
# run pmvs2
system.run('%s %s/ option-0000' % \
(context.pmvs2_path, tree.pmvs_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' % tree.pmvs_model)

Wyświetl plik

@ -7,6 +7,7 @@ from opendm import system
from opendm import io
from opendm import types
class ODMResizeCell(ecto.Cell):
def declare_params(self, params):
params.declare("resize_to", "resizes images by the largest side", 2400)
@ -29,7 +30,7 @@ class ODMResizeCell(ecto.Cell):
if not photos:
log.ODM_ERROR('Not enough photos in photos to resize')
return ecto.QUIT
# create working directory
system.mkdir_p(tree.dataset_resize)
@ -78,17 +79,17 @@ class ODMResizeCell(ecto.Cell):
photo.update_focal()
# log message
log.ODM_DEBUG('Resized %s | dimensions: %s' % \
(photo.filename, img_r.shape))
log.ODM_DEBUG('Resized %s | dimensions: %s' %
(photo.filename, img_r.shape))
else:
# log message
log.ODM_WARNING('Already resized %s | dimensions: %s x %s' % \
(photo.filename, photo.width, photo.height))
log.ODM_WARNING('Already resized %s | dimensions: %s x %s' %
(photo.filename, photo.width, photo.height))
log.ODM_INFO('Resized %s images' % len(photos))
# append photos to cell output
self.outputs.photos = photos
log.ODM_INFO('Running ODM Resize Cell - Finished')
return ecto.OK if args['end_with'] != 'resize' else ecto.QUIT
return ecto.OK if args['end_with'] != 'resize' else ecto.QUIT