[ui] Support for imageList and sequence in SequencePlayer

This commit is contained in:
Aurore LAFAURIE 2024-05-14 17:58:59 +02:00
parent 7af0997a73
commit 4590868317
3 changed files with 39 additions and 22 deletions

View file

@ -144,4 +144,4 @@ class FilepathHelper(QObject):
""" """
if extension is None: if extension is None:
extension = ".*" 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)] return [self.basename(FilepathHelper, f) for f in glob.glob(os.path.join(folderPath, f"*{extension}")) if os.path.isfile(f)]

View file

@ -29,6 +29,7 @@ FloatingPane {
property bool loading: fetchButton.checked || m.playing property bool loading: fetchButton.checked || m.playing
property alias settings_SequencePlayer: settings_SequencePlayer property alias settings_SequencePlayer: settings_SequencePlayer
property alias frameId: m.frame property alias frameId: m.frame
property var frameRange: {"min" : 0, "max" : sortedViewIds.length - 1}
Settings { Settings {
id: settings_SequencePlayer id: settings_SequencePlayer
@ -39,7 +40,7 @@ FloatingPane {
if (isOutputSequence) if (isOutputSequence)
return return
if (_reconstruction && m.frame >= 0 && m.frame < sortedViewIds.length) { if (_reconstruction && m.frame >= 0 && m.frame < sortedViewIds.length) {
if (!m.playing && !frameSlider.pressed){ if (!m.playing && !frameSlider.pressed) {
_reconstruction.selectedViewId = sortedViewIds[m.frame]; _reconstruction.selectedViewId = sortedViewIds[m.frame];
} else { } else {
_reconstruction.pickedViewId = sortedViewIds[m.frame]; _reconstruction.pickedViewId = sortedViewIds[m.frame];
@ -52,17 +53,22 @@ FloatingPane {
onIsOutputSequenceChanged: { onIsOutputSequenceChanged: {
if (!isOutputSequence) { if (!isOutputSequence) {
frameId = 0 frameId = frameRange.min
} }
} }
onSortedViewIdsChanged: {
frameSlider.from = frameRange.min
frameSlider.to = frameRange.max
}
// Sequence player model: // Sequence player model:
// - current frame // - current frame
// - data related to automatic sequence playing // - data related to automatic sequence playing
QtObject { QtObject {
id: m id: m
property int frame: 0 property int frame: frameRange.min
property bool syncFeaturesSelected: true property bool syncFeaturesSelected: true
property bool sync3DSelected: true property bool sync3DSelected: true
property bool playing: false property bool playing: false
@ -74,11 +80,10 @@ FloatingPane {
} }
onPlayingChanged: { onPlayingChanged: {
if(!playing){ if (!playing) {
updateReconstructionView(); updateReconstructionView();
}else if(playing && (frame + 1 >= sortedViewIds.length)) } else if (playing && (frame + 1 >= frameRange + 1)) {
{ frame = frameRange.min;
frame = 0;
} }
viewer.playback(playing); viewer.playback(playing);
} }
@ -113,9 +118,9 @@ FloatingPane {
return; return;
} }
let nextIndex = m.frame + 1; let nextIndex = m.frame + 1;
if (nextIndex == sortedViewIds.length) { if (nextIndex == frameRange.max + 1) {
if (m.repeat) { if (m.repeat) {
m.frame = 0; m.frame = frameRange.min;
return; return;
} }
else { else {
@ -173,7 +178,7 @@ FloatingPane {
ToolTip.text: "Previous Frame" ToolTip.text: "Previous Frame"
onClicked: { onClicked: {
if (m.frame > 0) { if (m.frame > frameRange.min) {
m.frame -= 1; m.frame -= 1;
} }
} }
@ -193,7 +198,7 @@ FloatingPane {
onEditingFinished: { onEditingFinished: {
// We first assign the frame to the entered text even if it is an invalid frame number. We do it for extreme cases, for example without doing it, if we are at 0, and put a negative number, m.frame would be still 0 and nothing happens but we will still see the wrong number // We first assign the frame to the entered text even if it is an invalid frame number. We do it for extreme cases, for example without doing it, if we are at 0, and put a negative number, m.frame would be still 0 and nothing happens but we will still see the wrong number
m.frame = parseInt(text) m.frame = parseInt(text)
m.frame = Math.min((sortedViewIds.length - 1), Math.max(0, parseInt(text))); m.frame = Math.min(frameRange.max, Math.max(frameRange.min, parseInt(text)));
focus = false; focus = false;
} }
} }
@ -212,7 +217,7 @@ FloatingPane {
ToolTip.text: "Next Frame" ToolTip.text: "Next Frame"
onClicked: { onClicked: {
if (m.frame < sortedViewIds.length - 1) { if (m.frame < frameRange.max) {
m.frame += 1; m.frame += 1;
} }
} }
@ -251,8 +256,8 @@ FloatingPane {
snapMode: Slider.SnapAlways snapMode: Slider.SnapAlways
live: true live: true
from: 0 from: frameRange.min
to: sortedViewIds.length - 1 to: frameRange.max
onValueChanged: { onValueChanged: {
m.frame = value; m.frame = value;
@ -289,7 +294,7 @@ FloatingPane {
id: cacheView id: cacheView
model: viewer ? viewer.cachedFrames : [] model: viewer ? viewer.cachedFrames : []
property real frameLength: sortedViewIds.length > 0 ? frameSlider.width / sortedViewIds.length : 0 property real frameLength: sortedViewIds.length > 0 ? frameSlider.width / (frameRange.max-frameRange.min+1) : 0
Rectangle { Rectangle {
x: modelData.x * cacheView.frameLength x: modelData.x * cacheView.frameLength

View file

@ -32,6 +32,7 @@ FocusScope {
readonly property alias sync3DSelected: sequencePlayer.sync3DSelected readonly property alias sync3DSelected: sequencePlayer.sync3DSelected
property var sequence: [] property var sequence: []
property alias currentFrame: sequencePlayer.frameId property alias currentFrame: sequencePlayer.frameId
property alias frameRange: sequencePlayer.frameRange
QtObject { QtObject {
id: m id: m
@ -228,6 +229,7 @@ FocusScope {
function getImageFile() { function getImageFile() {
// Entry point for getting the image file URL // Entry point for getting the image file URL
let attr = getAttributeByName(displayedNode, outputAttribute.name)
if (useExternal) { if (useExternal) {
return sourceExternal return sourceExternal
} }
@ -238,8 +240,8 @@ FocusScope {
return Filepath.stringToUrl(path) return Filepath.stringToUrl(path)
} }
if (_reconstruction && displayedNode && displayedNode.hasSequenceOutput) { if (_reconstruction && displayedNode && displayedNode.hasSequenceOutput && (attr.desc.semantic === "imageList" || attr.desc.semantic === "sequence")) {
var path = sequence[currentFrame] var path = sequence[currentFrame-frameRange.min]
return Filepath.stringToUrl(path) return Filepath.stringToUrl(path)
} }
@ -259,12 +261,19 @@ FocusScope {
// ordered by path // ordered by path
let objs = [] let objs = []
let attr = getAttributeByName(displayedNode, outputAttribute.name)
if (displayedNode && displayedNode.hasSequenceOutput) { if (displayedNode && displayedNode.hasSequenceOutput && (attr.desc.semantic === "imageList" || attr.desc.semantic === "sequence")) {
currentFrame = 0
objs = Filepath.resolve(path_template, null) objs = Filepath.resolve(path_template, null)
//order by path //order by path
objs.sort() objs.sort()
// reset current frame to 0 if it is imageList but not sequence
if (attr.desc.semantic === "imageList")
frameRange.min = 0
frameRange.max = objs.length-1
currentFrame = 0
if (attr.desc.semantic === "sequence")
currentFrame = frameRange.min
return objs return objs
} else { } else {
for (let i = 0; i < _reconstruction.viewpoints.count; i++) { for (let i = 0; i < _reconstruction.viewpoints.count; i++) {
@ -311,7 +320,7 @@ FocusScope {
// store attr name for output attributes that represent images // store attr name for output attributes that represent images
for (var i = 0; i < displayedNode.attributes.count; i++) { for (var i = 0; i < displayedNode.attributes.count; i++) {
var attr = displayedNode.attributes.at(i) var attr = displayedNode.attributes.at(i)
if (attr.isOutput && (attr.desc.semantic === "image" || attr.desc.semantic === "sequence") && attr.enabled) { if (attr.isOutput && (attr.desc.semantic === "image" || attr.desc.semantic === "sequence" || attr.desc.semantic === "imageList") && attr.enabled) {
names.push(attr.name) names.push(attr.name)
} }
} }
@ -481,7 +490,10 @@ FocusScope {
'cropFisheye': false, 'cropFisheye': false,
'sequence': Qt.binding(function() { return ((root.enableSequencePlayer && (_reconstruction || (root.displayedNode && root.displayedNode.hasSequenceOutput))) ? getSequence() : []) }), 'sequence': Qt.binding(function() { return ((root.enableSequencePlayer && (_reconstruction || (root.displayedNode && root.displayedNode.hasSequenceOutput))) ? getSequence() : []) }),
'targetSize': Qt.binding(function() { return floatImageViewerLoader.targetSize }), 'targetSize': Qt.binding(function() { return floatImageViewerLoader.targetSize }),
'useSequence': Qt.binding(function() { return (root.enableSequencePlayer && !useExternal && (_reconstruction || (root.displayedNode && root.displayedNode.hasSequenceOutput))) }), 'useSequence': Qt.binding(function() {
let attr = getAttributeByName(root.displayedNode, outputAttribute.name)
return (root.enableSequencePlayer && !useExternal && (_reconstruction || (root.displayedNode && root.displayedNode.hasSequenceOutput)) && (attr.desc.semantic === "imageList" || attr.desc.semantic === "sequence"))
}),
'fetchingSequence': Qt.binding(function() { return sequencePlayer.loading }), 'fetchingSequence': Qt.binding(function() { return sequencePlayer.loading }),
'memoryLimit': Qt.binding(function() { return sequencePlayer.settings_SequencePlayer.maxCacheMemory }), 'memoryLimit': Qt.binding(function() { return sequencePlayer.settings_SequencePlayer.maxCacheMemory }),
}) })