diff --git a/meshroom/ui/qml/ImageGallery.qml b/meshroom/ui/qml/ImageGallery.qml index 735558de..28c78afc 100644 --- a/meshroom/ui/qml/ImageGallery.qml +++ b/meshroom/ui/qml/ImageGallery.qml @@ -26,7 +26,7 @@ Panel { title: "Images" property int currentIndex: 0 readonly property variant viewpoints: cameraInit.attribute('viewpoints').value - signal filesDropped(var drop) + signal filesDropped(var drop, var augmentSfm) ColumnLayout { anchors.fill: parent @@ -134,14 +134,56 @@ Panel { enabled: !root.readOnly // TODO: onEntered: call specific method to filter files based on extension onDropped: { - root.filesDropped(drop) + var augmentSfm = augmentArea.hovered + root.filesDropped(drop, augmentSfm) } - // DropArea overlay + + // Background opacifier Rectangle { + visible: dropArea.containsDrag anchors.fill: parent - opacity: 0.4 - visible: parent.containsDrag - color: palette.highlight + color: palette.window + opacity: 0.8 + } + + ColumnLayout { + anchors.fill: parent + visible: dropArea.containsDrag + spacing: 1 + Label { + id: addArea + property bool hovered: dropArea.drag.y < height + Layout.fillWidth: true + Layout.fillHeight: true + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: "Add Images" + font.bold: true + background: Rectangle { + color: parent.hovered ? palette.highlight : palette.window + opacity: 0.8 + border.color: palette.highlight + } + } + + // DropArea overlay + Label { + id: augmentArea + property bool hovered: visible && dropArea.drag.y >= y + Layout.fillWidth: true + Layout.preferredHeight: parent.height * 0.3 + horizontalAlignment: Text.AlignHCenter + verticalAlignment: Text.AlignVCenter + text: "Augment Reconstruction" + font.bold: true + wrapMode: Text.WrapAtWordBoundaryOrAnywhere + visible: viewpoints.count > 0 + background: Rectangle { + color: parent.hovered ? palette.highlight : palette.window + opacity: 0.8 + border.color: palette.highlight + } + } } } } diff --git a/meshroom/ui/qml/WorkspaceView.qml b/meshroom/ui/qml/WorkspaceView.qml index 85ec1747..a8090531 100644 --- a/meshroom/ui/qml/WorkspaceView.qml +++ b/meshroom/ui/qml/WorkspaceView.qml @@ -67,7 +67,7 @@ Item { currentIndex: reconstruction.cameraInitIndex onCurrentIndexChanged: reconstruction.cameraInitIndex = currentIndex onRemoveImageRequest: reconstruction.removeAttribute(attribute) - onFilesDropped: reconstruction.handleFilesDrop(drop, cameraInit) + onFilesDropped: reconstruction.handleFilesDrop(drop, augmentSfm ? null : cameraInit) } LiveSfmView { visible: settings_UILayout.showLiveReconstruction diff --git a/meshroom/ui/reconstruction.py b/meshroom/ui/reconstruction.py index af456227..33f81add 100755 --- a/meshroom/ui/reconstruction.py +++ b/meshroom/ui/reconstruction.py @@ -344,7 +344,10 @@ class Reconstruction(UIGraph): # Duplicate 'cameraInit' outside the graph. # => allows to compute intrinsics without modifying the node or the graph - attributes = cameraInit.toDict()["attributes"] + # If cameraInit is None (i.e: SfM augmentation): + # * create an uninitialized node + # * wait for the result before actually creating new nodes in the graph (see onIntrinsicsAvailable) + attributes = cameraInit.toDict()["attributes"] if cameraInit else {} cameraInitCopy = graph.Node("CameraInit", **attributes) try: @@ -365,9 +368,29 @@ class Reconstruction(UIGraph): def onIntrinsicsAvailable(self, cameraInit, views, intrinsics): """ Update CameraInit with given views and intrinsics. """ - with self.groupedGraphModification("Add Images"): - self.setAttribute(cameraInit.viewpoints, views) - self.setAttribute(cameraInit.intrinsics, intrinsics) + augmentSfM = cameraInit is None + commandTitle = "Add {} Images" + + # SfM augmentation + if augmentSfM: + # filter out views already involved in the reconstruction + allViewIds = self.allViewIds() + views = [view for view in views if int(view["viewId"]) not in allViewIds] + commandTitle = "Augment Reconstruction ({} Images)" + + # No additional views: early return + if not views: + return + + commandTitle = commandTitle.format(len(views)) + # allow updates between commands so that node depths + # are updated after "addSfmAugmentation" (useful for auto layout) + with self.groupedGraphModification(commandTitle, disableUpdates=False): + if augmentSfM: + cameraInit, self.sfm = self.addSfmAugmentation() + with self.groupedGraphModification("Set Views and Intrinsics"): + self.setAttribute(cameraInit.viewpoints, views) + self.setAttribute(cameraInit.intrinsics, intrinsics) self.setCameraInit(cameraInit) def setBuildingIntrinsics(self, value):