add more py files

This commit is contained in:
Jan Grewe 2024-12-20 11:53:19 +01:00
parent 1383d84b89
commit e4959b5bb1
6 changed files with 394 additions and 0 deletions

0
fixtracks/__init__.py Normal file
View File

View File

@ -0,0 +1,43 @@
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
class CentralWidget(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
layout = QStackedLayout()
self._tw = TasksWidget()
self._tw.clicked.connect(self._select_task)
self._tasksindex = layout.addWidget(self._tw)
self._mergewidget = MergeDetections(self)
self._trackwidget = FixTracks(self)
self._mergeindex = layout.addWidget(self._mergewidget)
self._trackindex = layout.addWidget(self._trackwidget)
self.setLayout(layout)
def _select_task(self, s):
logging.debug("Centralwidget: Selected task: %s", s)
if "merge" in s.lower():
self.layout().setCurrentIndex(self._mergeindex)
self._mergewidget.fileList = self._tw.fileList
elif "tracks" in s.lower():
self.layout().setCurrentIndex(self._trackindex)
self._trackwidget.fileList = self._tw.fileList
else:
logging.warning("Centralwidget: got invalid task request: %s", s)
# # @Slot(None)
# def on_exit(self):
# self.exit_signal.emit()
# # @Slot(None)
# def on_new(self):
# self._view.setScene(self._gamescene)

124
fixtracks/fixtracks.py Normal file
View File

@ -0,0 +1,124 @@
from PyQt6.QtCore import QSize, Qt
from PyQt6.QtWidgets import QMainWindow, QWidget, QToolBar, QMenu, QMenuBar, QSizePolicy, QFileDialog
from PyQt6.QtGui import QKeySequence, QAction, QIcon
from fixtracks.centralwidget import CentralWidget
# Subclass QMainWindow to customize your application's main window
class MainWindow(QMainWindow):
def __init__(self):
super().__init__()
self.create_actions()
self._toolbar = None
cw = CentralWidget()
self.setCentralWidget(cw)
# cw.exit_signal.connect(self.exit_request)
def create_actions(self):
self._file_open_action = QAction(QIcon(":/icons/file_open"), "Open", self)
self._file_open_action.setStatusTip("Open nix file")
self._file_open_action.setShortcut(QKeySequence("Ctrl+o"))
self._file_open_action.triggered.connect(self.on_file_open)
# self._file_close_action = QAction(QIcon(":/icons/file_close"), "Close", self)
# self._file_close_action.setStatusTip("Close current nix file")
# self._file_close_action.setShortcut(QKeySequence("Ctrl+w"))
# self._file_close_action.setEnabled(False)
# self._file_close_action.triggered.connect(self.on_file_close)
self._quit_action = QAction(QIcon(":quit"), "Quit", self)
self._quit_action.setStatusTip("Close current file and quit")
self._quit_action.setShortcut(QKeySequence("Ctrl+q"))
self._quit_action.triggered.connect(self.exit_request)
# self._plot_action = QAction(QIcon(":/icons/show_plot"), "Plot", self)
# self._plot_action.setStatusTip("Plot currently selected entity")
# self._plot_action.setShortcut(QKeySequence("Ctrl+p"))
# self._plot_action.setEnabled(False)
# self._plot_action.triggered.connect(self.on_item_plot)
# self._table_action = QAction(QIcon(":/icons/show_table"), "Show table", self)
# self._table_action.setStatusTip("Show data as table")
# self._table_action.setShortcut(QKeySequence("Ctrl+t"))
# self._table_action.setEnabled(False)
# self._table_action.triggered.connect(self.on_item_show_table)
self._about_action = QAction("about")
self._about_action.setStatusTip("Show about dialog")
self._about_action.setEnabled(True)
self._about_action.triggered.connect(self.on_about)
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.create_toolbar()
self.create_menu()
def create_menu(self):
menu = self.menuBar()
file_menu = menu.addMenu("&File")
file_menu.addAction(self._file_open_action)
# 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)
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}")
self._toolbar.setAllowedAreas(Qt.ToolBarArea.LeftToolBarArea | Qt.ToolBarArea.TopToolBarArea)
self._toolbar.setFloatable(False)
self._toolbar.setIconSize(QSize(32, 32))
self._toolbar.addAction(self._file_open_action)
# self._toolbar.addAction(self._file_close_action)
self._toolbar.addSeparator()
# 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)
self._toolbar.addSeparator()
self._toolbar.addAction(self._quit_action)
# settings = QSettings(info.ORGANIZATION, info.NAME)
# tb_orientation = settings.value("app/toolbar_area", "left")
# self.addToolBar(Qt.LeftToolBarArea if tb_orientation == "left" else Qt.TopToolBarArea, self._toolbar)
# 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)")
# dlg.setFileMode(QFileDialog.ExistingFile)
# filenames = None
# if dlg.exec_():
# filenames = dlg.selectedFiles()
# self.open_file(filenames[0])
def on_about(self, s):
pass
def on_help(self, s):
pass
# @Slot(None)
def exit_request(self):
self.close()

5
fixtracks/info.py Normal file
View File

@ -0,0 +1,5 @@
from packaging.version import Version
organization_name = "de.bendalab"
application_name = "FixTracks"
application_version = Version("0.0.1")

171
fixtracks/taskwidgets.py Normal file
View File

@ -0,0 +1,171 @@
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.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)
self._files = None
layout = QVBoxLayout()
layout.addWidget(QLabel("Fix Tracks!"))
self.setLayout(layout)
@property
def fileList(self, file_list):
self._files = file_list

51
fixtracks/util.py Normal file
View File

@ -0,0 +1,51 @@
import logging
import cv2 as cv
from PyQt6.QtCore import QRunnable, pyqtSlot, pyqtSignal, QObject
class ProducerSignals(QObject):
finished = pyqtSignal(bool)
# error = pyqtSignal(str)
# start = pyqtSignal(float)
# running = pyqtSignal()
class ImageReader(QRunnable):
finished = pyqtSignal(bool)
def __init__(self, filename, frame=1000) -> None:
super().__init__()
self._filename = filename
self._framenumber = frame
self._signals = ProducerSignals()
self._frame = None
@pyqtSlot()
def run(self):
'''
Your code goes in this function
'''
logging.debug("ImageReader: trying to open file %s", self._filename)
cap = cv.VideoCapture(self._filename)
if not cap.isOpened():
logging.debug("ImageReader: failed to open file %s", self._filename)
self._signals.finished.emit(False)
fn = 0
while cap.isOpened() and fn < self._framenumber:
ret, frame = cap.read()
if not ret:
logging.warning("ImageReader: failed to read frame %i", fn)
self._signals.finished.emit(False)
break
fn += 1
self._frame = frame # cv.cvtColor(frame, cv.COLOR_BGR2RGB)
self._signals.finished.emit(True)
@property
def signals(self):
return self._signals
@property
def frame(self):
return self._frame