Skip to content

Commit

Permalink
Merge pull request #808 from alicevision/dev/panoramaFisheye
Browse files Browse the repository at this point in the history
New panorama pipeline for fisheye images
  • Loading branch information
fabiencastan authored Jul 16, 2020
2 parents 12c5adc + 91f5334 commit 058cb87
Show file tree
Hide file tree
Showing 69 changed files with 2,078 additions and 679 deletions.
5 changes: 4 additions & 1 deletion bin/meshroom_photogrammetry
Original file line number Diff line number Diff line change
Expand Up @@ -114,7 +114,10 @@ with multiview.GraphModification(graph):
multiview.photogrammetry(inputViewpoints=views, inputIntrinsics=intrinsics, output=args.output, graph=graph)
elif args.pipeline.lower() == "hdri":
# default hdri pipeline
graph = multiview.hdri(inputViewpoints=views, inputIntrinsics=intrinsics, output=args.output, graph=graph)
multiview.hdri(inputViewpoints=views, inputIntrinsics=intrinsics, output=args.output, graph=graph)
elif args.pipeline.lower() == "hdrifisheye":
# default hdriFisheye pipeline
multiview.hdriFisheye(inputViewpoints=views, inputIntrinsics=intrinsics, output=args.output, graph=graph)
else:
# custom pipeline
graph.load(args.pipeline)
Expand Down
22 changes: 17 additions & 5 deletions meshroom/core/attribute.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
#!/usr/bin/env python
# coding:utf-8
import collections
import copy
import re
import weakref
import types

from meshroom.common import BaseObject, Property, Variant, Signal, ListModel, DictModel, Slot
from meshroom.core import desc, pyCompatibility, hashValue
Expand Down Expand Up @@ -54,7 +56,7 @@ def __init__(self, node, attributeDesc, isOutput, root=None, parent=None):
self._node = weakref.ref(node)
self.attributeDesc = attributeDesc
self._isOutput = isOutput
self._value = attributeDesc.value
self._value = copy.copy(attributeDesc.value)
self._label = attributeDesc.label

# invalidation value for output attributes
Expand Down Expand Up @@ -162,8 +164,15 @@ def isLinkExpression(value):
"""
return isinstance(value, pyCompatibility.basestring) and Attribute.stringIsLinkRe.match(value)

def getLinkParam(self):
return self.node.graph.edge(self).src if self.isLink else None
def getLinkParam(self, recursive=False):
if not self.isLink:
return None
linkParam = self.node.graph.edge(self).src
if not recursive:
return linkParam
if linkParam.isLink:
return linkParam.getLinkParam(recursive)
return linkParam

def _applyExpr(self):
"""
Expand All @@ -189,7 +198,7 @@ def getExportValue(self):
if self.isLink:
return self.getLinkParam().asLinkExpr()
if self.isOutput:
return self.desc.value
return self.defaultValue()
return self._value

def getValueStr(self):
Expand All @@ -201,7 +210,10 @@ def getValueStr(self):
return str(self.value)

def defaultValue(self):
return self.desc.value
if isinstance(self.desc.value, types.FunctionType):
return self.desc.value(self)
# Need to force a copy, for the case where the value is a list (avoid reference to the desc value)
return copy.copy(self.desc.value)

def _isDefault(self):
return self._value == self.defaultValue()
Expand Down
1 change: 1 addition & 0 deletions meshroom/core/desc.py
Original file line number Diff line number Diff line change
Expand Up @@ -397,6 +397,7 @@ class Node(object):
outputs = []
size = StaticNodeSize(1)
parallelization = None
documentation = ''

def __init__(self):
pass
Expand Down
30 changes: 16 additions & 14 deletions meshroom/core/graph.py
Original file line number Diff line number Diff line change
Expand Up @@ -273,12 +273,15 @@ def load(self, filepath, setupProjectFile=True):
# Add node to the graph with raw attributes values
self._addNode(n, nodeName)

if setupProjectFile:
# Update filepath related members
self._setFilepath(filepath)
# Create graph edges by resolving attributes expressions
self._applyExpr()

