From 9449ad45adfd1054b8b4c1f1a6970bbf96ebdb9e Mon Sep 17 00:00:00 2001 From: Jan Grewe Date: Sun, 22 Dec 2024 00:06:14 +0100 Subject: [PATCH 1/3] working left preview --- fixtracks/detectionmerge.py | 46 +++++++++++++++++++++++++------------ 1 file changed, 31 insertions(+), 15 deletions(-) diff --git a/fixtracks/detectionmerge.py b/fixtracks/detectionmerge.py index 4cfd1a2..b0adad6 100644 --- a/fixtracks/detectionmerge.py +++ b/fixtracks/detectionmerge.py @@ -1,7 +1,7 @@ import logging -from PyQt6.QtWidgets import QWidget, QGridLayout, QVBoxLayout, QLabel, QPushButton, QComboBox, QSizePolicy, QSpinBox, QGraphicsView, QGraphicsScene -from PyQt6.QtCore import QThreadPool, QLineF, QPointF +from PyQt6.QtWidgets import QWidget, QGridLayout, QVBoxLayout, QLabel, QPushButton, QComboBox, QSizePolicy, QSpinBox, QGraphicsView, QGraphicsScene, QGraphicsLineItem +from PyQt6.QtCore import QThreadPool, QLineF, QPointF, QRectF, Qt from PyQt6.QtGui import QImage, QPixmap, QColor, QPen from fixtracks.util import ImageReader @@ -18,6 +18,8 @@ class MergeDetections(QWidget): layout = QVBoxLayout() layout.addWidget(QLabel("Merge Detections!")) + self.line_pen = QPen(QColor.fromString("red"), 4) + self.left_datacombo = QComboBox() self.left_videocombo = QComboBox() self.left_datacombo.addItems(self._files) @@ -27,6 +29,7 @@ class MergeDetections(QWidget): self.left_preview = QGraphicsView() self.left_preview.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self.left_line = None + self.scene = None self.right_datacombo = QComboBox() self.right_videocombo = QComboBox() @@ -45,7 +48,9 @@ class MergeDetections(QWidget): splitter.setColumnStretch(0, 1) splitter.setColumnStretch(1, 1) layout.addLayout(splitter) + self.setLayout(layout) + def layout_controls(self): grd = QGridLayout() @@ -134,22 +139,33 @@ class MergeDetections(QWidget): height, width, _ = frame.shape bytesPerLine = 3 * width img = QImage(frame.data, width, height, bytesPerLine, QImage.Format.Format_BGR888).rgbSwapped() - scene = QGraphicsScene() - scene.addPixmap(QPixmap.fromImage(img).scaledToHeight(self.left_preview.height())) - self.left_preview.setScene(scene) + self.scene = QGraphicsScene() + self._left_pixmap = self.scene.addPixmap(QPixmap.fromImage(img)) + self.left_preview.setScene(self.scene) + self.left_preview.fitInView(self.scene.sceneRect(), mode=Qt.AspectRatioMode.KeepAspectRatio) + # self.left_preview.setPixmap(QPixmap.fromImage(img).scaledToHeight(self.left_preview.height())) self.left_posspinner.setMaximum(width-1) self.left_posspinner.setValue(width-1) - origin = self.left_preview.mapToScene(int(width//2), 0) - destination = self.left_preview.mapToScene(width//2, height) - line = QLineF(origin, destination) - p = QPen(5) - c = QColor.fromString("red") - p.setColor(c) - self.left_line = scene.addLine(line, p) + image_rect = self._left_pixmap.boundingRect() + + x = self.left_posspinner.value() + start_x = image_rect.left() + x + start_y = image_rect.top() + end_y = image_rect.bottom() + + self.left_line = self.scene.addLine(start_x, start_y, start_x, end_y, self.line_pen) self.left_preview.show() def on_leftmergelinemove(self): - print(self.left_posspinner.value()) - if self.left_line is not None: - self.left_line.setX(self.left_posspinner.value()) \ No newline at end of file + image_rect = self._left_pixmap.boundingRect() + for i in self.scene.items(): + if isinstance(i, QGraphicsLineItem): + self.scene.removeItem(i) + + x = self.left_posspinner.value() + start_x = image_rect.left() + x + start_y = image_rect.top() + end_y = image_rect.bottom() + + self.scene.addLine(start_x, start_y, start_x, end_y, self.line_pen) From 37f505a7255990f67ea564d062e74ffc97b63595 Mon Sep 17 00:00:00 2001 From: Jan Grewe Date: Sun, 22 Dec 2024 00:15:12 +0100 Subject: [PATCH 2/3] working left preview extract VideoPreview class and refactoring --- fixtracks/detectionmerge.py | 111 ++++++++++++++++++++---------------- 1 file changed, 61 insertions(+), 50 deletions(-) diff --git a/fixtracks/detectionmerge.py b/fixtracks/detectionmerge.py index b0adad6..38204a2 100644 --- a/fixtracks/detectionmerge.py +++ b/fixtracks/detectionmerge.py @@ -7,6 +7,44 @@ from PyQt6.QtGui import QImage, QPixmap, QColor, QPen from fixtracks.util import ImageReader +class VideoPreview(QWidget): + def __init__(self, parent=None): + super().__init__(parent) + self._image = None + self._line_pen = QPen(QColor.fromString("red"), 4) + self._view = QGraphicsView() + self._view.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + self._scene = None + self._pixmap = None + layout = QVBoxLayout() + layout.addWidget(self._view) + self.setLayout(layout) + + def set_image(self, img): + self._scene = QGraphicsScene() + self._pixmap = self._scene.addPixmap(QPixmap.fromImage(img)) + self._view.setScene(self._scene) + self._view.fitInView(self._scene.sceneRect(), mode=Qt.AspectRatioMode.KeepAspectRatio) + image_rect = self._pixmap.boundingRect() + start_x = image_rect.right() + start_y = image_rect.top() + end_y = image_rect.bottom() + + self._scene.addLine(start_x, start_y, start_x, end_y, self._line_pen) + self._view.show() + + def set_lineposition(self, position): + image_rect = self._pixmap.boundingRect() + for i in self._scene.items(): + if isinstance(i, QGraphicsLineItem): + self._scene.removeItem(i) + + start_x = image_rect.left() + position + start_y = image_rect.top() + end_y = image_rect.bottom() + self._scene.addLine(start_x, start_y, start_x, end_y, self._line_pen) + + class MergeDetections(QWidget): def __init__(self, parent=None): super().__init__(parent) @@ -18,39 +56,31 @@ class MergeDetections(QWidget): layout = QVBoxLayout() layout.addWidget(QLabel("Merge Detections!")) - self.line_pen = QPen(QColor.fromString("red"), 4) - 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_posspinner.valueChanged.connect(self.on_leftmergelinemove) - self.left_preview = QGraphicsView() - self.left_preview.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) - self.left_line = None - self.scene = None - + self.left_preview = VideoPreview(self) + 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) - self.right_line = None + self.right_posspinner.valueChanged.connect(self.on_rightmergelinemove) + self.right_preview = VideoPreview(self) layout.addLayout(self.layout_controls()) splitter = QGridLayout() - # splitter.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) splitter.addWidget(self.left_preview, 0, 0) splitter.addWidget(self.right_preview, 0, 1) splitter.setColumnStretch(0, 1) splitter.setColumnStretch(1, 1) layout.addLayout(splitter) - + self.setLayout(layout) - def layout_controls(self): grd = QGridLayout() @@ -110,6 +140,13 @@ class MergeDetections(QWidget): self.left_videocombo.currentIndexChanged.connect(self.on_leftvideoSelection) # self._files = file_list + def _toImage(self, frame): + height, width, _ = frame.shape + bytesPerLine = 3 * width + img = QImage(frame.data, width, height, bytesPerLine, QImage.Format.Format_BGR888).rgbSwapped() + # pm = QPixmap.fromImage(img) + return img + def on_rightvideoSelection(self): logging.debug("Video selection of the %s side", "right") self.right_imagereader = ImageReader(self.right_videocombo.currentText(), 100) @@ -119,13 +156,10 @@ class MergeDetections(QWidget): 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())) - self.right_posspinner.setMaximum(width) - self.left_posspinner.setValue(width-1) - + img = self._toImage(frame) + self.right_preview.set_image(img) + self.right_posspinner.setMaximum(img.width() - 1) + self.right_posspinner.setValue(img.width() - 1) def on_leftvideoSelection(self): logging.debug("Video selection of the %s side", "left") @@ -136,36 +170,13 @@ class MergeDetections(QWidget): 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.scene = QGraphicsScene() - self._left_pixmap = self.scene.addPixmap(QPixmap.fromImage(img)) - self.left_preview.setScene(self.scene) - self.left_preview.fitInView(self.scene.sceneRect(), mode=Qt.AspectRatioMode.KeepAspectRatio) - - # self.left_preview.setPixmap(QPixmap.fromImage(img).scaledToHeight(self.left_preview.height())) - self.left_posspinner.setMaximum(width-1) - self.left_posspinner.setValue(width-1) - image_rect = self._left_pixmap.boundingRect() - - x = self.left_posspinner.value() - start_x = image_rect.left() + x - start_y = image_rect.top() - end_y = image_rect.bottom() - - self.left_line = self.scene.addLine(start_x, start_y, start_x, end_y, self.line_pen) - self.left_preview.show() + img = self._toImage(frame) + self.left_preview.set_image(img) + self.left_posspinner.setMaximum(img.width() - 1) + self.left_posspinner.setValue(img.width() - 1) def on_leftmergelinemove(self): - image_rect = self._left_pixmap.boundingRect() - for i in self.scene.items(): - if isinstance(i, QGraphicsLineItem): - self.scene.removeItem(i) + self.left_preview.set_lineposition(self.left_posspinner.value()) - x = self.left_posspinner.value() - start_x = image_rect.left() + x - start_y = image_rect.top() - end_y = image_rect.bottom() - - self.scene.addLine(start_x, start_y, start_x, end_y, self.line_pen) + def on_leftmergelinemove(self): + self.right_preview.set_lineposition(self.right_posspinner.value()) From 1a2236287202d27f0074fdf6f5dd512edf3e80f6 Mon Sep 17 00:00:00 2001 From: Jan Grewe Date: Sun, 22 Dec 2024 01:00:17 +0100 Subject: [PATCH 3/3] make preview left-right aware --- fixtracks/centralwidget.py | 3 +++ fixtracks/detectionmerge.py | 18 ++++++++---------- fixtracks/taskwidget.py | 20 ++++++++++++++------ 3 files changed, 25 insertions(+), 16 deletions(-) diff --git a/fixtracks/centralwidget.py b/fixtracks/centralwidget.py index 2858499..8b9a5e6 100644 --- a/fixtracks/centralwidget.py +++ b/fixtracks/centralwidget.py @@ -1,5 +1,6 @@ import logging from PyQt6.QtWidgets import QWidget, QStackedLayout +from PyQt6.QtCore import Qt from fixtracks.taskwidgets import FixTracks from fixtracks.detectionmerge import MergeDetections @@ -10,7 +11,9 @@ class CentralWidget(QWidget): def __init__(self, parent=None): super().__init__(parent) layout = QStackedLayout() + layout.setAlignment(Qt.AlignmentFlag.AlignVCenter) self._tw = TasksWidget() + self._tw.setMaximumHeight(200) self._tw.clicked.connect(self._select_task) self._tasksindex = layout.addWidget(self._tw) self._mergewidget = MergeDetections(self) diff --git a/fixtracks/detectionmerge.py b/fixtracks/detectionmerge.py index 38204a2..697f5c3 100644 --- a/fixtracks/detectionmerge.py +++ b/fixtracks/detectionmerge.py @@ -8,14 +8,15 @@ from fixtracks.util import ImageReader class VideoPreview(QWidget): - def __init__(self, parent=None): - super().__init__(parent) + def __init__(self, left=True, parent=None): + super().__init__(None) self._image = None self._line_pen = QPen(QColor.fromString("red"), 4) self._view = QGraphicsView() self._view.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) self._scene = None self._pixmap = None + self._left = left layout = QVBoxLayout() layout.addWidget(self._view) self.setLayout(layout) @@ -26,7 +27,7 @@ class VideoPreview(QWidget): self._view.setScene(self._scene) self._view.fitInView(self._scene.sceneRect(), mode=Qt.AspectRatioMode.KeepAspectRatio) image_rect = self._pixmap.boundingRect() - start_x = image_rect.right() + start_x = image_rect.right() if self._left else image_rect.left() start_y = image_rect.top() end_y = image_rect.bottom() @@ -62,7 +63,7 @@ class MergeDetections(QWidget): self.left_videocombo.addItems(self._files) self.left_posspinner = QSpinBox() self.left_posspinner.valueChanged.connect(self.on_leftmergelinemove) - self.left_preview = VideoPreview(self) + self.left_preview = VideoPreview() self.right_datacombo = QComboBox() self.right_videocombo = QComboBox() @@ -70,7 +71,7 @@ class MergeDetections(QWidget): self.right_videocombo.addItems(self._files) self.right_posspinner = QSpinBox() self.right_posspinner.valueChanged.connect(self.on_rightmergelinemove) - self.right_preview = VideoPreview(self) + self.right_preview = VideoPreview(left=False) layout.addLayout(self.layout_controls()) splitter = QGridLayout() @@ -106,7 +107,6 @@ class MergeDetections(QWidget): grd.setColumnStretch(3, 50) grd.setColumnMinimumWidth(0, 50) grd.setColumnMinimumWidth(2, 50) - # grd.setRowStretch(4, 100) return grd @property @@ -138,13 +138,11 @@ class MergeDetections(QWidget): 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 _toImage(self, frame): height, width, _ = frame.shape bytesPerLine = 3 * width img = QImage(frame.data, width, height, bytesPerLine, QImage.Format.Format_BGR888).rgbSwapped() - # pm = QPixmap.fromImage(img) return img def on_rightvideoSelection(self): @@ -159,7 +157,7 @@ class MergeDetections(QWidget): img = self._toImage(frame) self.right_preview.set_image(img) self.right_posspinner.setMaximum(img.width() - 1) - self.right_posspinner.setValue(img.width() - 1) + self.right_posspinner.setValue(0) def on_leftvideoSelection(self): logging.debug("Video selection of the %s side", "left") @@ -178,5 +176,5 @@ class MergeDetections(QWidget): def on_leftmergelinemove(self): self.left_preview.set_lineposition(self.left_posspinner.value()) - def on_leftmergelinemove(self): + def on_rightmergelinemove(self): self.right_preview.set_lineposition(self.right_posspinner.value()) diff --git a/fixtracks/taskwidget.py b/fixtracks/taskwidget.py index 167cb70..a967355 100644 --- a/fixtracks/taskwidget.py +++ b/fixtracks/taskwidget.py @@ -1,8 +1,8 @@ import logging import pathlib -from PyQt6.QtWidgets import QWidget, QVBoxLayout, QLabel, QPushButton, QFileDialog -from PyQt6.QtCore import pyqtSignal +from PyQt6.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QLabel, QPushButton, QFileDialog, QSizePolicy +from PyQt6.QtCore import pyqtSignal, Qt class TasksWidget(QWidget): @@ -10,20 +10,28 @@ class TasksWidget(QWidget): def __init__(self, parent = None): super().__init__(parent) - l = QVBoxLayout() - l.addWidget(QLabel("Tasks:")) + l = QHBoxLayout() + l.setAlignment(Qt.AlignmentFlag.AlignVCenter) folderBtn = QPushButton("Select data folder") folderBtn.setEnabled(True) + folderBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) folderBtn.clicked.connect(self._open_folder) l.addWidget(folderBtn) + + sublayout = QVBoxLayout() self.mergeBtn = QPushButton("Merge detections") self.mergeBtn.setEnabled(False) self.mergeBtn.clicked.connect(self._merge_clicked) + self.mergeBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + 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.tracksBtn.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding) + + sublayout.addWidget(self.mergeBtn) + sublayout.addWidget(self.tracksBtn) + l.addLayout(sublayout) self.setLayout(l) self._file_list = []