work work

This commit is contained in:
Jan Grewe 2025-01-24 17:21:34 +01:00
parent 8c62d17dde
commit 7586643faa
8 changed files with 218 additions and 40 deletions

View File

@ -47,7 +47,7 @@ class PreviewDialog(QDialog):
imgfile = file_dialog.selectedFiles()[0]
if imgfile is not None:
img = QImage(imgfile)
self.merge_preview.set_image(img)
self.merge_preview.setImage(img)
file_dialog = QFileDialog(self, "Select pickled DataFrame", "", "Pandas DataFrame (*.pkl)")
if file_dialog.exec():
@ -63,7 +63,7 @@ class PreviewDialog(QDialog):
self._progress_bar.setValue(0)
if state and self._reader is not None:
self._df = self._reader.data
self.merge_preview.set_dataframe(self._df)
self.merge_preview.setDataframe(self._df)
self._reader = None

View File

@ -1,4 +1,4 @@
from PySide6.QtCore import Signal, QObject
from PySide6.QtCore import Signal, QObject, QPointF
class ProducerSignals(QObject):
finished = Signal(bool)
@ -7,3 +7,13 @@ class ProducerSignals(QObject):
# running = pyqtSignal()
progress = Signal(float)
progress2 = Signal((str, float, float))
class DetectionSignals(QObject):
hover = Signal((int, QPointF))
clicked = Signal((int, QPointF))
class TimelineSignals(QObject):
changed = Signal(int)
class ControlSignals(QPointF):
test = Signal(int)

View File

@ -2,7 +2,7 @@ import logging
from PySide6.QtWidgets import QWidget, QStackedLayout, QSizePolicy
from PySide6.QtCore import Qt
from fixtracks.widgets.taskwidgets import FixTracks
from fixtracks.widgets.tracks import FixTracks
from fixtracks.widgets.detectionmerge import MergeDetections
from fixtracks.widgets.taskwidget import TasksWidget
from fixtracks.widgets.converter import Json2PandasConverter
@ -23,6 +23,7 @@ class CentralWidget(QWidget):
self._convertwidget.back.connect(self._on_back)
self._trackwidget = FixTracks(self)
self._trackwidget.back.connect(self._on_back)
layout = QStackedLayout()
layout.setAlignment(Qt.AlignmentFlag.AlignCenter)

View File

@ -22,7 +22,7 @@ class VideoPreview(QWidget):
layout.addWidget(self._view)
self.setLayout(layout)
def set_image(self, img):
def setImage(self, img):
self._image = img
self._scene = QGraphicsScene()
self._pixmapitem = self._scene.addPixmap(QPixmap.fromImage(img))
@ -36,7 +36,7 @@ class VideoPreview(QWidget):
self._scene.addLine(start_x, start_y, start_x, end_y, self._line_pen)
self._view.show()
def set_lineposition(self, position):
def setLineposition(self, position):
image_rect = self._pixmapitem.boundingRect()
for i in self._scene.items():
if isinstance(i, QGraphicsLineItem):
@ -206,7 +206,7 @@ class MergeDetections(QWidget):
frame = self.right_imagereader.frame
if frame is not None:
img = self._toImage(frame)
self.right_preview.set_image(img)
self.right_preview.setImage(img)
self.right_posspinner.setMaximum(img.width() - 1)
self.right_posspinner.setValue(0)
self.checkButtons()
@ -224,7 +224,7 @@ class MergeDetections(QWidget):
frame = self.left_imagereader.frame
if frame is not None:
img = self._toImage(frame)
self.left_preview.set_image(img)
self.left_preview.setImage(img)
self.left_posspinner.setMaximum(img.width() - 1)
self.left_posspinner.setValue(img.width() - 1)
self.checkButtons()
@ -260,10 +260,10 @@ class MergeDetections(QWidget):
self.checkButtons()
def on_leftmergelinemove(self):
self.left_preview.set_lineposition(self.left_posspinner.value())
self.left_preview.setLineposition(self.left_posspinner.value())
def on_rightmergelinemove(self):
self.right_preview.set_lineposition(self.right_posspinner.value())
self.right_preview.setLineposition(self.right_posspinner.value())
def on_mergePreview(self):
logging.debug("detectionmerge: mergePreview pressed")

View File

