mirror of
https://github.com/alicevision/Meshroom.git
synced 2025-07-31 07:18:25 +02:00
[ui] Load image sequence from node output in SequencePlayer
This commit is contained in:
parent
3eb90322a8
commit
b0063b0dde
3 changed files with 81 additions and 30 deletions
|
@ -4,6 +4,7 @@ from PySide2.QtCore import QUrl, QFileInfo
|
|||
from PySide2.QtCore import QObject, Slot
|
||||
|
||||
import os
|
||||
import glob
|
||||
|
||||
|
||||
class FilepathHelper(QObject):
|
||||
|
@ -103,15 +104,26 @@ class FilepathHelper(QObject):
|
|||
def resolve(self, path, vp):
|
||||
# Resolve dynamic path that depends on viewpoint
|
||||
|
||||
replacements = {}
|
||||
if vp == None:
|
||||
replacements = FilepathHelper.getFilenamesFromFolder(FilepathHelper, FilepathHelper.dirname(FilepathHelper, path), FilepathHelper.extension(FilepathHelper, path))
|
||||
resolved = [path for i in range(len(replacements))]
|
||||
for key in replacements:
|
||||
for i in range(len(resolved)):
|
||||
resolved[i] = resolved[i].replace("<FRAMEID>", replacements[i])
|
||||
return resolved
|
||||
else:
|
||||
|
||||
vpPath = vp.childAttribute("path").value
|
||||
filename = FilepathHelper.basename(FilepathHelper, vpPath)
|
||||
replacements = {
|
||||
"<VIEW_ID>": str(vp.childAttribute("viewId").value),
|
||||
"<INTRINSIC_ID>": str(vp.childAttribute("intrinsicId").value),
|
||||
"<POSE_ID>": str(vp.childAttribute("poseId").value),
|
||||
"<PATH>": vpPath,
|
||||
"<FILENAME>": FilepathHelper.basename(FilepathHelper, vpPath),
|
||||
"<FILESTEM>": FilepathHelper.removeExtension(FilepathHelper, FilepathHelper.basename(FilepathHelper, vpPath)),
|
||||
"<EXTENSION>": FilepathHelper.extension(FilepathHelper, vpPath),
|
||||
"<FILENAME>": filename,
|
||||
"<FILESTEM>": FilepathHelper.removeExtension(FilepathHelper, filename),
|
||||
"<EXTENSION>": FilepathHelper.extension(FilepathHelper, filename),
|
||||
}
|
||||
|
||||
resolved = path
|
||||
|
@ -119,3 +131,17 @@ class FilepathHelper(QObject):
|
|||
resolved = resolved.replace(key, replacements[key])
|
||||
|
||||
return resolved
|
||||
|
||||
@Slot(str, result="QVariantList")
|
||||
@Slot(str, str, result="QVariantList")
|
||||
def getFilenamesFromFolder(self, folderPath: str, extension: str = None):
|
||||
"""
|
||||
Get all filenames from a folder with a specific extension.
|
||||
|
||||
:param folderPath: Path to the folder.
|
||||
:param extension: Extension of the files to get.
|
||||
:return: List of filenames.
|
||||
"""
|
||||
if extension is None:
|
||||
extension = ".*"
|
||||
return [self.removeExtension(FilepathHelper, self.basename(FilepathHelper, f)) for f in glob.glob(os.path.join(folderPath, f"*{extension}")) if os.path.isfile(f)]
|
||||
|
|
|
@ -27,6 +27,7 @@ FloatingPane {
|
|||
readonly property alias syncFeaturesSelected: m.syncFeaturesSelected
|
||||
property bool loading: fetchButton.checked || m.playing
|
||||
property alias settings_SequencePlayer: settings_SequencePlayer
|
||||
property alias frameId: m.frame
|
||||
|
||||
Settings {
|
||||
id: settings_SequencePlayer
|
||||
|
@ -94,7 +95,7 @@ FloatingPane {
|
|||
id: timer
|
||||
|
||||
repeat: true
|
||||
running: m.playing
|
||||
running: m.playing && root.visible
|
||||
interval: 1000 / m.fps
|
||||
|
||||
onTriggered: {
|
||||
|
|
|
@ -30,6 +30,8 @@ FocusScope {
|
|||
property bool enableSequencePlayer: enableSequencePlayerAction.checked
|
||||
|
||||
readonly property alias sync3DSelected: sequencePlayer.sync3DSelected
|
||||
property var sequence: []
|
||||
property int currentFrame: sequencePlayer.frameId
|
||||
|
||||
QtObject {
|
||||
id: m
|
||||
|
@ -181,7 +183,7 @@ FocusScope {
|
|||
}
|
||||
|
||||
// node must have at least one output attribute with the image semantic
|
||||
if (!node.hasImageOutput) {
|
||||
if (!node.hasImageOutput && !node.hasSequenceOutput) {
|
||||
return false
|
||||
}
|
||||
|
||||
|
@ -223,7 +225,6 @@ FocusScope {
|
|||
return undefined
|
||||
}
|
||||
|
||||
|
||||
function getImageFile() {
|
||||
// Entry point for getting the image file URL
|
||||
|
||||
|
@ -237,6 +238,11 @@ FocusScope {
|
|||
return Filepath.stringToUrl(path)
|
||||
}
|
||||
|
||||
if (_reconstruction && displayedNode && displayedNode.hasSequenceOutput) {
|
||||
var path = sequence[currentFrame]
|
||||
return Filepath.stringToUrl(path)
|
||||
}
|
||||
|
||||
if (_reconstruction) {
|
||||
let vp = getViewpoint(_reconstruction.pickedViewId)
|
||||
let attr = getAttributeByName(displayedNode, outputAttribute.name)
|
||||
|
@ -253,11 +259,17 @@ FocusScope {
|
|||
// ordered by path
|
||||
|
||||
let objs = []
|
||||
|
||||
if (displayedNode && displayedNode.hasSequenceOutput) {
|
||||
objs = Filepath.resolve(path_template, null)
|
||||
//order by path
|
||||
objs.sort()
|
||||
return objs
|
||||
} else {
|
||||
for (let i = 0; i < _reconstruction.viewpoints.count; i++) {
|
||||
objs.push(_reconstruction.viewpoints.at(i))
|
||||
}
|
||||
objs.sort((a, b) => { return a.childAttribute("path").value < b.childAttribute("path").value ? -1 : 1; })
|
||||
|
||||
let seq = [];
|
||||
for (let i = 0; i < objs.length; i++) {
|
||||
seq.push(Filepath.resolve(path_template, objs[i]))
|
||||
|
@ -265,6 +277,7 @@ FocusScope {
|
|||
|
||||
return seq
|
||||
}
|
||||
}
|
||||
|
||||
function getSequence() {
|
||||
// Entry point for getting the current image sequence
|
||||
|
@ -300,12 +313,23 @@ FocusScope {
|
|||
if (attr.isOutput && attr.desc.semantic === "image" && attr.enabled) {
|
||||
names.push(attr.name)
|
||||
}
|
||||
|
||||
if (attr.isOutput && attr.desc.semantic === "sequence" && attr.enabled) {
|
||||
names.push(attr.name)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!displayedNode || displayedNode.isComputable) names.push("gallery")
|
||||
|
||||
outputAttribute.names = names
|
||||
if (displayedNode && !displayedNode.hasSequenceOutput) {
|
||||
|
||||
root.source = getImageFile()
|
||||
} else {
|
||||
root.sequence = getSequence()
|
||||
enableSequencePlayerAction.checked = true
|
||||
}
|
||||
}
|
||||
|
||||
Connections {
|
||||
|
@ -457,11 +481,11 @@ FocusScope {
|
|||
'sfmRequired': Qt.binding(function() { return displayLensDistortionViewer.checked ? true : false }),
|
||||
'surface.msfmData': Qt.binding(function() { return (msfmDataLoader.status === Loader.Ready && msfmDataLoader.item != null && msfmDataLoader.item.status === 2) ? msfmDataLoader.item : null }),
|
||||
'canBeHovered': false,
|
||||
'idView': Qt.binding(function() { return (_reconstruction ? _reconstruction.selectedViewId : -1) }),
|
||||
'idView': Qt.binding(function() { return ((root.displayedNode && !root.displayedNode.hasSequenceOutput && _reconstruction) ? _reconstruction.selectedViewId : -1) }),
|
||||
'cropFisheye': false,
|
||||
'sequence': Qt.binding(function() { return ((root.enableSequencePlayer && _reconstruction && _reconstruction.viewpoints.count > 0) ? getSequence() : []) }),
|
||||
'sequence': Qt.binding(function() { return ((root.enableSequencePlayer && (_reconstruction || (root.displayedNode && root.displayedNode.hasSequenceOutput))) ? getSequence() : []) }),
|
||||
'targetSize': Qt.binding(function() { return floatImageViewerLoader.targetSize }),
|
||||
'useSequence': Qt.binding(function() { return root.enableSequencePlayer && !useExternal && _reconstruction }),
|
||||
'useSequence': Qt.binding(function() { return (root.enableSequencePlayer && !useExternal && (_reconstruction || (root.displayedNode && root.displayedNode.hasSequenceOutput))) }),
|
||||
'fetchingSequence': Qt.binding(function() { return sequencePlayer.loading }),
|
||||
'memoryLimit': Qt.binding(function() { return sequencePlayer.settings_SequencePlayer.maxCacheMemory }),
|
||||
})
|
||||
|
@ -1434,7 +1458,7 @@ FocusScope {
|
|||
id: sequencePlayer
|
||||
anchors.margins: 0
|
||||
Layout.fillWidth: true
|
||||
sortedViewIds: (root.enableSequencePlayer && _reconstruction && _reconstruction.viewpoints.count > 0) ? buildOrderedSequence("<VIEW_ID>") : []
|
||||
sortedViewIds: { return (root.enableSequencePlayer && (root.displayedNode && root.displayedNode.hasSequenceOutput)) ? root.sequence : (_reconstruction && _reconstruction.viewpoints.count > 0) ? buildOrderedSequence("<VIEW_ID>") : [] }
|
||||
viewer: floatImageViewerLoader.status === Loader.Ready ? floatImageViewerLoader.item : null
|
||||
visible: root.enableSequencePlayer
|
||||
enabled: root.enableSequencePlayer
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue