Skip to content

Commit

Permalink
Merge pull request #1750 from alicevision/dev/abstractCamInit
Browse files Browse the repository at this point in the history
Add abstract InitNode
  • Loading branch information
fabiencastan authored Aug 5, 2022
2 parents 96b4ec8 + 659c8a0 commit 92e77e7
Show file tree
Hide file tree
Showing 4 changed files with 111 additions and 38 deletions.
55 changes: 19 additions & 36 deletions bin/meshroom_batch
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@ meshroom.setupEnvironment()

import meshroom.core.graph
from meshroom import multiview
from meshroom.core.desc import InitNode
import logging


parser = argparse.ArgumentParser(description='Launch the full photogrammetry or Panorama HDR pipeline.')
parser.add_argument('-i', '--input', metavar='SFM/FOLDERS/IMAGES', type=str, nargs='*',
default=[],
Expand Down Expand Up @@ -94,33 +96,24 @@ def getOnlyNodeOfType(g, nodeType):
return nodes[0]


def getInitNode(g):
"""
Helper function to get the Init node in the graph 'g' and raise an exception if there is no or
multiple candidates.
"""
nodes = g.findInitNodes()
if len(nodes) == 0:
raise RuntimeError("meshroom_batch requires an Init node in the pipeline.")
elif len(nodes) > 1:
raise RuntimeError("meshroom_batch requires exactly one Init node in the pipeline, {} found: {}"
.format(len(nodes), str(nodes)))
return nodes[0]


if not args.input and not args.inputRecursive:
print('Nothing to compute. You need to set --input or --inputRecursive.')
sys.exit(1)

views, intrinsics = [], []
# Build image files list from inputImages arguments
filesByType = multiview.FilesByType()

hasSearchedForImages = False

if args.input:
if len(args.input) == 1 and os.path.isfile(args.input[0]) and os.path.splitext(args.input[0])[-1] in ('.json', '.sfm'):
# args.input is a sfmData file: setup pre-calibrated views and intrinsics
from meshroom.nodes.aliceVision.CameraInit import readSfMData
views, intrinsics = readSfMData(args.input[0])
else:
filesByType.extend(multiview.findFilesByTypeInFolder(args.input, recursive=False))
hasSearchedForImages = True

if args.inputRecursive:
filesByType.extend(multiview.findFilesByTypeInFolder(args.inputRecursive, recursive=True))
hasSearchedForImages = True

if hasSearchedForImages and not filesByType.images:
print("No image found")
sys.exit(-1)

graph = multiview.Graph(name=args.pipeline)

with multiview.GraphModification(graph):
Expand All @@ -131,15 +124,10 @@ with multiview.GraphModification(graph):
else:
# custom pipeline
graph.load(args.pipeline, setupProjectFile=False)
# graph.update()

cameraInit = getOnlyNodeOfType(graph, 'CameraInit')
# reset graph inputs
cameraInit.viewpoints.resetValue()
cameraInit.intrinsics.resetValue()
# add views and intrinsics (if any) read from args.input
cameraInit.viewpoints.extend(views)
cameraInit.intrinsics.extend(intrinsics)
# get init node and initialize it
initNode = getInitNode(graph)
initNode.nodeDesc.initialize(initNode, args.input, args.inputRecursive)

if not graph.canComputeLeaves:
raise RuntimeError("Graph cannot be computed. Check for compatibility issues.")
Expand All @@ -151,11 +139,6 @@ with multiview.GraphModification(graph):
publish = getOnlyNodeOfType(graph, 'Publish')
publish.output.value = args.output

if filesByType.images:
views, intrinsics = cameraInit.nodeDesc.buildIntrinsics(cameraInit, filesByType.images)
cameraInit.viewpoints.value = views
cameraInit.intrinsics.value = intrinsics

if args.overrides:
import io
import json
Expand Down
52 changes: 52 additions & 0 deletions meshroom/core/desc.py
Original file line number Diff line number Diff line change
Expand Up @@ -527,3 +527,55 @@ def processChunk(self, chunk):
finally:
chunk.subprocess = None


# Test abstract node
class InitNode:
def __init__(self):
pass

def initialize(self, node, inputs, recursiveInputs):
"""
Initialize the attributes that are needed for a node to start running.
Args:
node (Node): the node whose attributes must be initialized
inputs (list): the user-provided list of input files/directories
recursiveInputs (list): the user-provided list of input directories to search recursively for images
"""
pass

def resetAttributes(self, node, attributeNames):
"""
Reset the values of the provided attributes for a node.
Args:
node (Node): the node whose attributes are to be reset
attributeNames (list): the list containing the names of the attributes to reset
"""
for attrName in attributeNames:
if node.hasAttribute(attrName):
node.attribute(attrName).resetValue()

def extendAttributes(self, node, attributesDict):
"""
Extend the values of the provided attributes for a node.
Args:
node (Node): the node whose attributes are to be extended
attributesDict (dict): the dictionary containing the attributes' names (as keys) and the values to extend with
"""
for attr in attributesDict.keys():
if node.hasAttribute(attr):
node.attribute(attr).extend(attributesDict[attr])

def setAttributes(self, node, attributesDict):
"""
Set the values of the provided attributes for a node.
Args:
node (Node): the node whose attributes are to be extended
attributesDict (dict): the dictionary containing the attributes' names (as keys) and the values to set
"""
for attr in attributesDict:
if node.hasAttribute(attr):
node.attribute(attr).value = attributesDict[attr]
8 changes: 8 additions & 0 deletions meshroom/core/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -547,6 +547,14 @@ def nodesOfType(self, nodeType, sortedByIndex=True):
nodes = [n for n in self._nodes.values() if n.nodeType == nodeType]
return self.sortNodesByIndex(nodes) if sortedByIndex else nodes

def findInitNodes(self):
"""
Returns:
list[Node]: the list of Init nodes (nodes inheriting from InitNode)
"""
nodes = [n for n in self._nodes.values() if isinstance(n.nodeDesc, meshroom.core.desc.InitNode)]
return nodes

def findNodeCandidates(self, nodeNameExpr):
pattern = re.compile(nodeNameExpr)
return [v for k, v in self._nodes.objects.items() if pattern.match(k)]
Expand Down
34 changes: 32 additions & 2 deletions meshroom/nodes/aliceVision/CameraInit.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import logging

from meshroom.core import desc, Version

from meshroom.multiview import FilesByType, findFilesByTypeInFolder

Viewpoint = [
desc.IntParam(name="viewId", label="Id", description="Image UID", value=-1, uid=[0], range=None),
Expand Down Expand Up @@ -119,7 +119,8 @@ def readSfMData(sfmFile):

return views, intrinsics

class CameraInit(desc.CommandLineNode):

class CameraInit(desc.CommandLineNode, desc.InitNode):
commandLine = 'aliceVision_cameraInit {allParams} --allowSingleView 1' # don't throw an error if there is only one image

size = desc.DynamicNodeSize('viewpoints')
Expand Down Expand Up @@ -250,6 +251,35 @@ class CameraInit(desc.CommandLineNode):
),
]

