mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-06-05 04:12:15 +02:00
wip [ui] display global stats from sfm: residuals,landmarks per view
This commit is contained in:
parent
f07b959a2b
commit
150e142f92
5 changed files with 213 additions and 5 deletions
|
@ -12,6 +12,8 @@ Repeater {
|
||||||
|
|
||||||
/// ViewID to display the features of
|
/// ViewID to display the features of
|
||||||
property int viewId
|
property int viewId
|
||||||
|
/// SfMData to display the data of SfM
|
||||||
|
property var sfmData
|
||||||
/// Folder containing the features files
|
/// Folder containing the features files
|
||||||
property string folder
|
property string folder
|
||||||
/// The list of describer types to load
|
/// The list of describer types to load
|
||||||
|
@ -35,6 +37,7 @@ Repeater {
|
||||||
viewId: root.viewId
|
viewId: root.viewId
|
||||||
color: root.colors[colorIndex]
|
color: root.colors[colorIndex]
|
||||||
displayMode: root.displayMode
|
displayMode: root.displayMode
|
||||||
|
msfmData: root.sfmData
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,6 +19,7 @@ FloatingPane {
|
||||||
|
|
||||||
clip: true
|
clip: true
|
||||||
padding: 4
|
padding: 4
|
||||||
|
anchors.rightMargin: 0
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert GPS metadata to degree coordinates.
|
* Convert GPS metadata to degree coordinates.
|
||||||
|
|
162
meshroom/ui/qml/Viewer/SfmGlobalStats.qml
Normal file
162
meshroom/ui/qml/Viewer/SfmGlobalStats.qml
Normal file
|
@ -0,0 +1,162 @@
|
||||||
|
import QtQuick 2.9
|
||||||
|
import QtQuick.Controls 2.3
|
||||||
|
import QtQuick.Layouts 1.3
|
||||||
|
import MaterialIcons 2.2
|
||||||
|
import QtPositioning 5.8
|
||||||
|
import QtLocation 5.9
|
||||||
|
import QtCharts 2.13
|
||||||
|
import Charts 1.0
|
||||||
|
|
||||||
|
import Controls 1.0
|
||||||
|
import Utils 1.0
|
||||||
|
|
||||||
|
import AliceVision 1.0 as AliceVision
|
||||||
|
|
||||||
|
|
||||||
|
FloatingPane {
|
||||||
|
id: root
|
||||||
|
|
||||||
|
property var msfmData
|
||||||
|
property color textColor: Colors.sysPalette.text
|
||||||
|
|
||||||
|
clip: true
|
||||||
|
padding: 4
|
||||||
|
|
||||||
|
// To avoid interaction with components in background
|
||||||
|
MouseArea {
|
||||||
|
anchors.fill: parent
|
||||||
|
acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
|
||||||
|
onPressed: {}
|
||||||
|
onReleased: {}
|
||||||
|
onWheel: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractiveChartView {
|
||||||
|
id: landmarksPerViewChart
|
||||||
|
width: parent.width * 0.5
|
||||||
|
height: parent.height * 0.5
|
||||||
|
|
||||||
|
title: "Landmarks Per View"
|
||||||
|
legend.visible: false
|
||||||
|
antialiasing: true
|
||||||
|
|
||||||
|
ValueAxis {
|
||||||
|
id: landmarksPerViewValueAxisX
|
||||||
|
titleText: "Ordered Views"
|
||||||
|
min: 0.0
|
||||||
|
max: sfmDataStat.landmarksPerViewMaxAxisX
|
||||||
|
}
|
||||||
|
ValueAxis {
|
||||||
|
id: landmarksPerViewValueAxisY
|
||||||
|
labelFormat: "%i"
|
||||||
|
titleText: "Number of Landmarks"
|
||||||
|
min: 0
|
||||||
|
max: sfmDataStat.landmarksPerViewMaxAxisY
|
||||||
|
}
|
||||||
|
LineSeries {
|
||||||
|
id: landmarksPerViewLineSerie
|
||||||
|
axisX: landmarksPerViewValueAxisX
|
||||||
|
axisY: landmarksPerViewValueAxisY
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
InteractiveChartView {
|
||||||
|
id: residualsPerViewChart
|
||||||
|
width: parent.width * 0.5
|
||||||
|
height: parent.height * 0.5
|
||||||
|
anchors.top: parent.top
|
||||||
|
anchors.topMargin: (parent.height) * 0.5
|
||||||
|
|
||||||
|
title: "Residuals Per View"
|
||||||
|
legend.visible: false
|
||||||
|
antialiasing: true
|
||||||
|
|
||||||
|
ValueAxis {
|
||||||
|
id: residualsPerViewValueAxisX
|
||||||
|
labelFormat: "%i"
|
||||||
|
titleText: "Ordered Views"
|
||||||
|
min: 0
|
||||||
|
max: sfmDataStat.residualsPerViewMaxAxisX
|
||||||
|
}
|
||||||
|
ValueAxis {
|
||||||
|
id: residualsPerViewValueAxisY
|
||||||
|
titleText: "Percentage of residuals"
|
||||||
|
min: 0
|
||||||
|
max: sfmDataStat.residualsPerViewMaxAxisY
|
||||||
|
tickAnchor: 0
|
||||||
|
tickInterval: 0.50
|
||||||
|
tickCount: sfmDataStat.residualsPerViewMaxAxisY * 2
|
||||||
|
}
|
||||||
|
LineSeries {
|
||||||
|
id: residualsMinPerViewLineSerie
|
||||||
|
axisX: residualsPerViewValueAxisX
|
||||||
|
axisY: residualsPerViewValueAxisY
|
||||||
|
name: "Min"
|
||||||
|
}
|
||||||
|
LineSeries {
|
||||||
|
id: residualsMaxPerViewLineSerie
|
||||||
|
axisX: residualsPerViewValueAxisX
|
||||||
|
axisY: residualsPerViewValueAxisY
|
||||||
|
name: "Max"
|
||||||
|
}
|
||||||
|
LineSeries {
|
||||||
|
id: residualsMeanPerViewLineSerie
|
||||||
|
axisX: residualsPerViewValueAxisX
|
||||||
|
axisY: residualsPerViewValueAxisY
|
||||||
|
name: "Mean"
|
||||||
|
}
|
||||||
|
LineSeries {
|
||||||
|
id: residualsMedianPerViewLineSerie
|
||||||
|
axisX: residualsPerViewValueAxisX
|
||||||
|
axisY: residualsPerViewValueAxisY
|
||||||
|
name: "Median"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Item {
|
||||||
|
id: residualsPerViewBtnContainer
|
||||||
|
|
||||||
|
Layout.fillWidth: true
|
||||||
|
anchors.bottom: residualsPerViewChart.bottom
|
||||||
|
anchors.bottomMargin: 35
|
||||||
|
anchors.left: residualsPerViewChart.left
|
||||||
|
anchors.leftMargin: residualsPerViewChart.width * 0.25
|
||||||
|
|
||||||
|
RowLayout {
|
||||||
|
|
||||||
|
ChartViewCheckBox {
|
||||||
|
id: allObservations
|
||||||
|
text: "ALL"
|
||||||
|
color: textColor
|
||||||
|
checkState: residualsPerViewLegend.buttonGroup.checkState
|
||||||
|
onClicked: {
|
||||||
|
var _checked = checked;
|
||||||
|
for(var i = 0; i < residualsPerViewChart.count; ++i)
|
||||||
|
{
|
||||||
|
residualsPerViewChart.series(i).visible = _checked;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ChartViewLegend {
|
||||||
|
id: residualsPerViewLegend
|
||||||
|
chartView: residualsPerViewChart
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stats from the sfmData
|
||||||
|
AliceVision.MSfMDataStats {
|
||||||
|
id: sfmDataStat
|
||||||
|
msfmData: (root.visible && root.msfmData && root.msfmData.status === AliceVision.MSfMData.Ready) ? root.msfmData : null
|
||||||
|
onStatsChanged: {
|
||||||
|
console.warn("QML AliceVision.MSfMDataStats statsChanged: " + sfmDataStat.msfmData);
|
||||||
|
fillLandmarksPerViewSerie(landmarksPerViewLineSerie);
|
||||||
|
fillResidualsMinPerViewSerie(residualsMinPerViewLineSerie);
|
||||||
|
fillResidualsMaxPerViewSerie(residualsMaxPerViewLineSerie);
|
||||||
|
fillResidualsMeanPerViewSerie(residualsMeanPerViewLineSerie);
|
||||||
|
fillResidualsMedianPerViewSerie(residualsMedianPerViewLineSerie);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -98,7 +98,6 @@ FloatingPane {
|
||||||
id: residualLegend
|
id: residualLegend
|
||||||
chartView: residualChart
|
chartView: residualChart
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -231,6 +231,7 @@ FocusScope {
|
||||||
'viewId': Qt.binding(function() { return _reconstruction.selectedViewId; }),
|
'viewId': Qt.binding(function() { return _reconstruction.selectedViewId; }),
|
||||||
'model': Qt.binding(function() { return _reconstruction.featureExtraction.attribute("describerTypes").value; }),
|
'model': Qt.binding(function() { return _reconstruction.featureExtraction.attribute("describerTypes").value; }),
|
||||||
'folder': Qt.binding(function() { return Filepath.stringToUrl(_reconstruction.featureExtraction.attribute("output").value); }),
|
'folder': Qt.binding(function() { return Filepath.stringToUrl(_reconstruction.featureExtraction.attribute("output").value); }),
|
||||||
|
'sfmData': Qt.binding(function() { return msfmDataLoader.status === Loader.Ready ? msfmDataLoader.item : null; }),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -297,8 +298,8 @@ FocusScope {
|
||||||
}
|
}
|
||||||
|
|
||||||
Loader {
|
Loader {
|
||||||
id: msfmData
|
id: msfmDataLoader
|
||||||
active: displaySfmStatsView.checked
|
active: displaySfmStatsView.checked || displayFeatures.checked || displaySfmDataGlobalStats.checked
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
// instantiate and initialize a SfmStatsView component dynamically using Loader.setSource
|
// instantiate and initialize a SfmStatsView component dynamically using Loader.setSource
|
||||||
|
@ -311,14 +312,27 @@ FocusScope {
|
||||||
Loader {
|
Loader {
|
||||||
id: sfmStatsView
|
id: sfmStatsView
|
||||||
anchors.fill: parent
|
anchors.fill: parent
|
||||||
active: msfmData.status === Loader.Ready && displaySfmStatsView.checked
|
active: msfmDataLoader.status === Loader.Ready && displaySfmStatsView.checked
|
||||||
|
|
||||||
Component.onCompleted: {
|
Component.onCompleted: {
|
||||||
// instantiate and initialize a SfmStatsView component dynamically using Loader.setSource
|
// instantiate and initialize a SfmStatsView component dynamically using Loader.setSource
|
||||||
// so it can fail safely if the c++ plugin is not available
|
// so it can fail safely if the c++ plugin is not available
|
||||||
setSource("SfmStatsView.qml", {
|
setSource("SfmStatsView.qml", {
|
||||||
|
'msfmData': Qt.binding(function() { return msfmDataLoader.item; }),
|
||||||
'viewId': Qt.binding(function() { return _reconstruction.selectedViewId; }),
|
'viewId': Qt.binding(function() { return _reconstruction.selectedViewId; }),
|
||||||
'msfmData': Qt.binding(function() { return msfmData.item; }),
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loader {
|
||||||
|
id: sfmGlobalStats
|
||||||
|
anchors.fill: parent
|
||||||
|
active: msfmDataLoader.status === Loader.Ready && displaySfmDataGlobalStats.checked
|
||||||
|
|
||||||
|
Component.onCompleted: {
|
||||||
|
// instantiate and initialize a SfmStatsView component dynamically using Loader.setSource
|
||||||
|
// so it can fail safely if the c++ plugin is not available
|
||||||
|
setSource("SfmGlobalStats.qml", {
|
||||||
|
'msfmData': Qt.binding(function() { return msfmDataLoader.item; }),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -457,7 +471,33 @@ FocusScope {
|
||||||
enabled: _reconstruction.sfm && _reconstruction.sfm.isComputed() && _reconstruction.selectedViewId >= 0
|
enabled: _reconstruction.sfm && _reconstruction.sfm.isComputed() && _reconstruction.selectedViewId >= 0
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if(checked == true)
|
if(checked == true)
|
||||||
|
{
|
||||||
|
displaySfmDataGlobalStats.checked = false
|
||||||
metadataCB.checked = false
|
metadataCB.checked = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
MaterialToolButton {
|
||||||
|
id: displaySfmDataGlobalStats
|
||||||
|
|
||||||
|
font.family: MaterialIcons.fontFamily
|
||||||
|
text: MaterialIcons.language
|
||||||
|
|
||||||
|
ToolTip.text: "StructureFromMotion Global Statistics"
|
||||||
|
ToolTip.visible: hovered
|
||||||
|
|
||||||
|
font.pointSize: 14
|
||||||
|
padding: 2
|
||||||
|
smooth: false
|
||||||
|
flat: true
|
||||||
|
checkable: enabled
|
||||||
|
enabled: _reconstruction.sfm && _reconstruction.sfm.isComputed()
|
||||||
|
onCheckedChanged: {
|
||||||
|
if(checked == true)
|
||||||
|
{
|
||||||
|
displaySfmStatsView.checked = false
|
||||||
|
metadataCB.checked = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
MaterialToolButton {
|
MaterialToolButton {
|
||||||
|
@ -477,7 +517,10 @@ FocusScope {
|
||||||
enabled: _reconstruction.selectedViewId >= 0
|
enabled: _reconstruction.selectedViewId >= 0
|
||||||
onCheckedChanged: {
|
onCheckedChanged: {
|
||||||
if(checked == true)
|
if(checked == true)
|
||||||
|
{
|
||||||
|
displaySfmDataGlobalStats.checked = false
|
||||||
displaySfmStatsView.checked = false
|
displaySfmStatsView.checked = false
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue