Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion meshroom/nodes/aliceVision/ExportAnimatedCamera.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ class ExportAnimatedCamera(desc.AVCommandLineNode):
name="outputUndistorted",
label="Undistorted Images",
description="Output undistorted images.",
value=desc.Node.internalFolder + "undistort",
semantic="image",
value=desc.Node.internalFolder + "undistort/" + "<INTRINSIC_ID>_<FILESTEM>.{undistortedImageTypeValue}",
group="", # exclude from command line
uid=[],
),
Expand Down
2 changes: 1 addition & 1 deletion meshroom/nodes/aliceVision/ImageSegmentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ class ImageSegmentation(desc.AVCommandLineNode):
label="Masks",
description="Generated segmentation masks.",
semantic="image",
value=lambda attr: desc.Node.internalFolder + "<VIEW_ID>.exr" if not attr.node.keepFilename.value else desc.Node.internalFolder + "<FILENAME>.exr",
value=lambda attr: desc.Node.internalFolder + "<VIEW_ID>.exr" if not attr.node.keepFilename.value else desc.Node.internalFolder + "<FILESTEM>.exr",
group="",
uid=[],
),
Expand Down
2 changes: 1 addition & 1 deletion meshroom/nodes/blender/ScenePreview.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ class ScenePreview(desc.CommandLineNode):
label="Frames",
description="Frames rendered in Blender.",
semantic="image",
value=desc.Node.internalFolder + "<FILENAME>_preview.jpg",
value=desc.Node.internalFolder + "<FILESTEM>_preview.jpg",
uid=[],
group="",
),
Expand Down
19 changes: 19 additions & 0 deletions meshroom/ui/components/filepath.py
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,22 @@ def globFirst(self, path):
def fileSizeMB(self, path):
""" Returns the file size in MB. """
return QFileInfo(self.asStr(path)).size() / (1024*1024)

@Slot(str, QObject, result=str)
def resolve(self, path, vp):
# Resolve dynamic path that depends on viewpoint

replacements = {
"<VIEW_ID>": str(vp.childAttribute("viewId").value),
"<INTRINSIC_ID>": str(vp.childAttribute("intrinsicId").value),
"<POSE_ID>": str(vp.childAttribute("poseId").value),
"<PATH>": vp.childAttribute("path").value,
"<FILENAME>": FilepathHelper.basename(FilepathHelper, vp.childAttribute("path").value),
"<FILESTEM>": FilepathHelper.removeExtension(FilepathHelper, FilepathHelper.basename(FilepathHelper, vp.childAttribute("path").value)),
}

resolved = path
for key in replacements:
resolved = resolved.replace(key, replacements[key])

return resolved
24 changes: 3 additions & 21 deletions meshroom/ui/qml/Viewer/Viewer2D.qml
Original file line number Diff line number Diff line change
Expand Up @@ -222,24 +222,6 @@ FocusScope {
return undefined
}

function resolve(path, vp) {
// Resolve dynamic path that depends on viewpoint

let replacements = {
"<VIEW_ID>": vp.childAttribute("viewId").value,
"<INTRINSIC_ID>": vp.childAttribute("intrinsicId").value,
"<POSE_ID>": vp.childAttribute("poseId").value,
"<PATH>": vp.childAttribute("path").value,
"<FILENAME>": Filepath.removeExtension(Filepath.basename(vp.childAttribute("path").value)),
}

let resolved = path;
for (let key in replacements) {
resolved = resolved.replace(key, replacements[key])
}

return resolved;
}

function getImageFile() {
// Entry point for getting the image file URL
Expand All @@ -258,7 +240,7 @@ FocusScope {
let vp = getViewpoint(_reconstruction.pickedViewId)
let attr = getAttributeByName(displayedNode, outputAttribute.name)
let path = attr ? attr.value : ""
let resolved = vp ? resolve(path, vp) : path
let resolved = vp ? Filepath.resolve(path, vp) : path
return Filepath.stringToUrl(resolved)
}

Expand All @@ -277,7 +259,7 @@ FocusScope {

let seq = [];
for (let i = 0; i < objs.length; i++) {
seq.push(resolve(path_template, objs[i]))
seq.push(Filepath.resolve(path_template, objs[i]))
}

return seq
Expand Down Expand Up @@ -1032,7 +1014,7 @@ FocusScope {
property var vp: _reconstruction ? getViewpoint(_reconstruction.selectedViewId) : null

sourceComponent: CameraResponseGraph {
responsePath: resolve(path, vp)
responsePath: Filepath.resolve(path, vp)
}
}
}
Expand Down
39 changes: 26 additions & 13 deletions meshroom/ui/reconstruction.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
from meshroom.core.node import Node, CompatibilityNode, Status, Position
from meshroom.ui.graph import UIGraph
from meshroom.ui.utils import makeProperty
from meshroom.ui.components.filepath import FilepathHelper


class Message(QObject):
Expand Down Expand Up @@ -169,8 +170,10 @@ class ViewpointWrapper(QObject):

initialParamsChanged = Signal()
sfmParamsChanged = Signal()
denseSceneParamsChanged = Signal()
undistortedImageParamsChanged = Signal()
internalChanged = Signal()
principalPointCorrectedChanged = Signal()
uvCenterOffsetChanged = Signal()

def __init__(self, viewpointAttribute, reconstruction):
"""
Expand All @@ -194,16 +197,21 @@ def __init__(self, viewpointAttribute, reconstruction):
# PrepareDenseScene
self._undistortedImagePath = ''
self._activeNode_PrepareDenseScene = self._reconstruction.activeNodes.get("PrepareDenseScene")
self._activeNode_ExportAnimatedCamera = self._reconstruction.activeNodes.get("ExportAnimatedCamera")
self._principalPointCorrected = False
self.principalPointCorrectedChanged.connect(self.uvCenterOffsetChanged)
self.sfmParamsChanged.connect(self.uvCenterOffsetChanged)

# update internally cached variables
self._updateInitialParams()
self._updateSfMParams()
self._updateDenseSceneParams()
self._updateUndistortedImageParams()

# trigger internal members updates when reconstruction members changes
self._reconstruction.cameraInitChanged.connect(self._updateInitialParams)
self._reconstruction.sfmReportChanged.connect(self._updateSfMParams)
self._activeNode_PrepareDenseScene.nodeChanged.connect(self._updateDenseSceneParams)
self._activeNode_PrepareDenseScene.nodeChanged.connect(self._updateUndistortedImageParams)
self._activeNode_ExportAnimatedCamera.nodeChanged.connect(self._updateUndistortedImageParams)

def _updateInitialParams(self):
""" Update internal members depending on CameraInit. """
Expand Down Expand Up @@ -235,15 +243,20 @@ def _updateSfMParams(self):
self._reconstructed = self._R is not None
self.sfmParamsChanged.emit()

def _updateDenseSceneParams(self):
""" Update internal members depending on PrepareDenseScene. """
def _updateUndistortedImageParams(self):
""" Update internal members depending on PrepareDenseScene or ExportAnimatedCamera. """
# undistorted image path
if not self._activeNode_PrepareDenseScene.node:
self._undistortedImagePath = ''
if self._activeNode_ExportAnimatedCamera.node:
self._undistortedImagePath = FilepathHelper.resolve(FilepathHelper, self._activeNode_ExportAnimatedCamera.node.outputUndistorted.value, self._viewpoint)
self._principalPointCorrected = self._activeNode_ExportAnimatedCamera.node.correctPrincipalPoint.value
elif self._activeNode_PrepareDenseScene.node:
self._undistortedImagePath = FilepathHelper.resolve(FilepathHelper, self._activeNode_PrepareDenseScene.node.undistorted.value, self._viewpoint)
self._principalPointCorrected = False
else:
filename = "{}.{}".format(self._viewpoint.viewId.value, self._activeNode_PrepareDenseScene.node.outputFileType.value)
self._undistortedImagePath = os.path.join(self._activeNode_PrepareDenseScene.node.output.value, filename)
self.denseSceneParamsChanged.emit()
self._undistortedImagePath = ''
self._principalPointCorrected = False
self.undistortedImageParamsChanged.emit()
self.principalPointCorrectedChanged.emit()

# Get the underlying Viewpoint attribute wrapped by this Viewpoint.
attribute = Property(QObject, lambda self: self._viewpoint, constant=True)
Expand Down Expand Up @@ -327,10 +340,10 @@ def upVector(self):
""" Get camera up vector. """
return QVector3D(0.0, 1.0, 0.0)

@Property(type=QVector2D, notify=sfmParamsChanged)
@Property(type=QVector2D, notify=uvCenterOffsetChanged)
def uvCenterOffset(self):
""" Get UV offset corresponding to the camera principal point. """
if not self.solvedIntrinsics:
if not self.solvedIntrinsics or self._principalPointCorrected:
return None
pp = self.solvedIntrinsics["principalPoint"]
# compute principal point offset in UV space
Expand All @@ -350,7 +363,7 @@ def fieldOfView(self):
sensorHeight = self.solvedIntrinsics["sensorHeight"]
return 2.0 * math.atan(float(sensorHeight) / (2.0 * float(focalLength))) * 180.0 / math.pi

@Property(type=QUrl, notify=denseSceneParamsChanged)
@Property(type=QUrl, notify=undistortedImageParamsChanged)
def undistortedImageSource(self):
""" Get path to undistorted image source if available. """
return QUrl.fromLocalFile(self._undistortedImagePath)
Expand Down