def __init__(self):
super(CameraInit, self).__init__()

def initialize(self, node, inputs, recursiveInputs):
# Reset graph inputs
self.resetAttributes(node, ["viewpoints", "intrinsics"])

filesByType = FilesByType()
searchedForImages = False

if recursiveInputs:
filesByType.extend(findFilesByTypeInFolder(recursiveInputs, recursive=True))
searchedForImages = True

# Add views and intrinsics from a file if it was provided, or look for the images
if len(inputs) == 1 and os.path.isfile(inputs[0]) and os.path.splitext(inputs[0])[-1] in ('.json', '.sfm'):
views, intrinsics = readSfMData(inputs[0])
self.extendAttributes(node, {"viewpoints": views, "intrinsics": intrinsics})
else:
filesByType.extend(findFilesByTypeInFolder(inputs, recursive=False))
searchedForImages = True

# If there was no input file, check that the directories do contain images
if searchedForImages and not filesByType.images:
raise ValueError("No valid input file or no image in the provided directories")

views, intrinsics = self.buildIntrinsics(node, filesByType.images)
self.setAttributes(node, {"viewpoints": views, "intrinsics": intrinsics})

def upgradeAttributeValues(self, attrValues, fromVersion):

# Starting with version 6, the principal point is now relative to the image center
Expand Down

0 comments on commit 92e77e7

Please sign in to comment.