[detectionpreview] nice and shiny

This commit is contained in:
2025-01-22 18:20:52 +01:00
parent 3b76969d9b
commit 12287df477
4 changed files with 783 additions and 32 deletions

View File

@@ -1,8 +1,7 @@
import logging
import pickle
import pandas as pd
from PySide6.QtWidgets import QDialog, QVBoxLayout, QHBoxLayout, QPushButton, QFileDialog, QProgressBar
from PySide6.QtCore import QThreadPool
from PySide6.QtGui import QImage
from fixtracks.widgets.mergepreview import MergePreview
from fixtracks.utils.reader import PickleLoader
@@ -24,16 +23,8 @@ class PreviewDialog(QDialog):
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)
@@ -43,9 +34,22 @@ class PreviewDialog(QDialog):
self.setLayout(layout)
def on_openData(self):
file_dialog = QFileDialog(self, "Select pickled DataFrame", "", "Pandas DataFrame (*.pkl)")
infile = None
imgfile = None
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.merge_preview.set_image(img)
file_dialog = QFileDialog(self, "Select pickled DataFrame", "", "Pandas DataFrame (*.pkl)")
if file_dialog.exec():
infile = file_dialog.selectedFiles()[0]
if infile is not None:
@@ -62,11 +66,6 @@ class PreviewDialog(QDialog):
self.merge_preview.set_dataframe(self._df)
self._reader = None
def on_openleftVideo(self):
pass
def on_openrightVideo(self):
pass
def main():

View File

@@ -323,11 +323,11 @@ class MergeDetections(QWidget):
lrect = QRect(0, 0, left_cut, limg.height())
rrect = QRect(right_cut, 0, rimg.width() - right_cut, rimg.height())
imgsize = QSize(lrect.width() + rrect.width(), rrect.height())
lselection = limg.copy(lrect)
rselection = rimg.copy(rrect)\
rselection = rimg.copy(rrect)
imgsize = QSize(lrect.width() + rrect.width(), rrect.height())
img = QImage(imgsize, limg.format())
painter = QPainter(img)
painter.drawImage(QPoint(0,0), lselection)
painter.drawImage(QPoint(lrect.width(), 0), rselection)

View File

@@ -3,6 +3,7 @@ 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 PySide6.QtGui import QPixmap, QBrush, QColor
from fixtracks.utils.reader import ImageReader
@@ -13,20 +14,66 @@ class MergePreview(QWidget):
super().__init__(parent)
self._dataframe = None
self._image = None
self._pixmapitem = None
self._frames = None
self._keypoints = None
self._scene = None
self._view = QGraphicsView()
self._view.setSizePolicy(QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Expanding)
self._brush = QBrush(QColor.fromString("red"))
self._brush2 = QBrush(QColor.fromString("white"))
self._startSlider = QSlider(orientation=Qt.Orientation.Horizontal)
self._stopSlider = QSlider(orientation=Qt.Orientation.Horizontal)
self._startSlider.setTickPosition(QSlider.TickPosition.TicksBelow)
self._startSlider.setRange(0, 100)
self._stopSlider.setRange(0, 100)
self._startSlider.setTickInterval(self._startSlider.maximum() // 10)
self._startSlider.sliderReleased.connect(self._on_startSliderReleased)
self._startSlider.valueChanged.connect(self._on_sliderChanged)
self._startSlider.valueChanged.connect(self._on_start_slider_changed)
self._stopSlider.valueChanged.connect(self._on_stop_slider_changed)
self._stopSlider = QSlider(orientation=Qt.Orientation.Horizontal)
self._stopSlider.setTickPosition(QSlider.TickPosition.TicksBelow)
self._stopSlider.setRange(0, 100)
self._stopSlider.setTickInterval(self._stopSlider.maximum() // 10)
self._stopSlider.sliderReleased.connect(self._on_stopSliderReleased)
self._stopSlider.valueChanged.connect(self._on_sliderChanged)
self._keypointCombo = QComboBox()
self._keypointCombo.currentIndexChanged.connect(self._on_keypointSelection)
self._numpointsSpinner = QSpinBox()
self._numpointsSpinner.setRange(500, 50000)
self._numpointsSpinner.setValue(25000)
self._numpointsSpinner.setSingleStep(500)
self._numpointsSpinner.valueChanged.connect(self.update)
settingsbox = QHBoxLayout()
settingsbox.addWidget(QLabel("Select keypoint"))
settingsbox.addWidget(self._keypointCombo)
settingsbox.addWidget(QLabel("Number of displayed points"))
settingsbox.addWidget(self._numpointsSpinner)
startsliderbox = QHBoxLayout()
startsliderbox.addWidget(QLabel("Start position"))
startsliderbox.addWidget(self._startSlider)
stopsliderbox = QHBoxLayout()
stopsliderbox.addWidget(QLabel("Stop position"))
stopsliderbox.addWidget(self._stopSlider)
self._startLabel = QLabel("0")
self._stopLabel = QLabel("100")
messagebox = QHBoxLayout()
messagebox.addWidget(QLabel("Current segment from frame:"))
messagebox.addWidget(self._startLabel)
messagebox.addWidget(QLabel("to"))
messagebox.addWidget(self._stopLabel)
messagebox.addSpacerItem(QSpacerItem(100, 10, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Fixed))
layout = QVBoxLayout()
layout.addWidget(QLabel("Start Slider"))
layout.addWidget(self._startSlider)
layout.addWidget(QLabel("Stop Slider"))
layout.addWidget(self._stopSlider)
layout.addWidget(self._view)
layout.addLayout(settingsbox)
layout.addLayout(startsliderbox)
layout.addLayout(stopsliderbox)
layout.addLayout(messagebox)
self.setLayout(layout)
def resetSlider(self, framecount=100):
@@ -34,20 +81,78 @@ class MergePreview(QWidget):
self._stopSlider.setRange(0, framecount)
self._startSlider.setSliderPosition(0)
self._stopSlider.setSliderPosition(framecount)
self._startSlider.setTickInterval(self._startSlider.maximum() // 10)
self._stopSlider.setTickInterval(self._stopSlider.maximum() // 10)
def resetKeypointcombo(self, numkeypoints):
self._keypointCombo.clear()
self._keypointCombo.addItems([f"keypoint {i}" for i in range(numkeypoints)])
def set_dataframe(self, newdf):
self._dataframe = newdf
self._frames = self._dataframe.frame.values
self._keypoints = self._dataframe.keypoints.values
self.resetSlider(np.max(self._dataframe.frame))
self.resetKeypointcombo(len(self._keypoints[0]))
self.update()
def _on_start_slider_changed(self, value):
def _on_keypointSelection(self):
self.update()
def _on_startSliderReleased(self):
value = self._startSlider.value()
if value > self._stopSlider.value():
self._stopSlider.setValue(value)
self.update()
def _on_stop_slider_changed(self, value):
def _on_stopSliderReleased(self):
value = self._stopSlider.value()
if value < self._startSlider.value():
self._startSlider.setValue(value)
self.update()
@staticmethod
def mergeImages(left, right, left_cut, right_cut):
def _on_sliderChanged(self, value):
self._startLabel.setText(str(self._startSlider.value()))
self._stopLabel.setText(str(self._stopSlider.value()))
pass
def set_image(self, img):
self._image = img
self.update()
def _draw_detections(self):
start_frame = self._startSlider.value()
stop_frame = self._stopSlider.value()
selection = self._keypoints[self._frames[(self._frames >= start_frame) & (self._frames < stop_frame)]]
image_rect = self._pixmapitem.boundingRect()
keypoint = self._keypointCombo.currentIndex()
num_points = self._numpointsSpinner.value()
step = 1 if len(selection) < num_points else int(len(selection) // num_points)
for coords in selection[::step]:
x = coords[keypoint, 0]
y = coords[keypoint, 1]
self._scene.addEllipse(image_rect.left() + x, image_rect.top() + y, 10, 10, brush=self._brush)
def update(self):
if self._image is not None:
self._scene = QGraphicsScene()
self._pixmapitem = self._scene.addPixmap(QPixmap.fromImage(self._image))
self._view.setScene(self._scene)
self._view.fitInView(self._scene.sceneRect(), aspectRadioMode=Qt.AspectRatioMode.KeepAspectRatio)
self._view.show()
if self._dataframe is not None:
self._scene = QGraphicsScene()
self._pixmapitem = self._scene.addPixmap(QPixmap.fromImage(self._image))
self._view.setScene(self._scene)
self._view.fitInView(self._scene.sceneRect(), aspectRadioMode=Qt.AspectRatioMode.KeepAspectRatio)
self._view.show()
self._draw_detections()
def fit_image_to_view(self):
"""Scale the image to fit the QGraphicsView."""
if self._pixmapitem is not None:
self._view.fitInView(self._pixmapitem, Qt.KeepAspectRatio)
def resizeEvent(self, event):
"""Handle window resizing to fit the image."""
super().resizeEvent(event)
self.fit_image_to_view()