Compare commits
5 Commits
47b1988539
...
20b2915b6b
Author | SHA1 | Date | |
---|---|---|---|
20b2915b6b | |||
33b46af8d0 | |||
dbd5b380ba | |||
9361069b74 | |||
2020fe6f8f |
@ -1,11 +1,9 @@
|
|||||||
from PySide6.QtCore import QSize, Qt
|
from PySide6.QtCore import QSize, Qt
|
||||||
from PySide6.QtWidgets import QMainWindow, QWidget, QToolBar, QMenu, QMenuBar, QSizePolicy, QFileDialog
|
from PySide6.QtWidgets import QMainWindow, QWidget, QToolBar, QSizePolicy, QFileDialog
|
||||||
from PySide6.QtWidgets import QDialog, QVBoxLayout
|
from PySide6.QtGui import QKeySequence, QAction, QIcon
|
||||||
from PySide6.QtGui import QKeySequence, QAction, QIcon, QPalette
|
|
||||||
|
|
||||||
from fixtracks.widgets.centralwidget import CentralWidget
|
from fixtracks.widgets.centralwidget import CentralWidget
|
||||||
from fixtracks.dialogs.previewdialog import PreviewDialog
|
from fixtracks.dialogs.previewdialog import PreviewDialog
|
||||||
from fixtracks.utils.reader import ImageReader, DataFrameReader
|
|
||||||
from fixtracks.dialogs.about import AboutDialog
|
from fixtracks.dialogs.about import AboutDialog
|
||||||
from fixtracks.dialogs.help import HelpDialog
|
from fixtracks.dialogs.help import HelpDialog
|
||||||
import fixtracks.resources
|
import fixtracks.resources
|
||||||
|
@ -54,6 +54,7 @@ class TrackingData(QObject):
|
|||||||
return self._indices
|
return self._indices
|
||||||
|
|
||||||
def setSelectionRange(self, col, start, stop):
|
def setSelectionRange(self, col, start, stop):
|
||||||
|
logging.debug("Trackingdata: set selection range based on column %s to %.2f - %.2f", col, start, stop)
|
||||||
self._start = start
|
self._start = start
|
||||||
self._stop = stop
|
self._stop = stop
|
||||||
self._selection_column = col
|
self._selection_column = col
|
||||||
@ -64,7 +65,7 @@ class TrackingData(QObject):
|
|||||||
|
|
||||||
def setUserSelection(self, ids):
|
def setUserSelection(self, ids):
|
||||||
"""
|
"""
|
||||||
Set the user selections. That is, e.g. when the user selected a number of ids.
|
Set the user selections. That is, e.g. when the user selected a number of detection ids (aka the index of the original data frame entries).
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
ids : array-like
|
ids : array-like
|
||||||
@ -73,16 +74,33 @@ class TrackingData(QObject):
|
|||||||
"""
|
"""
|
||||||
self._user_selections = ids.astype(int)
|
self._user_selections = ids.astype(int)
|
||||||
|
|
||||||
def assignUserSelection(self, track_id:int)-> None:
|
def assignUserSelection(self, track_id:int, userFlag:bool=True)-> None:
|
||||||
"""Assign a new track_id to the user-selected detections
|
"""Assign a new track_id to the user-selected detections
|
||||||
|
|
||||||
Parameters
|
Parameters
|
||||||
----------
|
----------
|
||||||
track_id : int
|
track_id : int
|
||||||
The new track id for the user-selected detections
|
The new track id for the user-selected detections
|
||||||
|
userFlag : bool
|
||||||
|
Should the "userlabeled" state of the detections be set to True or False?
|
||||||
"""
|
"""
|
||||||
self._data["track"][self._user_selections] = track_id
|
self._data["track"][self._user_selections] = track_id
|
||||||
self._data["userlabeled"][self._user_selections] = True
|
self.setAssignmentStatus(userFlag)
|
||||||
|
|
||||||
|
def setAssignmentStatus(self, isTrue: bool):
|
||||||
|
self._data["userlabeled"][self._user_selections] = isTrue
|
||||||
|
|
||||||
|
def revertAssignmentStatus(self):
|
||||||
|
self._data["userlabeled"][:] = False
|
||||||
|
|
||||||
|
def deleteDetections(self):
|
||||||
|
# from IPython import embed
|
||||||
|
# if self._user_selections is not None:
|
||||||
|
# ids = self._user_selections
|
||||||
|
# for c in self.columns:
|
||||||
|
# pass
|
||||||
|
# embed()
|
||||||
|
pass
|
||||||
|
|
||||||
def assignTracks(self, tracks):
|
def assignTracks(self, tracks):
|
||||||
"""assignTracks _summary_
|
"""assignTracks _summary_
|
||||||
@ -115,7 +133,7 @@ class TrackingData(QObject):
|
|||||||
return 0
|
return 0
|
||||||
return self._data["keypoints"][0].shape[0]
|
return self._data["keypoints"][0].shape[0]
|
||||||
|
|
||||||
def coordinates(self):
|
def coordinates(self, selection=False):
|
||||||
"""
|
"""
|
||||||
Returns the coordinates of all keypoints as a NumPy array.
|
Returns the coordinates of all keypoints as a NumPy array.
|
||||||
|
|
||||||
@ -123,6 +141,9 @@ class TrackingData(QObject):
|
|||||||
np.ndarray: A NumPy array of shape (N, M, 2) where N is the number of detections,
|
np.ndarray: A NumPy array of shape (N, M, 2) where N is the number of detections,
|
||||||
and M is number of keypoints
|
and M is number of keypoints
|
||||||
"""
|
"""
|
||||||
|
if selection:
|
||||||
|
return np.stack(self._data["keypoints"][self._start:self._stop, :, :]).astype(np.float32)
|
||||||
|
else:
|
||||||
return np.stack(self._data["keypoints"]).astype(np.float32)
|
return np.stack(self._data["keypoints"]).astype(np.float32)
|
||||||
|
|
||||||
def keypointScores(self):
|
def keypointScores(self):
|
||||||
@ -202,14 +223,6 @@ class TrackingData(QObject):
|
|||||||
def __getitem__(self, key):
|
def __getitem__(self, key):
|
||||||
return self._data[key]
|
return self._data[key]
|
||||||
|
|
||||||
# def __setitem__(self, key, value):
|
|
||||||
# self._data[key] = value
|
|
||||||
"""
|
|
||||||
self._data.setSelectionRange("index", 0, self._data.numDetections)
|
|
||||||
self._data.assignTracks(tracks)
|
|
||||||
self._timeline.setDetectionData(self._data.data)
|
|
||||||
self.update()
|
|
||||||
"""
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
import pandas as pd
|
import pandas as pd
|
||||||
@ -217,6 +230,8 @@ def main():
|
|||||||
import matplotlib.pyplot as plt
|
import matplotlib.pyplot as plt
|
||||||
from fixtracks.info import PACKAGE_ROOT
|
from fixtracks.info import PACKAGE_ROOT
|
||||||
|
|
||||||
|
logging.basicConfig(level=logging.DEBUG, force=True)
|
||||||
|
|
||||||
def as_dict(df:pd.DataFrame):
|
def as_dict(df:pd.DataFrame):
|
||||||
d = {c: df[c].values for c in df.columns}
|
d = {c: df[c].values for c in df.columns}
|
||||||
d["index"] = df.index.values
|
d["index"] = df.index.values
|
||||||
@ -251,7 +266,7 @@ def main():
|
|||||||
plt.plot([positions[si, 0], positions[ei, 0]],
|
plt.plot([positions[si, 0], positions[ei, 0]],
|
||||||
[positions[si, 1], positions[ei, 1]], color="tab:green")
|
[positions[si, 1], positions[ei, 1]], color="tab:green")
|
||||||
|
|
||||||
datafile = PACKAGE_ROOT / "data/merged2.pkl"
|
datafile = PACKAGE_ROOT / "data/merged_small.pkl"
|
||||||
with open(datafile, "rb") as f:
|
with open(datafile, "rb") as f:
|
||||||
df = pickle.load(f)
|
df = pickle.load(f)
|
||||||
|
|
||||||
|
@ -239,7 +239,7 @@ class SizeClassifier(QWidget):
|
|||||||
|
|
||||||
def setCoordinates(self, coordinates):
|
def setCoordinates(self, coordinates):
|
||||||
self._coordinates = coordinates
|
self._coordinates = coordinates
|
||||||
self._sizes = self.estimate_length(coordinates)
|
self._sizes = self.estimate_length(coordinates, bodyaxis=[0, 1, 2, 5])
|
||||||
n, e = self.estimate_histogram(self._sizes)
|
n, e = self.estimate_histogram(self._sizes)
|
||||||
plot = self._plot_widget.addPlot()
|
plot = self._plot_widget.addPlot()
|
||||||
bgi = pg.BarGraphItem(x0=e[:-1], x1=e[1:], height=n, pen='w', brush=(0,0,255,150))
|
bgi = pg.BarGraphItem(x0=e[:-1], x1=e[1:], height=n, pen='w', brush=(0,0,255,150))
|
||||||
@ -600,6 +600,7 @@ def main():
|
|||||||
df = pickle.load(f)
|
df = pickle.load(f)
|
||||||
data = TrackingData()
|
data = TrackingData()
|
||||||
data.setData(as_dict(df))
|
data.setData(as_dict(df))
|
||||||
|
coords = data.coordinates()
|
||||||
|
|
||||||
app = QApplication([])
|
app = QApplication([])
|
||||||
window = QWidget()
|
window = QWidget()
|
||||||
@ -610,6 +611,7 @@ def main():
|
|||||||
# else:
|
# else:
|
||||||
w = ClassifierWidget()
|
w = ClassifierWidget()
|
||||||
w.setData(data)
|
w.setData(data)
|
||||||
|
w.size_classifier.setCoordinates(coords)
|
||||||
|
|
||||||
layout = QVBoxLayout()
|
layout = QVBoxLayout()
|
||||||
layout.addWidget(w)
|
layout.addWidget(w)
|
||||||
|
248
fixtracks/widgets/selection_control.py
Normal file
248
fixtracks/widgets/selection_control.py
Normal file
@ -0,0 +1,248 @@
|
|||||||
|
import logging
|
||||||
|
import numpy as np
|
||||||
|
|
||||||
|
from PySide6.QtCore import Qt, Signal, QSize
|
||||||
|
from PySide6.QtGui import QFont
|
||||||
|
from PySide6.QtWidgets import QWidget, QLabel, QPushButton, QSizePolicy
|
||||||
|
from PySide6.QtWidgets import QGridLayout, QVBoxLayout
|
||||||
|
|
||||||
|
|
||||||
|
class SelectionControls(QWidget):
|
||||||
|
fwd = Signal(float)
|
||||||
|
back = Signal(float)
|
||||||
|
assignOne = Signal()
|
||||||
|
assignTwo = Signal()
|
||||||
|
assignOther = Signal()
|
||||||
|
accept = Signal()
|
||||||
|
unaccept = Signal()
|
||||||
|
delete = Signal()
|
||||||
|
revertall = Signal()
|
||||||
|
|
||||||
|
def __init__(self, parent = None,):
|
||||||
|
super().__init__(parent)
|
||||||
|
font = QFont()
|
||||||
|
font.setBold(True)
|
||||||
|
font.setPointSize(10)
|
||||||
|
fullstep = 1.0
|
||||||
|
halfstep = 0.5
|
||||||
|
quarterstep = 0.25
|
||||||
|
|
||||||
|
backBtn = QPushButton("|<<")
|
||||||
|
backBtn.setFont(font)
|
||||||
|
backBtn.setShortcut(Qt.Key.Key_Left)
|
||||||
|
backBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
backBtn.setToolTip(f"Go back to previous window ({backBtn.shortcut().toString()})")
|
||||||
|
backBtn.clicked.connect(lambda: self.on_Back(fullstep))
|
||||||
|
halfstepBackBtn = QPushButton("<<")
|
||||||
|
halfstepBackBtn.setFont(font)
|
||||||
|
halfstepBackBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
halfstepBackBtn.setShortcut(Qt.KeyboardModifier.AltModifier | Qt.Key.Key_Left)
|
||||||
|
halfstepBackBtn.setToolTip(f"Go back by half a window ({halfstepBackBtn.shortcut().toString()})")
|
||||||
|
halfstepBackBtn.clicked.connect(lambda: self.on_Back(halfstep))
|
||||||
|
quarterstepBackBtn = QPushButton("<")
|
||||||
|
quarterstepBackBtn.setFont(font)
|
||||||
|
quarterstepBackBtn.setShortcut(Qt.KeyboardModifier.ShiftModifier | Qt.Key.Key_Left)
|
||||||
|
quarterstepBackBtn.setToolTip(f"Go back by a quarter window ({quarterstepBackBtn.shortcut().toString()})")
|
||||||
|
quarterstepBackBtn.clicked.connect(lambda: self.on_Back(quarterstep))
|
||||||
|
quarterstepBackBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
|
||||||
|
|
||||||
|
fwdBtn = QPushButton(">>|")
|
||||||
|
fwdBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
fwdBtn.setShortcut(Qt.Key.Key_Right)
|
||||||
|
fwdBtn.setFont(font)
|
||||||
|
fwdBtn.setToolTip(f"Proceed to next window ({fwdBtn.shortcut().toString()})")
|
||||||
|
fwdBtn.clicked.connect(lambda: self.on_Fwd(fullstep))
|
||||||
|
halfstepFwdBtn = QPushButton(">>")
|
||||||
|
halfstepFwdBtn.setFont(font)
|
||||||
|
halfstepFwdBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
halfstepFwdBtn.setShortcut(Qt.KeyboardModifier.AltModifier | Qt.Key.Key_Right)
|
||||||
|
halfstepFwdBtn.setToolTip(f"Proceed by half a window ({halfstepFwdBtn.shortcut().toString()})")
|
||||||
|
halfstepFwdBtn.clicked.connect(lambda: self.on_Fwd(halfstep))
|
||||||
|
quarterstepFwdBtn = QPushButton(">")
|
||||||
|
quarterstepFwdBtn.setFont(font)
|
||||||
|
quarterstepFwdBtn.setShortcut(Qt.KeyboardModifier.ShiftModifier | Qt.Key.Key_Right)
|
||||||
|
quarterstepFwdBtn.setToolTip(f"Proceed by a quarter window ({quarterstepFwdBtn.shortcut().toString()})")
|
||||||
|
quarterstepFwdBtn.clicked.connect(lambda: self.on_Fwd(quarterstep))
|
||||||
|
quarterstepFwdBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
|
||||||
|
assignOneBtn = QPushButton("Track One")
|
||||||
|
assignOneBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
assignOneBtn.setStyleSheet("QPushButton { background-color: orange; }")
|
||||||
|
assignOneBtn.setShortcut("Ctrl+1")
|
||||||
|
assignOneBtn.setToolTip(f"Assign current selection to Track One ({assignOneBtn.shortcut().toString()})")
|
||||||
|
assignOneBtn.setFont(font)
|
||||||
|
assignOneBtn.clicked.connect(self.on_TrackOne)
|
||||||
|
|
||||||
|
assignTwoBtn = QPushButton("Track Two")
|
||||||
|
assignTwoBtn.setShortcut("Ctrl+2")
|
||||||
|
assignTwoBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
assignTwoBtn.setStyleSheet("QPushButton { background-color: green; }")
|
||||||
|
assignTwoBtn.setToolTip(f"Assign current selection to Track Two ({assignTwoBtn.shortcut().toString()})")
|
||||||
|
assignTwoBtn.setFont(font)
|
||||||
|
assignTwoBtn.clicked.connect(self.on_TrackTwo)
|
||||||
|
|
||||||
|
assignOtherBtn = QPushButton("Other")
|
||||||
|
assignOtherBtn.setShortcut("Ctrl+0")
|
||||||
|
assignOtherBtn.setFont(font)
|
||||||
|
assignOtherBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
# assignOtherBtn.setStyleSheet("QPushButton { background-color: gray; }")
|
||||||
|
assignOtherBtn.setToolTip(f"Assign current selection to Unassigned ({assignOtherBtn.shortcut().toString()})")
|
||||||
|
assignOtherBtn.clicked.connect(self.on_TrackOther)
|
||||||
|
|
||||||
|
acceptBtn = QPushButton("accept")
|
||||||
|
acceptBtn.setFont(font)
|
||||||
|
acceptBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
# acceptBtn.setStyleSheet("QPushButton { background-color: red; }")
|
||||||
|
acceptBtn.setToolTip(f"Accept assignments of current selection as TRUE")
|
||||||
|
acceptBtn.clicked.connect(self.on_Accept)
|
||||||
|
|
||||||
|
unacceptBtn = QPushButton("un-accept")
|
||||||
|
unacceptBtn.setFont(font)
|
||||||
|
unacceptBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
# acceptBtn.setStyleSheet("QPushButton { background-color: red; }")
|
||||||
|
unacceptBtn.setToolTip(f"Revoke current selection TRUE status")
|
||||||
|
unacceptBtn.clicked.connect(self.on_Unaccept)
|
||||||
|
|
||||||
|
deleteBtn = QPushButton("delete")
|
||||||
|
deleteBtn.setFont(font)
|
||||||
|
deleteBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
deleteBtn.setStyleSheet("QPushButton { background-color: red; }")
|
||||||
|
deleteBtn.setToolTip(f"DANGERZONE! Delete current selection of detections!")
|
||||||
|
deleteBtn.clicked.connect(self.on_Delete)
|
||||||
|
|
||||||
|
revertBtn = QPushButton("revert assignments")
|
||||||
|
revertBtn.setFont(font)
|
||||||
|
revertBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
||||||
|
revertBtn.setStyleSheet("QPushButton { background-color: red; }")
|
||||||
|
revertBtn.setToolTip(f"DANGERZONE! Remove ALL assignments!")
|
||||||
|
revertBtn.clicked.connect(self.on_RevertAll)
|
||||||
|
|
||||||
|
self.tone_selection = QLabel("0")
|
||||||
|
self.ttwo_selection = QLabel("0")
|
||||||
|
self.tother_selection = QLabel("0")
|
||||||
|
self.startframe = QLabel("0")
|
||||||
|
self.endframe = QLabel("0")
|
||||||
|
self._total = 0
|
||||||
|
|
||||||
|
grid = QGridLayout()
|
||||||
|
grid.addWidget(backBtn, 0, 0, 3, 2)
|
||||||
|
grid.addWidget(fwdBtn, 0, 6, 3, 2)
|
||||||
|
grid.addWidget(halfstepBackBtn, 3, 0, 2, 2)
|
||||||
|
grid.addWidget(halfstepFwdBtn, 3, 6, 2, 2)
|
||||||
|
grid.addWidget(quarterstepBackBtn, 5, 0, 2, 2)
|
||||||
|
grid.addWidget(quarterstepFwdBtn, 5, 6, 2, 2)
|
||||||
|
|
||||||
|
cwLabel = QLabel("Current window:")
|
||||||
|
cwLabel.setFont(font)
|
||||||
|
grid.addWidget(cwLabel, 0, 2, 1, 4)
|
||||||
|
grid.addWidget(QLabel("start:"), 1, 2, 1, 2)
|
||||||
|
grid.addWidget(self.startframe, 1, 4, 1, 2, Qt.AlignmentFlag.AlignRight)
|
||||||
|
grid.addWidget(QLabel("end:"), 2, 2, 1, 2)
|
||||||
|
grid.addWidget(self.endframe, 2, 4, 1, 2, Qt.AlignmentFlag.AlignRight)
|
||||||
|
|
||||||
|
csLabel = QLabel("Current selection:")
|
||||||
|
csLabel.setFont(font)
|
||||||
|
grid.addWidget(csLabel, 3, 2, 1, 4)
|
||||||
|
grid.addWidget(QLabel("track One:"), 4, 2, 1, 2)
|
||||||
|
grid.addWidget(self.tone_selection, 4, 4, 1, 2, Qt.AlignmentFlag.AlignRight)
|
||||||
|
grid.addWidget(QLabel("track Two:"), 5, 2, 1, 2)
|
||||||
|
grid.addWidget(self.ttwo_selection, 5, 4, 1, 2, Qt.AlignmentFlag.AlignRight)
|
||||||
|
grid.addWidget(QLabel("Unassigned:"), 6, 2, 1, 2)
|
||||||
|
grid.addWidget(self.tother_selection, 6, 4, 1, 2, Qt.AlignmentFlag.AlignRight)
|
||||||
|
|
||||||
|
grid.addWidget(assignOneBtn, 7, 0, 1, 3)
|
||||||
|
grid.addWidget(assignOtherBtn, 7, 3, 1, 2)
|
||||||
|
grid.addWidget(assignTwoBtn, 7, 5, 1, 3)
|
||||||
|
grid.addWidget(acceptBtn, 8, 0, 1, 4)
|
||||||
|
grid.addWidget(unacceptBtn, 8, 4, 1, 4)
|
||||||
|
grid.addWidget(deleteBtn, 9, 0, 1, 4)
|
||||||
|
grid.addWidget(revertBtn, 9, 4, 1, 4)
|
||||||
|
|
||||||
|
grid.setColumnStretch(0, 1)
|
||||||
|
grid.setColumnStretch(7, 1)
|
||||||
|
self.setLayout(grid)
|
||||||
|
self.setMaximumSize(QSize(400, 300))
|
||||||
|
|
||||||
|
def setWindow(self, start:int=0, end:int=0):
|
||||||
|
self.startframe.setText(f"{start:.0f}")
|
||||||
|
self.endframe.setText(f"{end:g}")
|
||||||
|
|
||||||
|
def _updateNumbers(self, track):
|
||||||
|
labels = {1: self.tone_selection, 2: self.ttwo_selection, 3: self.tother_selection}
|
||||||
|
for k in labels:
|
||||||
|
if k == track:
|
||||||
|
labels[k].setText(str(self._total))
|
||||||
|
else:
|
||||||
|
labels[k].setText("0")
|
||||||
|
|
||||||
|
def on_Fwd(self, stepsize):
|
||||||
|
logging.debug("SelectionControls: forward step by %.2f", stepsize)
|
||||||
|
self.fwd.emit(stepsize)
|
||||||
|
|
||||||
|
def on_Back(self, stepsize):
|
||||||
|
logging.debug("SelectionControls: backward step by %.2f", stepsize)
|
||||||
|
self.back.emit(stepsize)
|
||||||
|
|
||||||
|
def on_TrackOne(self):
|
||||||
|
logging.debug("SelectionControl: TrackONEBtn")
|
||||||
|
self.assignOne.emit()
|
||||||
|
self._updateNumbers(1)
|
||||||
|
|
||||||
|
def on_TrackTwo(self):
|
||||||
|
logging.debug("SelectionControl: TrackTWOBtn")
|
||||||
|
self.assignTwo.emit()
|
||||||
|
self._updateNumbers(2)
|
||||||
|
|
||||||
|
def on_TrackOther(self):
|
||||||
|
logging.debug("SelectionControl: TrackOtherBtn")
|
||||||
|
self.assignOther.emit()
|
||||||
|
self._updateNumbers(3)
|
||||||
|
|
||||||
|
def on_Accept(self):
|
||||||
|
logging.debug("SelectionControl: accept AssignmentBtn")
|
||||||
|
self.accept.emit()
|
||||||
|
|
||||||
|
def on_Unaccept(self):
|
||||||
|
logging.debug("SelectionControl: revoke user assignmentBtn")
|
||||||
|
self.unaccept.emit()
|
||||||
|
|
||||||
|
def on_RevertAll(self):
|
||||||
|
logging.debug("SelectionControl: revert Btn")
|
||||||
|
self.revertall.emit()
|
||||||
|
|
||||||
|
def on_Delete(self):
|
||||||
|
logging.debug("SelectionControl: delete Btn")
|
||||||
|
self.delete.emit()
|
||||||
|
|
||||||
|
def setSelectedTracks(self, tracks):
|
||||||
|
logging.debug("SelectionControl: setSelectedTracks")
|
||||||
|
if tracks is not None:
|
||||||
|
tone = np.sum(tracks == 1)
|
||||||
|
ttwo = np.sum(tracks == 2)
|
||||||
|
else:
|
||||||
|
tone = 0
|
||||||
|
ttwo = 0
|
||||||
|
|
||||||
|
self.tone_selection.setText(str(tone))
|
||||||
|
self.ttwo_selection.setText(str(ttwo))
|
||||||
|
self.tother_selection.setText(str(len(tracks) - tone - ttwo if tracks is not None else 0))
|
||||||
|
self._total = len(tracks) if tracks is not None else 0
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
from PySide6.QtWidgets import QApplication
|
||||||
|
logging.basicConfig(level=logging.DEBUG, force=True)
|
||||||
|
|
||||||
|
app = QApplication([])
|
||||||
|
window = QWidget()
|
||||||
|
window.setMinimumSize(200, 200)
|
||||||
|
layout = QVBoxLayout()
|
||||||
|
controls = SelectionControls()
|
||||||
|
layout.addWidget(controls)
|
||||||
|
window.setLayout(layout)
|
||||||
|
window.show()
|
||||||
|
app.exec()
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
@ -14,166 +14,7 @@ from fixtracks.widgets.detectionview import DetectionView, DetectionData
|
|||||||
from fixtracks.widgets.detectiontimeline import DetectionTimeline
|
from fixtracks.widgets.detectiontimeline import DetectionTimeline
|
||||||
from fixtracks.widgets.skeleton import SkeletonWidget
|
from fixtracks.widgets.skeleton import SkeletonWidget
|
||||||
from fixtracks.widgets.classifier import ClassifierWidget
|
from fixtracks.widgets.classifier import ClassifierWidget
|
||||||
|
from fixtracks.widgets.selection_control import SelectionControls
|
||||||
|
|
||||||
class SelectionControls(QWidget):
|
|
||||||
fwd = Signal(float)
|
|
||||||
back = Signal(float)
|
|
||||||
assignOne = Signal()
|
|
||||||
assignTwo = Signal()
|
|
||||||
assignOther = Signal()
|
|
||||||
|
|
||||||
def __init__(self, parent = None,):
|
|
||||||
super().__init__(parent)
|
|
||||||
font = QFont()
|
|
||||||
font.setBold(True)
|
|
||||||
font.setPointSize(10)
|
|
||||||
fullstep = 1.0
|
|
||||||
halfstep = 0.5
|
|
||||||
quarterstep = 0.25
|
|
||||||
|
|
||||||
backBtn = QPushButton("|<<")
|
|
||||||
backBtn.setFont(font)
|
|
||||||
backBtn.setShortcut(Qt.Key.Key_Left)
|
|
||||||
backBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
|
||||||
backBtn.setToolTip(f"Go back to previous window ({backBtn.shortcut().toString()})")
|
|
||||||
backBtn.clicked.connect(lambda: self.on_Back(fullstep))
|
|
||||||
halfstepBackBtn = QPushButton("<<")
|
|
||||||
halfstepBackBtn.setFont(font)
|
|
||||||
halfstepBackBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
|
||||||
halfstepBackBtn.setShortcut(Qt.KeyboardModifier.AltModifier | Qt.Key.Key_Left)
|
|
||||||
halfstepBackBtn.setToolTip(f"Go back by half a window ({halfstepBackBtn.shortcut().toString()})")
|
|
||||||
halfstepBackBtn.clicked.connect(lambda: self.on_Back(halfstep))
|
|
||||||
quarterstepBackBtn = QPushButton("<")
|
|
||||||
quarterstepBackBtn.setFont(font)
|
|
||||||
quarterstepBackBtn.setShortcut(Qt.KeyboardModifier.ShiftModifier | Qt.Key.Key_Left)
|
|
||||||
quarterstepBackBtn.setToolTip(f"Go back by a quarter window ({quarterstepBackBtn.shortcut().toString()})")
|
|
||||||
quarterstepBackBtn.clicked.connect(lambda: self.on_Back(quarterstep))
|
|
||||||
|
|
||||||
fwdBtn = QPushButton(">>|")
|
|
||||||
fwdBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
|
||||||
fwdBtn.setShortcut(Qt.Key.Key_Right)
|
|
||||||
fwdBtn.setFont(font)
|
|
||||||
fwdBtn.setToolTip(f"Proceed to next window ({fwdBtn.shortcut().toString()})")
|
|
||||||
fwdBtn.clicked.connect(lambda: self.on_Fwd(fullstep))
|
|
||||||
halfstepFwdBtn = QPushButton(">>")
|
|
||||||
halfstepFwdBtn.setFont(font)
|
|
||||||
halfstepFwdBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
|
||||||
halfstepFwdBtn.setShortcut(Qt.KeyboardModifier.AltModifier | Qt.Key.Key_Right)
|
|
||||||
halfstepFwdBtn.setToolTip(f"Proceed by half a window ({halfstepFwdBtn.shortcut().toString()})")
|
|
||||||
halfstepFwdBtn.clicked.connect(lambda: self.on_Fwd(halfstep))
|
|
||||||
quarterstepFwdBtn = QPushButton(">")
|
|
||||||
quarterstepFwdBtn.setFont(font)
|
|
||||||
quarterstepFwdBtn.setShortcut(Qt.KeyboardModifier.ShiftModifier | Qt.Key.Key_Right)
|
|
||||||
quarterstepFwdBtn.setToolTip(f"Proceed by a quarter window ({quarterstepFwdBtn.shortcut().toString()})")
|
|
||||||
quarterstepFwdBtn.clicked.connect(lambda: self.on_Fwd(quarterstep))
|
|
||||||
|
|
||||||
assignOneBtn = QPushButton("Track One")
|
|
||||||
assignOneBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
|
||||||
assignOneBtn.setStyleSheet("QPushButton { background-color: orange; }")
|
|
||||||
assignOneBtn.setShortcut("Ctrl+1")
|
|
||||||
assignOneBtn.setToolTip(f"Assign current selection to Track One ({assignOneBtn.shortcut().toString()})")
|
|
||||||
assignOneBtn.setFont(font)
|
|
||||||
assignOneBtn.clicked.connect(self.on_TrackOne)
|
|
||||||
|
|
||||||
assignTwoBtn = QPushButton("Track Two")
|
|
||||||
assignTwoBtn.setShortcut("Ctrl+2")
|
|
||||||
assignTwoBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
|
||||||
assignTwoBtn.setStyleSheet("QPushButton { background-color: green; }")
|
|
||||||
assignTwoBtn.setToolTip(f"Assign current selection to Track Two ({assignTwoBtn.shortcut().toString()})")
|
|
||||||
assignTwoBtn.setFont(font)
|
|
||||||
assignTwoBtn.clicked.connect(self.on_TrackTwo)
|
|
||||||
|
|
||||||
assignOtherBtn = QPushButton("Other")
|
|
||||||
assignOtherBtn.setShortcut("Ctrl+0")
|
|
||||||
assignOtherBtn.setFont(font)
|
|
||||||
assignOtherBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
|
|
||||||
assignOtherBtn.setStyleSheet("QPushButton { background-color: red; }")
|
|
||||||
assignOtherBtn.setToolTip(f"Assign current selection to Unassigned ({assignOtherBtn.shortcut().toString()})")
|
|
||||||
assignOtherBtn.clicked.connect(self.on_TrackOther)
|
|
||||||
|
|
||||||
self.tone_selection = QLabel("0")
|
|
||||||
self.ttwo_selection = QLabel("0")
|
|
||||||
self.tother_selection = QLabel("0")
|
|
||||||
self.startframe = QLabel("0")
|
|
||||||
self.endframe = QLabel("0")
|
|
||||||
self._total = 0
|
|
||||||
|
|
||||||
grid = QGridLayout()
|
|
||||||
grid.addWidget(backBtn, 0, 0, 3, 2)
|
|
||||||
grid.addWidget(halfstepBackBtn, 3, 0, 2, 2)
|
|
||||||
grid.addWidget(quarterstepBackBtn, 5, 0, 2, 2)
|
|
||||||
grid.addWidget(fwdBtn, 0, 6, 3, 2)
|
|
||||||
grid.addWidget(halfstepFwdBtn, 3, 6, 2, 2)
|
|
||||||
grid.addWidget(quarterstepFwdBtn, 5, 6, 2, 2)
|
|
||||||
|
|
||||||
grid.addWidget(QLabel("Current window:"), 0, 2, 1, 4)
|
|
||||||
grid.addWidget(QLabel("start:"), 1, 3, 1, 1)
|
|
||||||
grid.addWidget(self.startframe, 1, 4, 1, 2, Qt.AlignmentFlag.AlignRight)
|
|
||||||
grid.addWidget(QLabel("end:"), 2, 3, 1, 1)
|
|
||||||
grid.addWidget(self.endframe, 2, 4, 1, 2, Qt.AlignmentFlag.AlignRight)
|
|
||||||
grid.addWidget(QLabel("Current selection:"), 3, 2, 1, 4)
|
|
||||||
grid.addWidget(QLabel("Track One:"), 4, 3, 1, 2)
|
|
||||||
grid.addWidget(self.tone_selection, 4, 5, 1, 1, Qt.AlignmentFlag.AlignRight)
|
|
||||||
grid.addWidget(QLabel("Track Two:"), 5, 3, 1, 2)
|
|
||||||
grid.addWidget(self.ttwo_selection, 5, 5, 1, 1, Qt.AlignmentFlag.AlignRight)
|
|
||||||
grid.addWidget(QLabel("Unassigned:"), 6, 3, 1, 2)
|
|
||||||
grid.addWidget(self.tother_selection, 6, 5, 1, 1, Qt.AlignmentFlag.AlignRight)
|
|
||||||
|
|
||||||
grid.addWidget(assignOneBtn, 7, 0, 4, 3)
|
|
||||||
grid.addWidget(assignOtherBtn, 7, 3, 4, 2)
|
|
||||||
grid.addWidget(assignTwoBtn, 7, 5, 4, 3)
|
|
||||||
grid.setColumnStretch(0, 1)
|
|
||||||
grid.setColumnStretch(7, 1)
|
|
||||||
self.setLayout(grid)
|
|
||||||
self.setMaximumSize(QSize(400, 200))
|
|
||||||
|
|
||||||
def setWindow(self, start:int=0, end:int=0):
|
|
||||||
self.startframe.setText(f"{start:.0f}")
|
|
||||||
self.endframe.setText(f"{end:g}")
|
|
||||||
|
|
||||||
def _updateNumbers(self, track):
|
|
||||||
labels = {1: self.tone_selection, 2: self.ttwo_selection, 3: self.tother_selection}
|
|
||||||
for k in labels:
|
|
||||||
if k == track:
|
|
||||||
labels[k].setText(str(self._total))
|
|
||||||
else:
|
|
||||||
labels[k].setText("0")
|
|
||||||
|
|
||||||
def on_Fwd(self, stepsize):
|
|
||||||
logging.debug("SelectionControls: forward step by %.2f", stepsize)
|
|
||||||
self.fwd.emit(stepsize)
|
|
||||||
|
|
||||||
def on_Back(self, stepsize):
|
|
||||||
logging.debug("SelectionControls: backward step by %.2f", stepsize)
|
|
||||||
self.back.emit(stepsize)
|
|
||||||
|
|
||||||
def on_TrackOne(self):
|
|
||||||
self.assignOne.emit()
|
|
||||||
self._updateNumbers(1)
|
|
||||||
|
|
||||||
def on_TrackTwo(self):
|
|
||||||
self.assignTwo.emit()
|
|
||||||
self._updateNumbers(2)
|
|
||||||
|
|
||||||
def on_TrackOther(self):
|
|
||||||
self.assignOther.emit()
|
|
||||||
self._updateNumbers(3)
|
|
||||||
|
|
||||||
def setSelectedTracks(self, tracks):
|
|
||||||
logging.debug("SelectionControl: setSelectedTracks")
|
|
||||||
if tracks is not None:
|
|
||||||
tone = np.sum(tracks == 1)
|
|
||||||
ttwo = np.sum(tracks == 2)
|
|
||||||
else:
|
|
||||||
tone = 0
|
|
||||||
ttwo = 0
|
|
||||||
|
|
||||||
self.tone_selection.setText(str(tone))
|
|
||||||
self.ttwo_selection.setText(str(ttwo))
|
|
||||||
self.tother_selection.setText(str(len(tracks) - tone - ttwo if tracks is not None else 0))
|
|
||||||
self._total = len(tracks) if tracks is not None else 0
|
|
||||||
|
|
||||||
|
|
||||||
class FixTracks(QWidget):
|
class FixTracks(QWidget):
|
||||||
back = Signal()
|
back = Signal()
|
||||||
@ -239,6 +80,10 @@ class FixTracks(QWidget):
|
|||||||
self._controls_widget.assignOther.connect(self.on_assignOther)
|
self._controls_widget.assignOther.connect(self.on_assignOther)
|
||||||
self._controls_widget.fwd.connect(self.on_forward)
|
self._controls_widget.fwd.connect(self.on_forward)
|
||||||
self._controls_widget.back.connect(self.on_backward)
|
self._controls_widget.back.connect(self.on_backward)
|
||||||
|
self._controls_widget.accept.connect(self.on_setUserFlag)
|
||||||
|
self._controls_widget.unaccept.connect(self.on_unsetUserFlag)
|
||||||
|
self._controls_widget.delete.connect(self.on_deleteDetection)
|
||||||
|
self._controls_widget.revertall.connect(self.on_revertUserFlags)
|
||||||
|
|
||||||
self._saveBtn = QPushButton("Save")
|
self._saveBtn = QPushButton("Save")
|
||||||
self._saveBtn.setShortcut("Ctrl+S")
|
self._saveBtn.setShortcut("Ctrl+S")
|
||||||
@ -446,12 +291,31 @@ class FixTracks(QWidget):
|
|||||||
|
|
||||||
def on_assignOther(self):
|
def on_assignOther(self):
|
||||||
logging.debug("Assigning user selection to track Other")
|
logging.debug("Assigning user selection to track Other")
|
||||||
self._data.assignUserSelection(self.trackother_id)
|
self._data.assignUserSelection(self.trackother_id, False)
|
||||||
self._timeline.setDetectionData(self._data.data)
|
self._timeline.setDetectionData(self._data.data)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
def on_setUserFlag(self):
|
||||||
|
self._data.setAssignmentStatus(True)
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def on_unsetUserFlag(self):
|
||||||
|
logging.debug("Tracks:unsetUserFlag")
|
||||||
|
self._data.setAssignmentStatus(False)
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def on_revertUserFlags(self):
|
||||||
|
logging.debug("Tracks:revert ALL UserFlags")
|
||||||
|
self._data.revertAssignmentStatus()
|
||||||
|
self.update()
|
||||||
|
|
||||||
|
def on_deleteDetection(self):
|
||||||
|
logging.debug("Tracks:delete detections")
|
||||||
|
# self._data.deleteDetections()
|
||||||
|
self.update()
|
||||||
|
|
||||||
def on_windowChanged(self):
|
def on_windowChanged(self):
|
||||||
logging.info("Timeline reports window change ")
|
logging.debug("Tracks:Timeline reports window change ")
|
||||||
self._currentWindowPos = np.round(self._timeline.rangeStart * self._maxframes)
|
self._currentWindowPos = np.round(self._timeline.rangeStart * self._maxframes)
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
|
2
main.py
2
main.py
@ -11,7 +11,7 @@ from PySide6.QtGui import QIcon, QPalette
|
|||||||
|
|
||||||
from fixtracks import fixtracks, info
|
from fixtracks import fixtracks, info
|
||||||
|
|
||||||
logging.basicConfig(level=logging.DEBUG, force=True)
|
logging.basicConfig(level=logging.INFO, force=True)
|
||||||
|
|
||||||
|
|
||||||
def is_dark_mode(app: QApplication) -> bool:
|
def is_dark_mode(app: QApplication) -> bool:
|
||||||
|
Loading…
Reference in New Issue
Block a user