Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/alicevision/meshroom.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabien Castan <fabcastan@gmail.com>2022-10-19 17:16:57 +0300
committerGitHub <noreply@github.com>2022-10-19 17:16:57 +0300
commit1f78158c3bcc6971b76c22ce262ede76e94afba1 (patch)
tree1f2c4769bcfb2152e73dc665155d72071c5cdbaa
parentab0e132121a0372e6712f346f63c3ffd7348a070 (diff)
parent0424ae13c0aae341bae2ae1ecdcc1e729d849fe5 (diff)
Merge pull request #1776 from alicevision/dev/lv/adapt2DViewerToNode
Show generated images in 2D viewer when double-clicking on node
-rw-r--r--meshroom/core/node.py8
-rw-r--r--meshroom/nodes/aliceVision/CameraLocalization.py4
-rw-r--r--meshroom/nodes/aliceVision/CameraRigCalibration.py2
-rw-r--r--meshroom/nodes/aliceVision/CameraRigLocalization.py2
-rw-r--r--meshroom/nodes/aliceVision/ColorCheckerCorrection.py4
-rw-r--r--meshroom/nodes/aliceVision/ConvertMesh.py2
-rw-r--r--meshroom/nodes/aliceVision/DepthMap.py23
-rw-r--r--meshroom/nodes/aliceVision/DepthMapFilter.py21
-rw-r--r--meshroom/nodes/aliceVision/DistortionCalibration.py2
-rw-r--r--meshroom/nodes/aliceVision/ExportAnimatedCamera.py6
-rw-r--r--meshroom/nodes/aliceVision/ExportColoredPointCloud.py2
-rw-r--r--meshroom/nodes/aliceVision/ExportMatches.py2
-rw-r--r--meshroom/nodes/aliceVision/ExportMaya.py2
-rw-r--r--meshroom/nodes/aliceVision/FeatureRepeatability.py2
-rw-r--r--meshroom/nodes/aliceVision/GlobalSfM.py2
-rw-r--r--meshroom/nodes/aliceVision/ImageMatchingMultiSfM.py4
-rw-r--r--meshroom/nodes/aliceVision/ImageProcessing.py9
-rw-r--r--meshroom/nodes/aliceVision/KeyframeSelection.py2
-rw-r--r--meshroom/nodes/aliceVision/LdrToHdrCalibration.py2
-rw-r--r--meshroom/nodes/aliceVision/LdrToHdrMerge.py2
-rw-r--r--meshroom/nodes/aliceVision/LdrToHdrSampling.py2
-rw-r--r--meshroom/nodes/aliceVision/LightingEstimation.py2
-rw-r--r--meshroom/nodes/aliceVision/MergeMeshes.py2
-rw-r--r--meshroom/nodes/aliceVision/MeshDecimate.py2
-rw-r--r--meshroom/nodes/aliceVision/MeshMasking.py2
-rw-r--r--meshroom/nodes/aliceVision/MeshResampling.py2
-rw-r--r--meshroom/nodes/aliceVision/PanoramaCompositing.py2
-rw-r--r--meshroom/nodes/aliceVision/PanoramaEstimation.py4
-rw-r--r--meshroom/nodes/aliceVision/PanoramaInit.py2
-rw-r--r--meshroom/nodes/aliceVision/PanoramaMerging.py3
-rw-r--r--meshroom/nodes/aliceVision/PanoramaPrepareImages.py2
-rw-r--r--meshroom/nodes/aliceVision/PanoramaSeams.py2
-rw-r--r--meshroom/nodes/aliceVision/PanoramaWarping.py29
-rw-r--r--meshroom/nodes/aliceVision/PrepareDenseScene.py5
-rw-r--r--meshroom/nodes/aliceVision/SfMAlignment.py4
-rw-r--r--meshroom/nodes/aliceVision/SfMTransfer.py4
-rw-r--r--meshroom/nodes/aliceVision/SfMTransform.py4
-rw-r--r--meshroom/nodes/aliceVision/Split360Images.py2
-rw-r--r--meshroom/nodes/aliceVision/StructureFromMotion.py2
-rw-r--r--meshroom/nodes/aliceVision/Texturing.py4
-rw-r--r--meshroom/ui/qml/ImageGallery/ImageGallery.qml6
-rw-r--r--meshroom/ui/qml/Viewer/Viewer2D.qml177
-rw-r--r--meshroom/ui/qml/WorkspaceView.qml11
-rwxr-xr-xmeshroom/ui/qml/main.qml48
-rwxr-xr-xmeshroom/ui/reconstruction.py7
45 files changed, 303 insertions, 130 deletions
diff --git a/meshroom/core/node.py b/meshroom/core/node.py
index 372c5384..29df5be3 100644
--- a/meshroom/core/node.py
+++ b/meshroom/core/node.py
@@ -393,6 +393,9 @@ class NodeChunk(BaseObject):
def isStopped(self):
return self._status.status == Status.STOPPED
+ def isFinished(self):
+ return self._status.status == Status.SUCCESS
+
def process(self, forceCompute=False):
if not forceCompute and self._status.status == Status.SUCCESS:
logging.info("Node chunk already computed: {}".format(self.name))
@@ -752,6 +755,11 @@ class BaseNode(BaseObject):
""" Return True if all chunks of this Node is either finished or running, False otherwise. """
return all(chunk.isFinishedOrRunning() for chunk in self._chunks)
+ @Slot(result=bool)
+ def isPartiallyFinished(self):
+ """ Return True is at least one chunk of this Node is finished, False otherwise. """
+ return any(chunk.isFinished() for chunk in self._chunks)
+
def alreadySubmittedChunks(self):
return [ch for ch in self._chunks if ch.isAlreadySubmitted()]
diff --git a/meshroom/nodes/aliceVision/CameraLocalization.py b/meshroom/nodes/aliceVision/CameraLocalization.py
index d8aabe9a..1f98119d 100644
--- a/meshroom/nodes/aliceVision/CameraLocalization.py
+++ b/meshroom/nodes/aliceVision/CameraLocalization.py
@@ -209,14 +209,14 @@ class CameraLocalization(desc.CommandLineNode):
outputs = [
desc.File(
name='outputAlembic',
- label='Output Alembic',
+ label='Alembic',
description='''Filename for the SfMData export file (where camera poses will be stored)''',
value=desc.Node.internalFolder + 'trackedCameras.abc',
uid=[],
),
desc.File(
name='outputJSON',
- label='Output JSON',
+ label='JSON',
description='''Filename for the localization results as .json''',
value=desc.Node.internalFolder + 'trackedCameras.json',
uid=[],
diff --git a/meshroom/nodes/aliceVision/CameraRigCalibration.py b/meshroom/nodes/aliceVision/CameraRigCalibration.py
index 117457c3..3fa103e1 100644
--- a/meshroom/nodes/aliceVision/CameraRigCalibration.py
+++ b/meshroom/nodes/aliceVision/CameraRigCalibration.py
@@ -165,7 +165,7 @@ class CameraRigCalibration(desc.CommandLineNode):
outputs = [
desc.File(
name='outfile',
- label='Output File',
+ label='File',
description='''The name of the file where to store the calibration data''',
value=desc.Node.internalFolder + 'cameraRigCalibration.rigCal',
uid=[],
diff --git a/meshroom/nodes/aliceVision/CameraRigLocalization.py b/meshroom/nodes/aliceVision/CameraRigLocalization.py
index 6cff2d31..ca4875c2 100644
--- a/meshroom/nodes/aliceVision/CameraRigLocalization.py
+++ b/meshroom/nodes/aliceVision/CameraRigLocalization.py
@@ -172,7 +172,7 @@ class CameraRigLocalization(desc.CommandLineNode):
outputs = [
desc.File(
name='outputAlembic',
- label='Output Alembic',
+ label='Alembic',
description='''Filename for the SfMData export file (where camera poses will be stored).''',
value=desc.Node.internalFolder + 'trackedcameras.abc',
uid=[],
diff --git a/meshroom/nodes/aliceVision/ColorCheckerCorrection.py b/meshroom/nodes/aliceVision/ColorCheckerCorrection.py
index 1fb02baa..0b5e6554 100644
--- a/meshroom/nodes/aliceVision/ColorCheckerCorrection.py
+++ b/meshroom/nodes/aliceVision/ColorCheckerCorrection.py
@@ -63,7 +63,7 @@ If multiple color charts are submitted, only the first one will be taken in acco
outputs = [
desc.File(
name='outSfMData',
- label='Output sfmData',
+ label='SfmData',
description='Output sfmData.',
value=lambda attr: (desc.Node.internalFolder + os.path.basename(attr.node.input.value)) if (os.path.splitext(attr.node.input.value)[1] in ['.abc', '.sfm']) else '',
uid=[],
@@ -71,7 +71,7 @@ If multiple color charts are submitted, only the first one will be taken in acco
),
desc.File(
name='output',
- label='Output Folder',
+ label='Folder',
description='Output Images Folder.',
value=desc.Node.internalFolder,
uid=[],
diff --git a/meshroom/nodes/aliceVision/ConvertMesh.py b/meshroom/nodes/aliceVision/ConvertMesh.py
index 55dac2dc..9ea7b570 100644
--- a/meshroom/nodes/aliceVision/ConvertMesh.py
+++ b/meshroom/nodes/aliceVision/ConvertMesh.py
@@ -41,7 +41,7 @@ class ConvertMesh(desc.CommandLineNode):
outputs = [
desc.File(
name='output',
- label='Output Mesh',
+ label='Mesh',
description='''Output mesh (*.obj, *.mesh, *.meshb, *.ply, *.off, *.stl).''',
value=desc.Node.internalFolder + 'mesh.' + '{outputMeshFileTypeValue}',
uid=[],
diff --git a/meshroom/nodes/aliceVision/DepthMap.py b/meshroom/nodes/aliceVision/DepthMap.py
index e1d84225..6f150854 100644
--- a/meshroom/nodes/aliceVision/DepthMap.py
+++ b/meshroom/nodes/aliceVision/DepthMap.py
@@ -293,9 +293,30 @@ Use a downscale factor of one (full-resolution) only if the quality of the input
outputs = [
desc.File(
name='output',
- label='Output',
+ label='Folder',
description='Output folder for generated depth maps.',
value=desc.Node.internalFolder,
uid=[],
),
+ # these attributes are only here to describe more accurately the output of the node
+ # by specifying that it generates 2 sequences of images
+ # (see in Viewer2D.qml how these attributes can be used)
+ desc.File(
+ name='depth',
+ label='Depth Maps',
+ description='Generated depth maps.',
+ semantic='image',
+ value=desc.Node.internalFolder + '<VIEW_ID>_depthMap.exr',
+ uid=[],
+ group='', # do not export on the command line
+ ),
+ desc.File(
+ name='sim',
+ label='Sim Maps',
+ description='Generated sim maps.',
+ semantic='image',
+ value=desc.Node.internalFolder + '<VIEW_ID>_simMap.exr',
+ uid=[],
+ group='', # do not export on the command line
+ ),
]
diff --git a/meshroom/nodes/aliceVision/DepthMapFilter.py b/meshroom/nodes/aliceVision/DepthMapFilter.py
index 5043d074..c52dd233 100644
--- a/meshroom/nodes/aliceVision/DepthMapFilter.py
+++ b/meshroom/nodes/aliceVision/DepthMapFilter.py
@@ -128,4 +128,25 @@ This allows to filter unstable points before starting the fusion of all depth ma
value=desc.Node.internalFolder,
uid=[],
),
+ # these attributes are only here to describe more accurately the output of the node
+ # by specifying that it generates 2 sequences of images
+ # (see in Viewer2D.qml how these attributes can be used)
+ desc.File(
+ name='depth',
+ label='Depth Maps',
+ description='Filtered depth maps.',
+ semantic='image',
+ value=desc.Node.internalFolder + '<VIEW_ID>_depthMap.exr',
+ uid=[],
+ group='', # do not export on the command line
+ ),
+ desc.File(
+ name='sim',
+ label='Sim Maps',
+ description='Filtered sim maps.',
+ semantic='image',
+ value=desc.Node.internalFolder + '<VIEW_ID>_simMap.exr',
+ uid=[],
+ group='', # do not export on the command line
+ ),
]
diff --git a/meshroom/nodes/aliceVision/DistortionCalibration.py b/meshroom/nodes/aliceVision/DistortionCalibration.py
index 87fa9606..8f006062 100644
--- a/meshroom/nodes/aliceVision/DistortionCalibration.py
+++ b/meshroom/nodes/aliceVision/DistortionCalibration.py
@@ -45,7 +45,7 @@ class DistortionCalibration(desc.CommandLineNode):
outputs = [
desc.File(
name='outSfMData',
- label='Output SfmData File',
+ label='SfmData File',
description='Path to the output sfmData file',
value=desc.Node.internalFolder + 'sfmData.sfm',
uid=[],
diff --git a/meshroom/nodes/aliceVision/ExportAnimatedCamera.py b/meshroom/nodes/aliceVision/ExportAnimatedCamera.py
index 4eb378d8..1fc1ac95 100644
--- a/meshroom/nodes/aliceVision/ExportAnimatedCamera.py
+++ b/meshroom/nodes/aliceVision/ExportAnimatedCamera.py
@@ -87,14 +87,14 @@ Based on the input image filenames, it will recognize the input video sequence t
outputs = [
desc.File(
name='output',
- label='Output filepath',
+ label='Filepath',
description='Output filepath for the alembic animated camera.',
value=desc.Node.internalFolder,
uid=[],
),
desc.File(
name='outputCamera',
- label='Output Camera Filepath',
+ label='Camera Filepath',
description='Output filename for the alembic animated camera.',
value=desc.Node.internalFolder + 'camera.abc',
group='', # exclude from command line
@@ -102,7 +102,7 @@ Based on the input image filenames, it will recognize the input video sequence t
),
desc.File(
name='outputUndistorted',
- label='Output Undistorted images Filepath',
+ label='Undistorted images Filepath',
description='Output Undistorted images.',
value=desc.Node.internalFolder + 'undistort',
group='', # exclude from command line
diff --git a/meshroom/nodes/aliceVision/ExportColoredPointCloud.py b/meshroom/nodes/aliceVision/ExportColoredPointCloud.py
index a922a4a9..7ab7855b 100644
--- a/meshroom/nodes/aliceVision/ExportColoredPointCloud.py
+++ b/meshroom/nodes/aliceVision/ExportColoredPointCloud.py
@@ -30,7 +30,7 @@ class ExportColoredPointCloud(desc.CommandLineNode):
outputs = [
desc.File(
name='output',
- label='Output Point Cloud Filepath',
+ label='Point Cloud Filepath',
description='Output point cloud with visibilities as SfMData file.',
value="{cache}/{nodeType}/{uid0}/pointCloud.abc",
uid=[],
diff --git a/meshroom/nodes/aliceVision/ExportMatches.py b/meshroom/nodes/aliceVision/ExportMatches.py
index b90c6358..2a1aeebc 100644
--- a/meshroom/nodes/aliceVision/ExportMatches.py
+++ b/meshroom/nodes/aliceVision/ExportMatches.py
@@ -65,7 +65,7 @@ class ExportMatches(desc.CommandLineNode):
outputs = [
desc.File(
name='output',
- label='Output Folder',
+ label='Folder',
description='Output path for the features and descriptors files (*.feat, *.desc).',
value=desc.Node.internalFolder,
uid=[],
diff --git a/meshroom/nodes/aliceVision/ExportMaya.py b/meshroom/nodes/aliceVision/ExportMaya.py
index aeea1b81..99dacf12 100644
--- a/meshroom/nodes/aliceVision/ExportMaya.py
+++ b/meshroom/nodes/aliceVision/ExportMaya.py
@@ -27,7 +27,7 @@ MeshroomMaya contains a user interface to browse all cameras.
outputs = [
desc.File(
name='output',
- label='Output Folder',
+ label='Folder',
description='Folder for MeshroomMaya outputs: undistorted images and thumbnails.',
value=desc.Node.internalFolder,
uid=[],
diff --git a/meshroom/nodes/aliceVision/FeatureRepeatability.py b/meshroom/nodes/aliceVision/FeatureRepeatability.py
index 12cd9012..ed22cf34 100644
--- a/meshroom/nodes/aliceVision/FeatureRepeatability.py
+++ b/meshroom/nodes/aliceVision/FeatureRepeatability.py
@@ -125,7 +125,7 @@ Compare feature/descriptor matching repeatability on some dataset with known hom
outputs = [
desc.File(
name='output',
- label='Output Folder',
+ label='Folder',
description='Output path for the features and descriptors files (*.feat, *.desc).',
value=desc.Node.internalFolder,
uid=[],
diff --git a/meshroom/nodes/aliceVision/GlobalSfM.py b/meshroom/nodes/aliceVision/GlobalSfM.py
index a400570a..8d6ebe0b 100644
--- a/meshroom/nodes/aliceVision/GlobalSfM.py
+++ b/meshroom/nodes/aliceVision/GlobalSfM.py
@@ -119,7 +119,7 @@ It is known to be faster but less robust to challenging datasets than the Increm
),
desc.File(
name='extraInfoFolder',
- label='Output Folder',
+ label='Folder',
description='Folder for intermediate reconstruction files and additional reconstruction information files.',
value=desc.Node.internalFolder,
uid=[],
diff --git a/meshroom/nodes/aliceVision/ImageMatchingMultiSfM.py b/meshroom/nodes/aliceVision/ImageMatchingMultiSfM.py
index 313534b1..c11776e7 100644
--- a/meshroom/nodes/aliceVision/ImageMatchingMultiSfM.py
+++ b/meshroom/nodes/aliceVision/ImageMatchingMultiSfM.py
@@ -141,14 +141,14 @@ Thanks to this node, the FeatureMatching node will only compute the matches betw
outputs = [
desc.File(
name='output',
- label='Output List File',
+ label='List File',
description='Filepath to the output file with the list of selected image pairs.',
value=desc.Node.internalFolder + 'imageMatches.txt',
uid=[],
),
desc.File(
name='outputCombinedSfM',
- label='Output Combined SfM',
+ label='Combined SfM',
description='Path for the combined SfMData file',
value=desc.Node.internalFolder + 'combineSfM.sfm',
uid=[],
diff --git a/meshroom/nodes/aliceVision/ImageProcessing.py b/meshroom/nodes/aliceVision/ImageProcessing.py
index e276c365..8aaebff6 100644
--- a/meshroom/nodes/aliceVision/ImageProcessing.py
+++ b/meshroom/nodes/aliceVision/ImageProcessing.py
@@ -12,7 +12,7 @@ def outputImagesValueFunct(attr):
if inputExt in ['.abc', '.sfm']:
# If we have an SfM in input
- return desc.Node.internalFolder + '*' + (outputExt or '.*')
+ return desc.Node.internalFolder + '<VIEW_ID>' + (outputExt or '.*')
if inputExt:
# if we have one or multiple files in input
@@ -325,7 +325,7 @@ Convert or apply filtering to the input images.
outputs = [
desc.File(
name='outSfMData',
- label='Output sfmData',
+ label='SfmData',
description='Output sfmData.',
value=lambda attr: (desc.Node.internalFolder + os.path.basename(attr.node.input.value)) if (os.path.splitext(attr.node.input.value)[1] in ['.abc', '.sfm']) else '',
uid=[],
@@ -333,15 +333,16 @@ Convert or apply filtering to the input images.
),
desc.File(
name='output',
- label='Output Folder',
+ label='Folder',
description='Output Images Folder.',
value=desc.Node.internalFolder,
uid=[],
),
desc.File(
name='outputImages',
- label='Output Images',
+ label='Images',
description='Output Image Files.',
+ semantic='image',
value= outputImagesValueFunct,
group='', # do not export on the command line
uid=[],
diff --git a/meshroom/nodes/aliceVision/KeyframeSelection.py b/meshroom/nodes/aliceVision/KeyframeSelection.py
index e1037cd3..63ecb1f6 100644
--- a/meshroom/nodes/aliceVision/KeyframeSelection.py
+++ b/meshroom/nodes/aliceVision/KeyframeSelection.py
@@ -182,7 +182,7 @@ You can extract frames at regular interval by configuring only the min/maxFrameS
outputs = [
desc.File(
name='outputFolder',
- label='Output Folder',
+ label='Folder',
description='''Output keyframes folder for extracted frames.''',
value=desc.Node.internalFolder,
uid=[],
diff --git a/meshroom/nodes/aliceVision/LdrToHdrCalibration.py b/meshroom/nodes/aliceVision/LdrToHdrCalibration.py
index 5b6ebbbf..a1a384a3 100644
--- a/meshroom/nodes/aliceVision/LdrToHdrCalibration.py
+++ b/meshroom/nodes/aliceVision/LdrToHdrCalibration.py
@@ -139,7 +139,7 @@ class LdrToHdrCalibration(desc.CommandLineNode):
outputs = [
desc.File(
name='response',
- label='Output response File',
+ label='Response File',
description='Path to the output response file',
value=desc.Node.internalFolder + 'response.csv',
uid=[],
diff --git a/meshroom/nodes/aliceVision/LdrToHdrMerge.py b/meshroom/nodes/aliceVision/LdrToHdrMerge.py
index 391ae9e3..cc1ee60f 100644
--- a/meshroom/nodes/aliceVision/LdrToHdrMerge.py
+++ b/meshroom/nodes/aliceVision/LdrToHdrMerge.py
@@ -177,7 +177,7 @@ class LdrToHdrMerge(desc.CommandLineNode):
outputs = [
desc.File(
name='outSfMData',
- label='Output SfMData File',
+ label='SfMData File',
description='Path to the output sfmdata file',
value=desc.Node.internalFolder + 'sfmData.sfm',
uid=[],
diff --git a/meshroom/nodes/aliceVision/LdrToHdrSampling.py b/meshroom/nodes/aliceVision/LdrToHdrSampling.py
index a32f86c1..3324733b 100644
--- a/meshroom/nodes/aliceVision/LdrToHdrSampling.py
+++ b/meshroom/nodes/aliceVision/LdrToHdrSampling.py
@@ -146,7 +146,7 @@ class LdrToHdrSampling(desc.CommandLineNode):
outputs = [
desc.File(
name='output',
- label='Output Folder',
+ label='Folder',
description='Output path for the samples.',
value=desc.Node.internalFolder,
uid=[],
diff --git a/meshroom/nodes/aliceVision/LightingEstimation.py b/meshroom/nodes/aliceVision/LightingEstimation.py
index c9d44b1a..077b3538 100644
--- a/meshroom/nodes/aliceVision/LightingEstimation.py
+++ b/meshroom/nodes/aliceVision/LightingEstimation.py
@@ -83,7 +83,7 @@ class LightingEstimation(desc.CommandLineNode):
outputs = [
desc.File(
name='output',
- label='Output Folder',
+ label='Folder',
description='Folder for output lighting vector files.',
value=desc.Node.internalFolder,
uid=[],
diff --git a/meshroom/nodes/aliceVision/MergeMeshes.py b/meshroom/nodes/aliceVision/MergeMeshes.py
index 1669dde5..739e5b04 100644
--- a/meshroom/nodes/aliceVision/MergeMeshes.py
+++ b/meshroom/nodes/aliceVision/MergeMeshes.py
@@ -69,7 +69,7 @@ Operation types used to merge two meshes:
outputs = [
desc.File(
name='output',
- label='Output mesh',
+ label='Mesh',
description='''Output mesh (*.obj, *.mesh, *.meshb, *.ply, *.off, *.stl).''',
value=desc.Node.internalFolder + 'mesh.stl',
uid=[],
diff --git a/meshroom/nodes/aliceVision/MeshDecimate.py b/meshroom/nodes/aliceVision/MeshDecimate.py
index 4294e858..29b51e42 100644
--- a/meshroom/nodes/aliceVision/MeshDecimate.py
+++ b/meshroom/nodes/aliceVision/MeshDecimate.py
@@ -77,7 +77,7 @@ This node allows to reduce the density of the Mesh.
outputs = [
desc.File(
name="output",
- label="Output mesh",
+ label="Mesh",
description="Output mesh (OBJ file format).",
value=desc.Node.internalFolder + 'mesh.obj',
uid=[],
diff --git a/meshroom/nodes/aliceVision/MeshMasking.py b/meshroom/nodes/aliceVision/MeshMasking.py
index 9188072b..1888f563 100644
--- a/meshroom/nodes/aliceVision/MeshMasking.py
+++ b/meshroom/nodes/aliceVision/MeshMasking.py
@@ -100,7 +100,7 @@ Decimate triangles based on image masks.
outputs = [
desc.File(
name='outputMesh',
- label='Output Mesh',
+ label='Mesh',
description='''Output mesh.''',
value=desc.Node.internalFolder + 'mesh.{outputMeshFileTypeValue}',
uid=[],
diff --git a/meshroom/nodes/aliceVision/MeshResampling.py b/meshroom/nodes/aliceVision/MeshResampling.py
index d9a836cd..047d572b 100644
--- a/meshroom/nodes/aliceVision/MeshResampling.py
+++ b/meshroom/nodes/aliceVision/MeshResampling.py
@@ -82,7 +82,7 @@ This node allows to recompute the mesh surface with a new topology and uniform d
outputs = [
desc.File(
name="output",
- label="Output mesh",
+ label="Mesh",
description="Output mesh (OBJ file format).",
value=desc.Node.internalFolder + 'mesh.obj',
uid=[],
diff --git a/meshroom/nodes/aliceVision/PanoramaCompositing.py b/meshroom/nodes/aliceVision/PanoramaCompositing.py
index 896759e7..756d76db 100644
--- a/meshroom/nodes/aliceVision/PanoramaCompositing.py
+++ b/meshroom/nodes/aliceVision/PanoramaCompositing.py
@@ -106,7 +106,7 @@ Multiple cameras are contributing to the low frequencies and only the best one c
outputs = [
desc.File(
name='output',
- label='Output Folder',
+ label='Folder',
description='',
value=desc.Node.internalFolder,
uid=[],
diff --git a/meshroom/nodes/aliceVision/PanoramaEstimation.py b/meshroom/nodes/aliceVision/PanoramaEstimation.py
index 6e78dd7c..476d29b1 100644
--- a/meshroom/nodes/aliceVision/PanoramaEstimation.py
+++ b/meshroom/nodes/aliceVision/PanoramaEstimation.py
@@ -178,14 +178,14 @@ Estimate relative camera rotations between input images.
outputs = [
desc.File(
name='output',
- label='Output SfMData File',
+ label='SfMData File',
description='Path to the output sfmdata file',
value=desc.Node.internalFolder + 'panorama.abc',
uid=[],
),
desc.File(
name='outputViewsAndPoses',
- label='Output Poses',
+ label='Poses',
description='''Path to the output sfmdata file with cameras (views and poses).''',
value=desc.Node.internalFolder + 'cameras.sfm',
uid=[],
diff --git a/meshroom/nodes/aliceVision/PanoramaInit.py b/meshroom/nodes/aliceVision/PanoramaInit.py
index 947f0922..edac5cd6 100644
--- a/meshroom/nodes/aliceVision/PanoramaInit.py
+++ b/meshroom/nodes/aliceVision/PanoramaInit.py
@@ -156,7 +156,7 @@ This node allows to setup the Panorama:
outputs = [
desc.File(
name='outSfMData',
- label='Output SfMData File',
+ label='SfMData File',
description='Path to the output sfmdata file',
value=desc.Node.internalFolder + 'sfmData.sfm',
uid=[],
diff --git a/meshroom/nodes/aliceVision/PanoramaMerging.py b/meshroom/nodes/aliceVision/PanoramaMerging.py
index 99a14ec7..f0fc6fca 100644
--- a/meshroom/nodes/aliceVision/PanoramaMerging.py
+++ b/meshroom/nodes/aliceVision/PanoramaMerging.py
@@ -69,8 +69,9 @@ Merge all inputs coming from the PanoramaCompositing node.
outputs = [
desc.File(
name='outputPanorama',
- label='Output Folder',
+ label='Panorama',
description='',
+ semantic='image',
value=desc.Node.internalFolder + 'panorama.{outputFileTypeValue}',
uid=[],
),
diff --git a/meshroom/nodes/aliceVision/PanoramaPrepareImages.py b/meshroom/nodes/aliceVision/PanoramaPrepareImages.py
index 1add6c47..89099f19 100644
--- a/meshroom/nodes/aliceVision/PanoramaPrepareImages.py
+++ b/meshroom/nodes/aliceVision/PanoramaPrepareImages.py
@@ -36,7 +36,7 @@ Prepare images for Panorama pipeline: ensures that images orientations are coher
outputs = [
desc.File(
name='output',
- label='Output sfmData',
+ label='SfmData',
description='Output sfmData.',
value=lambda attr: desc.Node.internalFolder + os.path.basename(attr.node.input.value),
uid=[],
diff --git a/meshroom/nodes/aliceVision/PanoramaSeams.py b/meshroom/nodes/aliceVision/PanoramaSeams.py
index c36beb92..6817d984 100644
--- a/meshroom/nodes/aliceVision/PanoramaSeams.py
+++ b/meshroom/nodes/aliceVision/PanoramaSeams.py
@@ -61,7 +61,7 @@ Estimate the seams lines between the inputs to provide an optimal compositing in
outputs = [
desc.File(
name='output',
- label='Output Labels',
+ label='Labels',
description='',
value=desc.Node.internalFolder + 'labels.exr',
uid=[],
diff --git a/meshroom/nodes/aliceVision/PanoramaWarping.py b/meshroom/nodes/aliceVision/PanoramaWarping.py
index 33d3e0a9..99a38d5c 100644
--- a/meshroom/nodes/aliceVision/PanoramaWarping.py
+++ b/meshroom/nodes/aliceVision/PanoramaWarping.py
@@ -92,9 +92,36 @@ Compute the image warping for each input image in the panorama coordinate system
outputs = [
desc.File(
name='output',
- label='Output directory',
+ label='Folder',
description='',
value=desc.Node.internalFolder,
uid=[],
),
+ desc.File(
+ name='warping',
+ label='Warping',
+ description='',
+ group='', # do not export on the command line
+ semantic='image',
+ value=desc.Node.internalFolder+'<VIEW_ID>.exr',
+ uid=[]
+ ),
+ desc.File(
+ name='mask',
+ label='Mask',
+ description='',
+ group='', # do not export on the command line
+ semantic='image',
+ value=desc.Node.internalFolder+'<VIEW_ID>_mask.exr',
+ uid=[]
+ ),
+ desc.File(
+ name='weight',
+ label='Weight',
+ description='',
+ group='', # do not export on the command line
+ semantic='image',
+ value=desc.Node.internalFolder+'<VIEW_ID>_weight.exr',
+ uid=[]
+ ),
]
diff --git a/meshroom/nodes/aliceVision/PrepareDenseScene.py b/meshroom/nodes/aliceVision/PrepareDenseScene.py
index 31d0ecf1..5d475e51 100644
--- a/meshroom/nodes/aliceVision/PrepareDenseScene.py
+++ b/meshroom/nodes/aliceVision/PrepareDenseScene.py
@@ -100,10 +100,11 @@ This node export undistorted images so the depth map and texturing can be comput
uid=[],
),
desc.File(
- name='outputUndistorted',
+ name='undistorted',
label='Undistorted Images',
description='List of undistorted images.',
- value=desc.Node.internalFolder + '*.{outputFileTypeValue}',
+ semantic='image',
+ value=desc.Node.internalFolder + '<VIEW_ID>.{outputFileTypeValue}',
uid=[],
group='',
advanced=True
diff --git a/meshroom/nodes/aliceVision/SfMAlignment.py b/meshroom/nodes/aliceVision/SfMAlignment.py
index 60d6d2e3..accd9bfb 100644
--- a/meshroom/nodes/aliceVision/SfMAlignment.py
+++ b/meshroom/nodes/aliceVision/SfMAlignment.py
@@ -110,14 +110,14 @@ The alignment can be based on:
outputs = [
desc.File(
name='output',
- label='Output SfMData File',
+ label='SfMData File',
description='SfMData file.',
value=lambda attr: desc.Node.internalFolder + (os.path.splitext(os.path.basename(attr.node.input.value))[0] or 'sfmData') + '.abc',
uid=[],
),
desc.File(
name='outputViewsAndPoses',
- label='Output Poses',
+ label='Poses',
description='''Path to the output sfmdata file with cameras (views and poses).''',
value=desc.Node.internalFolder + 'cameras.sfm',
uid=[],
diff --git a/meshroom/nodes/aliceVision/SfMTransfer.py b/meshroom/nodes/aliceVision/SfMTransfer.py
index dd0f8c4a..edc5acff 100644
--- a/meshroom/nodes/aliceVision/SfMTransfer.py
+++ b/meshroom/nodes/aliceVision/SfMTransfer.py
@@ -94,14 +94,14 @@ This node allows to transfer poses and/or intrinsics form one SfM scene onto ano
outputs = [
desc.File(
name='output',
- label='Output SfMData File',
+ label='SfMData File',
description='SfMData file.',
value=lambda attr: desc.Node.internalFolder + (os.path.splitext(os.path.basename(attr.node.input.value))[0] or 'sfmData') + '.abc',
uid=[],
),
desc.File(
name='outputViewsAndPoses',
- label='Output Poses',
+ label='Poses',
description='''Path to the output sfmdata file with cameras (views and poses).''',
value=desc.Node.internalFolder + 'cameras.sfm',
uid=[],
diff --git a/meshroom/nodes/aliceVision/SfMTransform.py b/meshroom/nodes/aliceVision/SfMTransform.py
index 0466ec50..439ba3af 100644
--- a/meshroom/nodes/aliceVision/SfMTransform.py
+++ b/meshroom/nodes/aliceVision/SfMTransform.py
@@ -197,14 +197,14 @@ The transformation can be based on:
outputs = [
desc.File(
name='output',
- label='Output SfMData File',
+ label='SfMData File',
description='''Aligned SfMData file .''',
value=lambda attr: desc.Node.internalFolder + (os.path.splitext(os.path.basename(attr.node.input.value))[0] or 'sfmData') + '.abc',
uid=[],
),
desc.File(
name='outputViewsAndPoses',
- label='Output Poses',
+ label='Poses',
description='''Path to the output sfmdata file with cameras (views and poses).''',
value=desc.Node.internalFolder + 'cameras.sfm',
uid=[],
diff --git a/meshroom/nodes/aliceVision/Split360Images.py b/meshroom/nodes/aliceVision/Split360Images.py
index daee4598..4ff56bb9 100644
--- a/meshroom/nodes/aliceVision/Split360Images.py
+++ b/meshroom/nodes/aliceVision/Split360Images.py
@@ -89,7 +89,7 @@ class Split360Images(desc.CommandLineNode):
outputs = [
desc.File(
name='output',
- label='Output Folder',
+ label='Folder',
description="Output folder for extracted frames.",
value=desc.Node.internalFolder,
uid=[],
diff --git a/meshroom/nodes/aliceVision/StructureFromMotion.py b/meshroom/nodes/aliceVision/StructureFromMotion.py
index 4cacd6a1..08a4541c 100644
--- a/meshroom/nodes/aliceVision/StructureFromMotion.py
+++ b/meshroom/nodes/aliceVision/StructureFromMotion.py
@@ -367,7 +367,7 @@ It iterates like that, adding cameras and triangulating new 2D features into 3D
),
desc.File(
name='extraInfoFolder',
- label='Output Folder',
+ label='Folder',
description='Folder for intermediate reconstruction files and additional reconstruction information files.',
value=desc.Node.internalFolder,
uid=[],
diff --git a/meshroom/nodes/aliceVision/Texturing.py b/meshroom/nodes/aliceVision/Texturing.py
index 34ed45d4..83d46d90 100644
--- a/meshroom/nodes/aliceVision/Texturing.py
+++ b/meshroom/nodes/aliceVision/Texturing.py
@@ -348,8 +348,8 @@ Many cameras are contributing to the low frequencies and only the best ones cont
description='Output Texture files.',
value= lambda attr: desc.Node.internalFolder + 'texture_*.' + attr.node.colorMapping.colorMappingFileType.value if attr.node.colorMapping.enable.value else '',
uid=[],
- group='',
- ),
+ group=''
+ )
]
def upgradeAttributeValues(self, attrValues, fromVersion):
diff --git a/meshroom/ui/qml/ImageGallery/ImageGallery.qml b/meshroom/ui/qml/ImageGallery/ImageGallery.qml
index 94c6637c..0ab31577 100644
--- a/meshroom/ui/qml/ImageGallery/ImageGallery.qml
+++ b/meshroom/ui/qml/ImageGallery/ImageGallery.qml
@@ -30,7 +30,7 @@ Panel {
signal removeImageRequest(var attribute)
signal filesDropped(var drop, var augmentSfm)
- title: "Images"
+ title: "Image Gallery"
implicitWidth: (root.defaultCellSize + 2) * 2
QtObject {
@@ -332,17 +332,14 @@ Panel {
}
else
{
- grid.updateSelectedViewFromGrid = false
if(event.key == Qt.Key_Right)
{
grid.moveCurrentIndexRight()
- // grid.setCurrentIndex(Math.min(grid.model.count - 1, grid.currentIndex + 1))
event.accepted = true
}
else if(event.key == Qt.Key_Left)
{
grid.moveCurrentIndexLeft()
- // grid.setCurrentIndex(Math.max(0, grid.currentIndex - 1))
event.accepted = true
}
else if(event.key == Qt.Key_Up)
@@ -355,7 +352,6 @@ Panel {
grid.moveCurrentIndexDown()
event.accepted = true
}
- grid.updateSelectedViewFromGrid = true
}
}
diff --git a/meshroom/ui/qml/Viewer/Viewer2D.qml b/meshroom/ui/qml/Viewer/Viewer2D.qml
index 8bd2ceb1..b407199a 100644
--- a/meshroom/ui/qml/Viewer/Viewer2D.qml
+++ b/meshroom/ui/qml/Viewer/Viewer2D.qml
@@ -9,6 +9,11 @@ FocusScope {
clip: true
+ property var displayedNode: null
+
+ property bool useExternal: false
+ property url sourceExternal
+
property url source
property var metadata
property var viewIn3D
@@ -153,18 +158,129 @@ FocusScope {
imgContainer.y = Math.max((imgLayout.height - imgContainer.image.height * imgContainer.scale)*0.5, 0)
}
- function getImageFile(type) {
- if(!_reconstruction.activeNodes)
- return "";
- var depthMapNode = _reconstruction.activeNodes.get('allDepthMap').node;
- if (type == "image") {
- return root.source;
- } else if (depthMapNode != undefined && _reconstruction.selectedViewId >= 0) {
- return Filepath.stringToUrl(depthMapNode.internalFolder+_reconstruction.selectedViewId+"_"+type+"Map.exr");
+ function tryLoadNode(node) {
+ useExternal = false;
+
+ // safety check
+ if (!node) {
+ return false;
+ }
+
+ // node must be computed or at least running
+ if (!node.isPartiallyFinished()) {
+ return false;
+ }
+
+ // node must have at least one output attribute with the image semantic
+ var hasImageOutputAttr = false;
+ for (var i = 0; i < node.attributes.count; i++) {
+ var attr = node.attributes.at(i);
+ if (attr.isOutput && attr.desc.semantic == "image") {
+ hasImageOutputAttr = true;
+ break;
+ }
+ }
+ if (!hasImageOutputAttr) {
+ return false;
+ }
+
+ displayedNode = node;
+ return true;
+ }
+
+ function loadExternal(path) {
+ useExternal = true;
+ sourceExternal = path;
+ displayedNode = null;
+ }
+
+ function getImageFile() {
+ // entry point for getting the image file URL
+ if (useExternal) {
+ return sourceExternal;
+ }
+ if (!displayedNode || outputAttribute.name == "gallery") {
+ return getViewpointPath(_reconstruction.selectedViewId);
+ }
+ return getFileAttributePath(displayedNode, outputAttribute.name, _reconstruction.selectedViewId);
+ }
+
+ function getMetadata() {
+ // entry point for getting the image metadata
+ if (useExternal) {
+ return {};
+ } else {
+ return getViewpointMetadata(_reconstruction.selectedViewId);
+ }
+ }
+
+ function getFileAttributePath(node, attrName, viewId) {
+ // get output attribute with matching name
+ // and parse its value to get the image filepath
+ for (var i = 0; i < node.attributes.count; i++) {
+ var attr = node.attributes.at(i);
+ if (attr.name == attrName) {
+ let pattern = String(attr.value).replace("<VIEW_ID>", viewId);
+ let path = Filepath.globFirst(pattern);
+ return Filepath.stringToUrl(path);
+ }
+ }
+ return "";
+ }
+
+ function getViewpointPath(viewId) {
+ // get viewpoint from cameraInit with matching id
+ // and get its image filepath
+ for (var i = 0; i < _reconstruction.viewpoints.count; i++) {
+ var vp = _reconstruction.viewpoints.at(i);
+ if (vp.childAttribute("viewId").value == viewId) {
+ return Filepath.stringToUrl(vp.childAttribute("path").value);
+ }
}
return "";
}
+ function getViewpointMetadata(viewId) {
+ // get viewpoint from cameraInit with matching id
+ // and get its image filepath
+ for (var i = 0; i < _reconstruction.viewpoints.count; i++) {
+ var vp = _reconstruction.viewpoints.at(i);
+ if (vp.childAttribute("viewId").value == viewId) {
+ return JSON.parse(vp.childAttribute("metadata").value);
+ }
+ }
+ return {};
+ }
+
+ onDisplayedNodeChanged: {
+ // clear metadata if no displayed node
+ if (!displayedNode) {
+ metadata = {};
+ }
+
+ // update output attribute names
+ var names = [];
+ if (displayedNode) {
+ // store attr name for output attributes that represent images
+ for (var i = 0; i < displayedNode.attributes.count; i++) {
+ var attr = displayedNode.attributes.at(i);
+ if (attr.isOutput && attr.desc.semantic == "image") {
+ names.push(attr.name);
+ }
+ }
+ }
+ names.push("gallery");
+ outputAttribute.names = names;
+ }
+
+ Connections {
+ target: _reconstruction
+ onSelectedViewIdChanged: {
+ root.source = getImageFile();
+ root.metadata = getMetadata();
+ }
+ }
+
// context menu
property Component contextMenu: Menu {
MenuItem {
@@ -272,7 +388,7 @@ FocusScope {
// Note: It does not work to use previously created component, so we re-create it with setSource.
// floatViewerComp.createObject(floatImageViewerLoader, {
setSource("FloatImage.qml", {
- 'source': Qt.binding(function() { return getImageFile(imageType.type); }),
+ 'source': Qt.binding(function() { return getImageFile(); }),
'gamma': Qt.binding(function() { return hdrImageToolbar.gammaValue; }),
'gain': Qt.binding(function() { return hdrImageToolbar.gainValue; }),
'channelModeString': Qt.binding(function() { return hdrImageToolbar.channelModeValue; }),
@@ -336,7 +452,7 @@ FocusScope {
fillMode: Image.PreserveAspectFit
autoTransform: true
onWidthChanged: if(status==Image.Ready) fit()
- source: getImageFile(imageType.type)
+ source: getImageFile()
onStatusChanged: {
// update cache source when image is loaded
if(status === Image.Ready)
@@ -500,15 +616,13 @@ FocusScope {
font.pointSize: 8
readOnly: true
selectByMouse: true
- text: Filepath.urlToString(getImageFile(imageType.type))
+ text: Filepath.urlToString(getImageFile())
}
- // show which depthmap node is active
+ // write which node is being displayed
Label {
- id: depthMapNodeName
- property var activeNode: root.oiioPluginAvailable ? _reconstruction.activeNodes.get("allDepthMap").node : null
- visible: (imageType.type != "image") && activeNode
- text: activeNode ? activeNode.label : ""
+ id: displayedNodeName
+ text: root.displayedNode ? root.displayedNode.label : ""
font.pointSize: 8
horizontalAlignment: TextInput.AlignLeft
@@ -516,6 +630,17 @@ FocusScope {
Layout.preferredWidth: contentWidth
height: contentHeight
}
+
+ // button to clear currently displayed node
+ MaterialToolButton {
+ id: clearDisplayedNode
+ text: MaterialIcons.close
+ ToolTip.text: "Clear node"
+ enabled: root.displayedNode
+ onClicked: {
+ root.displayedNode = null
+ }
+ }
}
}
Item {
@@ -990,19 +1115,21 @@ FocusScope {
}
ComboBox {
- id: imageType
- property var activeNode: root.oiioPluginAvailable ? _reconstruction.activeNodes.get('allDepthMap').node : null
- // set min size to 5 characters + one margin for the combobox
+ id: outputAttribute
clip: true
Layout.minimumWidth: 0
- Layout.preferredWidth: 6.0 * Qt.application.font.pixelSize
flat: true
- property var types: ["image", "depth", "sim"]
- property string type: enabled ? types[currentIndex] : types[0]
+ property var names: ["gallery"]
+ property string name: names[currentIndex]
- model: types
- enabled: activeNode
+ model: names.map(n => (n == "gallery") ? "Image Gallery" : displayedNode.attributes.get(n).label)
+ enabled: count > 0
+
+ FontMetrics {
+ id: fontMetrics
+ }
+ Layout.preferredWidth: model.reduce((acc, label) => Math.max(acc, fontMetrics.boundingRect(label).width), 0) + 3.0*Qt.application.font.pixelSize
}
MaterialToolButton {
@@ -1014,7 +1141,7 @@ FocusScope {
Layout.minimumWidth: 0
onClicked: {
- root.viewIn3D(root.getImageFile("depth"))
+ root.viewIn3D(root.getFileAttributePath(activeNode, "depth", _reconstruction.selectedViewId));
}
}
diff --git a/meshroom/ui/qml/WorkspaceView.qml b/meshroom/ui/qml/WorkspaceView.qml
index ced16fe2..2c4d6ae2 100644
--- a/meshroom/ui/qml/WorkspaceView.qml
+++ b/meshroom/ui/qml/WorkspaceView.qml
@@ -148,20 +148,11 @@ Item {
viewIn3D: root.load3DMedia
- Connections {
- target: imageGallery
- onCurrentItemChanged: {
- viewer2D.source = imageGallery.currentItemSource
- viewer2D.metadata = imageGallery.currentItemMetadata
- }
- }
-
DropArea {
anchors.fill: parent
keys: ["text/uri-list"]
onDropped: {
- viewer2D.source = drop.urls[0]
- viewer2D.metadata = {}
+ viewer2D.loadExternal(drop.urls[0]);
}
}
Rectangle {
diff --git a/meshroom/ui/qml/main.qml b/meshroom/ui/qml/main.qml
index db218e19..22550f80 100755
--- a/meshroom/ui/qml/main.qml
+++ b/meshroom/ui/qml/main.qml
@@ -851,11 +851,16 @@ ApplicationWindow {
reconstruction: _reconstruction
readOnly: _reconstruction.computing
- function viewAttribute(attribute, mouse) {
- let viewable = false;
- viewable = workspaceView.viewIn2D(attribute);
- viewable |= workspaceView.viewIn3D(attribute, mouse);
- return viewable;
+ function viewNode(node, mouse) {
+ // 2D viewer
+ viewer2D.tryLoadNode(node);
+
+ // 3D viewer
+ for (var i = 0; i < node.attributes.count; i++) {
+ var attr = node.attributes.at(i)
+ if(attr.isOutput && attr.desc.semantic != "image" && workspaceView.viewIn3D(attr, mouse))
+ break;
+ }
}
function viewIn3D(attribute, mouse) {
@@ -867,29 +872,6 @@ ApplicationWindow {
panel3dViewer.viewer3D.solo(attribute);
return loaded;
}
-
- function viewIn2D(attribute) {
- var imageExts = ['.exr', '.jpg', '.tif', '.png'];
- var ext = Filepath.extension(attribute.value);
- if(imageExts.indexOf(ext) == -1)
- {
- return false;
- }
-
- if(attribute.value.includes('*'))
- {
- // For now, the viewer only supports a single image.
- var firstFile = Filepath.globFirst(attribute.value)
- viewer2D.source = Filepath.stringToUrl(firstFile);
- }
- else
- {
- viewer2D.source = Filepath.stringToUrl(attribute.value);
- return true;
- }
-
- return false;
- }
}
}
@@ -955,14 +937,7 @@ ApplicationWindow {
onNodeDoubleClicked: {
_reconstruction.setActiveNode(node);
-
- let viewable = false;
- for(var i=0; i < node.attributes.count; ++i)
- {
- var attr = node.attributes.at(i)
- if(attr.isOutput && workspaceView.viewAttribute(attr, mouse))
- break;
- }
+ workspaceView.viewNode(node, mouse);
}
onComputeRequest: computeManager.compute(node)
onSubmitRequest: computeManager.submit(node)
@@ -989,7 +964,6 @@ ApplicationWindow {
// Make NodeEditor readOnly when computing
readOnly: node ? node.locked : false
- onAttributeDoubleClicked: workspaceView.viewAttribute(attribute, mouse)
onUpgradeRequest: {
var n = _reconstruction.upgradeNode(node);
_reconstruction.selectedNode = n;
diff --git a/meshroom/ui/reconstruction.py b/meshroom/ui/reconstruction.py
index 8d303101..4e9683c0 100755
--- a/meshroom/ui/reconstruction.py
+++ b/meshroom/ui/reconstruction.py
@@ -565,7 +565,12 @@ class Reconstruction(UIGraph):
def getViewpoints(self):
""" Return the Viewpoints model. """
# TODO: handle multiple Viewpoints models
- return self._cameraInit.viewpoints.value if self._cameraInit else QObjectListModel(parent=self)
+ if self.tempCameraInit:
+ return self.tempCameraInit.viewpoints.value
+ elif self._cameraInit:
+ return self._cameraInit.viewpoints.value
+ else:
+ return QObjectListModel(parent=self)
def updateCameraInits(self):
cameraInits = self._graph.nodesOfType("CameraInit", sortedByIndex=True)