# Create graph edges by resolving attributes expressions
self._applyExpr()
if setupProjectFile:
# Update filepath related members
# Note: needs to be done at the end as it will trigger an updateInternals.
self._setFilepath(filepath)

return True

@property
def updateEnabled(self):
Expand Down Expand Up @@ -558,7 +561,7 @@ def findNode(self, nodeExpr):
candidates = self.findNodeCandidates('^' + nodeExpr)
if not candidates:
raise KeyError('No node candidate for "{}"'.format(nodeExpr))
elif len(candidates) > 1:
if len(candidates) > 1:
raise KeyError('Multiple node candidates for "{}": {}'.format(nodeExpr, str([c.name for c in candidates])))
return candidates[0]

Expand Down Expand Up @@ -678,11 +681,11 @@ def _dfsVisit(self, u, visitor, colors, nodeChildren, longestPathFirst):
# (u,v) is a tree edge
self.dfsVisit(v, visitor, colors, nodeChildren, longestPathFirst) # TODO: avoid recursion
elif colors[v] == GRAY:
# (u,v) is a back edge
visitor.backEdge((u, v), self)
pass # (u,v) is a back edge
elif colors[v] == BLACK:
# (u,v) is a cross or forward edge
visitor.forwardOrCrossEdge((u, v), self)
pass # (u,v) is a cross or forward edge
visitor.finishEdge((u, v), self)
colors[u] = BLACK
visitor.finishVertex(u, self)
Expand Down Expand Up @@ -737,8 +740,7 @@ def finishVertex(vertex, graph):
def finishEdge(edge, graph):
if edge[0].hasStatus(Status.SUCCESS) or edge[1].hasStatus(Status.SUCCESS):
return
else:
edges.append(edge)
edges.append(edge)

visitor.finishVertex = finishVertex
visitor.finishEdge = finishEdge
Expand Down Expand Up @@ -869,23 +871,23 @@ def flowEdges(self, startNodes=None):
flowEdges.append(link)
return flowEdges

def nodesFromNode(self, startNode, filterType=None):
def nodesFromNode(self, startNode, filterTypes=None):
"""
Return the node chain from startNode to the graph leaves.
Args:
startNode (Node): the node to start the visit from.
filterType (str): (optional) only return the nodes of the given type
filterTypes (str list): (optional) only return the nodes of the given types
(does not stop the visit, this is a post-process only)
Returns:
The list of nodes from startNode to the graph leaves following edges.
The list of nodes and edges, from startNode to the graph leaves following edges.
"""
nodes = []
edges = []
visitor = Visitor()

def discoverVertex(vertex, graph):
if not filterType or vertex.nodeType == filterType:
if not filterTypes or vertex.nodeType in filterTypes:
nodes.append(vertex)

visitor.discoverVertex = discoverVertex
Expand Down
47 changes: 35 additions & 12 deletions meshroom/core/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -465,6 +465,9 @@ def getLabel(self):
t, idx = self._name.split("_")
return "{}{}".format(t, idx if int(idx) > 1 else "")

def getDocumentation(self):
return self.nodeDesc.documentation

@property
def packageFullName(self):
return '-'.join([self.packageName, self.packageVersion])
Expand Down Expand Up @@ -495,6 +498,9 @@ def attribute(self, name):
def getAttributes(self):
return self._attributes

def hasAttribute(self, name):
return name in self._attributes.keys()

def _applyExpr(self):
for attr in self._attributes:
attr._applyExpr()
Expand Down Expand Up @@ -540,6 +546,23 @@ def _computeUids(self):
self._uids[uidIndex] = hashValue(uidAttributes)

def _buildCmdVars(self):
def _buildAttributeCmdVars(cmdVars, name, attr):
if attr.attributeDesc.group is not None:
# if there is a valid command line "group"
v = attr.getValueStr()
cmdVars[name] = '--{name} {value}'.format(name=name, value=v)
cmdVars[name + 'Value'] = str(v)

if v:
cmdVars[attr.attributeDesc.group] = cmdVars.get(attr.attributeDesc.group, '') + \
' ' + cmdVars[name]
elif isinstance(attr, GroupAttribute):
assert isinstance(attr.value, DictModel)
# if the GroupAttribute is not set in a single command line argument,
# the sub-attributes may need to be exposed individually
for v in attr._value:
_buildAttributeCmdVars(cmdVars, v.name, v)

""" Generate command variables using input attributes and resolved output attributes names and values. """
for uidIndex, value in self._uids.items():
self._cmdVars['uid{}'.format(uidIndex)] = value
Expand All @@ -548,14 +571,7 @@ def _buildCmdVars(self):
for name, attr in self._attributes.objects.items():
if attr.isOutput:
continue # skip outputs
v = attr.getValueStr()

self._cmdVars[name] = '--{name} {value}'.format(name=name, value=v)
self._cmdVars[name + 'Value'] = str(v)

if v:
self._cmdVars[attr.attributeDesc.group] = self._cmdVars.get(attr.attributeDesc.group, '') + \
' ' + self._cmdVars[name]
_buildAttributeCmdVars(self._cmdVars, name, attr)

# For updating output attributes invalidation values
cmdVarsNoCache = self._cmdVars.copy()
Expand All @@ -570,8 +586,14 @@ def _buildCmdVars(self):
if not isinstance(attr.attributeDesc, desc.File):
continue

attr.value = attr.attributeDesc.value.format(**self._cmdVars)
attr._invalidationValue = attr.attributeDesc.value.format(**cmdVarsNoCache)
defaultValue = attr.defaultValue()
try:
attr.value = defaultValue.format(**self._cmdVars)
attr._invalidationValue = defaultValue.format(**cmdVarsNoCache)
except KeyError as e:
logging.warning('Invalid expression with missing key on "{nodeName}.{attrName}" with value "{defaultValue}".\nError: {err}'.format(nodeName=self.name, attrName=attr.name, defaultValue=defaultValue, err=str(e)))
except ValueError as e:
logging.warning('Invalid expression value on "{nodeName}.{attrName}" with value "{defaultValue}".\nError: {err}'.format(nodeName=self.name, attrName=attr.name, defaultValue=defaultValue, err=str(e)))
v = attr.getValueStr()

self._cmdVars[name] = '--{name} {value}'.format(name=name, value=v)
Expand All @@ -597,8 +619,7 @@ def hasStatus(self, status):
return False
return True

@Slot(result=bool)
def isComputed(self):
def _isComputed(self):
return self.hasStatus(Status.SUCCESS)

@Slot()
Expand Down Expand Up @@ -748,6 +769,7 @@ def __repr__(self):
name = Property(str, getName, constant=True)
label = Property(str, getLabel, constant=True)
nodeType = Property(str, nodeType.fget, constant=True)
documentation = Property(str, getDocumentation, constant=True)
positionChanged = Signal()
position = Property(Variant, position.fget, position.fset, notify=positionChanged)
x = Property(float, lambda self: self._position.x, notify=positionChanged)
Expand All @@ -764,6 +786,7 @@ def __repr__(self):
size = Property(int, getSize, notify=sizeChanged)
globalStatusChanged = Signal()
globalStatus = Property(str, lambda self: self.getGlobalStatus().name, notify=globalStatusChanged)
isComputed = Property(bool, _isComputed, notify=globalStatusChanged)


class Node(BaseNode):
Expand Down
2 changes: 1 addition & 1 deletion meshroom/core/stats.py
Original file line number Diff line number Diff line change
Expand Up @@ -303,7 +303,7 @@ def run(self):
if self.proc.is_running():
self.updateStats()
return
except (KeyboardInterrupt, SystemError, GeneratorExit):
except (KeyboardInterrupt, SystemError, GeneratorExit, psutil.NoSuchProcess):
pass

def stopRequest(self):
Expand Down
Loading

0 comments on commit 058cb87

Please sign in to comment.