mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-07-19 09:37:14 +02:00
[ui] new generic way to manage "active" nodes per node type
This commit is contained in:
parent
ea5b639245
commit
ec67c772fa
12 changed files with 344 additions and 205 deletions
|
@ -881,7 +881,7 @@ class Graph(BaseObject):
|
||||||
filterTypes (str list): (optional) only return the nodes of the given types
|
filterTypes (str list): (optional) only return the nodes of the given types
|
||||||
(does not stop the visit, this is a post-process only)
|
(does not stop the visit, this is a post-process only)
|
||||||
Returns:
|
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 = []
|
nodes = []
|
||||||
edges = []
|
edges = []
|
||||||
|
|
|
@ -58,8 +58,9 @@ Item {
|
||||||
}
|
}
|
||||||
MenuItem {
|
MenuItem {
|
||||||
text: "Define As Center Image"
|
text: "Define As Center Image"
|
||||||
enabled: !root.readOnly && _viewpoint.viewId != -1 && _reconstruction && _reconstruction.sfmTransform
|
property var activeNode: _reconstruction.activeNodes.get("SfMTransform").node
|
||||||
onClicked: _reconstruction.sfmTransform.attribute("transformation").value = _viewpoint.viewId.toString()
|
enabled: !root.readOnly && _viewpoint.viewId != -1 && _reconstruction && activeNode
|
||||||
|
onClicked: activeNode.attribute("transformation").value = _viewpoint.viewId.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -16,7 +16,7 @@ Panel {
|
||||||
|
|
||||||
property variant cameraInits
|
property variant cameraInits
|
||||||
property variant cameraInit
|
property variant cameraInit
|
||||||
property variant hdrCameraInit
|
property variant tempCameraInit
|
||||||
readonly property alias currentItem: grid.currentItem
|
readonly property alias currentItem: grid.currentItem
|
||||||
readonly property string currentItemSource: grid.currentItem ? grid.currentItem.source : ""
|
readonly property string currentItemSource: grid.currentItem ? grid.currentItem.source : ""
|
||||||
readonly property var currentItemMetadata: grid.currentItem ? grid.currentItem.metadata : undefined
|
readonly property var currentItemMetadata: grid.currentItem ? grid.currentItem.metadata : undefined
|
||||||
|
@ -38,7 +38,7 @@ Panel {
|
||||||
|
|
||||||
QtObject {
|
QtObject {
|
||||||
id: m
|
id: m
|
||||||
property variant currentCameraInit: displayHDR.checked ? _reconstruction.hdrCameraInit : root.cameraInit
|
property variant currentCameraInit: _reconstruction.tempCameraInit ? _reconstruction.tempCameraInit : root.cameraInit
|
||||||
property variant viewpoints: currentCameraInit ? currentCameraInit.attribute('viewpoints').value : undefined
|
property variant viewpoints: currentCameraInit ? currentCameraInit.attribute('viewpoints').value : undefined
|
||||||
property bool readOnly: root.readOnly || displayHDR.checked
|
property bool readOnly: root.readOnly || displayHDR.checked
|
||||||
}
|
}
|
||||||
|
@ -194,7 +194,7 @@ Panel {
|
||||||
// Center of SfMTransform
|
// Center of SfMTransform
|
||||||
Loader {
|
Loader {
|
||||||
id: sfmTransformIndicator
|
id: sfmTransformIndicator
|
||||||
active: (viewpoint.get("viewId").value == centerViewId)
|
active: viewpoint && (viewpoint.get("viewId").value == centerViewId)
|
||||||
sourceComponent: ImageBadge {
|
sourceComponent: ImageBadge {
|
||||||
text: MaterialIcons.gamepad
|
text: MaterialIcons.gamepad
|
||||||
ToolTip.text: "Camera used to define the center of the scene."
|
ToolTip.text: "Camera used to define the center of the scene."
|
||||||
|
@ -343,54 +343,114 @@ Panel {
|
||||||
}
|
}
|
||||||
|
|
||||||
footerContent: RowLayout {
|
footerContent: RowLayout {
|
||||||
|
// Images count
|
||||||
// Image count
|
MaterialToolLabel {
|
||||||
RowLayout {
|
ToolTip.text: grid.model.count + " Input Images"
|
||||||
Layout.fillWidth: true
|
iconText: MaterialIcons.image
|
||||||
spacing: 8
|
label: grid.model.count.toString()
|
||||||
RowLayout {
|
// enabled: grid.model.count > 0
|
||||||
MaterialLabel { text: MaterialIcons.image }
|
// margin: 4
|
||||||
Label { text: grid.model.count }
|
|
||||||
}
|
|
||||||
RowLayout {
|
|
||||||
visible: _reconstruction.cameraInit && _reconstruction.nbCameras
|
|
||||||
MaterialLabel { text: MaterialIcons.videocam }
|
|
||||||
Label { text: _reconstruction.cameraInit ? _reconstruction.nbCameras : 0 }
|
|
||||||
}
|
}
|
||||||
|
// cameras count
|
||||||
|
MaterialToolLabel {
|
||||||
|
ToolTip.text: label + " Estimated Cameras"
|
||||||
|
iconText: MaterialIcons.videocam
|
||||||
|
label: _reconstruction ? _reconstruction.nbCameras.toString() : "0"
|
||||||
|
// margin: 4
|
||||||
|
// enabled: _reconstruction.cameraInit && _reconstruction.nbCameras
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialToolButton {
|
Item { Layout.fillHeight: true; Layout.fillWidth: true }
|
||||||
|
|
||||||
|
MaterialToolLabelButton {
|
||||||
id: displayHDR
|
id: displayHDR
|
||||||
font.pointSize: 20
|
property var activeNode: _reconstruction.activeNodes.get("LdrToHdrMerge").node
|
||||||
padding: 0
|
ToolTip.text: "Visualize HDR images: " + (activeNode ? activeNode.label : "No Node")
|
||||||
anchors.margins: 0
|
iconText: MaterialIcons.filter
|
||||||
implicitHeight: 14
|
label: activeNode ? activeNode.attribute("nbBrackets").value : ""
|
||||||
ToolTip.text: "Visualize HDR images: " + (_reconstruction.ldr2hdr ? _reconstruction.ldr2hdr.label : "No Node")
|
// visible: activeNode
|
||||||
text: MaterialIcons.hdr_on
|
enabled: activeNode && activeNode.isComputed
|
||||||
visible: _reconstruction.ldr2hdr
|
property string nodeID: activeNode ? (activeNode.label + activeNode.isComputed) : ""
|
||||||
enabled: _reconstruction.ldr2hdr && _reconstruction.ldr2hdr.isComputed
|
|
||||||
property string nodeID: _reconstruction.ldr2hdr ? (_reconstruction.ldr2hdr.label + _reconstruction.ldr2hdr.isComputed) : ""
|
|
||||||
onNodeIDChanged: {
|
onNodeIDChanged: {
|
||||||
if(checked)
|
if(checked) {
|
||||||
{
|
open();
|
||||||
_reconstruction.setupLDRToHDRCameraInit();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onEnabledChanged: {
|
onEnabledChanged: {
|
||||||
// Reset the toggle to avoid getting stuck
|
// Reset the toggle to avoid getting stuck
|
||||||
// with the HDR node checked but disabled.
|
// with the HDR node checked but disabled.
|
||||||
|
if(checked) {
|
||||||
checked = false;
|
checked = false;
|
||||||
|
close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
checkable: true
|
checkable: true
|
||||||
checked: false
|
checked: false
|
||||||
onClicked: { _reconstruction.setupLDRToHDRCameraInit(); }
|
onClicked: {
|
||||||
|
if(checked) {
|
||||||
|
open();
|
||||||
|
} else {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function open() {
|
||||||
|
if(imageProcessing.checked)
|
||||||
|
imageProcessing.checked = false;
|
||||||
|
_reconstruction.setupTempCameraInit(activeNode, "outSfMDataFilename");
|
||||||
|
}
|
||||||
|
function close() {
|
||||||
|
_reconstruction.clearTempCameraInit();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Item { Layout.fillHeight: true; Layout.fillWidth: true }
|
MaterialToolButton {
|
||||||
|
id: imageProcessing
|
||||||
|
property var activeNode: _reconstruction.activeNodes.get("ImageProcessing").node
|
||||||
|
font.pointSize: 15
|
||||||
|
padding: 0
|
||||||
|
ToolTip.text: "Preprocessed Images: " + (activeNode ? activeNode.label : "No Node")
|
||||||
|
text: MaterialIcons.wallpaper
|
||||||
|
visible: activeNode && activeNode.attribute("outSfMData").value
|
||||||
|
enabled: activeNode && activeNode.isComputed
|
||||||
|
property string nodeID: activeNode ? (activeNode.label + activeNode.isComputed) : ""
|
||||||
|
onNodeIDChanged: {
|
||||||
|
if(checked) {
|
||||||
|
open();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onEnabledChanged: {
|
||||||
|
// Reset the toggle to avoid getting stuck
|
||||||
|
// with the HDR node checked but disabled.
|
||||||
|
if(checked) {
|
||||||
|
checked = false;
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
checkable: true
|
||||||
|
checked: false
|
||||||
|
onClicked: {
|
||||||
|
if(checked) {
|
||||||
|
open();
|
||||||
|
} else {
|
||||||
|
close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
function open() {
|
||||||
|
if(displayHDR.checked)
|
||||||
|
displayHDR.checked = false;
|
||||||
|
_reconstruction.setupTempCameraInit(activeNode, "outSfMData");
|
||||||
|
}
|
||||||
|
function close() {
|
||||||
|
_reconstruction.clearTempCameraInit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item { Layout.fillHeight: true; width: 1 }
|
||||||
|
|
||||||
// Thumbnail size icon and slider
|
// Thumbnail size icon and slider
|
||||||
MaterialToolButton {
|
MaterialToolButton {
|
||||||
text: MaterialIcons.photo_size_select_large
|
text: MaterialIcons.photo_size_select_large
|
||||||
|
ToolTip.text: "Thumbnails Scale"
|
||||||
padding: 0
|
padding: 0
|
||||||
anchors.margins: 0
|
anchors.margins: 0
|
||||||
font.pointSize: 11
|
font.pointSize: 11
|
||||||
|
@ -404,5 +464,4 @@ Panel {
|
||||||
implicitWidth: 70
|
implicitWidth: 70
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
23
meshroom/ui/qml/MaterialIcons/MLabel.qml
Normal file
23
meshroom/ui/qml/MaterialIcons/MLabel.qml
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.4
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MLabel is a standard Label.
|
||||||
|
* If ToolTip.text is set, it shows up a tooltip when hovered.
|
||||||
|
*/
|
||||||
|
Label {
|
||||||
|
padding: 4
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
}
|
||||||
|
ToolTip.visible: mouseArea.containsMouse
|
||||||
|
ToolTip.delay: 500
|
||||||
|
background: Rectangle {
|
||||||
|
anchors.fill: parent
|
||||||
|
color: mouseArea.containsMouse ? Qt.darker(parent.palette.base, 0.6) : "transparent"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
import QtQuick 2.9
|
import QtQuick 2.9
|
||||||
import QtQuick.Controls 2.3
|
import QtQuick.Controls 2.3
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -7,6 +8,7 @@ import QtQuick.Controls 2.3
|
||||||
* It also shows up its tooltip when hovered.
|
* It also shows up its tooltip when hovered.
|
||||||
*/
|
*/
|
||||||
ToolButton {
|
ToolButton {
|
||||||
|
id: control
|
||||||
font.family: MaterialIcons.fontFamily
|
font.family: MaterialIcons.fontFamily
|
||||||
padding: 4
|
padding: 4
|
||||||
font.pointSize: 13
|
font.pointSize: 13
|
||||||
|
|
45
meshroom/ui/qml/MaterialIcons/MaterialToolLabel.qml
Normal file
45
meshroom/ui/qml/MaterialIcons/MaterialToolLabel.qml
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.3
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MaterialToolLabel is a Label with an icon (using MaterialIcons).
|
||||||
|
* It shows up its tooltip when hovered.
|
||||||
|
*/
|
||||||
|
Item {
|
||||||
|
id: control
|
||||||
|
property alias iconText: icon.text
|
||||||
|
property alias iconSize: icon.font.pointSize
|
||||||
|
property alias label: labelItem.text
|
||||||
|
width: childrenRect.width
|
||||||
|
height: childrenRect.height
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
Label {
|
||||||
|
id: icon
|
||||||
|
font.family: MaterialIcons.fontFamily
|
||||||
|
font.pointSize: 13
|
||||||
|
padding: 0
|
||||||
|
text: ""
|
||||||
|
color: palette.text
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
id: labelItem
|
||||||
|
text: ""
|
||||||
|
color: palette.text
|
||||||
|
}
|
||||||
|
Item {
|
||||||
|
width: 5
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MouseArea {
|
||||||
|
id: mouseArea
|
||||||
|
anchors.fill: parent
|
||||||
|
hoverEnabled: true
|
||||||
|
acceptedButtons: Qt.NoButton
|
||||||
|
}
|
||||||
|
ToolTip.visible: mouseArea.containsMouse
|
||||||
|
ToolTip.delay: 500
|
||||||
|
}
|
51
meshroom/ui/qml/MaterialIcons/MaterialToolLabelButton.qml
Normal file
51
meshroom/ui/qml/MaterialIcons/MaterialToolLabelButton.qml
Normal file
|
@ -0,0 +1,51 @@
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.3
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* MaterialToolButton is a standard ToolButton using MaterialIcons font.
|
||||||
|
* It also shows up its tooltip when hovered.
|
||||||
|
*/
|
||||||
|
ToolButton {
|
||||||
|
id: control
|
||||||
|
property alias iconText: icon.text
|
||||||
|
property alias iconSize: icon.font.pointSize
|
||||||
|
property alias label: labelItem.text
|
||||||
|
padding: 0
|
||||||
|
ToolTip.visible: ToolTip.text && hovered
|
||||||
|
ToolTip.delay: 100
|
||||||
|
width: childrenRect.width
|
||||||
|
height: childrenRect.height
|
||||||
|
contentItem: RowLayout {
|
||||||
|
Layout.margins: 0
|
||||||
|
Label {
|
||||||
|
id: icon
|
||||||
|
font.family: MaterialIcons.fontFamily
|
||||||
|
font.pointSize: 13
|
||||||
|
padding: 0
|
||||||
|
text: ""
|
||||||
|
color: (checked ? palette.highlight : palette.text)
|
||||||
|
}
|
||||||
|
Label {
|
||||||
|
id: labelItem
|
||||||
|
text: ""
|
||||||
|
padding: 0
|
||||||
|
color: (checked ? palette.highlight : palette.text)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
background: Rectangle {
|
||||||
|
color: {
|
||||||
|
if(pressed || checked || hovered)
|
||||||
|
{
|
||||||
|
if(pressed || checked)
|
||||||
|
return Qt.darker(parent.palette.base, 1.3)
|
||||||
|
if(hovered)
|
||||||
|
return Qt.darker(parent.palette.base, 0.6)
|
||||||
|
}
|
||||||
|
return "transparent";
|
||||||
|
}
|
||||||
|
|
||||||
|
border.color: checked ? Qt.darker(parent.palette.base, 1.4) : "transparent"
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,7 @@
|
||||||
module MaterialIcons
|
module MaterialIcons
|
||||||
singleton MaterialIcons 2.2 MaterialIcons.qml
|
singleton MaterialIcons 2.2 MaterialIcons.qml
|
||||||
MaterialToolButton 2.2 MaterialToolButton.qml
|
MaterialToolButton 2.2 MaterialToolButton.qml
|
||||||
|
MaterialToolLabelButton 2.2 MaterialToolLabelButton.qml
|
||||||
|
MaterialToolLabel 2.2 MaterialToolLabel.qml
|
||||||
MaterialLabel 2.2 MaterialLabel.qml
|
MaterialLabel 2.2 MaterialLabel.qml
|
||||||
|
MLabel 2.2 MLabel.qml
|
||||||
|
|
|
@ -104,10 +104,11 @@ FocusScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
function getImageFile(type) {
|
function getImageFile(type) {
|
||||||
|
var depthMapNode = _reconstruction.activeNodes.get('allDepthMap').node;
|
||||||
if (type == "image") {
|
if (type == "image") {
|
||||||
return root.source;
|
return root.source;
|
||||||
} else if (_reconstruction.depthMap != undefined && _reconstruction.selectedViewId >= 0) {
|
} else if (depthMapNode != undefined && _reconstruction.selectedViewId >= 0) {
|
||||||
return Filepath.stringToUrl(_reconstruction.depthMap.internalFolder+_reconstruction.selectedViewId+"_"+type+"Map.exr");
|
return Filepath.stringToUrl(depthMapNode.internalFolder+_reconstruction.selectedViewId+"_"+type+"Map.exr");
|
||||||
}
|
}
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
@ -245,8 +246,8 @@ FocusScope {
|
||||||
// note: requires QtAliceVision plugin - use a Loader to evaluate plugin availability at runtime
|
// note: requires QtAliceVision plugin - use a Loader to evaluate plugin availability at runtime
|
||||||
Loader {
|
Loader {
|
||||||
id: featuresViewerLoader
|
id: featuresViewerLoader
|
||||||
|
|
||||||
active: displayFeatures.checked
|
active: displayFeatures.checked
|
||||||
|
property var activeNode: _reconstruction.activeNodes.get("FeatureExtraction").node
|
||||||
|
|
||||||
// handle rotation/position based on available metadata
|
// handle rotation/position based on available metadata
|
||||||
rotation: {
|
rotation: {
|
||||||
|
@ -265,8 +266,8 @@ FocusScope {
|
||||||
// instantiate and initialize a FeaturesViewer component dynamically using Loader.setSource
|
// instantiate and initialize a FeaturesViewer component dynamically using Loader.setSource
|
||||||
setSource("FeaturesViewer.qml", {
|
setSource("FeaturesViewer.qml", {
|
||||||
'viewId': Qt.binding(function() { return _reconstruction.selectedViewId; }),
|
'viewId': Qt.binding(function() { return _reconstruction.selectedViewId; }),
|
||||||
'model': Qt.binding(function() { return _reconstruction.featureExtraction ? _reconstruction.featureExtraction.attribute("describerTypes").value : ""; }),
|
'model': Qt.binding(function() { return activeNode ? activeNode.attribute("describerTypes").value : ""; }),
|
||||||
'featureFolder': Qt.binding(function() { return _reconstruction.featureExtraction ? Filepath.stringToUrl(_reconstruction.featureExtraction.attribute("output").value) : ""; }),
|
'featureFolder': Qt.binding(function() { return activeNode ? Filepath.stringToUrl(activeNode.attribute("output").value) : ""; }),
|
||||||
'tracks': Qt.binding(function() { return mtracksLoader.status === Loader.Ready ? mtracksLoader.item : null; }),
|
'tracks': Qt.binding(function() { return mtracksLoader.status === Loader.Ready ? mtracksLoader.item : null; }),
|
||||||
'sfmData': Qt.binding(function() { return msfmDataLoader.status === Loader.Ready ? msfmDataLoader.item : null; }),
|
'sfmData': Qt.binding(function() { return msfmDataLoader.status === Loader.Ready ? msfmDataLoader.item : null; }),
|
||||||
})
|
})
|
||||||
|
@ -281,7 +282,8 @@ FocusScope {
|
||||||
// note: use a Loader to evaluate if a PanoramaInit node exist and displayFisheyeCircle checked at runtime
|
// note: use a Loader to evaluate if a PanoramaInit node exist and displayFisheyeCircle checked at runtime
|
||||||
Loader {
|
Loader {
|
||||||
anchors.centerIn: parent
|
anchors.centerIn: parent
|
||||||
active: (displayFisheyeCircleLoader.checked && _reconstruction.panoramaInit)
|
property var activeNode: _reconstruction.activeNodes.get("PanoramaInit").node
|
||||||
|
active: (displayFisheyeCircleLoader.checked && activeNode)
|
||||||
|
|
||||||
// handle rotation/position based on available metadata
|
// handle rotation/position based on available metadata
|
||||||
rotation: {
|
rotation: {
|
||||||
|
@ -294,28 +296,28 @@ FocusScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceComponent: CircleGizmo {
|
sourceComponent: CircleGizmo {
|
||||||
property bool useAuto: _reconstruction.panoramaInit.attribute("estimateFisheyeCircle").value
|
property bool useAuto: activeNode.attribute("estimateFisheyeCircle").value
|
||||||
readOnly: useAuto
|
readOnly: useAuto
|
||||||
visible: (!useAuto) || _reconstruction.panoramaInit.isComputed
|
visible: (!useAuto) || activeNode.isComputed
|
||||||
property real userFisheyeRadius: _reconstruction.panoramaInit.attribute("fisheyeRadius").value
|
property real userFisheyeRadius: activeNode.attribute("fisheyeRadius").value
|
||||||
property variant fisheyeAutoParams: _reconstruction.getAutoFisheyeCircle(_reconstruction.panoramaInit)
|
property variant fisheyeAutoParams: _reconstruction.getAutoFisheyeCircle(activeNode)
|
||||||
|
|
||||||
x: useAuto ? fisheyeAutoParams.x : _reconstruction.panoramaInit.attribute("fisheyeCenterOffset.fisheyeCenterOffset_x").value
|
x: useAuto ? fisheyeAutoParams.x : activeNode.attribute("fisheyeCenterOffset.fisheyeCenterOffset_x").value
|
||||||
y: useAuto ? fisheyeAutoParams.y : _reconstruction.panoramaInit.attribute("fisheyeCenterOffset.fisheyeCenterOffset_y").value
|
y: useAuto ? fisheyeAutoParams.y : activeNode.attribute("fisheyeCenterOffset.fisheyeCenterOffset_y").value
|
||||||
radius: useAuto ? fisheyeAutoParams.z : ((imgContainer.image ? Math.min(imgContainer.image.width, imgContainer.image.height) : 1.0) * 0.5 * (userFisheyeRadius * 0.01))
|
radius: useAuto ? fisheyeAutoParams.z : ((imgContainer.image ? Math.min(imgContainer.image.width, imgContainer.image.height) : 1.0) * 0.5 * (userFisheyeRadius * 0.01))
|
||||||
|
|
||||||
border.width: Math.max(1, (3.0 / imgContainer.scale))
|
border.width: Math.max(1, (3.0 / imgContainer.scale))
|
||||||
onMoved: {
|
onMoved: {
|
||||||
if(!useAuto)
|
if(!useAuto)
|
||||||
{
|
{
|
||||||
_reconstruction.setAttribute(_reconstruction.panoramaInit.attribute("fisheyeCenterOffset.fisheyeCenterOffset_x"), x)
|
_reconstruction.setAttribute(activeNode.attribute("fisheyeCenterOffset.fisheyeCenterOffset_x"), x)
|
||||||
_reconstruction.setAttribute(_reconstruction.panoramaInit.attribute("fisheyeCenterOffset.fisheyeCenterOffset_y"), y)
|
_reconstruction.setAttribute(activeNode.attribute("fisheyeCenterOffset.fisheyeCenterOffset_y"), y)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
onIncrementRadius: {
|
onIncrementRadius: {
|
||||||
if(!useAuto)
|
if(!useAuto)
|
||||||
{
|
{
|
||||||
_reconstruction.setAttribute(_reconstruction.panoramaInit.attribute("fisheyeRadius"), _reconstruction.panoramaInit.attribute("fisheyeRadius").value + radiusOffset)
|
_reconstruction.setAttribute(activeNode.attribute("fisheyeRadius"), activeNode.attribute("fisheyeRadius").value + radiusOffset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -352,8 +354,9 @@ FocusScope {
|
||||||
// show which depthmap node is active
|
// show which depthmap node is active
|
||||||
Label {
|
Label {
|
||||||
id: depthMapNodeName
|
id: depthMapNodeName
|
||||||
visible: (_reconstruction.depthMap != undefined) && (imageType.type != "image")
|
property var activeNode: _reconstruction.activeNodes.get("allDepthMap").node
|
||||||
text: (_reconstruction.depthMap != undefined ? _reconstruction.depthMap.label : "")
|
visible: (activeNode != undefined) && (imageType.type != "image")
|
||||||
|
text: (activeNode != undefined ? activeNode.label : "")
|
||||||
font.pointSize: 8
|
font.pointSize: 8
|
||||||
|
|
||||||
horizontalAlignment: TextInput.AlignLeft
|
horizontalAlignment: TextInput.AlignLeft
|
||||||
|
@ -422,10 +425,9 @@ FocusScope {
|
||||||
}
|
}
|
||||||
Loader {
|
Loader {
|
||||||
id: mtracksLoader
|
id: mtracksLoader
|
||||||
// active: _reconstruction.featureMatching
|
|
||||||
|
|
||||||
property bool isUsed: displayFeatures.checked || displaySfmStatsView.checked || displaySfmDataGlobalStats.checked
|
property bool isUsed: displayFeatures.checked || displaySfmStatsView.checked || displaySfmDataGlobalStats.checked
|
||||||
property var activeNode: _reconstruction.featureMatching
|
property var activeNode: _reconstruction.activeNodes.get('FeatureMatching').node
|
||||||
property bool isComputed: activeNode && activeNode.isComputed
|
property bool isComputed: activeNode && activeNode.isComputed
|
||||||
|
|
||||||
active: false
|
active: false
|
||||||
|
@ -498,7 +500,7 @@ FocusScope {
|
||||||
active: displayFeatures.checked && featuresViewerLoader.status === Loader.Ready
|
active: displayFeatures.checked && featuresViewerLoader.status === Loader.Ready
|
||||||
|
|
||||||
sourceComponent: FeaturesInfoOverlay {
|
sourceComponent: FeaturesInfoOverlay {
|
||||||
featureExtractionNode: _reconstruction.featureExtraction
|
featureExtractionNode: _reconstruction.activeNodes.get('FeatureExtraction').node
|
||||||
pluginStatus: featuresViewerLoader.status
|
pluginStatus: featuresViewerLoader.status
|
||||||
featuresViewer: featuresViewerLoader.item
|
featuresViewer: featuresViewerLoader.item
|
||||||
}
|
}
|
||||||
|
@ -514,9 +516,8 @@ FocusScope {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
|
|
||||||
// zoom label
|
// zoom label
|
||||||
Label {
|
MLabel {
|
||||||
text: ((imgContainer.image && (imgContainer.image.status === Image.Ready)) ? imgContainer.scale.toFixed(2) : "1.00") + "x"
|
text: ((imgContainer.image && (imgContainer.image.status === Image.Ready)) ? imgContainer.scale.toFixed(2) : "1.00") + "x"
|
||||||
state: "xsmall"
|
|
||||||
MouseArea {
|
MouseArea {
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
acceptedButtons: Qt.LeftButton | Qt.RightButton
|
||||||
|
@ -533,6 +534,7 @@ FocusScope {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ToolTip.text: "Zoom"
|
||||||
}
|
}
|
||||||
MaterialToolButton {
|
MaterialToolButton {
|
||||||
id: displayAlphaBackground
|
id: displayAlphaBackground
|
||||||
|
@ -566,31 +568,30 @@ FocusScope {
|
||||||
}
|
}
|
||||||
MaterialToolButton {
|
MaterialToolButton {
|
||||||
id: displayFisheyeCircleLoader
|
id: displayFisheyeCircleLoader
|
||||||
ToolTip.text: "Display Fisheye Circle: " + (_reconstruction.panoramaInit ? _reconstruction.panoramaInit.label : "No Node")
|
property var activeNode: _reconstruction.activeNodes.get('PanoramaInit').node
|
||||||
text: MaterialIcons.panorama_fish_eye
|
ToolTip.text: "Display Fisheye Circle: " + (activeNode ? activeNode.label : "No Node")
|
||||||
|
text: MaterialIcons.vignette
|
||||||
|
// text: MaterialIcons.panorama_fish_eye
|
||||||
font.pointSize: 11
|
font.pointSize: 11
|
||||||
Layout.minimumWidth: 0
|
Layout.minimumWidth: 0
|
||||||
checkable: true
|
checkable: true
|
||||||
checked: false
|
checked: false
|
||||||
enabled: _reconstruction.panoramaInit && _reconstruction.panoramaInit.attribute("useFisheye").value
|
enabled: activeNode && activeNode.attribute("useFisheye").value
|
||||||
visible: _reconstruction.panoramaInit
|
visible: activeNode
|
||||||
}
|
}
|
||||||
|
|
||||||
Label {
|
Label {
|
||||||
id: resolutionLabel
|
id: resolutionLabel
|
||||||
Layout.fillWidth: true
|
Layout.fillWidth: true
|
||||||
text: imgContainer.image ? (imgContainer.image.sourceSize.width + "x" + imgContainer.image.sourceSize.height) : ""
|
text: (imgContainer.image && imgContainer.image.sourceSize.width > 0) ? (imgContainer.image.sourceSize.width + "x" + imgContainer.image.sourceSize.height) : ""
|
||||||
|
|
||||||
elide: Text.ElideRight
|
elide: Text.ElideRight
|
||||||
horizontalAlignment: Text.AlignHCenter
|
horizontalAlignment: Text.AlignHCenter
|
||||||
/*Rectangle {
|
|
||||||
anchors.fill: parent
|
|
||||||
color: "blue"
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ComboBox {
|
ComboBox {
|
||||||
id: imageType
|
id: imageType
|
||||||
|
property var activeNode: _reconstruction.activeNodes.get('allDepthMap').node
|
||||||
// set min size to 5 characters + one margin for the combobox
|
// set min size to 5 characters + one margin for the combobox
|
||||||
clip: true
|
clip: true
|
||||||
Layout.minimumWidth: 0
|
Layout.minimumWidth: 0
|
||||||
|
@ -601,12 +602,13 @@ FocusScope {
|
||||||
property string type: enabled ? types[currentIndex] : types[0]
|
property string type: enabled ? types[currentIndex] : types[0]
|
||||||
|
|
||||||
model: types
|
model: types
|
||||||
enabled: _reconstruction.depthMap != undefined
|
enabled: activeNode
|
||||||
}
|
}
|
||||||
|
|
||||||
MaterialToolButton {
|
MaterialToolButton {
|
||||||
enabled: _reconstruction.depthMap != undefined
|
property var activeNode: _reconstruction.activeNodes.get('allDepthMap').node
|
||||||
ToolTip.text: "View Depth Map in 3D (" + (_reconstruction.depthMap != undefined ? _reconstruction.depthMap.label : "No DepthMap Node Selected") + ")"
|
enabled: activeNode
|
||||||
|
ToolTip.text: "View Depth Map in 3D (" + (activeNode ? activeNode.label : "No DepthMap Node Selected") + ")"
|
||||||
text: MaterialIcons.input
|
text: MaterialIcons.input
|
||||||
font.pointSize: 11
|
font.pointSize: 11
|
||||||
Layout.minimumWidth: 0
|
Layout.minimumWidth: 0
|
||||||
|
@ -618,6 +620,7 @@ FocusScope {
|
||||||
|
|
||||||
MaterialToolButton {
|
MaterialToolButton {
|
||||||
id: displaySfmStatsView
|
id: displaySfmStatsView
|
||||||
|
property var activeNode: _reconstruction.activeNodes.get('sfm').node
|
||||||
|
|
||||||
font.family: MaterialIcons.fontFamily
|
font.family: MaterialIcons.fontFamily
|
||||||
text: MaterialIcons.assessment
|
text: MaterialIcons.assessment
|
||||||
|
@ -630,10 +633,9 @@ FocusScope {
|
||||||
smooth: false
|
smooth: false
|
||||||
flat: true
|
flat: true
|
||||||
checkable: enabled
|
checkable: enabled
|
||||||
enabled: _reconstruction.sfm && _reconstruction.sfm.isComputed && _reconstruction.selectedViewId >= 0
|
enabled: activeNode && activeNode.isComputed && _reconstruction.selectedViewId >= 0
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if(checked == true)
|
if(checked == true) {
|
||||||
{
|
|
||||||
displaySfmDataGlobalStats.checked = false
|
displaySfmDataGlobalStats.checked = false
|
||||||
metadataCB.checked = false
|
metadataCB.checked = false
|
||||||
}
|
}
|
||||||
|
@ -642,6 +644,7 @@ FocusScope {
|
||||||
|
|
||||||
MaterialToolButton {
|
MaterialToolButton {
|
||||||
id: displaySfmDataGlobalStats
|
id: displaySfmDataGlobalStats
|
||||||
|
property var activeNode: _reconstruction.activeNodes.get('sfm').node
|
||||||
|
|
||||||
font.family: MaterialIcons.fontFamily
|
font.family: MaterialIcons.fontFamily
|
||||||
text: MaterialIcons.language
|
text: MaterialIcons.language
|
||||||
|
@ -654,10 +657,9 @@ FocusScope {
|
||||||
smooth: false
|
smooth: false
|
||||||
flat: true
|
flat: true
|
||||||
checkable: enabled
|
checkable: enabled
|
||||||
enabled: _reconstruction.sfm && _reconstruction.sfm.isComputed
|
enabled: activeNode && activeNode.isComputed
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if(checked == true)
|
if(checked == true) {
|
||||||
{
|
|
||||||
displaySfmStatsView.checked = false
|
displaySfmStatsView.checked = false
|
||||||
metadataCB.checked = false
|
metadataCB.checked = false
|
||||||
}
|
}
|
||||||
|
|
|
@ -65,7 +65,7 @@ Item {
|
||||||
readOnly: root.readOnly
|
readOnly: root.readOnly
|
||||||
cameraInits: root.cameraInits
|
cameraInits: root.cameraInits
|
||||||
cameraInit: reconstruction.cameraInit
|
cameraInit: reconstruction.cameraInit
|
||||||
hdrCameraInit: reconstruction.hdrCameraInit
|
tempCameraInit: reconstruction.tempCameraInit
|
||||||
currentIndex: reconstruction.cameraInitIndex
|
currentIndex: reconstruction.cameraInitIndex
|
||||||
onRemoveImageRequest: reconstruction.removeAttribute(attribute)
|
onRemoveImageRequest: reconstruction.removeAttribute(attribute)
|
||||||
onFilesDropped: reconstruction.handleFilesDrop(drop, augmentSfm ? null : cameraInit)
|
onFilesDropped: reconstruction.handleFilesDrop(drop, augmentSfm ? null : cameraInit)
|
||||||
|
@ -191,7 +191,7 @@ Item {
|
||||||
mediaLibrary: viewer3D.library
|
mediaLibrary: viewer3D.library
|
||||||
camera: viewer3D.mainCamera
|
camera: viewer3D.mainCamera
|
||||||
uigraph: reconstruction
|
uigraph: reconstruction
|
||||||
onNodeActivated: _reconstruction.setActiveNodeOfType(node)
|
onNodeActivated: _reconstruction.setActiveNode(node)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -703,7 +703,6 @@ ApplicationWindow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
GraphEditor {
|
GraphEditor {
|
||||||
id: graphEditor
|
id: graphEditor
|
||||||
|
|
||||||
|
@ -713,7 +712,7 @@ ApplicationWindow {
|
||||||
readOnly: graphLocked
|
readOnly: graphLocked
|
||||||
|
|
||||||
onNodeDoubleClicked: {
|
onNodeDoubleClicked: {
|
||||||
_reconstruction.setActiveNodeOfType(node);
|
_reconstruction.setActiveNode(node);
|
||||||
|
|
||||||
let viewable = false;
|
let viewable = false;
|
||||||
for(var i=0; i < node.attributes.count; ++i)
|
for(var i=0; i < node.attributes.count; ++i)
|
||||||
|
|
|
@ -8,6 +8,7 @@ from PySide2.QtCore import QObject, Slot, Property, Signal, QUrl, QSizeF
|
||||||
from PySide2.QtGui import QMatrix4x4, QMatrix3x3, QQuaternion, QVector3D, QVector2D
|
from PySide2.QtGui import QMatrix4x4, QMatrix3x3, QQuaternion, QVector3D, QVector2D
|
||||||
|
|
||||||
import meshroom.core
|
import meshroom.core
|
||||||
|
import meshroom.common
|
||||||
from meshroom import multiview
|
from meshroom import multiview
|
||||||
from meshroom.common.qt import QObjectListModel
|
from meshroom.common.qt import QObjectListModel
|
||||||
from meshroom.core import Version
|
from meshroom.core import Version
|
||||||
|
@ -196,6 +197,7 @@ class ViewpointWrapper(QObject):
|
||||||
self._reconstructed = False
|
self._reconstructed = False
|
||||||
# PrepareDenseScene
|
# PrepareDenseScene
|
||||||
self._undistortedImagePath = ''
|
self._undistortedImagePath = ''
|
||||||
|
self._activeNode_PrepareDenseScene = self._reconstruction.activeNodes.get("PrepareDenseScene")
|
||||||
|
|
||||||
# update internally cached variables
|
# update internally cached variables
|
||||||
self._updateInitialParams()
|
self._updateInitialParams()
|
||||||
|
@ -205,7 +207,7 @@ class ViewpointWrapper(QObject):
|
||||||
# trigger internal members updates when reconstruction members changes
|
# trigger internal members updates when reconstruction members changes
|
||||||
self._reconstruction.cameraInitChanged.connect(self._updateInitialParams)
|
self._reconstruction.cameraInitChanged.connect(self._updateInitialParams)
|
||||||
self._reconstruction.sfmReportChanged.connect(self._updateSfMParams)
|
self._reconstruction.sfmReportChanged.connect(self._updateSfMParams)
|
||||||
self._reconstruction.prepareDenseSceneChanged.connect(self._updateDenseSceneParams)
|
self._activeNode_PrepareDenseScene.nodeChanged.connect(self._updateDenseSceneParams)
|
||||||
|
|
||||||
def _updateInitialParams(self):
|
def _updateInitialParams(self):
|
||||||
""" Update internal members depending on CameraInit. """
|
""" Update internal members depending on CameraInit. """
|
||||||
|
@ -235,11 +237,11 @@ class ViewpointWrapper(QObject):
|
||||||
def _updateDenseSceneParams(self):
|
def _updateDenseSceneParams(self):
|
||||||
""" Update internal members depending on PrepareDenseScene. """
|
""" Update internal members depending on PrepareDenseScene. """
|
||||||
# undistorted image path
|
# undistorted image path
|
||||||
if not self._reconstruction.prepareDenseScene:
|
if not self._activeNode_PrepareDenseScene.node:
|
||||||
self._undistortedImagePath = ''
|
self._undistortedImagePath = ''
|
||||||
else:
|
else:
|
||||||
filename = "{}.{}".format(self._viewpoint.viewId.value, self._reconstruction.prepareDenseScene.outputFileType.value)
|
filename = "{}.{}".format(self._viewpoint.viewId.value, self._activeNode_PrepareDenseScene.node.outputFileType.value)
|
||||||
self._undistortedImagePath = os.path.join(self._reconstruction.prepareDenseScene.output.value, filename)
|
self._undistortedImagePath = os.path.join(self._activeNode_PrepareDenseScene.node.output.value, filename)
|
||||||
self.denseSceneParamsChanged.emit()
|
self.denseSceneParamsChanged.emit()
|
||||||
|
|
||||||
@Property(type=QObject, constant=True)
|
@Property(type=QObject, constant=True)
|
||||||
|
@ -388,37 +390,50 @@ def parseSfMJsonFile(sfmJsonFile):
|
||||||
return views, poses, intrinsics
|
return views, poses, intrinsics
|
||||||
|
|
||||||
|
|
||||||
sfmHolderNodeTypes = ["StructureFromMotion", "GlobalSfM", "PanoramaEstimation", "SfMTransfer", "SfMTransform", "SfMAlignment"]
|
class ActiveNode(QObject):
|
||||||
|
"""
|
||||||
|
Hold one active node for a given NodeType.
|
||||||
|
"""
|
||||||
|
def __init__(self, nodeType, parent=None):
|
||||||
|
super(ActiveNode, self).__init__(parent)
|
||||||
|
self.nodeType = nodeType
|
||||||
|
self._node = None
|
||||||
|
|
||||||
|
nodeChanged = Signal()
|
||||||
|
node = makeProperty(QObject, "_node", nodeChanged, resetOnDestroy=True)
|
||||||
|
|
||||||
|
|
||||||
class Reconstruction(UIGraph):
|
class Reconstruction(UIGraph):
|
||||||
"""
|
"""
|
||||||
Specialization of a UIGraph designed to manage a 3D reconstruction.
|
Specialization of a UIGraph designed to manage a 3D reconstruction.
|
||||||
"""
|
"""
|
||||||
|
activeNodeCategories = {
|
||||||
|
"sfm": ["StructureFromMotion", "GlobalSfM", "PanoramaEstimation", "SfMTransfer", "SfMTransform",
|
||||||
|
"SfMAlignment"],
|
||||||
|
"undistort": ["PrepareDenseScene", "PanoramaWarping"],
|
||||||
|
"allDepthMap": ["DepthMap", "DepthMapFilter"],
|
||||||
|
}
|
||||||
|
|
||||||
def __init__(self, defaultPipeline='', parent=None):
|
def __init__(self, defaultPipeline='', parent=None):
|
||||||
super(Reconstruction, self).__init__(parent)
|
super(Reconstruction, self).__init__(parent)
|
||||||
|
|
||||||
# initialize member variables for key steps of the 3D reconstruction pipeline
|
# initialize member variables for key steps of the 3D reconstruction pipeline
|
||||||
|
|
||||||
|
self._activeNodes = meshroom.common.DictModel(keyAttrName="nodeType")
|
||||||
|
self.initActiveNodes()
|
||||||
|
|
||||||
# - CameraInit
|
# - CameraInit
|
||||||
self._cameraInit = None # current CameraInit node
|
self._cameraInit = None # current CameraInit node
|
||||||
self._cameraInits = QObjectListModel(parent=self) # all CameraInit nodes
|
self._cameraInits = QObjectListModel(parent=self) # all CameraInit nodes
|
||||||
self._buildingIntrinsics = False
|
self._buildingIntrinsics = False
|
||||||
self.intrinsicsBuilt.connect(self.onIntrinsicsAvailable)
|
self.intrinsicsBuilt.connect(self.onIntrinsicsAvailable)
|
||||||
|
|
||||||
self._hdrCameraInit = None
|
self.cameraInitChanged.connect(self.onCameraInitChanged)
|
||||||
|
|
||||||
|
self._tempCameraInit = None
|
||||||
|
|
||||||
self.importImagesFailed.connect(self.onImportImagesFailed)
|
self.importImagesFailed.connect(self.onImportImagesFailed)
|
||||||
|
|
||||||
# - Feature Extraction
|
|
||||||
self._featureExtraction = None
|
|
||||||
self.cameraInitChanged.connect(self.updateFeatureExtraction)
|
|
||||||
|
|
||||||
# - Feature Matching
|
|
||||||
self._featureMatching = None
|
|
||||||
self.cameraInitChanged.connect(self.updateFeatureMatching)
|
|
||||||
|
|
||||||
# - SfM
|
# - SfM
|
||||||
self._sfm = None
|
self._sfm = None
|
||||||
self._views = None
|
self._views = None
|
||||||
|
@ -428,28 +443,6 @@ class Reconstruction(UIGraph):
|
||||||
self._selectedViewpoint = None
|
self._selectedViewpoint = None
|
||||||
self._liveSfmManager = LiveSfmManager(self)
|
self._liveSfmManager = LiveSfmManager(self)
|
||||||
|
|
||||||
# - Prepare Dense Scene (undistorted images)
|
|
||||||
self._prepareDenseScene = None
|
|
||||||
|
|
||||||
# - Depth Map
|
|
||||||
self._depthMap = None
|
|
||||||
self.cameraInitChanged.connect(self.updateDepthMapNode)
|
|
||||||
|
|
||||||
# - Texturing
|
|
||||||
self._texturing = None
|
|
||||||
|
|
||||||
# - LDR2HDR
|
|
||||||
self._ldr2hdr = None
|
|
||||||
self.cameraInitChanged.connect(self.updateLdr2hdrNode)
|
|
||||||
|
|
||||||
# - PanoramaInit
|
|
||||||
self._panoramaInit = None
|
|
||||||
self.cameraInitChanged.connect(self.updatePanoramaInitNode)
|
|
||||||
|
|
||||||
# - PanoramaInit
|
|
||||||
self._sfmTransform = None
|
|
||||||
self.cameraInitChanged.connect(self.updateSfMTransformNode)
|
|
||||||
|
|
||||||
# react to internal graph changes to update those variables
|
# react to internal graph changes to update those variables
|
||||||
self.graphChanged.connect(self.onGraphChanged)
|
self.graphChanged.connect(self.onGraphChanged)
|
||||||
|
|
||||||
|
@ -458,6 +451,18 @@ class Reconstruction(UIGraph):
|
||||||
def setDefaultPipeline(self, defaultPipeline):
|
def setDefaultPipeline(self, defaultPipeline):
|
||||||
self._defaultPipeline = defaultPipeline
|
self._defaultPipeline = defaultPipeline
|
||||||
|
|
||||||
|
def initActiveNodes(self):
|
||||||
|
# Create all possible entries
|
||||||
|
for category, _ in self.activeNodeCategories.iteritems():
|
||||||
|
self._activeNodes.add(ActiveNode(category, self))
|
||||||
|
for nodeType, _ in meshroom.core.nodesDesc.iteritems():
|
||||||
|
self._activeNodes.add(ActiveNode(nodeType, self))
|
||||||
|
|
||||||
|
def onCameraInitChanged(self):
|
||||||
|
# Update active nodes when CameraInit changes
|
||||||
|
nodes = self._graph.nodesFromNode(self._cameraInit)[0]
|
||||||
|
self.setActiveNodes(nodes)
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
@Slot(str)
|
@Slot(str)
|
||||||
def new(self, pipeline=None):
|
def new(self, pipeline=None):
|
||||||
|
@ -528,16 +533,8 @@ class Reconstruction(UIGraph):
|
||||||
""" React to the change of the internal graph. """
|
""" React to the change of the internal graph. """
|
||||||
self._liveSfmManager.reset()
|
self._liveSfmManager.reset()
|
||||||
self.selectedViewId = "-1"
|
self.selectedViewId = "-1"
|
||||||
self.featureExtraction = None
|
|
||||||
self.featureMatching = None
|
|
||||||
self.sfm = None
|
self.sfm = None
|
||||||
self.prepareDenseScene = None
|
self.tempCameraInit = None
|
||||||
self.depthMap = None
|
|
||||||
self.texturing = None
|
|
||||||
self.ldr2hdr = None
|
|
||||||
self.hdrCameraInit = None
|
|
||||||
self.panoramaInit = None
|
|
||||||
self.sfmTransform = None
|
|
||||||
self.updateCameraInits()
|
self.updateCameraInits()
|
||||||
if not self._graph:
|
if not self._graph:
|
||||||
return
|
return
|
||||||
|
@ -578,35 +575,23 @@ class Reconstruction(UIGraph):
|
||||||
camInit = self._cameraInits[idx] if self._cameraInits else None
|
camInit = self._cameraInits[idx] if self._cameraInits else None
|
||||||
self.cameraInit = camInit
|
self.cameraInit = camInit
|
||||||
|
|
||||||
def updateFeatureExtraction(self):
|
|
||||||
""" Set the current FeatureExtraction node based on the current CameraInit node. """
|
|
||||||
self.featureExtraction = self.lastNodeOfType(['FeatureExtraction'], self.cameraInit) if self.cameraInit else None
|
|
||||||
|
|
||||||
def updateFeatureMatching(self):
|
|
||||||
""" Set the current FeatureMatching node based on the current CameraInit node. """
|
|
||||||
self.featureMatching = self.lastNodeOfType(['FeatureMatching'], self.cameraInit) if self.cameraInit else None
|
|
||||||
|
|
||||||
def updateDepthMapNode(self):
|
|
||||||
""" Set the current FeatureExtraction node based on the current CameraInit node. """
|
|
||||||
self.depthMap = self.lastNodeOfType(['DepthMapFilter'], self.cameraInit) if self.cameraInit else None
|
|
||||||
|
|
||||||
def updateLdr2hdrNode(self):
|
|
||||||
""" Set the current LDR2HDR node based on the current CameraInit node. """
|
|
||||||
self.ldr2hdr = self.lastNodeOfType(['LdrToHdrMerge'], self.cameraInit) if self.cameraInit else None
|
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def setupLDRToHDRCameraInit(self):
|
def clearTempCameraInit(self):
|
||||||
if not self.ldr2hdr:
|
self.tempCameraInit = None
|
||||||
self.hdrCameraInit = Node("CameraInit")
|
|
||||||
|
@Slot(QObject, str)
|
||||||
|
def setupTempCameraInit(self, node, attrName):
|
||||||
|
if not node or not attrName:
|
||||||
|
self.tempCameraInit = None
|
||||||
return
|
return
|
||||||
sfmFile = self.ldr2hdr.attribute("outSfMDataFilename").value
|
sfmFile = node.attribute(attrName).value
|
||||||
if not sfmFile or not os.path.isfile(sfmFile):
|
if not sfmFile or not os.path.isfile(sfmFile):
|
||||||
self.hdrCameraInit = Node("CameraInit")
|
self.tempCameraInit = None
|
||||||
return
|
return
|
||||||
nodeDesc = meshroom.core.nodesDesc["CameraInit"]()
|
nodeDesc = meshroom.core.nodesDesc["CameraInit"]()
|
||||||
views, intrinsics = nodeDesc.readSfMData(sfmFile)
|
views, intrinsics = nodeDesc.readSfMData(sfmFile)
|
||||||
tmpCameraInit = Node("CameraInit", viewpoints=views, intrinsics=intrinsics)
|
tmpCameraInit = Node("CameraInit", viewpoints=views, intrinsics=intrinsics)
|
||||||
self.hdrCameraInit = tmpCameraInit
|
self.tempCameraInit = tmpCameraInit
|
||||||
|
|
||||||
@Slot(QObject, result=QVector3D)
|
@Slot(QObject, result=QVector3D)
|
||||||
def getAutoFisheyeCircle(self, panoramaInit):
|
def getAutoFisheyeCircle(self, panoramaInit):
|
||||||
|
@ -633,17 +618,9 @@ class Reconstruction(UIGraph):
|
||||||
float(intrinsic.get("fisheyeCircleRadius", 0.0)))
|
float(intrinsic.get("fisheyeCircleRadius", 0.0)))
|
||||||
return res
|
return res
|
||||||
|
|
||||||
def updatePanoramaInitNode(self):
|
|
||||||
""" Set the current FeatureExtraction node based on the current CameraInit node. """
|
|
||||||
self.panoramaInit = self.lastNodeOfType(["PanoramaInit"], self.cameraInit) if self.cameraInit else None
|
|
||||||
|
|
||||||
def updateSfMTransformNode(self):
|
|
||||||
""" Set the current SfMTransform node based on the current CameraInit node. """
|
|
||||||
self.sfmTransform = self.lastNodeOfType(["SfMTransform"], self.cameraInit) if self.cameraInit else None
|
|
||||||
|
|
||||||
def lastSfmNode(self):
|
def lastSfmNode(self):
|
||||||
""" Retrieve the last SfM node from the initial CameraInit node. """
|
""" Retrieve the last SfM node from the initial CameraInit node. """
|
||||||
return self.lastNodeOfType(sfmHolderNodeTypes, self._cameraInit, Status.SUCCESS)
|
return self.lastNodeOfType(self.activeNodeCategories['sfm'], self._cameraInit, Status.SUCCESS)
|
||||||
|
|
||||||
def lastNodeOfType(self, nodeTypes, startNode, preferredStatus=None):
|
def lastNodeOfType(self, nodeTypes, startNode, preferredStatus=None):
|
||||||
"""
|
"""
|
||||||
|
@ -938,10 +915,11 @@ class Reconstruction(UIGraph):
|
||||||
self._buildingIntrinsics = value
|
self._buildingIntrinsics = value
|
||||||
self.buildingIntrinsicsChanged.emit()
|
self.buildingIntrinsicsChanged.emit()
|
||||||
|
|
||||||
|
activeNodes = makeProperty(QObject, "_activeNodes", resetOnDestroy=True)
|
||||||
cameraInitChanged = Signal()
|
cameraInitChanged = Signal()
|
||||||
cameraInit = makeProperty(QObject, "_cameraInit", cameraInitChanged, resetOnDestroy=True)
|
cameraInit = makeProperty(QObject, "_cameraInit", cameraInitChanged, resetOnDestroy=True)
|
||||||
hdrCameraInitChanged = Signal()
|
tempCameraInitChanged = Signal()
|
||||||
hdrCameraInit = makeProperty(QObject, "_hdrCameraInit", hdrCameraInitChanged, resetOnDestroy=True)
|
tempCameraInit = makeProperty(QObject, "_tempCameraInit", tempCameraInitChanged, resetOnDestroy=True)
|
||||||
cameraInitIndex = Property(int, getCameraInitIndex, setCameraInitIndex, notify=cameraInitChanged)
|
cameraInitIndex = Property(int, getCameraInitIndex, setCameraInitIndex, notify=cameraInitChanged)
|
||||||
viewpoints = Property(QObject, getViewpoints, notify=cameraInitChanged)
|
viewpoints = Property(QObject, getViewpoints, notify=cameraInitChanged)
|
||||||
cameraInits = Property(QObject, lambda self: self._cameraInits, constant=True)
|
cameraInits = Property(QObject, lambda self: self._cameraInits, constant=True)
|
||||||
|
@ -952,27 +930,30 @@ class Reconstruction(UIGraph):
|
||||||
liveSfmManager = Property(QObject, lambda self: self._liveSfmManager, constant=True)
|
liveSfmManager = Property(QObject, lambda self: self._liveSfmManager, constant=True)
|
||||||
|
|
||||||
@Slot(QObject)
|
@Slot(QObject)
|
||||||
def setActiveNodeOfType(self, node):
|
def setActiveNode(self, node):
|
||||||
""" Set node as the active node of its type. """
|
""" Set node as the active node of its type. """
|
||||||
if node.nodeType in sfmHolderNodeTypes:
|
for category, nodeTypes in self.activeNodeCategories.iteritems():
|
||||||
self.sfm = node
|
if node.nodeType in nodeTypes:
|
||||||
|
self.activeNodes.get(category).node = node
|
||||||
|
if category == 'sfm':
|
||||||
|
self.setSfm(node)
|
||||||
|
self.activeNodes.get(node.nodeType).node = node
|
||||||
|
|
||||||
if node.nodeType == "FeatureExtraction":
|
@Slot(QObject)
|
||||||
self.featureExtraction = node
|
def setActiveNodes(self, nodes):
|
||||||
elif node.nodeType == "FeatureMatching":
|
""" Set node as the active node of its type. """
|
||||||
self.featureMatching = node
|
# Setup the active node per category only once, on the last one
|
||||||
elif node.nodeType == "CameraInit":
|
nodesByCategory = {}
|
||||||
self.cameraInit = node
|
for node in nodes:
|
||||||
elif node.nodeType == "PrepareDenseScene":
|
for category, nodeTypes in self.activeNodeCategories.iteritems():
|
||||||
self.prepareDenseScene = node
|
if node.nodeType in nodeTypes:
|
||||||
elif node.nodeType in ("DepthMap", "DepthMapFilter"):
|
nodesByCategory[category] = node
|
||||||
self.depthMap = node
|
for category, node in nodesByCategory.iteritems():
|
||||||
elif node.nodeType == "LdrToHdrMerge":
|
self.activeNodes.get(category).node = node
|
||||||
self.ldr2hdr = node
|
if category == 'sfm':
|
||||||
elif node.nodeType == "PanoramaInit":
|
self.setSfm(node)
|
||||||
self.panoramaInit = node
|
for node in nodes:
|
||||||
elif node.nodeType == "SfMTransform":
|
self.activeNodes.get(node.nodeType).node = node
|
||||||
self.sfmTransform = node
|
|
||||||
|
|
||||||
def updateSfMResults(self):
|
def updateSfMResults(self):
|
||||||
"""
|
"""
|
||||||
|
@ -1021,9 +1002,6 @@ class Reconstruction(UIGraph):
|
||||||
self._sfm.destroyed.disconnect(self._unsetSfm)
|
self._sfm.destroyed.disconnect(self._unsetSfm)
|
||||||
self._setSfm(node)
|
self._setSfm(node)
|
||||||
|
|
||||||
self.texturing = self.lastNodeOfType(["Texturing"], self._sfm, Status.SUCCESS)
|
|
||||||
self.prepareDenseScene = self.lastNodeOfType(["PrepareDenseScene"], self._sfm, Status.SUCCESS)
|
|
||||||
|
|
||||||
@Slot(QObject, result=bool)
|
@Slot(QObject, result=bool)
|
||||||
def isInViews(self, viewpoint):
|
def isInViews(self, viewpoint):
|
||||||
if not viewpoint:
|
if not viewpoint:
|
||||||
|
@ -1129,35 +1107,11 @@ class Reconstruction(UIGraph):
|
||||||
sfmChanged = Signal()
|
sfmChanged = Signal()
|
||||||
sfm = Property(QObject, getSfm, setSfm, notify=sfmChanged)
|
sfm = Property(QObject, getSfm, setSfm, notify=sfmChanged)
|
||||||
|
|
||||||
featureExtractionChanged = Signal()
|
|
||||||
featureExtraction = makeProperty(QObject, "_featureExtraction", featureExtractionChanged, resetOnDestroy=True)
|
|
||||||
|
|
||||||
featureMatchingChanged = Signal()
|
|
||||||
featureMatching = makeProperty(QObject, "_featureMatching", featureMatchingChanged, resetOnDestroy=True)
|
|
||||||
|
|
||||||
sfmReportChanged = Signal()
|
sfmReportChanged = Signal()
|
||||||
# convenient property for QML binding re-evaluation when sfm report changes
|
# convenient property for QML binding re-evaluation when sfm report changes
|
||||||
sfmReport = Property(bool, lambda self: len(self._poses) > 0, notify=sfmReportChanged)
|
sfmReport = Property(bool, lambda self: len(self._poses) > 0, notify=sfmReportChanged)
|
||||||
sfmAugmented = Signal(Node, Node)
|
sfmAugmented = Signal(Node, Node)
|
||||||
|
|
||||||
prepareDenseSceneChanged = Signal()
|
|
||||||
prepareDenseScene = makeProperty(QObject, "_prepareDenseScene", notify=prepareDenseSceneChanged, resetOnDestroy=True)
|
|
||||||
|
|
||||||
depthMapChanged = Signal()
|
|
||||||
depthMap = makeProperty(QObject, "_depthMap", depthMapChanged, resetOnDestroy=True)
|
|
||||||
|
|
||||||
texturingChanged = Signal()
|
|
||||||
texturing = makeProperty(QObject, "_texturing", notify=texturingChanged, resetOnDestroy=True)
|
|
||||||
|
|
||||||
ldr2hdrChanged = Signal()
|
|
||||||
ldr2hdr = makeProperty(QObject, "_ldr2hdr", notify=ldr2hdrChanged, resetOnDestroy=True)
|
|
||||||
|
|
||||||
panoramaInitChanged = Signal()
|
|
||||||
panoramaInit = makeProperty(QObject, "_panoramaInit", notify=panoramaInitChanged, resetOnDestroy=True)
|
|
||||||
|
|
||||||
sfmTransformChanged = Signal()
|
|
||||||
sfmTransform = makeProperty(QObject, "_sfmTransform", notify=sfmTransformChanged, resetOnDestroy=True)
|
|
||||||
|
|
||||||
nbCameras = Property(int, reconstructedCamerasCount, notify=sfmReportChanged)
|
nbCameras = Property(int, reconstructedCamerasCount, notify=sfmReportChanged)
|
||||||
|
|
||||||
# Signals to propagate high-level messages
|
# Signals to propagate high-level messages
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue