diff --git a/fixtracks/centralwidget.py b/fixtracks/centralwidget.py index 8566b6f..2858499 100644 --- a/fixtracks/centralwidget.py +++ b/fixtracks/centralwidget.py @@ -1,12 +1,9 @@ import logging -from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel, QStackedLayout, QPushButton -from PyQt6.QtWidgets import QFileDialog -from PyQt6.QtCore import Qt, pyqtSignal - -from fixtracks.taskwidgets import MergeDetections, FixTracks, TasksWidget - - +from PyQt6.QtWidgets import QWidget, QStackedLayout +from fixtracks.taskwidgets import FixTracks +from fixtracks.detectionmerge import MergeDetections +from fixtracks.taskwidget import TasksWidget class CentralWidget(QWidget): diff --git a/fixtracks/detectionmerge.py b/fixtracks/detectionmerge.py new file mode 100644 index 0000000..40f0962 --- /dev/null +++ b/fixtracks/detectionmerge.py @@ -0,0 +1,127 @@ +import logging + +from PyQt6.QtWidgets import QWidget, QGridLayout, QVBoxLayout, QLabel, QPushButton, QFileDialog, QHBoxLayout, QComboBox, QSizePolicy, QSpinBox +from PyQt6.QtCore import QThreadPool +from PyQt6.QtGui import QImage, QPixmap + +from fixtracks.util import ImageReader + + +class MergeDetections(QWidget): + def __init__(self, parent=None): + super().__init__(parent) + self._files = [] + self.threadpool = QThreadPool() + self.right_imagereader = None + self.left_imagereader = None + + layout = QVBoxLayout() + layout.addWidget(QLabel("Merge Detections!")) + + self.left_datacombo = QComboBox() + self.left_videocombo = QComboBox() + self.left_datacombo.addItems(self._files) + self.left_videocombo.addItems(self._files) + self.left_posspinner = QSpinBox() + self.left_preview = QLabel() + self.left_preview.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + + self.right_datacombo = QComboBox() + self.right_videocombo = QComboBox() + self.right_datacombo.addItems(self._files) + self.right_videocombo.addItems(self._files) + self.right_posspinner = QSpinBox() + self.right_preview = QLabel() + self.right_preview.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + + layout.addLayout(self.layout_controls()) + self.setLayout(layout) + + def layout_controls(self): + grd = QGridLayout() + grd.addWidget(QLabel("Left:"), 0, 0) + grd.addWidget(QLabel("Data"), 1, 0) + grd.addWidget(QLabel("Video"), 2, 0) + grd.addWidget(QLabel("Mergeline"), 3, 0) + grd.addWidget(self.left_preview, 4, 0, 1, 2) + grd.addWidget(self.left_datacombo, 1, 1) + grd.addWidget(self.left_videocombo, 2, 1) + grd.addWidget(self.left_posspinner, 3, 1) + + grd.addWidget(QLabel("Right"), 0, 2) + grd.addWidget(QLabel("Data"), 1, 2) + grd.addWidget(QLabel("Video"), 2, 2) + grd.addWidget(QLabel("Mergeline"), 3, 2) + grd.addWidget(self.right_preview, 4, 2, 1, 2) + grd.addWidget(self.right_datacombo, 1, 3) + grd.addWidget(self.right_videocombo, 2, 3) + grd.addWidget(self.right_posspinner, 3, 3) + + grd.setColumnStretch(0, 0) + grd.setColumnStretch(2, 0) + grd.setColumnStretch(1, 50) + grd.setColumnStretch(3, 50) + grd.setColumnMinimumWidth(0, 50) + grd.setColumnMinimumWidth(2, 50) + grd.setColumnStretch(1, 1) + grd.setRowStretch(4, 100) + return grd + + @property + def fileList(self): + return self._files + + @fileList.setter + def fileList(self, file_list): + logging.debug("MergeDetections.fileList: set new file list") + + logging.debug("MergeDetections.fileList: setting video combo boxes") + videoformats = [".mp4", ".avi"] + self._files = [str(f) for f in file_list if f.suffix in videoformats] + self.right_videocombo.addItem("Please select") + self.left_videocombo.addItem("Please select") + self.right_videocombo.addItems(self.fileList) + self.left_videocombo.addItems(self.fileList) + self.left_videocombo.setCurrentIndex(0) + self.right_videocombo.setCurrentIndex(0) + + logging.debug("MergeDetections.fileList: setting data combo boxes") + dataformats = [".csv"] + self._files = [str(f) for f in file_list if f.suffix in dataformats] + self.right_datacombo.addItem("Please select") + self.left_datacombo.addItem("Please select") + self.right_datacombo.addItems(self.fileList) + self.left_datacombo.addItems(self.fileList) + self.left_datacombo.setCurrentIndex(0) + self.right_datacombo.setCurrentIndex(0) + self.right_videocombo.currentIndexChanged.connect(self.on_rightvideoSelection) + self.left_videocombo.currentIndexChanged.connect(self.on_leftvideoSelection) + # self._files = file_list + + def on_rightvideoSelection(self): + logging.debug("Video selection of the %s side", "right") + self.right_imagereader = ImageReader(self.right_videocombo.currentText(), 100) + self.right_imagereader.signals.finished.connect(self.right_imgreaderDone) + self.threadpool.start(self.right_imagereader) + + def right_imgreaderDone(self, state): + logging.debug("Right image reader done with state %s", str(state)) + frame = self.right_imagereader.frame + height, width, _ = frame.shape + bytesPerLine = 3 * width + img = QImage(frame.data, width, height, bytesPerLine, QImage.Format.Format_BGR888).rgbSwapped() + self.right_preview.setPixmap(QPixmap.fromImage(img).scaledToHeight(self.right_preview.height())) + + def on_leftvideoSelection(self): + logging.debug("Video selection of the %s side", "left") + self.left_imagereader = ImageReader(self.left_videocombo.currentText(), 100) + self.left_imagereader.signals.finished.connect(self.left_imgreaderDone) + self.threadpool.start(self.left_imagereader) + + def left_imgreaderDone(self, state): + logging.debug("Left image reader done with state %s", str(state)) + frame = self.left_imagereader.frame + height, width, _ = frame.shape + bytesPerLine = 3 * width + img = QImage(frame.data, width, height, bytesPerLine, QImage.Format.Format_BGR888).rgbSwapped() + self.left_preview.setPixmap(QPixmap.fromImage(img).scaledToHeight(self.left_preview.height())) diff --git a/fixtracks/taskwidget.py b/fixtracks/taskwidget.py new file mode 100644 index 0000000..167cb70 --- /dev/null +++ b/fixtracks/taskwidget.py @@ -0,0 +1,53 @@ +import logging +import pathlib + +from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton, QFileDialog +from PyQt6.QtCore import pyqtSignal + + +class TasksWidget(QWidget): + clicked = pyqtSignal((str,)) + + def __init__(self, parent = None): + super().__init__(parent) + l = QVBoxLayout() + l.addWidget(QLabel("Tasks:")) + folderBtn = QPushButton("Select data folder") + folderBtn.setEnabled(True) + folderBtn.clicked.connect(self._open_folder) + l.addWidget(folderBtn) + self.mergeBtn = QPushButton("Merge detections") + self.mergeBtn.setEnabled(False) + self.mergeBtn.clicked.connect(self._merge_clicked) + self.tracksBtn = QPushButton("Join tracks") + self.tracksBtn.setEnabled(False) + self.tracksBtn.clicked.connect(self._tracks_clicked) + l.addWidget(self.mergeBtn) + l.addWidget(self.tracksBtn) + self.setLayout(l) + self._file_list = [] + + def _merge_clicked(self): + self.clicked.emit("Merge") + + def _tracks_clicked(self): + self.clicked.emit("Tracks") + + def _open_folder(self): + logging.debug("TasksWidget:select data folder") + folder = QFileDialog.getExistingDirectory() + if len(folder.strip()) == 0: + logging.debug("TasksWidget: is EMPTY") + return + p = pathlib.Path(folder) + logging.debug("TasksWidget: selected path is %s", p) + for d in p.iterdir(): + if d.is_file(): + self._file_list.append(d) + if len(self._file_list) > 0: + self.mergeBtn.setEnabled(True) + self.tracksBtn.setEnabled(True) + + @property + def fileList(self): + return self._file_list diff --git a/fixtracks/taskwidgets.py b/fixtracks/taskwidgets.py index eea9f71..2648f55 100644 --- a/fixtracks/taskwidgets.py +++ b/fixtracks/taskwidgets.py @@ -1,163 +1,11 @@ import logging -import pathlib -import cv2 as cv from PyQt6.QtWidgets import QWidget, QGridLayout, QVBoxLayout, QLabel, QPushButton, QFileDialog, QHBoxLayout, QComboBox, QSizePolicy -from PyQt6.QtCore import pyqtSignal, pyqtSlot, QThreadPool +from PyQt6.QtCore import QThreadPool from PyQt6.QtGui import QImage, QPixmap from fixtracks.util import ImageReader -class TasksWidget(QWidget): - clicked = pyqtSignal((str,)) - - def __init__(self, parent = None): - super().__init__(parent) - l = QVBoxLayout() - l.addWidget(QLabel("Tasks:")) - folderBtn = QPushButton("Select data folder") - folderBtn.setEnabled(True) - folderBtn.clicked.connect(self._open_folder) - l.addWidget(folderBtn) - self.mergeBtn = QPushButton("Merge detections") - self.mergeBtn.setEnabled(False) - self.mergeBtn.clicked.connect(self._merge_clicked) - self.tracksBtn = QPushButton("Join tracks") - self.tracksBtn.setEnabled(False) - self.tracksBtn.clicked.connect(self._tracks_clicked) - l.addWidget(self.mergeBtn) - l.addWidget(self.tracksBtn) - self.setLayout(l) - self._file_list = [] - - def _merge_clicked(self): - self.clicked.emit("Merge") - - def _tracks_clicked(self): - self.clicked.emit("Tracks") - - def _open_folder(self): - logging.debug("TasksWidget:select data folder") - folder = QFileDialog.getExistingDirectory() - if len(folder.strip()) == 0: - logging.debug("TasksWidget: is EMPTY") - return - p = pathlib.Path(folder) - logging.debug("TasksWidget: selected path is %s", p) - for d in p.iterdir(): - if d.is_file(): - self._file_list.append(d) - if len(self._file_list) > 0: - self.mergeBtn.setEnabled(True) - self.tracksBtn.setEnabled(True) - - @property - def fileList(self): - return self._file_list - - -class MergeDetections(QWidget): - def __init__(self, parent=None): - super().__init__(parent) - self._files = [] - self.threadpool = QThreadPool() - self.right_imagereader = None - self.left_imagereader = None - - layout = QVBoxLayout() - layout.addWidget(QLabel("Merge Detections!")) - hbox = QHBoxLayout() - - leftvbox = QVBoxLayout() - self.leftdatacombo = QComboBox() - self.leftvideocombo = QComboBox() - self.leftvideocombo.addItems(self._files) - self.left_preview = QLabel() - self.left_preview.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) - - leftvbox.addWidget(self.left_preview) - leftvbox.addWidget(QLabel("Left data file:")) - leftvbox.addWidget(self.leftdatacombo) - leftvbox.addWidget(QLabel("Left video:")) - leftvbox.addWidget(self.leftvideocombo) - - rightvbox = QVBoxLayout() - self.rightdatacombo = QComboBox() - self.rightvideocombo = QComboBox() - self.rightvideocombo.addItems(self._files) - self.right_preview = QLabel() - self.right_preview.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) - rightvbox.addWidget(QLabel("Right data file:")) - rightvbox.addWidget(self.rightdatacombo) - rightvbox.addWidget(QLabel("Right video:")) - rightvbox.addWidget(self.rightvideocombo) - rightvbox.addWidget(self.right_preview) - - hbox.addLayout(leftvbox) - hbox.addLayout(rightvbox) - layout.addLayout(hbox) - self.setLayout(layout) - - @property - def fileList(self): - return self._files - - @fileList.setter - def fileList(self, file_list): - logging.debug("MergeDetections.fileList: set new file list") - - logging.debug("MergeDetections.fileList: setting video combo boxes") - videoformats = [".mp4", ".avi"] - self._files = [str(f) for f in file_list if f.suffix in videoformats] - self.rightvideocombo.addItem("Please select") - self.leftvideocombo.addItem("Please select") - self.rightvideocombo.addItems(self.fileList) - self.leftvideocombo.addItems(self.fileList) - self.leftvideocombo.setCurrentIndex(0) - self.rightvideocombo.setCurrentIndex(0) - - logging.debug("MergeDetections.fileList: setting data combo boxes") - dataformats = [".csv"] - self._files = [str(f) for f in file_list if f.suffix in dataformats] - self.rightdatacombo.addItem("Please select") - self.leftdatacombo.addItem("Please select") - self.rightdatacombo.addItems(self.fileList) - self.leftdatacombo.addItems(self.fileList) - self.leftdatacombo.setCurrentIndex(0) - self.rightdatacombo.setCurrentIndex(0) - self.rightvideocombo.currentIndexChanged.connect(self.on_rightvideoSelection) - self.leftvideocombo.currentIndexChanged.connect(self.on_leftvideoSelection) - # self._files = file_list - - def on_rightvideoSelection(self): - logging.debug("Video selection of the %s side", "right") - self.right_imagereader = ImageReader(self.rightvideocombo.currentText(), 100) - self.right_imagereader.signals.finished.connect(self.right_imgreaderDone) - self.threadpool.start(self.right_imagereader) - - def right_imgreaderDone(self, state): - logging.debug("Right image reader done with state %s", str(state)) - frame = self.right_imagereader.frame - height, width, _ = frame.shape - bytesPerLine = 3 * width - img = QImage(frame.data, width, height, bytesPerLine, QImage.Format.Format_BGR888).rgbSwapped() - self.right_preview.setPixmap(QPixmap.fromImage(img).scaledToHeight(self.right_preview.height())) - - def on_leftvideoSelection(self): - logging.debug("Video selection of the %s side", "left") - self.left_imagereader = ImageReader(self.leftvideocombo.currentText(), 100) - self.left_imagereader.signals.finished.connect(self.left_imgreaderDone) - self.threadpool.start(self.left_imagereader) - - def left_imgreaderDone(self, state): - logging.debug("Left image reader done with state %s", str(state)) - frame = self.left_imagereader.frame - height, width, _ = frame.shape - bytesPerLine = 3 * width - img = QImage(frame.data, width, height, bytesPerLine, QImage.Format.Format_BGR888).rgbSwapped() - self.left_preview.setPixmap(QPixmap.fromImage(img).scaledToHeight(self.left_preview.height())) - - class FixTracks(QWidget): def __init__(self, parent=None): super().__init__(parent)