447 lines
21 KiB
Python
447 lines
21 KiB
Python
#!/usr/bin/python3
|
|
# -*- encoding: utf-8 -*-
|
|
#
|
|
# Created by @FlachyJoe
|
|
"""
|
|
This script is for an easy use of OpenMVG, COLMAP, and OpenMVS
|
|
|
|
usage: MvgMvs_Pipeline.py [-h] [--steps STEPS [STEPS ...]] [--preset PRESET]
|
|
[--0 0 [0 ...]] [--1 1 [1 ...]] [--2 2 [2 ...]]
|
|
[--3 3 [3 ...]] [--4 4 [4 ...]] [--5 5 [5 ...]]
|
|
[--6 6 [6 ...]] [--7 7 [7 ...]] [--8 8 [8 ...]]
|
|
[--9 9 [9 ...]] [--10 10 [10 ...]] [--11 11 [11 ...]]
|
|
[--12 12 [12 ...]] [--13 13 [13 ...]] [--14 14 [14 ...]]
|
|
[--15 15 [15 ...]] [--16 16 [16 ...]] [--17 17 [17 ...]]
|
|
[--18 18 [18 ...]] [--19 19 [19 ...]] [--20 20 [20 ...]]
|
|
[--21 21 [21 ...]] [--22 22 [22 ...]]
|
|
input_dir output_dir
|
|
|
|
Photogrammetry reconstruction with these steps:
|
|
0. Intrinsics analysis openMVG_main_SfMInit_ImageListing
|
|
1. Compute features openMVG_main_ComputeFeatures
|
|
2. Compute pairs openMVG_main_PairGenerator
|
|
3. Compute matches openMVG_main_ComputeMatches
|
|
4. Filter matches openMVG_main_GeometricFilter
|
|
5. Incremental reconstruction openMVG_main_SfM
|
|
6. Global reconstruction openMVG_main_SfM
|
|
7. Colorize Structure openMVG_main_ComputeSfM_DataColor
|
|
8. Structure from Known Poses openMVG_main_ComputeStructureFromKnownPoses
|
|
9. Colorized robust triangulation openMVG_main_ComputeSfM_DataColor
|
|
10. Control Points Registration ui_openMVG_control_points_registration
|
|
11. Export to openMVS openMVG_main_openMVG2openMVS
|
|
12. Feature Extractor colmap
|
|
13. Exhaustive Matcher colmap
|
|
14. Mapper colmap
|
|
15. Image Undistorter colmap
|
|
16. Export to openMVS InterfaceCOLMAP
|
|
17. Densify point-cloud DensifyPointCloud
|
|
18. Reconstruct the mesh ReconstructMesh
|
|
19. Refine the mesh RefineMesh
|
|
20. Texture the mesh TextureMesh
|
|
21. Estimate disparity-maps DensifyPointCloud
|
|
22. Fuse disparity-maps DensifyPointCloud
|
|
|
|
positional arguments:
|
|
input_dir the directory which contains the pictures set.
|
|
output_dir the directory which will contain the resulting files.
|
|
|
|
optional arguments:
|
|
-h, --help show this help message and exit
|
|
--steps STEPS [STEPS ...] steps to process
|
|
--preset PRESET steps list preset in
|
|
SEQUENTIAL = [0, 1, 2, 3, 4, 5, 11, 17, 18, 19, 20]
|
|
GLOBAL = [0, 1, 2, 3, 4, 6, 11, 17, 18, 19, 20]
|
|
MVG_SEQ = [0, 1, 2, 3, 4, 5, 7, 8, 9, 11]
|
|
MVG_GLOBAL = [0, 1, 2, 3, 4, 6, 7, 8, 9, 11]
|
|
COLMAP_MVS = [12, 13, 14, 15, 16, 17, 18, 19, 20]
|
|
COLMAP = [12, 13, 14, 15, 16]
|
|
MVS = [17, 18, 19, 20]
|
|
MVS_SGM = [21, 22]
|
|
default : SEQUENTIAL
|
|
|
|
Passthrough:
|
|
Option to be passed to command lines (remove - in front of option names)
|
|
e.g. --1 p ULTRA to use the ULTRA preset in openMVG_main_ComputeFeatures
|
|
For example, running the script
|
|
[MvgMvsPipeline.py input_dir output_dir --steps 0 1 2 3 4 5 11 17 18 20 --1 p HIGH n 8 --3 n HNSWL2]
|
|
[--steps 0 1 2 3 4 5 11 17 18 20] runs only the desired steps
|
|
[--1 p HIGH n 8] where --1 refer to openMVG_main_ComputeFeatures,
|
|
p refers to describerPreset option and set to HIGH, and n refers
|
|
to numThreads and set to 8. The second step (Compute matches),
|
|
[--3 n HNSWL2] where --3 refer to openMVG_main_ComputeMatches,
|
|
n refers to nearest_matching_method option and set to HNSWL2
|
|
"""
|
|
|
|
import os
|
|
import subprocess
|
|
import sys
|
|
import argparse
|
|
|
|
# Enable debug mode conditionally
|
|
DEBUGDEBUG_MODE_ENABLED = False
|
|
|
|
# Define delimiters based on the operating system
|
|
PATH_DELIMITER = ';' if sys.platform.startswith('win') else ':'
|
|
FOLDER_DELIMITER = '\\' if sys.platform.startswith('win') else '/'
|
|
|
|
# Append the script's and current working directory's paths to the system PATH
|
|
script_directory = os.path.dirname(os.path.abspath(__file__))
|
|
|
|
# add this script's directory to PATH
|
|
os.environ['PATH'] += PATH_DELIMITER + script_directory
|
|
|
|
# add current directory to PATH
|
|
os.environ['PATH'] += PATH_DELIMITER + os.getcwd()
|
|
|
|
def locate_executable(afile):
|
|
"""
|
|
return directory in which afile is, None if not found. Look in PATH
|
|
Attempts to find the directory containing the executable specified by 'file_name'.
|
|
Uses 'where' command on Windows and 'which' on other platforms.
|
|
Returns the directory path if found, None otherwise.
|
|
"""
|
|
command = "where" if sys.platform.startswith('win') else "which"
|
|
try:
|
|
process_result = subprocess.run([command, afile], stdout=subprocess.PIPE, stderr=subprocess.STDOUT, check=True)
|
|
return os.path.split(process_result.stdout.decode())[0]
|
|
except subprocess.CalledProcessError:
|
|
return None
|
|
|
|
|
|
def find_file_in_path(afile):
|
|
"""
|
|
As whereis look only for executable on linux, this find look for all file type
|
|
Searches for 'file_name' in all directories specified in the PATH environment variable.
|
|
Returns the first directory containing the file, or None if not found.
|
|
"""
|
|
for directory in os.environ['PATH'].split(PATH_DELIMITER):
|
|
if os.path.isfile(os.path.join(directory, afile)):
|
|
return directory
|
|
return None
|
|
|
|
|
|
# Attempt to locate binaries for specific software tools
|
|
openMVG_binary = locate_executable("openMVG_main_SfMInit_ImageListing")
|
|
colmap_binary = locate_executable("colmap")
|
|
openMVS_binary = locate_executable("ReconstructMesh")
|
|
|
|
# Try to find openMVG camera sensor database
|
|
camera_sensor_db_file = "sensor_width_camera_database.txt"
|
|
camera_sensor_db_directory = find_file_in_path(camera_sensor_db_file)
|
|
|
|
# Prompt user for directories if software binaries or database files weren't found
|
|
if not openMVG_binary:
|
|
openMVG_binary = input("Directory for openMVG binaries?\n")
|
|
if not colmap_binary:
|
|
colmap_binary = input("Directory for COLMAP binaries?\n")
|
|
if not openMVS_binary:
|
|
openMVS_binary = input("Directory for openMVS binaries?\n")
|
|
if not camera_sensor_db_directory:
|
|
camera_sensor_db_directory = input(f"Directory for the openMVG camera database ({camera_sensor_db_file})?\n")
|
|
|
|
colmap_binary = os.path.join(colmap_binary, "colmap")
|
|
# Adjust the binary name for COLMAP on Windows
|
|
if sys.platform.startswith('win'):
|
|
colmap_binary += ".bat"
|
|
|
|
# Define presets for various software tools
|
|
SOFTWARE_PRESETS = {'SEQUENTIAL': [0, 1, 2, 3, 4, 5, 11, 17, 18, 19, 20],
|
|
'GLOBAL': [0, 1, 2, 3, 4, 6, 11, 17, 18, 19, 20],
|
|
'MVG_SEQ': [0, 1, 2, 3, 4, 5, 7, 8, 9, 11],
|
|
'MVG_GLOBAL': [0, 1, 2, 3, 4, 6, 7, 8, 9, 11],
|
|
'COLMAP_MVS': [12, 13, 14, 15, 16, 17, 18, 19, 20],
|
|
'COLMAP': [12, 13, 14, 15, 16],
|
|
'MVS': [17, 18, 19, 20],
|
|
'MVS_SGM': [21, 22],
|
|
'TEXTURE': [20]}
|
|
|
|
# Default preset selection
|
|
PRESET_DEFAULT = 'COLMAP'
|
|
|
|
# HELPERS for terminal colors
|
|
BLACK, RED, GREEN, YELLOW, BLUE, MAGENTA, CYAN, WHITE = range(8)
|
|
NO_EFFECT, BOLD, UNDERLINE, BLINK, INVERSE, HIDDEN = (0, 1, 4, 5, 7, 8)
|
|
|
|
|
|
# from Python cookbook, #475186
|
|
def has_colors(stream):
|
|
'''
|
|
Return stream colours capability
|
|
Checks if the given stream supports colors.
|
|
Returns True if it does, False otherwise.
|
|
'''
|
|
if not hasattr(stream, "isatty"):
|
|
return False
|
|
if not stream.isatty():
|
|
return False # auto color only on TTYs
|
|
try:
|
|
import curses
|
|
curses.setupterm()
|
|
return curses.tigetnum("colors") > 2
|
|
except Exception:
|
|
# guess false in case of error
|
|
return False
|
|
|
|
HAS_COLORS = has_colors(sys.stdout)
|
|
|
|
|
|
def printout(text, colour=WHITE, background=BLACK, effect=NO_EFFECT):
|
|
"""
|
|
print() with colour
|
|
"""
|
|
if HAS_COLORS:
|
|
seq = "\x1b[%d;%d;%dm" % (effect, 30+colour, 40+background) + text + "\x1b[0m"
|
|
sys.stdout.write(seq+'\r\n')
|
|
else:
|
|
sys.stdout.write(text+'\r\n')
|
|
|
|
|
|
# OBJECTS to store config and data in
|
|
class ConfigContainer:
|
|
"""
|
|
Container for storing configuration variables.
|
|
"""
|
|
def __init__(self):
|
|
pass
|
|
|
|
|
|
class ProcessStep:
|
|
"""
|
|
Represents a step in the processing pipeline, storing necessary information to execute it.
|
|
"""
|
|
def __init__(self, description, command, options):
|
|
self.info = description
|
|
self.cmd = command
|
|
self.opt = options
|
|
|
|
|
|
class StepsStore:
|
|
""" List of steps with facilities to configure them """
|
|
def __init__(self):
|
|
self.steps_data = [
|
|
["Intrinsics analysis", # 0
|
|
os.path.join(openMVG_binary, "openMVG_main_SfMInit_ImageListing"),
|
|
["-i", "%input_dir%", "-o", "%matches_dir%", "-d", "%camera_file_params%"]],
|
|
["Compute features", # 1
|
|
os.path.join(openMVG_binary, "openMVG_main_ComputeFeatures"),
|
|
["-i", "%matches_dir%"+FOLDER_DELIMITER+"sfm_data.json", "-o", "%matches_dir%", "-m", "SIFT"]],
|
|
["Compute pairs", # 2
|
|
os.path.join(openMVG_binary, "openMVG_main_PairGenerator"),
|
|
["-i", "%matches_dir%"+FOLDER_DELIMITER+"sfm_data.json", "-o", "%matches_dir%"+FOLDER_DELIMITER+"pairs.bin"]],
|
|
["Compute matches", # 3
|
|
os.path.join(openMVG_binary, "openMVG_main_ComputeMatches"),
|
|
["-i", "%matches_dir%"+FOLDER_DELIMITER+"sfm_data.json", "-p", "%matches_dir%"+FOLDER_DELIMITER+"pairs.bin", "-o", "%matches_dir%"+FOLDER_DELIMITER+"matches.putative.bin", "-n", "AUTO"]],
|
|
["Filter matches", # 4
|
|
os.path.join(openMVG_binary, "openMVG_main_GeometricFilter"),
|
|
["-i", "%matches_dir%"+FOLDER_DELIMITER+"sfm_data.json", "-m", "%matches_dir%"+FOLDER_DELIMITER+"matches.putative.bin", "-o", "%matches_dir%"+FOLDER_DELIMITER+"matches.f.bin"]],
|
|
["Incremental reconstruction", # 5
|
|
os.path.join(openMVG_binary, "openMVG_main_SfM"),
|
|
["-i", "%matches_dir%"+FOLDER_DELIMITER+"sfm_data.json", "-m", "%matches_dir%", "-o", "%reconstruction_dir%", "-s", "INCREMENTAL"]],
|
|
["Global reconstruction", # 6
|
|
os.path.join(openMVG_binary, "openMVG_main_SfM"),
|
|
["-i", "%matches_dir%"+FOLDER_DELIMITER+"sfm_data.json", "-m", "%matches_dir%", "-o", "%reconstruction_dir%", "-s", "GLOBAL", "-M", "%matches_dir%"+FOLDER_DELIMITER+"matches.e.bin"]],
|
|
["Colorize Structure", # 7
|
|
os.path.join(openMVG_binary, "openMVG_main_ComputeSfM_DataColor"),
|
|
["-i", "%reconstruction_dir%"+FOLDER_DELIMITER+"sfm_data.bin", "-o", "%reconstruction_dir%"+FOLDER_DELIMITER+"colorized.ply"]],
|
|
["Structure from Known Poses", # 8
|
|
os.path.join(openMVG_binary, "openMVG_main_ComputeStructureFromKnownPoses"),
|
|
["-i", "%reconstruction_dir%"+FOLDER_DELIMITER+"sfm_data.bin", "-m", "%matches_dir%", "-f", "%matches_dir%"+FOLDER_DELIMITER+"matches.f.bin", "-o", "%reconstruction_dir%"+FOLDER_DELIMITER+"robust.bin"]],
|
|
["Colorized robust triangulation", # 9
|
|
os.path.join(openMVG_binary, "openMVG_main_ComputeSfM_DataColor"),
|
|
["-i", "%reconstruction_dir%"+FOLDER_DELIMITER+"robust.bin", "-o", "%reconstruction_dir%"+FOLDER_DELIMITER+"robust_colorized.ply"]],
|
|
["Control Points Registration", # 10
|
|
os.path.join(openMVG_binary, "ui_openMVG_control_points_registration"),
|
|
["-i", "%reconstruction_dir%"+FOLDER_DELIMITER+"sfm_data.bin"]],
|
|
["Export to openMVS", # 11
|
|
os.path.join(openMVG_binary, "openMVG_main_openMVG2openMVS"),
|
|
["-i", "%reconstruction_dir%"+FOLDER_DELIMITER+"sfm_data.bin", "-o", "%mvs_dir%"+FOLDER_DELIMITER+"scene.mvs", "-d", "%mvs_dir%"+FOLDER_DELIMITER+"images"]],
|
|
["Feature Extractor", # 12
|
|
colmap_binary,
|
|
["feature_extractor", "--database_path", "%matches_dir%"+FOLDER_DELIMITER+"database.db", "--image_path", "%input_dir%"]],
|
|
["Exhaustive Matcher", # 13
|
|
colmap_binary,
|
|
["exhaustive_matcher", "--database_path", "%matches_dir%"+FOLDER_DELIMITER+"database.db"]],
|
|
["Mapper", # 14
|
|
colmap_binary,
|
|
["mapper", "--database_path", "%matches_dir%"+FOLDER_DELIMITER+"database.db", "--image_path", "%input_dir%", "--output_path", "%reconstruction_dir%"]],
|
|
["Image Undistorter", # 15
|
|
colmap_binary,
|
|
["image_undistorter", "--image_path", "%input_dir%", "--input_path", "%reconstruction_dir%"+FOLDER_DELIMITER+"0", "--output_path", "%reconstruction_dir%"+FOLDER_DELIMITER+"dense", "--output_type", "COLMAP"]],
|
|
["Export to openMVS", # 16
|
|
os.path.join(openMVS_binary, "InterfaceCOLMAP"),
|
|
["-i", "%reconstruction_dir%"+FOLDER_DELIMITER+"dense", "-o", "scene.mvs", "--image-folder", "%reconstruction_dir%"+FOLDER_DELIMITER+"dense"+FOLDER_DELIMITER+"images", "-w", "\"%mvs_dir%\""]],
|
|
["Densify point cloud", # 17
|
|
os.path.join(openMVS_binary, "DensifyPointCloud"),
|
|
["scene.mvs", "--dense-config-file", "Densify.ini", "--resolution-level", "1", "--number-views", "8", "-w", "\"%mvs_dir%\""]],
|
|
["Reconstruct the mesh", # 18
|
|
os.path.join(openMVS_binary, "ReconstructMesh"),
|
|
["scene_dense.mvs", "-p", "scene_dense.ply", "-w", "\"%mvs_dir%\""]],
|
|
["Refine the mesh", # 19
|
|
os.path.join(openMVS_binary, "RefineMesh"),
|
|
["scene_dense.mvs", "-m", "scene_dense_mesh.ply", "-o", "scene_dense_mesh_refine.mvs", "--scales", "1", "--gradient-step", "25.05", "-w", "\"%mvs_dir%\""]],
|
|
["Texture the mesh", # 20
|
|
os.path.join(openMVS_binary, "TextureMesh"),
|
|
["scene_dense.mvs", "-m", "scene_dense_mesh_refine.ply", "-o", "scene_dense_mesh_refine_texture.mvs", "--decimate", "0.5", "-w", "\"%mvs_dir%\""]],
|
|
["Estimate disparity-maps", # 21
|
|
os.path.join(openMVS_binary, "DensifyPointCloud"),
|
|
["scene.mvs", "--dense-config-file", "Densify.ini", "--fusion-mode", "-1", "-w", "\"%mvs_dir%\""]],
|
|
["Fuse disparity-maps", # 22
|
|
os.path.join(openMVS_binary, "DensifyPointCloud"),
|
|
["scene.mvs", "--dense-config-file", "Densify.ini", "--fusion-mode", "-2", "-w", "\"%mvs_dir%\""]]
|
|
]
|
|
|
|
def __getitem__(self, indice):
|
|
return ProcessStep(*self.steps_data[indice])
|
|
|
|
def length(self):
|
|
return len(self.steps_data)
|
|
|
|
def configure_steps(self, conf):
|
|
""" replace each %var% per conf.var value in steps data """
|
|
for step in self.steps_data:
|
|
updated_options = []
|
|
for option in step[2]:
|
|
configured_option = option.replace("%input_dir%", conf.input_dir)
|
|
configured_option = configured_option.replace("%output_dir%", conf.output_dir)
|
|
configured_option = configured_option.replace("%matches_dir%", conf.matches_dir)
|
|
configured_option = configured_option.replace("%reconstruction_dir%", conf.reconstruction_dir)
|
|
configured_option = configured_option.replace("%mvs_dir%", conf.mvs_dir)
|
|
configured_option = configured_option.replace("%camera_file_params%", conf.camera_file_params)
|
|
updated_options.append(configured_option)
|
|
step[2] = updated_options
|
|
|
|
def replace_option(self, idx, str_exist, str_new):
|
|
""" replace each existing str_exist with str_new per opt value in step idx data """
|
|
step = self.steps_data[idx]
|
|
updated_options = []
|
|
for option in step[2]:
|
|
configured_option = option.replace(str_exist, str_new)
|
|
updated_options.append(configured_option)
|
|
step[2] = updated_options
|
|
|
|
|
|
CONF = ConfigContainer()
|
|
STEPS = StepsStore()
|
|
|
|
# ARGS
|
|
PARSER = argparse.ArgumentParser(
|
|
formatter_class=argparse.RawTextHelpFormatter,
|
|
description="Photogrammetry reconstruction with these steps: \r\n" +
|
|
"\r\n".join(("\t%i. %s\t %s" % (t, STEPS[t].info, STEPS[t].cmd) for t in range(STEPS.length())))
|
|
)
|
|
PARSER.add_argument('input_dir',
|
|
help="the directory which contains the pictures set.")
|
|
PARSER.add_argument('output_dir',
|
|
help="the directory which will contain the resulting files.")
|
|
PARSER.add_argument('--steps',
|
|
type=int,
|
|
nargs="+",
|
|
help="Specify steps to process by index.")
|
|
PARSER.add_argument('--preset',
|
|
help="steps list preset in \r\n" +
|
|
" \r\n".join([k + " = " + str(SOFTWARE_PRESETS[k]) for k in SOFTWARE_PRESETS]) +
|
|
" \r\ndefault : " + PRESET_DEFAULT)
|
|
|
|
GROUP = PARSER.add_argument_group('Passthrough', description="Option to be passed to command lines (remove - in front of option names)\r\ne.g. --1 p ULTRA to use the ULTRA preset in openMVG_main_ComputeFeatures\r\nFor example, running the script as follows,\r\nMvgMvsPipeline.py input_dir output_dir --1 p HIGH n 8 --3 n ANNL2\r\nwhere --1 refer to openMVG_main_ComputeFeatures, p refers to\r\ndescriberPreset option which HIGH was chosen, and n refers to\r\nnumThreads which 8 was used. --3 refer to second step (openMVG_main_ComputeMatches),\r\nn refers to nearest_matching_method option which ANNL2 was chosen")
|
|
for n in range(STEPS.length()):
|
|
GROUP.add_argument('--'+str(n), nargs='+')
|
|
|
|
PARSER.parse_args(namespace=CONF) # store args in the ConfContainer
|
|
|
|
|
|
# FOLDERS
|
|
# Method to ensure a directory exists; creates it if it does not
|
|
def ensure_directory_exists(dirname):
|
|
"""Create the folder if not presents"""
|
|
if not os.path.exists(dirname):
|
|
os.mkdir(dirname)
|
|
|
|
|
|
# Absolute path for input and output dirs
|
|
CONF.input_dir = os.path.abspath(CONF.input_dir)
|
|
CONF.output_dir = os.path.abspath(CONF.output_dir)
|
|
|
|
if not os.path.exists(CONF.input_dir):
|
|
sys.exit("%s: path not found" % CONF.input_dir)
|
|
|
|
CONF.reconstruction_dir = os.path.join(CONF.output_dir, "sfm")
|
|
CONF.matches_dir = os.path.join(CONF.reconstruction_dir, "matches")
|
|
CONF.mvs_dir = os.path.join(CONF.output_dir, "mvs")
|
|
CONF.camera_file_params = os.path.join(camera_sensor_db_directory, camera_sensor_db_file)
|
|
|
|
ensure_directory_exists(CONF.output_dir)
|
|
ensure_directory_exists(CONF.reconstruction_dir)
|
|
ensure_directory_exists(CONF.matches_dir)
|
|
ensure_directory_exists(CONF.mvs_dir)
|
|
|
|
# Update directories in steps commandlines
|
|
STEPS.configure_steps(CONF)
|
|
|
|
# PRESET
|
|
if CONF.steps and CONF.preset:
|
|
sys.exit("Steps and preset arguments can't be set together.")
|
|
elif CONF.preset:
|
|
try:
|
|
CONF.steps = SOFTWARE_PRESETS[CONF.preset]
|
|
except KeyError:
|
|
sys.exit("Unknown preset %s, choose %s" % (CONF.preset, ' or '.join([s for s in SOFTWARE_PRESETS])))
|
|
elif not CONF.steps:
|
|
CONF.steps = SOFTWARE_PRESETS[PRESET_DEFAULT]
|
|
|
|
# WALK
|
|
print("# Using input dir: %s" % CONF.input_dir)
|
|
print("# output dir: %s" % CONF.output_dir)
|
|
print("# Steps: %s" % str(CONF.steps))
|
|
|
|
if 4 in CONF.steps: # GeometricFilter
|
|
if 6 in CONF.steps: # GlobalReconstruction
|
|
# Set the geometric_model of ComputeMatches to Essential
|
|
STEPS.replace_option(4, FOLDER_DELIMITER+"matches.f.bin", FOLDER_DELIMITER+"matches.e.bin")
|
|
STEPS[4].opt.extend(["-g", "e"])
|
|
|
|
if 20 in CONF.steps: # TextureMesh
|
|
if 19 not in CONF.steps: # RefineMesh
|
|
# RefineMesh step is not run, use ReconstructMesh output
|
|
STEPS.replace_option(20, "scene_dense_mesh_refine.ply", "scene_dense_mesh.ply")
|
|
STEPS.replace_option(20, "scene_dense_mesh_refine_texture.mvs", "scene_dense_mesh_texture.mvs")
|
|
|
|
for cstep in CONF.steps:
|
|
printout("#%i. %s" % (cstep, STEPS[cstep].info), effect=INVERSE)
|
|
|
|
# Retrieve "passthrough" commandline options
|
|
options = getattr(CONF, str(cstep))
|
|
if options:
|
|
# add - sign to short options and -- to long ones
|
|
for o in range(0, len(options), 2):
|
|
if len(options[o]) > 1:
|
|
options[o] = '-' + options[o]
|
|
options[o] = '-' + options[o]
|
|
else:
|
|
options = []
|
|
|
|
# Remove STEPS[cstep].opt options now defined in opt
|
|
for anOpt in STEPS[cstep].opt:
|
|
if anOpt in options:
|
|
idx = STEPS[cstep].opt.index(anOpt)
|
|
if DEBUGDEBUG_MODE_ENABLED:
|
|
print('#\tRemove ' + str(anOpt) + ' from defaults options at id ' + str(idx))
|
|
del STEPS[cstep].opt[idx:idx+2]
|
|
|
|
# create a commandline for the current step
|
|
cmdline = [STEPS[cstep].cmd] + STEPS[cstep].opt + options
|
|
print('CMD: ' + ' '.join(cmdline))
|
|
|
|
if not DEBUGDEBUG_MODE_ENABLED:
|
|
# Launch the current step
|
|
try:
|
|
pStep = subprocess.Popen(cmdline)
|
|
pStep.wait()
|
|
if pStep.returncode != 0:
|
|
break
|
|
except KeyboardInterrupt:
|
|
sys.exit('\r\nProcess canceled by user, all files remains')
|
|
else:
|
|
print('\t'.join(cmdline))
|
|
|
|
printout("# Pipeline end #", effect=INVERSE)
|