From 851ffa31f7d2a41a46e308733cff63bccfe43203 Mon Sep 17 00:00:00 2001 From: Fabien Castan Date: Wed, 20 Sep 2017 00:56:04 +0200 Subject: [PATCH] nodes: add first steps of the pipeline --- meshroom/nodes/CameraInit.py | 116 ++++++++++++++++ meshroom/nodes/FeatureExtraction.py | 70 ++++++++++ meshroom/nodes/FeatureMatching.py | 187 ++++++++++++++++++++++++++ meshroom/nodes/ImageMatching.py | 55 ++++++++ meshroom/nodes/StructureFromMotion.py | 133 ++++++++++++++++++ 5 files changed, 561 insertions(+) create mode 100644 meshroom/nodes/CameraInit.py create mode 100644 meshroom/nodes/FeatureExtraction.py create mode 100644 meshroom/nodes/FeatureMatching.py create mode 100644 meshroom/nodes/ImageMatching.py create mode 100644 meshroom/nodes/StructureFromMotion.py diff --git a/meshroom/nodes/CameraInit.py b/meshroom/nodes/CameraInit.py new file mode 100644 index 00000000..611dc96e --- /dev/null +++ b/meshroom/nodes/CameraInit.py @@ -0,0 +1,116 @@ + +from meshroom.processGraph import desc + +class CameraInit(desc.CommandLineNode): + internalFolder = '{cache}/{nodeType}/{uid0}/' + commandLine = 'openMVG_main_SfMInit_ImageListing {allParams}' + + imageDirectory = desc.ParamAttribute( + label='Image Directory', + description='''''', + value='', + shortName='i', + arg='', + uid=[0], + isOutput=False, + ) + jsonFile = desc.FileAttribute( + label='Json File', + description='''Input file with all the user options. It can be used to provide a list of images instead of a directory.''', + value='', + shortName='j', + arg='', + uid=[0], + isOutput=False, + ) + sensorWidthDatabase = desc.ParamAttribute( + label='Sensor Width Database', + description='''''', + value='', + shortName='d', + arg='', + uid=[0], + isOutput=False, + ) + outputDirectory = desc.ParamAttribute( + label='Output Directory', + description='''''', + value='{cache}/{nodeType}/{uid0}/', + shortName='o', + arg='', + uid=[0], + isOutput=True, + ) + outputSfm = desc.ParamAttribute( # not command line + label='Output SfM', + description='''''', + value='{cache}/{nodeType}/{uid0}/sfm_data.json', + shortName='o', + arg='', + uid=[0], + isOutput=True, + group='', + ) + focal = desc.ParamAttribute( + label='Focal', + description='''(pixels)''', + value='', + shortName='f', + arg='', + uid=[0], + isOutput=False, + ) + sensorWidth = desc.ParamAttribute( + label='Sensor Width', + description='''(mm)''', + value='', + shortName='s', + arg='', + uid=[0], + isOutput=False, + ) + intrinsics = desc.ParamAttribute( + label='Intrinsics', + description='''Kmatrix: "f;0;ppx;0;f;ppy;0;0;1"''', + value='', + shortName='k', + arg='', + uid=[0], + isOutput=False, + ) + camera_model = desc.ParamAttribute( + label='Camera Model', + description='''Camera model type (pinhole, radial1, radial3, brown or fisheye4)''', + value='', + shortName='c', + arg='', + uid=[0], + isOutput=False, + ) + group_camera_model = desc.FileAttribute( + label='Group Camera Model', + description='''0-> each view have its own camera intrinsic parameters, 1-> (default) view share camera intrinsic parameters based on metadata, if no metadata each view has its own camera intrinsic parameters 2-> view share camera intrinsic parameters based on metadata, if no metadata they are grouped by folder''', + value='', + shortName='g', + arg='', + uid=[0], + isOutput=False, + ) + use_UID = desc.ParamAttribute( + label='Use U I D', + description='''Generate a UID (unique identifier) for each view. By default, the key is the image index.''', + value='', + shortName='u', + arg='', + uid=[0], + isOutput=False, + ) + storeMetadata = desc.ParamAttribute( + label='Store Metadata', + description='''Store image metadata in the sfm data Unrecognized option --help''', + value='', + shortName='m', + arg='', + uid=[0], + isOutput=False, + ) \ No newline at end of file diff --git a/meshroom/nodes/FeatureExtraction.py b/meshroom/nodes/FeatureExtraction.py new file mode 100644 index 00000000..bf89ddb7 --- /dev/null +++ b/meshroom/nodes/FeatureExtraction.py @@ -0,0 +1,70 @@ + +from meshroom.processGraph import desc + +class FeatureExtraction(desc.CommandLineNode): + internalFolder = '{cache}/{nodeType}/{uid0}/' + commandLine = 'openMVG_main_ComputeFeatures {allParams}' + + input_file = desc.FileAttribute( + label='Input File', + description='''a SfM_Data file''', + value='', + shortName='i', + arg='', + uid=[0], + isOutput=False, + ) + outdir = desc.FileAttribute( + label='Outdir', + description='''output path for the features and descriptors files (*.feat, *.desc) [Optional]''', + value='{cache}/{nodeType}/{uid0}/', + shortName='o', + arg='path', + uid=[0], + isOutput=True, + ) + force = desc.ParamAttribute( + label='Force', + description='''Force to recompute data''', + value='', + shortName='f', + arg='', + uid=[0], + isOutput=False, + ) + describerMethods = desc.ParamAttribute( + label='Describer Methods', + description='''(methods to use to describe an image): SIFT (default), SIFT_FLOAT to use SIFT stored as float, AKAZE: AKAZE with floating point descriptors, AKAZE_MLDB: AKAZE with binary descriptors''', + value='', + shortName='m', + arg='', + uid=[0], + isOutput=False, + ) + upright = desc.ParamAttribute( + label='Upright', + description='''Use Upright feature 0 or 1''', + value='', + shortName='u', + arg='', + uid=[0], + isOutput=False, + ) + describerPreset = desc.ParamAttribute( + label='Describer Preset', + description='''(used to control the Image_describer configuration): LOW, MEDIUM, NORMAL (default), HIGH, ULTRA: !!Can take long time!!''', + value='', + shortName='p', + arg='', + uid=[0], + isOutput=False, + ) + jobs = desc.ParamAttribute( + label='Jobs', + description='''Specifies the number of jobs to run simultaneously. Use -j 0 for automatic mode. Unrecognized option --help''', + value='', + shortName='j', + arg='', + uid=[0], + isOutput=False, + ) \ No newline at end of file diff --git a/meshroom/nodes/FeatureMatching.py b/meshroom/nodes/FeatureMatching.py new file mode 100644 index 00000000..45028a73 --- /dev/null +++ b/meshroom/nodes/FeatureMatching.py @@ -0,0 +1,187 @@ + +from meshroom.processGraph import desc + +class FeatureMatching(desc.CommandLineNode): + internalFolder = '{cache}/{nodeType}/{uid0}/' + commandLine = 'openMVG_main_ComputeMatches {allParams}' + + input_file = desc.FileAttribute( + label='Input File', + description='''a SfM_Data file''', + value='', + shortName='i', + arg='', + uid=[0], + isOutput=False, + ) + out_dir = desc.FileAttribute( + label='Out Dir', + description='''path to directory in which computed matches will be stored [Optional]''', + value='{cache}/{nodeType}/{uid0}/', + shortName='o', + arg='path', + uid=[0], + isOutput=True, + ) + describerMethods = desc.ParamAttribute( + label='Describer Methods', + description='''(methods to use to describe an image): SIFT (default), SIFT_FLOAT to use SIFT stored as float, AKAZE: AKAZE with floating point descriptors, AKAZE_MLDB: AKAZE with binary descriptors use the found model to improve the pairwise correspondences.''', + value='', + shortName='m', + arg='', + uid=[0], + isOutput=False, + ) + featuresDir = desc.FileAttribute( + label='Features Dir', + description='''Path to directory containing the extracted features (default: $out_dir)''', + value='', + shortName='F', + arg='', + uid=[0], + isOutput=False, + ) + save_putative_matches = desc.ParamAttribute( + label='Save Putative Matches', + description='''Save putative matches''', + value='', + shortName='p', + arg='', + uid=[0], + isOutput=False, + ) + ratio = desc.ParamAttribute( + label='Ratio', + description='''Distance ratio to discard non meaningful matches 0.8: (default).''', + value='', + shortName='r', + arg='', + uid=[0], + isOutput=False, + ) + geometric_model = desc.ParamAttribute( + label='Geometric Model', + description='''(pairwise correspondences filtering thanks to robust model estimation): f: (default) fundamental matrix, e: essential matrix, h: homography matrix.''', + value='', + shortName='g', + arg='', + uid=[0], + isOutput=False, + ) + video_mode_matching = desc.ParamAttribute( + label='Video Mode Matching', + description='''(sequence matching with an overlap of X images) X: with match 0 with (1->X), ...] 2: will match 0 with (1,2), 1 with (2,3), ... 3: will match 0 with (1,2,3), 1 with (2,3,4), ...''', + value='', + shortName='v', + arg='', + uid=[0], + isOutput=False, + ) + pair_list = desc.FileAttribute( + label='Pair List', + description='''filepath A file which contains the list of matches to perform.''', + value='', + shortName='l', + arg='', + uid=[0], + isOutput=False, + ) + range_start = desc.ParamAttribute( + label='Range Start', + description='''range image index start To compute only the matches for specified range. This allows to compute different matches on different computers in parallel.''', + value='', + shortName='s', + arg='', + uid=[0], + isOutput=False, + ) + range_size = desc.ParamAttribute( + label='Range Size', + description='''range size To compute only the matches for specified range. This allows to compute different matches on different computers in parallel.''', + value='', + shortName='d', + arg='', + uid=[0], + isOutput=False, + ) + nearest_matching_method = desc.ParamAttribute( + label='Nearest Matching Method', + description='''For Scalar based regions descriptor: BRUTE_FORCE_L2: L2 BruteForce matching, ANN_L2: L2 Approximate Nearest Neighbor matching (default), CASCADE_HASHING_L2: L2 Cascade Hashing matching. FAST_CASCADE_HASHING_L2: L2 Cascade Hashing with precomputed hashed regions (faster than CASCADE_HASHING_L2 but use more memory). For Binary based descriptor: BRUTE_FORCE_HAMMING: BruteForce Hamming matching.''', + value='', + shortName='n', + arg='', + uid=[0], + isOutput=False, + ) + geometricEstimator = desc.ParamAttribute( + label='Geometric Estimator', + description='''Geometric estimator acransac: A-Contrario Ransac (default), loransac: LO-Ransac (only available for fundamental matrix)''', + value='', + shortName='G', + arg='', + uid=[0], + isOutput=False, + ) + guided_matching = desc.ParamAttribute( + label='Guided Matching', + description='''use the found model to improve the pairwise correspondences.''', + value='', + shortName='M', + arg='', + uid=[0], + isOutput=False, + ) + max_iteration = desc.ParamAttribute( + label='Max Iteration', + description='''number of maximum iterations allowed in ransac step.''', + value='', + shortName='I', + arg='', + uid=[0], + isOutput=False, + ) + match_file_per_image = desc.FileAttribute( + label='Match File Per Image', + description='''Save matches in a separate file per image''', + value='', + shortName='x', + arg='', + uid=[0], + isOutput=False, + ) + max_matches = desc.ParamAttribute( + label='Max Matches', + description='''''', + value='', + shortName='u', + arg='', + uid=[0], + isOutput=False, + ) + use_grid_sort = desc.ParamAttribute( + label='Use Grid Sort', + description='''Use matching grid sort''', + value='', + shortName='y', + arg='', + uid=[0], + isOutput=False, + ) + export_debug_files = desc.FileAttribute( + label='Export Debug Files', + description='''Export debug files (svg, dot)''', + value='', + shortName='e', + arg='', + uid=[0], + isOutput=False, + ) + fileExtension = desc.FileAttribute( + label='File Extension', + description='''File extension to store matches: bin (default), txt Unrecognized option --help''', + value='', + shortName='t', + arg='', + uid=[0], + isOutput=False, + ) \ No newline at end of file diff --git a/meshroom/nodes/ImageMatching.py b/meshroom/nodes/ImageMatching.py new file mode 100644 index 00000000..ac97404c --- /dev/null +++ b/meshroom/nodes/ImageMatching.py @@ -0,0 +1,55 @@ + +from meshroom.processGraph import desc + +class ImageMatching(desc.CommandLineNode): + internalFolder = '{cache}/{nodeType}/{uid0}/' + commandLine = 'openMVG_main_generatePairList {allParams}' + + verbose = desc.ParamAttribute( + label='Verbose', + description='''Verbosity level, 0 to mute.''', + value=1, + shortName='v', + arg='arg', + uid=[0], + ) + weights = desc.FileAttribute( + label='Weights', + description='''Input name for the weight file, if not provided the weights will be computed on the database built with the provided set.''', + value='', + shortName='w', + arg='arg', + uid=[0], + ) + tree = desc.FileAttribute( + label='Tree', + description='''Input name for the tree file''', + value='', + shortName='t', + arg='arg', + uid=[0], + ) + keylist = desc.FileAttribute( + label='Keylist', + description='''Path to the list file (list.txt or sfm_data) generated by OpenMVG or the path to a directory containing the descriptors.''', + value='', + shortName='l', + arg='arg', + uid=[0], + ) + nbMaxDescriptors = desc.ParamAttribute( + label='Nb Max Descriptors', + description='''Limit the number of descriptors you load per image. Zero means no limit.''', + value=0, + shortName='m', + arg='arg', + uid=[0], + ) + outfile = desc.FileAttribute( + label='Outfile', + description='''(=pairList.txt) Name of the output file.''', + value='', + shortName='o', + arg='arg', + uid=[0], + ) \ No newline at end of file diff --git a/meshroom/nodes/StructureFromMotion.py b/meshroom/nodes/StructureFromMotion.py new file mode 100644 index 00000000..0d9aef09 --- /dev/null +++ b/meshroom/nodes/StructureFromMotion.py @@ -0,0 +1,133 @@ + +from meshroom.processGraph import desc + +class StructureFromMotion(desc.CommandLineNode): + internalFolder = '{cache}/{nodeType}/{uid0}/' + commandLine = 'openMVG_main_IncrementalSfM {allParams}' + + input_file = desc.FileAttribute( + label='Input File', + description='''path to a SfM_Data scene''', + value='', + shortName='i', + arg='', + uid=[0], + isOutput=False, + ) + describerMethods = desc.ParamAttribute( + label='Describer Methods', + description='''(methods to use to describe an image): SIFT (default), SIFT_FLOAT to use SIFT stored as float, AKAZE: AKAZE with floating point descriptors, AKAZE_MLDB: AKAZE with binary descriptors''', + value='SIFT', + shortName='d', + arg='', + uid=[0], + isOutput=False, + ) + matchdir = desc.FileAttribute( + label='Matchdir', + description='''path to the matches that corresponds to the provided SfM_Data scene''', + value='', + shortName='m', + arg='', + uid=[0], + isOutput=False, + ) + featuresDir = desc.FileAttribute( + label='Features Dir', + description='''path to directory containing the extracted features (default: $matchdir)''', + value='', + shortName='F', + arg='', + uid=[0], + isOutput=False, + ) + outdir = desc.FileAttribute( + label='Outdir', + description='''path where the output data will be stored''', + value='{cache}/{nodeType}/{uid0}/', + shortName='o', + arg='', + uid=[0], + isOutput=True, + ) + out_sfmdata_file = desc.FileAttribute( + label='Out Sfmdata File', + description='''path of the output sfmdata file (default: $outdir/sfm_data.json)''', + value='{cache}/{nodeType}/{uid0}/sfm.json', + shortName='s', + arg='', + uid=[0], + isOutput=True, + ) + inter_file_extension = desc.FileAttribute( + label='Inter File Extension', + description='''extension of the intermediate file export (default: .ply)''', + value='.ply', + shortName='e', + arg='', + uid=[0], + isOutput=False, + ) + # initialPairA = desc.FileAttribute( + # label='Initial Pair A', + # description='''filename of the first image (without path)''', + # value='', + # shortName='a', + # arg='', + # uid=[0], + # isOutput=False, + # ) + # initialPairB = desc.FileAttribute( + # label='Initial Pair B', + # description='''filename of the second image (without path)''', + # value='', + # shortName='b', + # arg='', + # uid=[0], + # isOutput=False, + # ) + camera_model = desc.ParamAttribute( + label='Camera Model', + description='''Camera model type for view with unknown intrinsic: 1: Pinhole 2: Pinhole radial 1 3: Pinhole radial 3 (default)''', + value=3, + shortName='c', + arg='', + uid=[0], + isOutput=False, + ) + refineIntrinsics = desc.ParamAttribute( + label='Refine Intrinsics', + description='''0-> intrinsic parameters are kept as constant 1-> refine intrinsic parameters (default).''', + value=1, + shortName='f', + arg='', + uid=[0], + isOutput=False, + ) + minInputTrackLength = desc.ParamAttribute( + label='Min Input Track Length', + description='''minimum track length in input of SfM (default: 2)''', + value=2, + shortName='t', + arg='N', + uid=[0], + isOutput=False, + ) + # matchFilePerImage = desc.FileAttribute( + # label='Match File Per Image', + # description='''To use one match file per image instead of a global file.''', + # value=1, + # shortName='p', + # arg='', + # uid=[0], + # isOutput=False, + # ) + allowUserInteraction = desc.ParamAttribute( + label='Allow User Interaction', + description='''Enable/Disable user interactions. (default: true) If the process is done on renderfarm, it doesn't make sense to wait for user inputs. Unrecognized option --help''', + value=0, + shortName='u', + arg='', + uid=[0], + isOutput=False, + ) \ No newline at end of file