diff --git a/fixtracks/dialogs/__init__.py b/fixtracks/dialogs/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fixtracks/dialogs/previewdialog.py b/fixtracks/dialogs/previewdialog.py new file mode 100644 index 0000000..c590d1b --- /dev/null +++ b/fixtracks/dialogs/previewdialog.py @@ -0,0 +1,83 @@ +import logging +import pickle +import pandas as pd +from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QFileDialog, QProgressBar +from PySide6.QtCore import QThreadPool + +from fixtracks.widgets.mergepreview import MergePreview +from fixtracks.utils.reader import PickleLoader + + +class PreviewDialog(QDialog): + def __init__(self, parent=None): + super().__init__(parent) + self._threadpool = QThreadPool(self) + self._df = None + self._reader = None + + self.setWindowTitle("Merge Preview") + self._progress_bar = QProgressBar(self) + # self._progress_bar.setRange(0, 0) # Set the progress bar to be indeterminate + self._progress_bar.setValue(0) + + self.merge_preview = MergePreview(parent=self) + self._opendataBtn = QPushButton("open data") + self._opendataBtn.clicked.connect(self.on_openData) + + self._openleftBtn = QPushButton("open left video") + self._openleftBtn.clicked.connect(self.on_openleftVideo) + + self._openrightBtn = QPushButton("open right video") + self._openrightBtn.clicked.connect(self.on_openrightVideo) + + btn_box = QHBoxLayout() + btn_box.addWidget(self._opendataBtn) + btn_box.addWidget(self._openleftBtn) + btn_box.addWidget(self._openrightBtn) + + layout = QVBoxLayout() + layout.addLayout(btn_box) + layout.addWidget(self.merge_preview) + layout.addWidget(self._progress_bar) + + self.setLayout(layout) + + def on_openData(self): + file_dialog = QFileDialog(self, "Select pickled DataFrame", "", "Pandas DataFrame (*.pkl)") + infile = None + + 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 _on_dataOpenend(self, state): + self._progress_bar.setRange(0, 100) + 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._reader = None + + def on_openleftVideo(self): + pass + + def on_openrightVideo(self): + pass + + +def main(): + from PySide6.QtWidgets import QApplication + import sys + app = QApplication(sys.argv) + dialog = PreviewDialog() + dialog.show() + sys.exit(app.exec()) + + +if __name__ == "__main__": + logging.basicConfig(level=logging.INFO, force=True) + main() \ No newline at end of file diff --git a/fixtracks/fixtracks.py b/fixtracks/fixtracks.py index 1f617fb..4e0729e 100644 --- a/fixtracks/fixtracks.py +++ b/fixtracks/fixtracks.py @@ -1,13 +1,12 @@ from PySide6.QtCore import QSize, Qt from PySide6.QtWidgets import QMainWindow, QWidget, QToolBar, QMenu, QMenuBar, QSizePolicy, QFileDialog +from PySide6.QtWidgets import QDialog, QVBoxLayout from PySide6.QtGui import QKeySequence, QAction, QIcon -from fixtracks.widgets.centralwidget import CentralWidget - import fixtracks.resources -# Subclass QMainWindow to customize your application's main window - - +from fixtracks.widgets.centralwidget import CentralWidget +from fixtracks.dialogs.previewdialog import PreviewDialog +from fixtracks.utils.reader import ImageReader, DataFrameReader class MainWindow(QMainWindow): def __init__(self): super().__init__() @@ -54,13 +53,17 @@ class MainWindow(QMainWindow): self._help_action = QAction(QIcon(":help"), "help") self._help_action.setStatusTip("Show help dialog") self._help_action.setShortcut(QKeySequence("F1")) - self._help_action.setEnabled(True) self._help_action.triggered.connect(self.on_help) + self._mergeview_action = QAction("View merge results") + self._mergeview_action.setStatusTip("Show help dialog") + self._mergeview_action.setEnabled(True) + self._mergeview_action.triggered.connect(self.on_mergeview) + self.create_toolbar() self.create_menu() - + def create_menu(self): menu = self.menuBar() file_menu = menu.addMenu("&File") @@ -68,16 +71,16 @@ class MainWindow(QMainWindow): # file_menu.addAction(self._file_close_action) file_menu.addSeparator() file_menu.addAction(self._quit_action) - + plot_menu = menu.addMenu("&Plot") # plot_menu.addAction(self._plot_action) - # plot_menu.addAction(self._table_action) - + plot_menu.addAction(self._mergeview_action) + help_menu = menu.addMenu("&Help") help_menu.addAction(self._about_action) help_menu.addAction(self._help_action) self.setMenuBar(menu) - + def create_toolbar(self): self._toolbar = QToolBar("My main toolbar") #self._toolbar.setStyleSheet("QToolButton:!hover {background-color:none}") @@ -91,7 +94,7 @@ class MainWindow(QMainWindow): # self._toolbar.addAction(self._plot_action) # self._toolbar.addAction(self._table_action) self._toolbar.addAction(self._help_action) - + empty = QWidget() empty.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self._toolbar.addWidget(empty) @@ -104,7 +107,6 @@ class MainWindow(QMainWindow): # self._toolbar.topLevelChanged.connect(self.tb_changed) # del settings - def on_file_open(self, s): QFileDialog.getExistingDirectory() # dlg = QFileDialog(self, 'Open dataset folder data file', '', "NIX files (*.h5 *.nix)") @@ -114,6 +116,12 @@ class MainWindow(QMainWindow): # filenames = dlg.selectedFiles() # self.open_file(filenames[0]) + def on_mergeview(self): + print("Display merging results") + dlg = PreviewDialog(self) + dlg.setModal(True) + dlg.exec() + def on_about(self, s): pass diff --git a/fixtracks/utils/reader.py b/fixtracks/utils/reader.py index 2893dc2..4f3b90d 100644 --- a/fixtracks/utils/reader.py +++ b/fixtracks/utils/reader.py @@ -1,4 +1,5 @@ import logging +import pickle import cv2 as cv import pandas as pd @@ -50,6 +51,32 @@ class ImageReader(QRunnable): def frame(self): return self._frame +class PickleLoader(QRunnable): + finished = Signal(bool) + + def __init__(self, filename) -> None: + super().__init__() + self._filename = filename + self._signals = ProducerSignals() + self._data = None + + @Slot() + def run(self): + ''' + Your code goes in this function + ''' + logging.debug("PickleLoader: trying to open file %s", self._filename) + with open(self._filename, "rb") as f: + self._data = pickle.load(f) + self._signals.finished.emit(True) + + @property + def signals(self): + return self._signals + + @property + def data(self): + return self._data class DataFrameReader(QRunnable): finished = Signal(bool) diff --git a/fixtracks/widgets/detectionmerge.py b/fixtracks/widgets/detectionmerge.py index 444b6c9..587a23c 100644 --- a/fixtracks/widgets/detectionmerge.py +++ b/fixtracks/widgets/detectionmerge.py @@ -189,7 +189,7 @@ class MergeDetections(QWidget): bytesPerLine = 3 * width img = QImage(frame.data, width, height, bytesPerLine, QImage.Format.Format_BGR888).rgbSwapped() return img - + def on_rightvideoSelection(self): logging.debug("Video selection of the %s side", "right") self.right_imagereader = ImageReader(self.right_videocombo.currentText(), self.right_framespinner.value()) diff --git a/fixtracks/widgets/mergepreview.py b/fixtracks/widgets/mergepreview.py new file mode 100644 index 0000000..a1156fb --- /dev/null +++ b/fixtracks/widgets/mergepreview.py @@ -0,0 +1,53 @@ +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.QtCore import Qt + +from fixtracks.utils.reader import ImageReader + + +class MergePreview(QWidget): + + def __init__(self, parent=None): + super().__init__(parent) + self._dataframe = None + self._image = None + + self._startSlider = QSlider(orientation=Qt.Orientation.Horizontal) + self._stopSlider = QSlider(orientation=Qt.Orientation.Horizontal) + self._startSlider.setRange(0, 100) + self._stopSlider.setRange(0, 100) + + self._startSlider.valueChanged.connect(self._on_start_slider_changed) + self._stopSlider.valueChanged.connect(self._on_stop_slider_changed) + + layout = QVBoxLayout() + layout.addWidget(QLabel("Start Slider")) + layout.addWidget(self._startSlider) + layout.addWidget(QLabel("Stop Slider")) + layout.addWidget(self._stopSlider) + self.setLayout(layout) + + def resetSlider(self, framecount=100): + self._startSlider.setRange(0, framecount) + self._stopSlider.setRange(0, framecount) + self._startSlider.setSliderPosition(0) + self._stopSlider.setSliderPosition(framecount) + + def set_dataframe(self, newdf): + self._dataframe = newdf + self.resetSlider(np.max(self._dataframe.frame)) + + def _on_start_slider_changed(self, value): + if value > self._stopSlider.value(): + self._stopSlider.setValue(value) + + def _on_stop_slider_changed(self, value): + if value < self._startSlider.value(): + self._startSlider.setValue(value) + + @staticmethod + def mergeImages(left, right, left_cut, right_cut): + + pass \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..7a581ac --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,16 @@ +[tool.poetry] +name = "fixtracks" +version = "0.1.0" +description = "A project to fix track metadata" +authors = ["Your Name "] +license = "MIT" + +[tool.poetry.dependencies] +python = "^3.8" + +[tool.poetry.dev-dependencies] +pytest = "^6.2.4" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" \ No newline at end of file