@ -1,12 +1,10 @@
import logging
import numpy as np
from PySide6.QtWidgets import QWidget, QGridLayout, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QComboBox, QSizePolicy, QSpinBox, QGraphicsView, QGraphicsScene, QGraphicsLineItem, QSpacerItem, QProgressDialog, QFileDialog, QSlider
from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QComboBox, QSizePolicy, QSpinBox, QGraphicsView, QGraphicsScene, QSpacerItem, QSlider
from PySide6.QtCore import Qt
from PySide6.QtGui import QPixmap, QBrush, QColor
from fixtracks.utils.reader import ImageReader
class MergePreview(QWidget):
@ -88,7 +86,7 @@ class MergePreview(QWidget):
self._keypointCombo.clear()
self._keypointCombo.addItems([f"keypoint {i}" for i in range(numkeypoints)])
def set_dataframe(self, newdf):
def setDataframe(self, newdf):
self._dataframe = newdf
self._frames = self._dataframe.frame.values
self._keypoints = self._dataframe.keypoints.values
@ -115,11 +113,11 @@ class MergePreview(QWidget):
self._startLabel.setText(str(self._startSlider.value()))
self._stopLabel.setText(str(self._stopSlider.value()))
def set_image(self, img):
def setImage(self, img):
self._image = img
self.update()
def _draw_detections(self):
def _drawDetections(self):
start_frame = self._startSlider.value()
stop_frame = self._stopSlider.value()
selection = self._keypoints[self._frames[(self._frames >= start_frame) & (self._frames < stop_frame)]]
@ -145,7 +143,7 @@ class MergePreview(QWidget):
self._view.setScene(self._scene)
self._view.fitInView(self._scene.sceneRect(), aspectRadioMode=Qt.AspectRatioMode.KeepAspectRatio)
self._view.show()
self._draw_detections()
self._drawDetections()
def fit_image_to_view(self):
"""Scale the image to fit the QGraphicsView."""

View File

@ -79,10 +79,6 @@ class TasksWidget(QWidget):
l.addWidget(mergeBtn, 1, 1, 1, 1, Qt.AlignmentFlag.AlignCenter)
l.addWidget(tracksBtn, 2, 1, 1, 1, Qt.AlignmentFlag.AlignCenter)
# l.addWidget(folderBtn)
# l.addWidget(self.convertBtn)
# l.addWidget(self.mergeBtn)
# l.addWidget(self.tracksBtn)
self.setLayout(l)

View File

