work work
This commit is contained in:
parent
8c62d17dde
commit
7586643faa
@ -47,7 +47,7 @@ class PreviewDialog(QDialog):
|
|||||||
imgfile = file_dialog.selectedFiles()[0]
|
imgfile = file_dialog.selectedFiles()[0]
|
||||||
if imgfile is not None:
|
if imgfile is not None:
|
||||||
img = QImage(imgfile)
|
img = QImage(imgfile)
|
||||||
self.merge_preview.set_image(img)
|
self.merge_preview.setImage(img)
|
||||||
|
|
||||||
file_dialog = QFileDialog(self, "Select pickled DataFrame", "", "Pandas DataFrame (*.pkl)")
|
file_dialog = QFileDialog(self, "Select pickled DataFrame", "", "Pandas DataFrame (*.pkl)")
|
||||||
if file_dialog.exec():
|
if file_dialog.exec():
|
||||||
@ -63,7 +63,7 @@ class PreviewDialog(QDialog):
|
|||||||
self._progress_bar.setValue(0)
|
self._progress_bar.setValue(0)
|
||||||
if state and self._reader is not None:
|
if state and self._reader is not None:
|
||||||
self._df = self._reader.data
|
self._df = self._reader.data
|
||||||
self.merge_preview.set_dataframe(self._df)
|
self.merge_preview.setDataframe(self._df)
|
||||||
self._reader = None
|
self._reader = None
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
from PySide6.QtCore import Signal, QObject
|
from PySide6.QtCore import Signal, QObject, QPointF
|
||||||
|
|
||||||
class ProducerSignals(QObject):
|
class ProducerSignals(QObject):
|
||||||
finished = Signal(bool)
|
finished = Signal(bool)
|
||||||
@ -7,3 +7,13 @@ class ProducerSignals(QObject):
|
|||||||
# running = pyqtSignal()
|
# running = pyqtSignal()
|
||||||
progress = Signal(float)
|
progress = Signal(float)
|
||||||
progress2 = Signal((str, float, 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)
|
@ -2,7 +2,7 @@ import logging
|
|||||||
from PySide6.QtWidgets import QWidget, QStackedLayout, QSizePolicy
|
from PySide6.QtWidgets import QWidget, QStackedLayout, QSizePolicy
|
||||||
from PySide6.QtCore import Qt
|
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.detectionmerge import MergeDetections
|
||||||
from fixtracks.widgets.taskwidget import TasksWidget
|
from fixtracks.widgets.taskwidget import TasksWidget
|
||||||
from fixtracks.widgets.converter import Json2PandasConverter
|
from fixtracks.widgets.converter import Json2PandasConverter
|
||||||
@ -23,6 +23,7 @@ class CentralWidget(QWidget):
|
|||||||
self._convertwidget.back.connect(self._on_back)
|
self._convertwidget.back.connect(self._on_back)
|
||||||
|
|
||||||
self._trackwidget = FixTracks(self)
|
self._trackwidget = FixTracks(self)
|
||||||
|
self._trackwidget.back.connect(self._on_back)
|
||||||
|
|
||||||
layout = QStackedLayout()
|
layout = QStackedLayout()
|
||||||
layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
|
||||||
|
@ -22,7 +22,7 @@ class VideoPreview(QWidget):
|
|||||||
layout.addWidget(self._view)
|
layout.addWidget(self._view)
|
||||||
self.setLayout(layout)
|
self.setLayout(layout)
|
||||||
|
|
||||||
def set_image(self, img):
|
def setImage(self, img):
|
||||||
self._image = img
|
self._image = img
|
||||||
self._scene = QGraphicsScene()
|
self._scene = QGraphicsScene()
|
||||||
self._pixmapitem = self._scene.addPixmap(QPixmap.fromImage(img))
|
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._scene.addLine(start_x, start_y, start_x, end_y, self._line_pen)
|
||||||
self._view.show()
|
self._view.show()
|
||||||
|
|
||||||
def set_lineposition(self, position):
|
def setLineposition(self, position):
|
||||||
image_rect = self._pixmapitem.boundingRect()
|
image_rect = self._pixmapitem.boundingRect()
|
||||||
for i in self._scene.items():
|
for i in self._scene.items():
|
||||||
if isinstance(i, QGraphicsLineItem):
|
if isinstance(i, QGraphicsLineItem):
|
||||||
@ -206,7 +206,7 @@ class MergeDetections(QWidget):
|
|||||||
frame = self.right_imagereader.frame
|
frame = self.right_imagereader.frame
|
||||||
if frame is not None:
|
if frame is not None:
|
||||||
img = self._toImage(frame)
|
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.setMaximum(img.width() - 1)
|
||||||
self.right_posspinner.setValue(0)
|
self.right_posspinner.setValue(0)
|
||||||
self.checkButtons()
|
self.checkButtons()
|
||||||
@ -224,7 +224,7 @@ class MergeDetections(QWidget):
|
|||||||
frame = self.left_imagereader.frame
|
frame = self.left_imagereader.frame
|
||||||
if frame is not None:
|
if frame is not None:
|
||||||
img = self._toImage(frame)
|
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.setMaximum(img.width() - 1)
|
||||||
self.left_posspinner.setValue(img.width() - 1)
|
self.left_posspinner.setValue(img.width() - 1)
|
||||||
self.checkButtons()
|
self.checkButtons()
|
||||||
@ -260,10 +260,10 @@ class MergeDetections(QWidget):
|
|||||||
self.checkButtons()
|
self.checkButtons()
|
||||||
|
|
||||||
def on_leftmergelinemove(self):
|
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):
|
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):
|
def on_mergePreview(self):
|
||||||
logging.debug("detectionmerge: mergePreview pressed")
|
logging.debug("detectionmerge: mergePreview pressed")
|
||||||
|
@ -1,12 +1,10 @@
|
|||||||
import logging
|
import logging
|
||||||
import numpy as np
|
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.QtCore import Qt
|
||||||
from PySide6.QtGui import QPixmap, QBrush, QColor
|
from PySide6.QtGui import QPixmap, QBrush, QColor
|
||||||
|
|
||||||
from fixtracks.utils.reader import ImageReader
|
|
||||||
|
|
||||||
|
|
||||||
class MergePreview(QWidget):
|
class MergePreview(QWidget):
|
||||||
|
|
||||||
@ -88,7 +86,7 @@ class MergePreview(QWidget):
|
|||||||
self._keypointCombo.clear()
|
self._keypointCombo.clear()
|
||||||
self._keypointCombo.addItems([f"keypoint {i}" for i in range(numkeypoints)])
|
self._keypointCombo.addItems([f"keypoint {i}" for i in range(numkeypoints)])
|
||||||
|
|
||||||
def set_dataframe(self, newdf):
|
def setDataframe(self, newdf):
|
||||||
self._dataframe = newdf
|
self._dataframe = newdf
|
||||||
self._frames = self._dataframe.frame.values
|
self._frames = self._dataframe.frame.values
|
||||||
self._keypoints = self._dataframe.keypoints.values
|
self._keypoints = self._dataframe.keypoints.values
|
||||||
@ -115,11 +113,11 @@ class MergePreview(QWidget):
|
|||||||
self._startLabel.setText(str(self._startSlider.value()))
|
self._startLabel.setText(str(self._startSlider.value()))
|
||||||
self._stopLabel.setText(str(self._stopSlider.value()))
|
self._stopLabel.setText(str(self._stopSlider.value()))
|
||||||
|
|
||||||
def set_image(self, img):
|
def setImage(self, img):
|
||||||
self._image = img
|
self._image = img
|
||||||
self.update()
|
self.update()
|
||||||
|
|
||||||
def _draw_detections(self):
|
def _drawDetections(self):
|
||||||
start_frame = self._startSlider.value()
|
start_frame = self._startSlider.value()
|
||||||
stop_frame = self._stopSlider.value()
|
stop_frame = self._stopSlider.value()
|
||||||
selection = self._keypoints[self._frames[(self._frames >= start_frame) & (self._frames < stop_frame)]]
|
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.setScene(self._scene)
|
||||||
self._view.fitInView(self._scene.sceneRect(), aspectRadioMode=Qt.AspectRatioMode.KeepAspectRatio)
|
self._view.fitInView(self._scene.sceneRect(), aspectRadioMode=Qt.AspectRatioMode.KeepAspectRatio)
|
||||||
self._view.show()
|
self._view.show()
|
||||||
self._draw_detections()
|
self._drawDetections()
|
||||||
|
|
||||||
def fit_image_to_view(self):
|
def fit_image_to_view(self):
|
||||||
"""Scale the image to fit the QGraphicsView."""
|
"""Scale the image to fit the QGraphicsView."""
|
||||||
|
@ -79,10 +79,6 @@ class TasksWidget(QWidget):
|
|||||||
l.addWidget(mergeBtn, 1, 1, 1, 1, Qt.AlignmentFlag.AlignCenter)
|
l.addWidget(mergeBtn, 1, 1, 1, 1, Qt.AlignmentFlag.AlignCenter)
|
||||||
l.addWidget(tracksBtn, 2, 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)
|
self.setLayout(l)
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
192
fixtracks/widgets/tracks.py
Normal 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)
|
Loading…
Reference in New Issue
Block a user