kopia lustrzana https://github.com/OpenDroneMap/ODM
rodzic
283b701066
commit
66bc2a5ae5
|
@ -6,9 +6,9 @@ processopts = ['resize', 'opensfm', 'cmvs', 'pmvs',
|
|||
'odm_orthophoto']
|
||||
|
||||
parser = argparse.ArgumentParser(description='OpenDroneMap')
|
||||
parser.add_argument('--images-src',
|
||||
parser.add_argument('--project-path',
|
||||
metavar='<string>',
|
||||
help='Path to the images to process')
|
||||
help='Path to the project to process')
|
||||
|
||||
parser.add_argument('--resize-to', # currently doesn't support 'orig'
|
||||
metavar='<integer>',
|
||||
|
|
|
@ -1,48 +0,0 @@
|
|||
import os
|
||||
|
||||
import log
|
||||
import context
|
||||
import datatypes
|
||||
|
||||
def load_dataset(images_dir, args):
|
||||
|
||||
# check if the extension is sopported
|
||||
def supported_extension(file_name):
|
||||
(pathfn, ext) = os.path.splitext(file_name)
|
||||
return ext.lower() in context.supported_extensions
|
||||
|
||||
log.ODM_DEBUG('Loading dataset from: %s' % images_dir)
|
||||
|
||||
# find files in the given directory
|
||||
files = os.listdir(images_dir)
|
||||
|
||||
# filter images for its extension type
|
||||
# by now only 'jpg' and 'jpeg are supported
|
||||
files = [f for f in files if supported_extension(f)]
|
||||
|
||||
if len(files) < 1:
|
||||
log.ODM_ERROR('Not found enough supported images in %s' % images_dir)
|
||||
return
|
||||
|
||||
photos = []
|
||||
|
||||
# create ODMPhoto list
|
||||
for f in files:
|
||||
path_file = os.path.join(images_dir, f)
|
||||
photos.append(datatypes.ODMPhoto(path_file, args))
|
||||
|
||||
log.ODM_INFO('Found %s usable images' % len(photos))
|
||||
return photos
|
||||
|
||||
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)
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
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)
|
|
@ -2,8 +2,10 @@ import os
|
|||
import errno
|
||||
import json
|
||||
import datetime
|
||||
import sys
|
||||
|
||||
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."""
|
||||
|
@ -12,10 +14,11 @@ def get_ccd_widths():
|
|||
|
||||
def run(cmd):
|
||||
"""Run a system command"""
|
||||
print 'running', cmd
|
||||
log.ODM_DEBUG('running %s' % cmd)
|
||||
returnCode = os.system(cmd)
|
||||
print 'b'
|
||||
|
||||
if (returnCode != 0):
|
||||
# TODO(edgar): add as log.ODM_ERROR
|
||||
sys.exit("\nquitting cause: \n\t" + cmd + "\nreturned with code " +
|
||||
str(returnCode) + ".\n")
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ import log
|
|||
import system
|
||||
|
||||
import dataset
|
||||
import datatypes
|
||||
import types
|
||||
|
||||
from scripts.resize import resize
|
||||
from scripts.opensfm import opensfm
|
||||
|
|
|
@ -3,41 +3,8 @@ import pyexiv2
|
|||
import subprocess
|
||||
|
||||
import log
|
||||
import dataset
|
||||
import io
|
||||
import system
|
||||
import tasks
|
||||
|
||||
class ODMApp:
|
||||
''' ODMApp - a class for ODM Activities
|
||||
'''
|
||||
def __init__(self, args):
|
||||
# Internal app config
|
||||
self.args = args
|
||||
self.project_path = os.path.abspath(args['images_src'])
|
||||
# Initialize odm photos
|
||||
self.photos = []
|
||||
# Task manager
|
||||
# configure and schedule tasks
|
||||
self.task_manager = tasks.ODMTaskManager(self)
|
||||
|
||||
# Run all tasks given an starting point
|
||||
def run_all(self, initial_task, final_task):
|
||||
|
||||
# found ids for tasks
|
||||
t_dict = tasks.tasks_dict
|
||||
initial_task_id = [k for k in t_dict if t_dict[k]==initial_task][0]
|
||||
final_task_id = [k for k in t_dict if t_dict[k]==final_task][0]
|
||||
|
||||
if initial_task_id > final_task_id:
|
||||
log.ODM_ERROR('Initial task must be lower than final')
|
||||
return
|
||||
|
||||
# setup task manager
|
||||
self.task_manager.initial_task_id = int(initial_task_id)
|
||||
self.task_manager.final_task_id = int(final_task_id)
|
||||
# run defined pipeline
|
||||
self.task_manager.run_tasks()
|
||||
|
||||
|
||||
class ODMPhoto:
|
||||
""" ODMPhoto - a class for ODMPhotos
|
||||
|
@ -46,7 +13,7 @@ class ODMPhoto:
|
|||
# general purpose
|
||||
self.path_file = path_file
|
||||
# useful attibutes
|
||||
self.file_name = None
|
||||
self.filename = None
|
||||
self.width = None
|
||||
self.height = None
|
||||
self.ccd_width = None
|
||||
|
@ -94,10 +61,10 @@ class ODMPhoto:
|
|||
self.height * (self.focal_length / self.ccd_width)
|
||||
|
||||
log.ODM_DEBUG('Loaded %s | dimensions: %s x %s | focal: %smm | ccd: %smm' % \
|
||||
(self.file_name, self.width, self.height, self.focal_length, self.ccd_width))
|
||||
(self.filename, self.width, self.height, self.focal_length, self.ccd_width))
|
||||
else:
|
||||
log.ODM_WARNING('No CCD width or focal length found for image file: \n' +
|
||||
self.file_name + ' camera: \"' + self.camera_model)
|
||||
self.filename + ' camera: \"' + self.camera_model)
|
||||
|
||||
|
||||
def parse_pyexiv2_values(self, _path_file, args):
|
||||
|
@ -116,14 +83,18 @@ class ODMPhoto:
|
|||
elif key == 'Exif.Photo.FocalLength':
|
||||
self.focal_length = float(val)
|
||||
|
||||
# extract and set filename from path file
|
||||
self.filename = io.extract_file_from_path_file(_path_file)
|
||||
|
||||
# find ccd_width from file if needed
|
||||
if self.ccd_width is None:
|
||||
if self.ccd_width is None and self.camera_model is not None:
|
||||
# load ccd_widths from file
|
||||
ccd_widths = system.get_ccd_widths()
|
||||
|
||||
key = [x for x in ccd_widths.keys() if self.camera_model in x][0]
|
||||
if key is not None:
|
||||
self.ccd_width = float(ccd_widths[key])
|
||||
# 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 len(key) > 0:
|
||||
self.ccd_width = float(ccd_widths[key][0])
|
||||
else:
|
||||
log.ODM_ERROR('Could not find ccd_width in file')
|
||||
|
||||
|
@ -150,7 +121,7 @@ class ODMPhoto:
|
|||
# parse values to attributes
|
||||
if key == 'File name':
|
||||
self.path_file = val
|
||||
self.file_name = dataset.extract_file_from_path_file(val)
|
||||
self.filename = io.extract_file_from_path_file(val)
|
||||
elif key == 'File size': self.file_size = val
|
||||
elif key == 'File date': self.file_date = val
|
||||
elif key == 'Camera make': self.camera_make = val
|
32
run.py
32
run.py
|
@ -1,14 +1,16 @@
|
|||
#!/usr/bin/python
|
||||
|
||||
import sys
|
||||
import ecto
|
||||
|
||||
from scripts.odm_app import ODMApp
|
||||
|
||||
from opendm import log
|
||||
from opendm import config
|
||||
from opendm import system
|
||||
from opendm.datatypes import ODMApp
|
||||
|
||||
def usage():
|
||||
log.ODM_ERROR('USAGE: %s --images-src dataset_path' % sys.argv[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)
|
||||
|
||||
|
@ -17,28 +19,18 @@ if __name__ == '__main__':
|
|||
log.ODM_INFO('Initializing OpenDroneMap app - %s' % system.now())
|
||||
|
||||
# Force to provide the images path
|
||||
if config.args.get('images_src') is None:
|
||||
if config.args.get('project_path') is None:
|
||||
usage()
|
||||
|
||||
# Initialize odm app
|
||||
# create an instance of my App BlackBox
|
||||
# internally configure all tasks
|
||||
app = ODMApp(config.args)
|
||||
app = ODMApp(project_path=config.args['project_path'], args=config.args)
|
||||
|
||||
log.ODM_INFO('Runnning OpenDroneMap app - %s' % system.now())
|
||||
# create a plasm that only contains the BlackBox
|
||||
plasm = ecto.Plasm()
|
||||
plasm.insert(app)
|
||||
|
||||
# run single task
|
||||
if config.args.get('run_only') is not None:
|
||||
# task to run
|
||||
tasks = config.args['run_only']
|
||||
app.run_all(tasks, tasks)
|
||||
|
||||
# run multiple tasks
|
||||
else:
|
||||
# get initial and final tasks
|
||||
initial_task = config.args['start_with']
|
||||
final_task = config.args['end_with']
|
||||
|
||||
# run tasks
|
||||
app.run_all(initial_task, final_task)
|
||||
# execute the plasm
|
||||
plasm.execute(niter=1)
|
||||
|
||||
log.ODM_INFO('OpenDroneMap app finished - %s' % system.now())
|
|
@ -1,32 +0,0 @@
|
|||
import system
|
||||
|
||||
def cmvs():
|
||||
"""Run CMVS"""
|
||||
print "\n - running cmvs - " + system.now()
|
||||
|
||||
os.chdir(jobOptions["jobDir"])
|
||||
|
||||
run("\"" + BIN_PATH + "/cmvs\" pmvs/ " + str(args['--cmvs-maxImages']) \
|
||||
+ " " + str(CORES))
|
||||
run("\"" + BIN_PATH + "/genOption\" pmvs/ " + str(args['--pmvs-level']) \
|
||||
+ " " + str(args['--pmvs-csize']) + " " + str(args['--pmvs-threshold']) \
|
||||
+ " " + str(args['--pmvs-wsize']) + " " + str(args['--pmvs-minImageNum']) \
|
||||
+ " " + str(CORES))
|
||||
|
||||
if args['--end-with'] != "cmvs":
|
||||
pmvs()
|
||||
|
||||
|
||||
def pmvs():
|
||||
"""Run PMVS"""
|
||||
print "\n - running pmvs - " + system.now()
|
||||
|
||||
os.chdir(jobOptions["jobDir"])
|
||||
|
||||
run("\"" + BIN_PATH + "/pmvs2\" pmvs/ option-0000")
|
||||
|
||||
run("cp -Rf \"" + jobOptions["jobDir"] + "/pmvs/models\" \"" + jobOptions["jobDir"] + "-results\"")
|
||||
|
||||
|
||||
if args['--end-with'] != "pmvs":
|
||||
odm_meshing()
|
|
@ -0,0 +1,39 @@
|
|||
import ecto
|
||||
|
||||
from opendm import io
|
||||
from opendm import log
|
||||
from opendm import system
|
||||
|
||||
class ODMCmvsCell(ecto.Cell):
|
||||
def declare_params(self, params):
|
||||
params.declare("cmvs_max_images", "The application arguments.", False)
|
||||
params.declare("pmvs_level", "The application arguments.", False)
|
||||
params.declare("pmvs_csize", "The application arguments.", 0)
|
||||
params.declare("pmvs_threshold", "The application arguments.", 0)
|
||||
params.declare("pmvs_wsize", "The application arguments.", 0)
|
||||
params.declare("pmvs_min_image_num", "The application arguments.", 0)
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("project_path", "The directory to the images to load.", "")
|
||||
inputs.declare("bundler_file_path", "Clusters output. list of reconstructions", [])
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
|
||||
log.ODM_INFO('Running OMD CMVS Cell')
|
||||
|
||||
# get inputs
|
||||
bundler_file_path = self.inputs.bundler_file_path
|
||||
project_path = io.absolute_path_file(self.inputs.project_path)
|
||||
|
||||
# run cmvs binary
|
||||
#bin_dir='/home/vagrant/software/OpenDroneMap-edgarriba/SuperBuild/build/cmvs/main/cmvs'
|
||||
bin_dir='/home/vagrant/software/OpenDroneMap-edgarriba/SuperBuild/build/cmvs/main/pmv2'
|
||||
|
||||
cmvs_max_images = self.params.cmvs_max_images
|
||||
num_cores = 4
|
||||
|
||||
system.run('%s %s %s %s' %
|
||||
(bin_dir, bundler_file_path, cmvs_max_images, num_cores))
|
||||
|
||||
|
||||
log.ODM_INFO('Running OMD CMVS Cell - Finished')
|
|
@ -0,0 +1,53 @@
|
|||
import os
|
||||
import ecto
|
||||
|
||||
from opendm import context
|
||||
from opendm import io
|
||||
from opendm import types
|
||||
from opendm import log
|
||||
|
||||
class ODMLoadDatasetCell(ecto.Cell):
|
||||
# def declare_params(self, params):
|
||||
# params.declare("args", "The application arguments.", {})
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("images_dir", "The directory to the images to load.", "")
|
||||
inputs.declare("args", "The application arguments.", {})
|
||||
outputs.declare("photos", "Clusters output. list of ODMPhoto's", [])
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
# check if the extension is sopported
|
||||
def supported_extension(file_name):
|
||||
(pathfn, ext) = os.path.splitext(file_name)
|
||||
return ext.lower() in context.supported_extensions
|
||||
|
||||
log.ODM_INFO('Running ODM Load Dataset Cell')
|
||||
|
||||
# get parameters
|
||||
args = self.inputs.args
|
||||
images_dir = io.absolute_path_file(self.inputs.images_dir)
|
||||
|
||||
log.ODM_DEBUG('Loading dataset from: %s' % images_dir)
|
||||
|
||||
# find files in the given directory
|
||||
files = io.get_files_list(images_dir)
|
||||
|
||||
# filter images for its extension type
|
||||
# by now only 'jpg' and 'jpeg are supported
|
||||
files = [f for f in files if supported_extension(f)]
|
||||
|
||||
photos = []
|
||||
|
||||
if len(files) < 1:
|
||||
log.ODM_ERROR('Not enough supported images in %s' % images_dir)
|
||||
else:
|
||||
# create ODMPhoto list
|
||||
for f in files:
|
||||
path_file = io.join_paths(images_dir, f)
|
||||
photos.append(types.ODMPhoto(path_file, args))
|
||||
log.ODM_INFO('Found %s usable images' % len(photos))
|
||||
|
||||
# append photos to cell output
|
||||
outputs.photos = photos
|
||||
|
||||
log.ODM_INFO('Running ODM Load Dataset Cell - Finished')
|
|
@ -0,0 +1,82 @@
|
|||
import ecto
|
||||
|
||||
from dataset import ODMLoadDatasetCell
|
||||
#from resize import OMDResizeCell
|
||||
from cmvs import ODMCmvsCell
|
||||
from opensfm import ODMOpenSfMCell, ODMLoadReconstructionCell, ODMConvertToBundleCell
|
||||
|
||||
class ODMApp(ecto.BlackBox):
|
||||
''' ODMApp - a class for ODM Activities
|
||||
'''
|
||||
def __init__(self, *args, **kwargs):
|
||||
ecto.BlackBox.__init__(self, *args, **kwargs)
|
||||
|
||||
@staticmethod
|
||||
def declare_direct_params(p):
|
||||
p.declare("args", "The application arguments.", {})
|
||||
p.declare("project_path", "The directory to the project.", "")
|
||||
|
||||
@staticmethod
|
||||
def declare_cells(p):
|
||||
print p.args
|
||||
"""
|
||||
Implement the virtual function from the base class
|
||||
Only cells from which something is forwarded have to be declared
|
||||
"""
|
||||
cells = { 'project_path': ecto.Constant(value=p.project_path),
|
||||
'args': ecto.Constant(value=p.args),
|
||||
'load_dataset': ODMLoadDatasetCell(),
|
||||
#'resize': OMDResizeCell()
|
||||
'opensfm': ODMOpenSfMCell(use_exif_size=False,
|
||||
feature_process_size=p.args['resize_to'],
|
||||
feature_min_frames=p.args['min_num_features'],
|
||||
processes=8,
|
||||
matching_gps_neighbors=p.args['matcher_k']),
|
||||
'load_reconstruction': ODMLoadReconstructionCell(),
|
||||
'convert_reconstruction': ODMConvertToBundleCell(),
|
||||
'cmvs': ODMCmvsCell(cmvs_max_images=p.args['cmvs_maxImages'],
|
||||
pmvs_level=p.args['pmvs_level'],
|
||||
pmvs_csize=p.args['pmvs_csize'],
|
||||
pmvs_threshold=p.args['pmvs_threshold'],
|
||||
pmvs_wsize=p.args['pmvs_wsize'],
|
||||
pmvs_min_image_num=p.args['pmvs_minImageNum'])
|
||||
|
||||
}
|
||||
|
||||
return cells
|
||||
|
||||
def connections(self, _p):
|
||||
# define initial and final tasks
|
||||
# TODO: not sure how to manage that
|
||||
initial_task = _p.args['start_with']
|
||||
final_task = _p.args['end_with']
|
||||
run_only = _p.args['run_only']
|
||||
print run_only
|
||||
|
||||
# define the connections like you would for the plasm
|
||||
connections = []
|
||||
|
||||
# load the dataset
|
||||
connections = [ self.project_path[:] >> self.load_dataset['images_dir'],
|
||||
self.args[:] >> self.load_dataset['args'] ]
|
||||
|
||||
# resize images
|
||||
#connections += [ self.load_dataset['photos'] >> self.resize['photos'] ]
|
||||
|
||||
# connect loaded data with opensfm
|
||||
connections += [ self.project_path[:] >> self.opensfm['project_path'],
|
||||
self.load_dataset['photos'] >> self.opensfm['photos'] ]
|
||||
|
||||
# load reconstruction
|
||||
connections += [ self.project_path[:] >> self.load_reconstruction['project_path'],
|
||||
self.load_dataset['photos'] >> self.load_reconstruction['photos'] ]
|
||||
|
||||
# convert data to Bundler format
|
||||
connections += [ self.project_path[:] >> self.convert_reconstruction['project_path'],
|
||||
self.load_reconstruction['reconstructions'] >> self.convert_reconstruction['reconstructions'] ]
|
||||
|
||||
# run cmvs
|
||||
# connections += [ self.project_path[:] >> self.cmvs['project_path'],
|
||||
# self.convert_reconstruction['bundler_file_path'] >> self.cmvs['bundler_file_path'] ]
|
||||
|
||||
return connections
|
|
@ -1,79 +1,130 @@
|
|||
import ecto
|
||||
|
||||
from opendm import log
|
||||
from opendm import dataset
|
||||
from opendm import io
|
||||
from opendm import system
|
||||
from opendm import context
|
||||
|
||||
def opensfm(project_path, args, photos):
|
||||
class ODMOpenSfMCell(ecto.Cell):
|
||||
|
||||
log.ODM_INFO('Running Open Structure from Motion (OpenSfm)')
|
||||
|
||||
# check if we have input data
|
||||
if len(photos) == 0:
|
||||
log.ODM_WARNING('Photos array is empty - Proceed to load images')
|
||||
images_dir = dataset.join_paths(project_path, 'images/')
|
||||
photos = dataset.load_dataset(images_dir, args)
|
||||
def declare_params(self, params):
|
||||
params.declare("use_exif_size", "The application arguments.", False)
|
||||
params.declare("feature_process_size", "The application arguments.", False)
|
||||
params.declare("feature_min_frames", "The application arguments.", 0)
|
||||
params.declare("processes", "The application arguments.", 0)
|
||||
params.declare("matching_gps_neighbors", "The application arguments.", 0)
|
||||
|
||||
# preconditions
|
||||
if len(photos) < 1:
|
||||
log.ODM_ERROR('Not enough photos in photos array to reconstruct')
|
||||
return False
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("project_path", "The directory to the images to load.", "")
|
||||
inputs.declare("photos", "Clusters output. list of ODMPhoto's", [])
|
||||
inputs.declare("reconstructions", "Clusters output. list of reconstructions", [])
|
||||
|
||||
# create working directory
|
||||
working_dir = dataset.join_paths(project_path, 'opensfm')
|
||||
system.mkdir_p(working_dir)
|
||||
def process(self, inputs, outputs):
|
||||
|
||||
try:
|
||||
# define opensfm execution command
|
||||
system.run('PYTHONPATH=%s %s/bin/run_all %s' % \
|
||||
(context.pyopencv_path, context.opensfm_path, images_dir))
|
||||
except Exception, e:
|
||||
log.ODM_ERROR(str(e))
|
||||
return False
|
||||
log.ODM_INFO('Running OMD OpenSfm Cell')
|
||||
|
||||
return True
|
||||
# get inputs
|
||||
photos = self.inputs.photos
|
||||
project_path = io.absolute_path_file(self.inputs.project_path)
|
||||
|
||||
def opensfm2():
|
||||
print "\n - running OpenSfM - " + now()
|
||||
# create file list directory
|
||||
list_path = io.join_paths(project_path, 'opensfm')
|
||||
system.mkdir_p(list_path)
|
||||
|
||||
os.chdir(jobOptions["jobDir"])
|
||||
# check if reconstruction was done before
|
||||
file_list_path = io.join_paths(list_path, 'image_list.txt')
|
||||
|
||||
# Create bundler's list.txt
|
||||
filesList = ""
|
||||
for fileObject in objects:
|
||||
if fileObject["isOk"]:
|
||||
filesList += "./" + fileObject["src"] + " 0 {:.5f}\n".format(fileObject["focalpx"])
|
||||
filesList = filesList.rstrip('\n')
|
||||
if io.file_exists(file_list_path):
|
||||
log.ODM_WARNING('Found a valid reconstruction file')
|
||||
log.ODM_INFO('Running OMD OpenSfm Cell - Finished')
|
||||
return
|
||||
|
||||
with open(jobOptions["step_3_filelist"], 'w') as fout:
|
||||
fout.write(filesList)
|
||||
# create file list
|
||||
with open(file_list_path, 'w') as fout:
|
||||
for photo in photos:
|
||||
fout.write('%s\n' % photo.path_file)
|
||||
|
||||
# Create opensfm working folder
|
||||
mkdir_p("opensfm")
|
||||
# create config file for OpenSfM
|
||||
config = [
|
||||
"use_exif_size: no",
|
||||
"feature_process_size: %s" % self.params.feature_process_size,
|
||||
"feature_min_frames: %s" % self.params.feature_min_frames,
|
||||
"processes: %s" % self.params.processes,
|
||||
"matching_gps_neighbors: %s" % self.params.matching_gps_neighbors
|
||||
]
|
||||
|
||||
# Configure OpenSfM
|
||||
config = [
|
||||
"use_exif_size: no",
|
||||
"feature_process_size: {}".format(jobOptions["resizeTo"]),
|
||||
"feature_min_frames: {}".format(args.min_num_features),
|
||||
"processes: {}".format(CORES),
|
||||
]
|
||||
if args.matcher_preselect:
|
||||
config.append("matching_gps_neighbors: {}".format(args.matcher_k))
|
||||
# write config file
|
||||
config_filename = io.join_paths(project_path, 'config.yaml')
|
||||
with open(config_filename, 'w') as fout:
|
||||
fout.write("\n".join(config))
|
||||
|
||||
with open('opensfm/config.yaml', 'w') as fout:
|
||||
fout.write("\n".join(config))
|
||||
# Run OpenSfM reconstruction
|
||||
system.run('PYTHONPATH=%s %s/bin/run_all %s' %
|
||||
(context.pyopencv_path, context.opensfm_path, list_path))
|
||||
|
||||
print 'running import_bundler'
|
||||
# Convert bundler's input to opensfm
|
||||
run('PYTHONPATH={} "{}/bin/import_bundler" opensfm --list list.txt'.format(PYOPENCV_PATH, OPENSFM_PATH))
|
||||
# append reconstructions to output
|
||||
self.outputs.reconstructions = []
|
||||
|
||||
log.ODM_INFO('Running OMD OpenSfm Cell - Finished')
|
||||
|
||||
# Run OpenSfM reconstruction
|
||||
run('PYTHONPATH={} "{}/bin/run_all" opensfm'.format(PYOPENCV_PATH, OPENSFM_PATH))
|
||||
# # Convert back to bundler's format
|
||||
# run('PYTHONPATH={} "{}/bin/export_bundler" opensfm'.format(PYOPENCV_PATH, OPENSFM_PATH))
|
||||
#
|
||||
# bundler_to_pmvs("opensfm/bundle_r000.out")
|
||||
|
||||
# Convert back to bundler's format
|
||||
run('PYTHONPATH={} "{}/bin/export_bundler" opensfm'.format(PYOPENCV_PATH, OPENSFM_PATH))
|
||||
|
||||
bundler_to_pmvs("opensfm/bundle_r000.out")
|
||||
#########################################################################################
|
||||
|
||||
|
||||
class ODMLoadReconstructionCell(ecto.Cell):
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("project_path", "The directory to the images to load.", "")
|
||||
inputs.declare("photos", "Clusters output. list of ODMPhoto's", [])
|
||||
outputs.declare("reconstructions", "Clusters output. list of reconstructions", [])
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
log.ODM_INFO('Running OMD Load Reconstruction Cell')
|
||||
log.ODM_INFO('Running OMD Load Reconstruction Cell - Finished')
|
||||
|
||||
|
||||
#########################################################################################
|
||||
|
||||
|
||||
class ODMConvertToBundleCell(ecto.Cell):
|
||||
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("project_path", "The directory to the images to load.", "")
|
||||
inputs.declare("reconstructions", "The directory to the images to load.", "")
|
||||
outputs.declare("bundler_file_path", "The directory to the images to load.", "")
|
||||
|
||||
def process(self, inputs, outputs):
|
||||
|
||||
log.ODM_INFO('Running OMD Convert to Bundle Cell')
|
||||
|
||||
# get inputs
|
||||
reconstructions = self.inputs.reconstructions
|
||||
project_path = io.absolute_path_file(self.inputs.project_path)
|
||||
|
||||
# create file list directory
|
||||
list_path = io.join_paths(project_path, 'opensfm')
|
||||
bundler_path_file = io.join_paths(list_path, 'bundle_r000.out')
|
||||
|
||||
# Run OpenSfM reconstruction
|
||||
# system.run('PYTHONPATH=%s %s/bin/export_bundler %s' %
|
||||
# (context.pyopencv_path, context.opensfm_path, list_path))
|
||||
|
||||
system.run('PYTHONPATH=%s %s/bin/export_pmvs %s' %
|
||||
(context.pyopencv_path, context.opensfm_path, list_path))
|
||||
|
||||
# appends created file to output
|
||||
self.outputs.bundler_file_path = bundler_path_file
|
||||
|
||||
if io.file_exists(bundler_path_file):
|
||||
log.ODM_DEBUG('Bundler file created to: %s' % bundler_path_file)
|
||||
else:
|
||||
log.ODM_ERROR('Something went wrong when exporting to Bundler')
|
||||
return
|
||||
|
||||
log.ODM_INFO('Running OMD Convert to Bundle Cell - Finished')
|
||||
|
||||
if args.end_with != "bundler":
|
||||
cmvs()
|
|
@ -1,60 +1,67 @@
|
|||
import ecto
|
||||
import cv2
|
||||
import pyexiv2
|
||||
|
||||
from opendm import log
|
||||
from opendm import system
|
||||
from opendm import dataset
|
||||
from opendm import io
|
||||
|
||||
def resize(project_path, args, photos):
|
||||
class OMDResizeCell(ecto.Cell):
|
||||
def declare_params(self, params):
|
||||
params.declare("args", "The application arguments.", [])
|
||||
|
||||
log.ODM_INFO('Preparing images - %s' % project_path)
|
||||
def declare_io(self, params, inputs, outputs):
|
||||
inputs.declare("project_path", "Clusters output. list of tuples", [])
|
||||
inputs.declare("photos", "Clusters inputs. list of ODMPhoto's", [])
|
||||
outputs.declare("photos", "Clusters output. list of ODMPhoto's", [])
|
||||
|
||||
# check if we have input data
|
||||
if len(photos) == 0:
|
||||
log.ODM_WARNING('Photos array is empty - Proceed to load images')
|
||||
images_dir = dataset.join_paths(project_path, 'images')
|
||||
photos = dataset.load_dataset(images_dir, args)
|
||||
def process(self, inputs, outputs):
|
||||
# get parameters
|
||||
args = self.params.args
|
||||
# get inputs
|
||||
photos = inputs.photos
|
||||
project_path = inputs.project_path
|
||||
|
||||
# preconditions
|
||||
if len(photos) < 1:
|
||||
log.ODM_ERROR('Not enough photos in photos to resize')
|
||||
return False
|
||||
# preconditions
|
||||
if len(photos) < 1:
|
||||
log.ODM_ERROR('Not enough photos in photos to resize')
|
||||
else:
|
||||
# create working directory
|
||||
working_dir = io.join_paths(project_path, 'images_resize')
|
||||
system.mkdir_p(working_dir)
|
||||
|
||||
# create working directory
|
||||
working_dir = dataset.join_paths(project_path, 'images_resize')
|
||||
system.mkdir_p(working_dir)
|
||||
# loop over photos
|
||||
for photo in photos:
|
||||
try:
|
||||
# open and resize image with opencv
|
||||
img = cv2.imread(photo.path_file)
|
||||
# compute new size
|
||||
max_side = max(photo.width, photo.height)
|
||||
ratio = float(args['resize_to']) / float(max_side)
|
||||
img_r = cv2.resize(img, None, fx=ratio, fy=ratio)
|
||||
# write image with opencv
|
||||
new_path_file = io.join_paths(working_dir, photo.file_name)
|
||||
cv2.imwrite(new_path_file, img_r)
|
||||
# read metadata with pyexiv2
|
||||
old_meta = pyexiv2.ImageMetadata(photo.path_file)
|
||||
new_meta = pyexiv2.ImageMetadata(new_path_file)
|
||||
old_meta.read()
|
||||
new_meta.read()
|
||||
# copy metadata
|
||||
old_meta.copy(new_meta)
|
||||
new_meta.write()
|
||||
# log message
|
||||
log.ODM_DEBUG('Resized image %s | dimensions: %s' % \
|
||||
(photo.file_name, img_r.shape))
|
||||
|
||||
# loop over photos
|
||||
for photo in photos:
|
||||
try:
|
||||
# open and resize image with opencv
|
||||
img = cv2.imread(photo.path_file)
|
||||
# compute new size
|
||||
max_side = max(photo.width, photo.height)
|
||||
ratio = float(args['resize_to']) / float(max_side)
|
||||
img_r = cv2.resize(img, None, fx=ratio, fy=ratio)
|
||||
# write image with opencv
|
||||
new_path_file = dataset.join_paths(working_dir, photo.file_name)
|
||||
cv2.imwrite(new_path_file, img_r)
|
||||
# read metadata with pyexiv2
|
||||
old_meta = pyexiv2.ImageMetadata(photo.path_file)
|
||||
new_meta = pyexiv2.ImageMetadata(new_path_file)
|
||||
old_meta.read()
|
||||
new_meta.read()
|
||||
# copy metadata
|
||||
old_meta.copy(new_meta)
|
||||
new_meta.write()
|
||||
# log message
|
||||
log.ODM_DEBUG('Resized image %s | dimensions: %s' % \
|
||||
(photo.file_name, img_r.shape))
|
||||
# TODO(edgar): update photos array
|
||||
photos[photo] = datatypes.ODMPhoto(photo.path_file, args)
|
||||
|
||||
# TODO(edgar): update photos array
|
||||
except cv2.error as e:
|
||||
# something went wrong with this image
|
||||
log.ODM_ERROR('Could not resize image %s' % photo.file_name)
|
||||
log.ODM_ERROR('%s' % e)
|
||||
|
||||
except cv2.error as e:
|
||||
# something went wrong with this image
|
||||
log.ODM_ERROR('Could not resize image %s' % photo.file_name)
|
||||
log.ODM_ERROR('%s' % e)
|
||||
return False
|
||||
|
||||
log.ODM_INFO('Resized %s images' % len(photos))
|
||||
return True
|
||||
log.ODM_INFO('Resized %s images' % len(photos))
|
||||
# append photos to cell output
|
||||
outputs.photos = photos
|
Ładowanie…
Reference in New Issue