@ -1,19 +0,0 @@
import logging
from PySide6.QtWidgets import QWidget, QGridLayout, QVBoxLayout, QLabel, QPushButton, QFileDialog, QHBoxLayout, QComboBox, QSizePolicy
from PySide6.QtCore import QThreadPool
from PySide6.QtGui import QImage, QPixmap
from fixtracks.utils.reader import ImageReader
class FixTracks(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self._files = None
layout = QVBoxLayout()
layout.addWidget(QLabel("Fix Tracks!"))
self.setLayout(layout)
@property
def fileList(self, file_list):
self._files = file_list

192
fixtracks/widgets/tracks.py Normal file
View File

@ -0,0 +1,192 @@
import logging
import pathlib
import numpy as np
from PySide6.QtCore import Qt, QThreadPool, Signal
from PySide6.QtGui import QImage, QStandardItemModel, QStandardItem
from PySide6.QtWidgets import QWidget, QVBoxLayout, QHBoxLayout, QLabel, QPushButton, QSizePolicy
from PySide6.QtWidgets import QSpinBox, QSpacerItem, QFileDialog, QProgressBar, QTableView, QSplitter
from fixtracks.utils.reader import PickleLoader
from fixtracks.widgets.detectionview import DetectionView
from fixtracks.widgets.timeline import Timeline
class FixTracks(QWidget):
back = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self._files = []
self._threadpool = QThreadPool()
self._reader = None
self._image = None
self._dataframe = None
self._unassignedmodel = None
self._leftmodel = None
self._rightmodel = None
self._detectionView = DetectionView()
self._progress_bar = QProgressBar(self)
self._progress_bar.setMaximumHeight(20)
# self._progress_bar.setRange(0, 0) # Set the progress bar to be indeterminate
self._progress_bar.setValue(0)
self._tasklabel = QLabel()
self._timeline = Timeline()
self._timeline.signals.changed.connect(self.on_windowChanged)
self._windowspinner = QSpinBox()
self._windowspinner.setRange(100, 10000)
self._windowspinner.setSingleStep(100)
self._windowspinner.valueChanged.connect(self.on_windowSizeChanged)
timelinebox = QHBoxLayout()
timelinebox.addWidget(self._timeline)
timelinebox.addWidget(QLabel("Window"))
timelinebox.addWidget(self._windowspinner)
self._left_table = QTableView()
assign1 = QPushButton("<<")
assign1.clicked.connect(self.on_assignLeft)
assign2 = QPushButton(">>")
assign2.clicked.connect(self.on_assignRight)
self._unassigned_table = QTableView()
self._right_table = QTableView()
tablebox = QHBoxLayout()
tablebox.addWidget(self._left_table)
tablebox.addWidget(assign1)
tablebox.addWidget(self._unassigned_table)
tablebox.addWidget(assign2)
tablebox.addWidget(self._right_table)
self._openBtn = QPushButton("Open")
self._openBtn.setEnabled(True)
self._openBtn.clicked.connect(self._on_open)
self._saveBtn = QPushButton("Save")
self._saveBtn.setEnabled(False)
self._saveBtn.clicked.connect(self.on_save)
self._backBtn = QPushButton("Back")
self._backBtn.clicked.connect(self.on_back)
btnBox = QHBoxLayout()
btnBox.setAlignment(Qt.AlignmentFlag.AlignLeft)
btnBox.addWidget(self._backBtn)
btnBox.addItem(QSpacerItem(100, 10, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed))
btnBox.addWidget(self._tasklabel)
btnBox.addWidget(self._progress_bar)
btnBox.addWidget(self._openBtn)
btnBox.addWidget(self._saveBtn)
vbox = QVBoxLayout()
vbox.addLayout(timelinebox)
vbox.addLayout(tablebox)
vbox.addLayout(btnBox)
container = QWidget()
container.setLayout(vbox)
splitter = QSplitter(Qt.Orientation.Horizontal)
splitter.addWidget(self._detectionView)
splitter.addWidget(container)
splitter.setStretchFactor(0, 3)
splitter.setStretchFactor(1, 1)
layout = QHBoxLayout()
layout.addWidget(splitter)
self.setLayout(layout)
def _on_open(self):
infile = None
imgfile = None
self._tasklabel.setText( "Select merged image")
file_dialog = QFileDialog(self, "Select merged image")
file_dialog.setFileMode(QFileDialog.ExistingFile)
file_dialog.setNameFilters([
"Image Files (*.png *.jpg *.jpeg)",
"All Files (*)"
])
if file_dialog.exec():
imgfile = file_dialog.selectedFiles()[0]
if imgfile is not None:
img = QImage(imgfile)
self._detectionView.setImage(img)
self._tasklabel.setText( "Open data")
file_dialog = QFileDialog(self, "Select pickled DataFrame", "", "Pandas DataFrame (*.pkl)")
if file_dialog.exec():
infile = file_dialog.selectedFiles()[0]
if infile is not None:
self._progress_bar.setRange(0,0)
self._reader = PickleLoader(infile)
self._reader.signals.finished.connect(self._on_dataOpenend)
self._threadpool.start(self._reader)
def populateTables(self):
left_trackid = 1
right_trackid = 2
start_frame = self._timeline.sliderPosition - self._windowspinner.value() // 2
stop_frame = self._timeline.sliderPosition + self._windowspinner.value() // 2
df = self._dataframe[(self._dataframe.frame >= start_frame) & (self._dataframe.frame < stop_frame)]
assigned_left = df[(df.track == left_trackid)]
assigned_right = df[(df.track == right_trackid)]
unassigned = df[(df.track != left_trackid) & (df.track != right_trackid)]
print(len(assigned_left), len(assigned_right), len(unassigned))
columns = ["frame", "track id"]
self._unassignedmodel = QStandardItemModel(len(unassigned), 2)
self._unassignedmodel.setHorizontalHeaderLabels(columns)
self._leftmodel = QStandardItemModel(len(assigned_left), 2)
self._leftmodel.setHorizontalHeaderLabels(columns)
self._rightmodel = QStandardItemModel(len(assigned_right), 2)
self._rightmodel.setHorizontalHeaderLabels(columns)
# Populate the models with data
for i in range(len(unassigned)):
row = unassigned.iloc[i]
if i == 0: print(row)
for j in range(len(columns)):
item = QStandardItem(f"{i, j}")
self._unassignedmodel.setItem(i, j, item)
self._unassigned_table.setModel(self._unassignedmodel)
for i in range(len(assigned_left)):
row = assigned_left.iloc[i]
for j in range(len(columns)):
item = QStandardItem(f"{i, j}")
self._leftmodel.setItem(i, j, item)
self._left_table.setModel(self._leftmodel)
for i in range(len(assigned_right)):
row = assigned_right.iloc[i]
for j in range(len(columns)):
item = QStandardItem(f"{i, j}")
self._rightmodel.setItem(i, j, item)
self._right_table.setModel(self._rightmodel)
def _on_dataOpenend(self, state):
logging.info("Finished loading data with state %s", state)
self._tasklabel.setText("")
self._progress_bar.setRange(0, 100)
self._progress_bar.setValue(0)
if state and self._reader is not None:
self._dataframe = self._reader.data
self._timeline.setRange(np.max(self._dataframe.frame.values), self._windowspinner.value())
self.populateTables()
def on_save(self):
logging.debug("Save fixtracks results")
def on_back(self):
logging.debug("Back button pressed!")
self.back.emit()
def on_assignLeft(self):
pass
def on_assignRight(self):
pass
def on_windowChanged(self, value):
self.populateTables()
def on_windowSizeChanged(self, value):
self._timeline.setWindowWidth(value)