[multiview] split pipeline creation into several functions

* add 'sfmPipeline', 'mvsPipeline' and 'photogrammetryPipeline' instantiating nodes in an existing graph
* rename main function (creating a new Graph) 'photogrammetry' + create a Publish node if 'output' is specified
This commit is contained in:
Yann Lanthony 2018-03-15 15:54:01 +01:00
parent 8ed0d0a7a2
commit b596bdffca
4 changed files with 121 additions and 43 deletions

View file

@ -43,7 +43,7 @@ if not args.input and not args.inputImages:
print('Nothing to compute. You need to set --input or --inputImages.') print('Nothing to compute. You need to set --input or --inputImages.')
exit(1) exit(1)
graph = multiview.photogrammetryPipeline(output=args.output, inputFolder=args.input, inputImages=args.inputImages) graph = multiview.photogrammetry(inputFolder=args.input, inputImages=args.inputImages, output=args.output)
graph.findNode('PrepareDenseScene').scale.value = args.scale graph.findNode('PrepareDenseScene').scale.value = args.scale
if args.save: if args.save:

View file

@ -2,7 +2,7 @@ import os
import fnmatch import fnmatch
import re import re
from .core.graph import Graph, GraphModification from meshroom.core.graph import Graph, GraphModification
def findFiles(folder, patterns): def findFiles(folder, patterns):
@ -17,11 +17,23 @@ def findFiles(folder, patterns):
return outFiles return outFiles
def photogrammetryPipeline(output='', inputFolder='', inputImages=[], inputViewpoints=[]): def photogrammetry(inputFolder='', inputImages=(), inputViewpoints=(), output=''):
# type: () -> Graph """
graph = Graph('pipeline') Create a new Graph with a complete photogrammetry pipeline.
Args:
inputFolder (str, optional): folder containing image files
inputImages (list of str, optional): list of image file paths
inputViewpoints (list of Viewpoint, optional): list of Viewpoints
output (str, optional): the path to export reconstructed model to
Returns:
Graph: the created graph
"""
graph = Graph('Photogrammetry')
with GraphModification(graph): with GraphModification(graph):
cameraInit = graph.addNewNode('CameraInit') sfmNodes, mvsNodes = photogrammetryPipeline(graph)
cameraInit = sfmNodes[0]
if inputFolder: if inputFolder:
images = findFiles(inputFolder, ['*.jpg', '*.png']) images = findFiles(inputFolder, ['*.jpg', '*.png'])
cameraInit.viewpoints.extend([{'path': image} for image in images]) cameraInit.viewpoints.extend([{'path': image} for image in images])
@ -29,35 +41,101 @@ def photogrammetryPipeline(output='', inputFolder='', inputImages=[], inputViewp
cameraInit.viewpoints.extend([{'path': image} for image in inputImages]) cameraInit.viewpoints.extend([{'path': image} for image in inputImages])
if inputViewpoints: if inputViewpoints:
cameraInit.viewpoints.extend(inputViewpoints) cameraInit.viewpoints.extend(inputViewpoints)
featureExtraction = graph.addNewNode('FeatureExtraction',
input=cameraInit.output) if output:
imageMatching = graph.addNewNode('ImageMatching', texturing = mvsNodes[-1]
input=featureExtraction.input, graph.addNewNode('Publish', output=output, inputFiles=[texturing.outputMesh,
featuresFolder=featureExtraction.output, texturing.outputMaterial,
) texturing.outputTextures])
featureMatching = graph.addNewNode('FeatureMatching',
input=imageMatching.input,
featuresFolder=imageMatching.featuresFolder,
imagePairsList=imageMatching.output)
structureFromMotion = graph.addNewNode('StructureFromMotion',
input=featureMatching.input,
featuresFolder=featureMatching.featuresFolder,
matchesFolder=featureMatching.output)
prepareDenseScene = graph.addNewNode('PrepareDenseScene',
input=structureFromMotion.output)
cameraConnection = graph.addNewNode('CameraConnection',
ini=prepareDenseScene.ini)
depthMap = graph.addNewNode('DepthMap',
ini=cameraConnection.ini)
depthMapFilter = graph.addNewNode('DepthMapFilter',
depthMapFolder=depthMap.output,
ini=depthMap.ini)
meshing = graph.addNewNode('Meshing',
depthMapFolder=depthMapFilter.depthMapFolder,
depthMapFilterFolder=depthMapFilter.output,
ini=depthMapFilter.ini)
texturing = graph.addNewNode('Texturing',
ini=meshing.ini,
inputDenseReconstruction=meshing.outputDenseReconstruction)
return graph return graph
def photogrammetryPipeline(graph):
"""
Instantiate a complete photogrammetry pipeline inside 'graph'.
Args:
graph (Graph/UIGraph): the graph in which nodes should be instantiated
Returns:
list of Node: the created nodes
"""
sfmNodes = sfmPipeline(graph)
mvsNodes = mvsPipeline(graph, sfmNodes[-1])
return sfmNodes, mvsNodes
def sfmPipeline(graph):
"""
Instantiate a SfM pipeline inside 'graph'.
Args:
graph (Graph/UIGraph): the graph in which nodes should be instantiated
Returns:
list of Node: the created nodes
"""
cameraInit = graph.addNewNode('CameraInit')
featureExtraction = graph.addNewNode('FeatureExtraction',
input=cameraInit.output)
imageMatching = graph.addNewNode('ImageMatching',
input=featureExtraction.input,
featuresFolder=featureExtraction.output,
)
featureMatching = graph.addNewNode('FeatureMatching',
input=imageMatching.input,
featuresFolder=imageMatching.featuresFolder,
imagePairsList=imageMatching.output)
structureFromMotion = graph.addNewNode('StructureFromMotion',
input=featureMatching.input,
featuresFolder=featureMatching.featuresFolder,
matchesFolder=featureMatching.output)
return [
cameraInit,
featureExtraction,
imageMatching,
featureMatching,
structureFromMotion
]
def mvsPipeline(graph, sfm=None):
"""
Instantiate a MVS pipeline inside 'graph'.
Args:
graph (Graph/UIGraph): the graph in which nodes should be instantiated
sfm (Node, optional): if specified, connect the MVS pipeline to this StructureFromMotion node
Returns:
list of Node: the created nodes
"""
if sfm and not sfm.nodeType == "StructureFromMotion":
raise ValueError("Invalid node type. Expected StructureFromMotion, got {}.".format(sfm.nodeType))
prepareDenseScene = graph.addNewNode('PrepareDenseScene',
input=sfm.output if sfm else "")
cameraConnection = graph.addNewNode('CameraConnection',
ini=prepareDenseScene.ini)
depthMap = graph.addNewNode('DepthMap',
ini=cameraConnection.ini)
depthMapFilter = graph.addNewNode('DepthMapFilter',
depthMapFolder=depthMap.output,
ini=depthMap.ini)
meshing = graph.addNewNode('Meshing',
depthMapFolder=depthMapFilter.depthMapFolder,
depthMapFilterFolder=depthMapFilter.output,
ini=depthMapFilter.ini)
texturing = graph.addNewNode('Texturing',
ini=meshing.ini,
inputDenseReconstruction=meshing.outputDenseReconstruction)
return [
prepareDenseScene,
cameraConnection,
depthMap,
depthMapFilter,
meshing,
texturing
]

View file

@ -170,7 +170,7 @@ class Reconstruction(UIGraph):
@Slot() @Slot()
def new(self): def new(self):
""" Create a new photogrammetry pipeline. """ """ Create a new photogrammetry pipeline. """
self.setGraph(multiview.photogrammetryPipeline()) self.setGraph(multiview.photogrammetry())
def onGraphChanged(self): def onGraphChanged(self):
""" React to the change of the internal graph. """ """ React to the change of the internal graph. """

View file

@ -4,15 +4,15 @@ import meshroom.multiview
def test_multiviewPipeline(): def test_multiviewPipeline():
graph1 = meshroom.multiview.photogrammetryPipeline(inputImages=['/non/existing/fileA']) graph1 = meshroom.multiview.photogrammetry(inputImages=['/non/existing/fileA'])
graph2 = meshroom.multiview.photogrammetryPipeline(inputImages=[]) graph2 = meshroom.multiview.photogrammetry(inputImages=[])
graph2b = meshroom.multiview.photogrammetryPipeline(inputImages=[]) graph2b = meshroom.multiview.photogrammetry(inputImages=[])
graph3 = meshroom.multiview.photogrammetryPipeline(inputImages=['/non/existing/file1', '/non/existing/file2']) graph3 = meshroom.multiview.photogrammetry(inputImages=['/non/existing/file1', '/non/existing/file2'])
graph4 = meshroom.multiview.photogrammetryPipeline(inputViewpoints=[ graph4 = meshroom.multiview.photogrammetry(inputViewpoints=[
{'path': '/non/existing/file1', 'intrinsicId': 50}, {'path': '/non/existing/file1', 'intrinsicId': 50},
{'path': '/non/existing/file2', 'intrinsicId': 55} {'path': '/non/existing/file2', 'intrinsicId': 55}
]) ])
graph4b = meshroom.multiview.photogrammetryPipeline(inputViewpoints=[ graph4b = meshroom.multiview.photogrammetry(inputViewpoints=[
{'path': '/non/existing/file1', 'intrinsicId': 50}, {'path': '/non/existing/file1', 'intrinsicId': 50},
{'path': '/non/existing/file2', 'intrinsicId': 55} {'path': '/non/existing/file2', 'intrinsicId': 55}
]) ])