diff --git a/.gitignore b/.gitignore index a05c910..1bcdeff 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,6 @@ -xgtf_to_excel/result.xlsx +xgtf_to_excel_dir/result.xlsx +gui-for-tester-tracker/save_state_pyqt.py +gui-for-tester-tracker/gui_for_tester_tracker .idea/misc.xml .idea/modules.xml .idea/vcs.xml diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..26d3352 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,3 @@ +# Default ignored files +/shelf/ +/workspace.xml diff --git a/.idea/WintreistsPractice.iml b/.idea/WintreistsPractice.iml new file mode 100644 index 0000000..9d7de2b --- /dev/null +++ b/.idea/WintreistsPractice.iml @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml new file mode 100644 index 0000000..105ce2d --- /dev/null +++ b/.idea/inspectionProfiles/profiles_settings.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..43ad0d4 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..110c2ab --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 8e4b0bb..c9c5d7c 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,7 +1,9 @@ { - "python.testing.pytestArgs": [ - "xgtf_to_excel" - ], - "python.testing.unittestEnabled": false, - "python.testing.pytestEnabled": true -} \ No newline at end of file + "python.testing.pytestArgs": ["xgtf_to_excel"], + "python.testing.unittestEnabled": false, + "python.testing.pytestEnabled": true, + "[python]": { + "editor.defaultFormatter": "ms-python.autopep8" + }, + "python.formatting.provider": "none" +} diff --git a/gui-for-tester-tracker/__pycache__/gui.cpython-310.pyc b/gui-for-tester-tracker/__pycache__/gui.cpython-310.pyc new file mode 100644 index 0000000..7315f81 Binary files /dev/null and b/gui-for-tester-tracker/__pycache__/gui.cpython-310.pyc differ diff --git a/gui-for-tester-tracker/__pycache__/tester.cpython-310.pyc b/gui-for-tester-tracker/__pycache__/tester.cpython-310.pyc new file mode 100644 index 0000000..5cbfbe2 Binary files /dev/null and b/gui-for-tester-tracker/__pycache__/tester.cpython-310.pyc differ diff --git a/gui-for-tester-tracker/__pycache__/tester.cpython-311.pyc b/gui-for-tester-tracker/__pycache__/tester.cpython-311.pyc new file mode 100644 index 0000000..1b34c26 Binary files /dev/null and b/gui-for-tester-tracker/__pycache__/tester.cpython-311.pyc differ diff --git a/gui-for-tester-tracker/compile.bat b/gui-for-tester-tracker/compile.bat new file mode 100644 index 0000000..443f682 --- /dev/null +++ b/gui-for-tester-tracker/compile.bat @@ -0,0 +1 @@ +C:\Users\User\PycharmProjects\WintreistsPractice\venv\Scripts\python.exe -m PyQt6.uic.pyuic C:\Users\User\PycharmProjects\WintreistsPractice\gui-for-tester-tracker\gui.ui -o C:\Users\User\PycharmProjects\WintreistsPractice\gui-for-tester-tracker\gui.py \ No newline at end of file diff --git a/gui-for-tester-tracker/gui.py b/gui-for-tester-tracker/gui.py new file mode 100644 index 0000000..82262cf --- /dev/null +++ b/gui-for-tester-tracker/gui.py @@ -0,0 +1,263 @@ +# Form implementation generated from reading ui file 'C:\Users\User\PycharmProjects\WintreistsPractice\gui-for-tester-tracker\gui.ui' +# +# Created by: PyQt6 UI code generator 6.5.2 +# +# WARNING: Any manual changes made to this file will be lost when pyuic6 is +# run again. Do not edit this file unless you know what you are doing. + + +from PyQt6 import QtCore, QtGui, QtWidgets + + +class Ui_MainWindow(object): + def setupUi(self, MainWindow): + MainWindow.setObjectName("MainWindow") + MainWindow.resize(589, 407) + MainWindow.setMinimumSize(QtCore.QSize(0, 0)) + self.centralwidget = QtWidgets.QWidget(parent=MainWindow) + self.centralwidget.setObjectName("centralwidget") + self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget) + self.verticalLayout.setObjectName("verticalLayout") + self.tabWidget = QtWidgets.QTabWidget(parent=self.centralwidget) + self.tabWidget.setLayoutDirection(QtCore.Qt.LayoutDirection.LeftToRight) + self.tabWidget.setObjectName("tabWidget") + self.tab = QtWidgets.QWidget() + self.tab.setObjectName("tab") + self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.tab) + self.verticalLayout_2.setObjectName("verticalLayout_2") + self.groupBox = QtWidgets.QGroupBox(parent=self.tab) + self.groupBox.setTitle("") + self.groupBox.setCheckable(False) + self.groupBox.setObjectName("groupBox") + self.gridLayout = QtWidgets.QGridLayout(self.groupBox) + self.gridLayout.setObjectName("gridLayout") + self.verticalLayout_3 = QtWidgets.QVBoxLayout() + self.verticalLayout_3.setObjectName("verticalLayout_3") + self.label = QtWidgets.QLabel(parent=self.groupBox) + self.label.setObjectName("label") + self.verticalLayout_3.addWidget(self.label) + self.label_2 = QtWidgets.QLabel(parent=self.groupBox) + self.label_2.setObjectName("label_2") + self.verticalLayout_3.addWidget(self.label_2) + self.label_3 = QtWidgets.QLabel(parent=self.groupBox) + self.label_3.setObjectName("label_3") + self.verticalLayout_3.addWidget(self.label_3) + self.label_5 = QtWidgets.QLabel(parent=self.groupBox) + self.label_5.setObjectName("label_5") + self.verticalLayout_3.addWidget(self.label_5) + self.gridLayout.addLayout(self.verticalLayout_3, 0, 0, 1, 1) + self.horizontalLayout_3 = QtWidgets.QHBoxLayout() + self.horizontalLayout_3.setObjectName("horizontalLayout_3") + self.label_4 = QtWidgets.QLabel(parent=self.groupBox) + self.label_4.setObjectName("label_4") + self.horizontalLayout_3.addWidget(self.label_4) + self.gridLayout.addLayout(self.horizontalLayout_3, 1, 0, 1, 1) + self.gridLayout_5 = QtWidgets.QGridLayout() + self.gridLayout_5.setObjectName("gridLayout_5") + self.lineEdit_to_networks_dir = QtWidgets.QLineEdit(parent=self.groupBox) + self.lineEdit_to_networks_dir.setReadOnly(True) + self.lineEdit_to_networks_dir.setObjectName("lineEdit_to_networks_dir") + self.gridLayout_5.addWidget(self.lineEdit_to_networks_dir, 0, 0, 1, 1) + self.toolButton_select_markup_dir = QtWidgets.QToolButton(parent=self.groupBox) + self.toolButton_select_markup_dir.setObjectName("toolButton_select_markup_dir") + self.gridLayout_5.addWidget(self.toolButton_select_markup_dir, 1, 1, 1, 1) + self.lineEdit_path_to_epf_file = QtWidgets.QLineEdit(parent=self.groupBox) + self.lineEdit_path_to_epf_file.setReadOnly(True) + self.lineEdit_path_to_epf_file.setObjectName("lineEdit_path_to_epf_file") + self.gridLayout_5.addWidget(self.lineEdit_path_to_epf_file, 3, 0, 1, 1) + self.toolButton_select_path_to_epf_file = QtWidgets.QToolButton(parent=self.groupBox) + self.toolButton_select_path_to_epf_file.setObjectName("toolButton_select_path_to_epf_file") + self.gridLayout_5.addWidget(self.toolButton_select_path_to_epf_file, 3, 1, 1, 1) + self.lineEdit_to_markup_dir = QtWidgets.QLineEdit(parent=self.groupBox) + self.lineEdit_to_markup_dir.setReadOnly(True) + self.lineEdit_to_markup_dir.setObjectName("lineEdit_to_markup_dir") + self.gridLayout_5.addWidget(self.lineEdit_to_markup_dir, 1, 0, 1, 1) + self.toolButton_select_result_dir = QtWidgets.QToolButton(parent=self.groupBox) + self.toolButton_select_result_dir.setObjectName("toolButton_select_result_dir") + self.gridLayout_5.addWidget(self.toolButton_select_result_dir, 2, 1, 1, 1) + self.lineEdit_to_result_dir = QtWidgets.QLineEdit(parent=self.groupBox) + self.lineEdit_to_result_dir.setReadOnly(True) + self.lineEdit_to_result_dir.setObjectName("lineEdit_to_result_dir") + self.gridLayout_5.addWidget(self.lineEdit_to_result_dir, 2, 0, 1, 1) + self.toolButton_select_networks_dir = QtWidgets.QToolButton(parent=self.groupBox) + self.toolButton_select_networks_dir.setObjectName("toolButton_select_networks_dir") + self.gridLayout_5.addWidget(self.toolButton_select_networks_dir, 0, 1, 1, 1) + self.gridLayout.addLayout(self.gridLayout_5, 0, 1, 1, 1) + self.verticalLayout_4 = QtWidgets.QVBoxLayout() + self.verticalLayout_4.setObjectName("verticalLayout_4") + self.listWidget_list_classes = QtWidgets.QListWidget(parent=self.groupBox) + self.listWidget_list_classes.setSelectionRectVisible(False) + self.listWidget_list_classes.setObjectName("listWidget_list_classes") + self.verticalLayout_4.addWidget(self.listWidget_list_classes) + self.horizontalLayout_6 = QtWidgets.QHBoxLayout() + self.horizontalLayout_6.setObjectName("horizontalLayout_6") + self.label_13 = QtWidgets.QLabel(parent=self.groupBox) + self.label_13.setObjectName("label_13") + self.horizontalLayout_6.addWidget(self.label_13) + self.lineEdit_add_new_class = QtWidgets.QLineEdit(parent=self.groupBox) + self.lineEdit_add_new_class.setObjectName("lineEdit_add_new_class") + self.horizontalLayout_6.addWidget(self.lineEdit_add_new_class) + self.toolButton_add_class = QtWidgets.QToolButton(parent=self.groupBox) + self.toolButton_add_class.setObjectName("toolButton_add_class") + self.horizontalLayout_6.addWidget(self.toolButton_add_class) + self.verticalLayout_4.addLayout(self.horizontalLayout_6) + self.gridLayout.addLayout(self.verticalLayout_4, 1, 1, 1, 1) + self.verticalLayout_2.addWidget(self.groupBox) + self.tabWidget.addTab(self.tab, "") + self.tab_2 = QtWidgets.QWidget() + self.tab_2.setObjectName("tab_2") + self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.tab_2) + self.verticalLayout_6.setObjectName("verticalLayout_6") + self.groupBox_2 = QtWidgets.QGroupBox(parent=self.tab_2) + self.groupBox_2.setObjectName("groupBox_2") + self.verticalLayout_7 = QtWidgets.QVBoxLayout(self.groupBox_2) + self.verticalLayout_7.setObjectName("verticalLayout_7") + self.gridLayout_3 = QtWidgets.QGridLayout() + self.gridLayout_3.setObjectName("gridLayout_3") + self.lineEdit_path_to_siamese_neural_network = QtWidgets.QLineEdit(parent=self.groupBox_2) + self.lineEdit_path_to_siamese_neural_network.setReadOnly(True) + self.lineEdit_path_to_siamese_neural_network.setObjectName("lineEdit_path_to_siamese_neural_network") + self.gridLayout_3.addWidget(self.lineEdit_path_to_siamese_neural_network, 0, 1, 1, 1) + self.label_10 = QtWidgets.QLabel(parent=self.groupBox_2) + self.label_10.setObjectName("label_10") + self.gridLayout_3.addWidget(self.label_10, 0, 0, 1, 1) + self.toolButton_select_path_to_siamese_neural_network = QtWidgets.QToolButton(parent=self.groupBox_2) + self.toolButton_select_path_to_siamese_neural_network.setObjectName("toolButton_select_path_to_siamese_neural_network") + self.gridLayout_3.addWidget(self.toolButton_select_path_to_siamese_neural_network, 0, 2, 1, 1) + self.verticalLayout_7.addLayout(self.gridLayout_3) + self.verticalLayout_8 = QtWidgets.QVBoxLayout() + self.verticalLayout_8.setObjectName("verticalLayout_8") + self.checkBox_hide_stationary_objects = QtWidgets.QCheckBox(parent=self.groupBox_2) + self.checkBox_hide_stationary_objects.setObjectName("checkBox_hide_stationary_objects") + self.verticalLayout_8.addWidget(self.checkBox_hide_stationary_objects) + self.gridLayout_4 = QtWidgets.QGridLayout() + self.gridLayout_4.setObjectName("gridLayout_4") + self.label_7 = QtWidgets.QLabel(parent=self.groupBox_2) + self.label_7.setObjectName("label_7") + self.gridLayout_4.addWidget(self.label_7, 0, 0, 1, 1) + self.lineEdit_sensitivity_detector_stationary_objects = QtWidgets.QLineEdit(parent=self.groupBox_2) + self.lineEdit_sensitivity_detector_stationary_objects.setObjectName("lineEdit_sensitivity_detector_stationary_objects") + self.gridLayout_4.addWidget(self.lineEdit_sensitivity_detector_stationary_objects, 0, 1, 1, 1) + self.verticalLayout_8.addLayout(self.gridLayout_4) + self.verticalLayout_7.addLayout(self.verticalLayout_8) + self.gridLayout_2 = QtWidgets.QGridLayout() + self.gridLayout_2.setObjectName("gridLayout_2") + self.label_8 = QtWidgets.QLabel(parent=self.groupBox_2) + self.label_8.setObjectName("label_8") + self.gridLayout_2.addWidget(self.label_8, 1, 0, 1, 1) + self.lineEdit_minimum_number_of_triggers = QtWidgets.QLineEdit(parent=self.groupBox_2) + self.lineEdit_minimum_number_of_triggers.setObjectName("lineEdit_minimum_number_of_triggers") + self.gridLayout_2.addWidget(self.lineEdit_minimum_number_of_triggers, 1, 1, 1, 1) + self.lineEdit_fps = QtWidgets.QLineEdit(parent=self.groupBox_2) + self.lineEdit_fps.setObjectName("lineEdit_fps") + self.gridLayout_2.addWidget(self.lineEdit_fps, 0, 1, 1, 1) + self.label_6 = QtWidgets.QLabel(parent=self.groupBox_2) + self.label_6.setObjectName("label_6") + self.gridLayout_2.addWidget(self.label_6, 0, 0, 1, 1) + self.label_9 = QtWidgets.QLabel(parent=self.groupBox_2) + self.label_9.setObjectName("label_9") + self.gridLayout_2.addWidget(self.label_9, 2, 0, 1, 1) + self.lineEdit_confidence_threshold = QtWidgets.QLineEdit(parent=self.groupBox_2) + self.lineEdit_confidence_threshold.setObjectName("lineEdit_confidence_threshold") + self.gridLayout_2.addWidget(self.lineEdit_confidence_threshold, 2, 1, 1, 1) + self.verticalLayout_7.addLayout(self.gridLayout_2) + self.verticalLayout_6.addWidget(self.groupBox_2) + self.groupBox_4 = QtWidgets.QGroupBox(parent=self.tab_2) + self.groupBox_4.setObjectName("groupBox_4") + self.verticalLayout_9 = QtWidgets.QVBoxLayout(self.groupBox_4) + self.verticalLayout_9.setObjectName("verticalLayout_9") + self.checkBox_use_MOT = QtWidgets.QCheckBox(parent=self.groupBox_4) + self.checkBox_use_MOT.setObjectName("checkBox_use_MOT") + self.verticalLayout_9.addWidget(self.checkBox_use_MOT) + self.horizontalLayout_2 = QtWidgets.QHBoxLayout() + self.horizontalLayout_2.setObjectName("horizontalLayout_2") + self.label_11 = QtWidgets.QLabel(parent=self.groupBox_4) + self.label_11.setEnabled(True) + self.label_11.setObjectName("label_11") + self.horizontalLayout_2.addWidget(self.label_11) + self.lineEdit_IOU_threshold = QtWidgets.QLineEdit(parent=self.groupBox_4) + self.lineEdit_IOU_threshold.setEnabled(True) + self.lineEdit_IOU_threshold.setObjectName("lineEdit_IOU_threshold") + self.horizontalLayout_2.addWidget(self.lineEdit_IOU_threshold) + self.verticalLayout_9.addLayout(self.horizontalLayout_2) + self.verticalLayout_6.addWidget(self.groupBox_4) + self.tabWidget.addTab(self.tab_2, "") + self.verticalLayout.addWidget(self.tabWidget) + self.horizontalLayout = QtWidgets.QHBoxLayout() + self.horizontalLayout.setObjectName("horizontalLayout") + spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem) + self.pushButton_start_work = QtWidgets.QPushButton(parent=self.centralwidget) + self.pushButton_start_work.setEnabled(False) + self.pushButton_start_work.setObjectName("pushButton_start_work") + self.horizontalLayout.addWidget(self.pushButton_start_work) + spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Minimum, QtWidgets.QSizePolicy.Policy.Minimum) + self.horizontalLayout.addItem(spacerItem1) + self.verticalLayout.addLayout(self.horizontalLayout) + MainWindow.setCentralWidget(self.centralwidget) + self.statusbar = QtWidgets.QStatusBar(parent=MainWindow) + self.statusbar.setObjectName("statusbar") + MainWindow.setStatusBar(self.statusbar) + self.menubar = QtWidgets.QMenuBar(parent=MainWindow) + self.menubar.setGeometry(QtCore.QRect(0, 0, 589, 21)) + self.menubar.setObjectName("menubar") + self.menu = QtWidgets.QMenu(parent=self.menubar) + self.menu.setObjectName("menu") + self.menu_2 = QtWidgets.QMenu(parent=self.menu) + self.menu_2.setObjectName("menu_2") + MainWindow.setMenuBar(self.menubar) + self.action_save_config = QtGui.QAction(parent=MainWindow) + self.action_save_config.setObjectName("action_save_config") + self.action_load_config = QtGui.QAction(parent=MainWindow) + self.action_load_config.setObjectName("action_load_config") + self.action_style_1 = QtGui.QAction(parent=MainWindow) + self.action_style_1.setObjectName("action_style_1") + self.menu.addAction(self.action_save_config) + self.menu.addAction(self.action_load_config) + self.menu.addAction(self.menu_2.menuAction()) + self.menubar.addAction(self.menu.menuAction()) + self.label_4.setBuddy(self.label_4) + + self.retranslateUi(MainWindow) + self.tabWidget.setCurrentIndex(0) + QtCore.QMetaObject.connectSlotsByName(MainWindow) + + def retranslateUi(self, MainWindow): + _translate = QtCore.QCoreApplication.translate + MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) + self.label.setText(_translate("MainWindow", "Путь к папке с сетями")) + self.label_2.setText(_translate("MainWindow", "Путь к папке с разметкой")) + self.label_3.setText(_translate("MainWindow", "Путь для сохранения результатов теста")) + self.label_5.setText(_translate("MainWindow", "Путь к .epf файлу")) + self.label_4.setText(_translate("MainWindow", "Список тестируемых классов:")) + self.toolButton_select_markup_dir.setText(_translate("MainWindow", "...")) + self.toolButton_select_path_to_epf_file.setText(_translate("MainWindow", "...")) + self.toolButton_select_result_dir.setText(_translate("MainWindow", "...")) + self.lineEdit_to_result_dir.setText(_translate("MainWindow", "/results")) + self.toolButton_select_networks_dir.setText(_translate("MainWindow", "...")) + self.label_13.setText(_translate("MainWindow", "Добавить новый класс:")) + self.toolButton_add_class.setText(_translate("MainWindow", "+")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Параметры тестера")) + self.groupBox_2.setTitle(_translate("MainWindow", "Параметры трекера")) + self.label_10.setText(_translate("MainWindow", "Путь к сиамской нейронной сети")) + self.toolButton_select_path_to_siamese_neural_network.setText(_translate("MainWindow", "...")) + self.checkBox_hide_stationary_objects.setText(_translate("MainWindow", "Скрывать неподвижные объекты")) + self.label_7.setText(_translate("MainWindow", "Чувствительность детектора неподвижных объектов")) + self.lineEdit_sensitivity_detector_stationary_objects.setText(_translate("MainWindow", "0.5")) + self.label_8.setText(_translate("MainWindow", "Минимальное число срабатываний")) + self.lineEdit_minimum_number_of_triggers.setText(_translate("MainWindow", "6")) + self.lineEdit_fps.setText(_translate("MainWindow", "13")) + self.label_6.setText(_translate("MainWindow", "Количество кадров трекера (FPS):")) + self.label_9.setText(_translate("MainWindow", "Доверительный порог")) + self.lineEdit_confidence_threshold.setText(_translate("MainWindow", "0.3")) + self.groupBox_4.setTitle(_translate("MainWindow", "Использование МОТ")) + self.checkBox_use_MOT.setText(_translate("MainWindow", "Использовать MOT вместо ViPER")) + self.label_11.setText(_translate("MainWindow", "IOU порог")) + self.lineEdit_IOU_threshold.setText(_translate("MainWindow", "0.3")) + self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "Параметры трекера")) + self.pushButton_start_work.setText(_translate("MainWindow", "Запустить тестирование")) + self.menu.setTitle(_translate("MainWindow", "Меню")) + self.menu_2.setTitle(_translate("MainWindow", "Стили")) + self.action_save_config.setText(_translate("MainWindow", "Сохранить")) + self.action_load_config.setText(_translate("MainWindow", "Загрузить")) + self.action_style_1.setText(_translate("MainWindow", "Стиль 1")) diff --git a/gui-for-tester-tracker/gui.ui b/gui-for-tester-tracker/gui.ui new file mode 100644 index 0000000..23e2920 --- /dev/null +++ b/gui-for-tester-tracker/gui.ui @@ -0,0 +1,438 @@ + + + MainWindow + + + + 0 + 0 + 589 + 407 + + + + + 0 + 0 + + + + MainWindow + + + + + + + Qt::LeftToRight + + + 0 + + + + Параметры тестера + + + + + + + + + false + + + + + + + + Путь к папке с сетями + + + + + + + Путь к папке с разметкой + + + + + + + Путь для сохранения результатов теста + + + + + + + Путь к .epf файлу + + + + + + + + + + + Список тестируемых классов: + + + label_4 + + + + + + + + + + + true + + + + + + + ... + + + + + + + true + + + + + + + ... + + + + + + + true + + + + + + + ... + + + + + + + /results + + + true + + + + + + + ... + + + + + + + + + + + false + + + + + + + + + Добавить новый класс: + + + + + + + + + + + + + + + + + + + + + + + + + + Параметры трекера + + + + + + Параметры трекера + + + + + + + + true + + + + + + + Путь к сиамской нейронной сети + + + + + + + ... + + + + + + + + + + + Скрывать неподвижные объекты + + + + + + + + + Чувствительность детектора неподвижных объектов + + + + + + + 0.5 + + + + + + + + + + + + + Минимальное число срабатываний + + + + + + + 6 + + + + + + + 13 + + + + + + + Количество кадров трекера (FPS): + + + + + + + Доверительный порог + + + + + + + 0.3 + + + + + + + + + + + + Использование МОТ + + + + + + Использовать MOT вместо ViPER + + + + + + + + + true + + + IOU порог + + + + + + + true + + + 0.3 + + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Запустить тестирование + + + + + + + Qt::Horizontal + + + QSizePolicy::Minimum + + + + 40 + 20 + + + + + + + + + + + + + 0 + 0 + 589 + 21 + + + + + Меню + + + + Стили + + + + + + + + + + + Сохранить + + + + + Загрузить + + + + + Стиль 1 + + + + + + diff --git a/gui-for-tester-tracker/gui_for_tester_tracker.ini b/gui-for-tester-tracker/gui_for_tester_tracker.ini new file mode 100644 index 0000000..38cc7d9 --- /dev/null +++ b/gui-for-tester-tracker/gui_for_tester_tracker.ini @@ -0,0 +1,14 @@ +[General] +lineEdit_confidence_threshold=0.3 +lineEdit_minimum_number_of_triggers=6 +lineEdit_IOU_threshold=0.3 +lineEdit_sensitivity_detector_stationary_objects=0.5 +lineEdit_fps=13 +lineEdit_path_to_siamese_neural_network= +lineEdit_path_to_epf_file= +lineEdit_to_markup_dir= +lineEdit_to_networks_dir= +lineEdit_to_result_dir=/results +checkBox_hide_stationary_objects= +checkBox_use_MOT= +listWidget_list_classes=@Variant(\0\0\0\b\0\0\0\x1\0\0\0\n\0H\0u\0m\0\x61\0n\0\0\0\x1\x1) diff --git a/gui-for-tester-tracker/gui_tracker.py b/gui-for-tester-tracker/gui_tracker.py new file mode 100644 index 0000000..a96ca20 --- /dev/null +++ b/gui-for-tester-tracker/gui_tracker.py @@ -0,0 +1,239 @@ +import sys +import os +from functools import partial +from pathlib import Path +from typing import Callable +from PyQt6.QtWidgets import ( + QLineEdit, QToolButton, QCheckBox, + QApplication, QMainWindow, QFileDialog, + QHBoxLayout, QWidget, QListWidgetItem, + QSpacerItem, QSizePolicy, QMessageBox, +) +from PyQt6 import QtGui +from PyQt6.QtCore import QSettings, Qt, QSize +from tester import main as testerTrackerMain +from gui import Ui_MainWindow + + +class MainWindow(QMainWindow, Ui_MainWindow): + # Сигналы + # onProgressWork = pyqtSignal(int, int, str, str) + # ~~~~~~~ + def __init__(self): + super(MainWindow, self).__init__() + self.setupUi(self) + self.add_class(lambda: "Human", True, False) + # Меню + # Конфиг + self.action_save_config.triggered.connect(self.save_state) + self.action_load_config.triggered.connect(self.load_state) + # ~~~~~ + # Сигналы + self.toolButton_select_markup_dir.clicked.connect( + partial(self.open_file_explorer, self.lineEdit_to_markup_dir, "Выберите путь к папке с разметкой")) + self.toolButton_select_networks_dir.clicked.connect( + partial(self.open_file_explorer, self.lineEdit_to_networks_dir, "Выберите путь к папке с сетями")) + self.toolButton_select_result_dir.clicked.connect( + partial(self.open_file_explorer, self.lineEdit_to_result_dir, "Выберите путь к папке для сохранения результатов")) + self.toolButton_select_path_to_siamese_neural_network.clicked.connect( + partial(self.open_file_location, self.lineEdit_path_to_siamese_neural_network, "Выберите путь к сиамской нейронной сети")) + self.toolButton_select_path_to_epf_file.clicked.connect( + partial(self.open_file_location, self.lineEdit_path_to_epf_file, "Выберите путь к .epf файлу", "*.epf")) + self.toolButton_add_class.clicked.connect( + partial(self.add_class, self.lineEdit_add_new_class.text, True, True)) + + self.lineEdit_add_new_class.returnPressed.connect( + partial(self.add_class, self.lineEdit_add_new_class.text, True, True)) + self.lineEdit_to_networks_dir.textChanged.connect( + self.all_needed_line_edits_are_not_empty) + self.lineEdit_to_markup_dir.textChanged.connect( + self.all_needed_line_edits_are_not_empty) + + self.pushButton_start_work.clicked.connect(self.start_work) + + # Стили + for filename in Path(__file__).parent.glob("./styles/*.qss"): + action = QtGui.QAction( + filename.name.rpartition(".")[0], self) + action.triggered.connect( + partial(self.set_style, filename)) + self.menu_2.addAction(action) + + def set_style(self, style_filename: Path): + self.setStyleSheet(style_filename.read_text()) + + def all_needed_line_edits_are_not_empty(self): + allNeededLineEdits = [ + self.lineEdit_to_networks_dir, + self.lineEdit_to_markup_dir, + ] + is_filled = all(lineEdit.text() for lineEdit in allNeededLineEdits) + self.pushButton_start_work.setEnabled(is_filled) + + def open_file_explorer(self, input_directory: QLineEdit, text: str = None): + text = text if text else "Выберите директорию" + directory = QFileDialog.getExistingDirectory(self, text) + if directory: + input_directory.setText(directory) + + def open_file_location(self, lineEdit_file_location: QLineEdit, text: str = None, filter: str = None): + text = text if text else "Выберите файл" + filter = filter if filter else None + file_location = QFileDialog.getOpenFileName(self, text, filter=filter) + if file_location[0]: + lineEdit_file_location.setText(file_location[0]) + + def start_work(self): + testing_classes = [] + for index in range(self.listWidget_list_classes.count()): + item = self.listWidget_list_classes.item(index) + widget: ListItemClass = self.listWidget_list_classes.itemWidget( + item) + if widget.checkbox.isChecked(): + testing_classes.append(widget.checkbox.text()) + if len(testing_classes) == 0: + QMessageBox.critical( + self, "Ошибка", "Вы пытаетесь запустить тестирование без активных классов!") + return True + self.hide() + testerTrackerMain( + netsDir=self.lineEdit_to_networks_dir.text(), + videosDir=self.lineEdit_to_markup_dir.text(), + resDir=self.lineEdit_to_result_dir.text(), + targetClasses=testing_classes, + path2Epf=self.lineEdit_path_to_epf_file.text(), + useMot=self.checkBox_use_MOT.isChecked(), + motIouThr=float(self.lineEdit_IOU_threshold.text()), + framerate=int(self.lineEdit_fps.text()), + hideStillObjects=self.checkBox_hide_stationary_objects.isChecked(), + hideStillObjectsSensitivity=float( + self.lineEdit_sensitivity_detector_stationary_objects.text()), + minDetectionTriggers=int( + self.lineEdit_minimum_number_of_triggers.text()), + confThreshold=float(self.lineEdit_confidence_threshold.text()), + siameseFile=self.lineEdit_path_to_siamese_neural_network.text(), + # onProgressCallback=self.onProgressWork.emit, + ) + self.show() + + def load_state(self): + path_to_settings = QFileDialog.getOpenFileName( + self, 'Выберите файл настроек') + if path_to_settings[0]: + self.settings = QSettings( + path_to_settings[0], QSettings.Format.IniFormat) + + self.lineEdit_to_markup_dir.setText( + self.settings.value(self.lineEdit_to_markup_dir.objectName(), "")) + self.lineEdit_to_networks_dir.setText( + self.settings.value(self.lineEdit_to_networks_dir.objectName(), "")) + self.lineEdit_to_result_dir.setText( + self.settings.value(self.lineEdit_to_result_dir.objectName(), "/results")) + self.lineEdit_path_to_siamese_neural_network.setText( + self.settings.value(self.lineEdit_path_to_siamese_neural_network.objectName(), "")) + self.lineEdit_path_to_epf_file.setText( + self.settings.value(self.lineEdit_path_to_epf_file.objectName(), "")) + self.lineEdit_confidence_threshold.setText( + self.settings.value(self.lineEdit_confidence_threshold.objectName(), "0.3")) + self.lineEdit_minimum_number_of_triggers.setText( + self.settings.value(self.lineEdit_minimum_number_of_triggers.objectName(), "6")) + self.lineEdit_IOU_threshold.setText( + self.settings.value(self.lineEdit_IOU_threshold.objectName(), "0.3")) + self.lineEdit_sensitivity_detector_stationary_objects.setText( + self.settings.value(self.lineEdit_sensitivity_detector_stationary_objects.objectName(), "0.5")) + self.lineEdit_fps.setText( + self.settings.value(self.lineEdit_fps.objectName(), "13")) + + self.checkBox_hide_stationary_objects.setChecked( + bool(self.settings.value(self.checkBox_hide_stationary_objects.objectName(), False))) + self.checkBox_use_MOT.setChecked( + bool(self.settings.value(self.checkBox_use_MOT.objectName(), False))) + + self.listWidget_list_classes.clear() + items = self.settings.value(self.listWidget_list_classes.objectName(), { + "Human": True + }) + for class_name, check_state in items.items(): + self.add_class(lambda: class_name, check_state) + + def save_state(self): + path_to_settings = QFileDialog.getSaveFileName( + self, "Выберите путь\файл настроек") + if path_to_settings[0]: + self.settings = QSettings( + path_to_settings[0], QSettings.Format.IniFormat) + self.settings.setValue(self.lineEdit_confidence_threshold.objectName(), + self.lineEdit_confidence_threshold.text()) + self.settings.setValue(self.lineEdit_minimum_number_of_triggers.objectName(), + self.lineEdit_minimum_number_of_triggers.text()) + self.settings.setValue(self.lineEdit_IOU_threshold.objectName(), + self.lineEdit_IOU_threshold.text()) + self.settings.setValue(self.lineEdit_sensitivity_detector_stationary_objects.objectName(), + self.lineEdit_sensitivity_detector_stationary_objects.text()) + self.settings.setValue(self.lineEdit_fps.objectName(), + self.lineEdit_fps.text()) + self.settings.setValue(self.lineEdit_path_to_siamese_neural_network.objectName(), + self.lineEdit_path_to_siamese_neural_network.text()) + self.settings.setValue(self.lineEdit_path_to_epf_file.objectName(), + self.lineEdit_path_to_epf_file.text()) + self.settings.setValue(self.lineEdit_to_markup_dir.objectName(), + self.lineEdit_to_markup_dir.text()) + self.settings.setValue(self.lineEdit_to_networks_dir.objectName(), + self.lineEdit_to_networks_dir.text()) + self.settings.setValue(self.lineEdit_to_result_dir.objectName(), + self.lineEdit_to_result_dir.text()) + self.settings.setValue(self.checkBox_hide_stationary_objects.objectName(), + True if self.checkBox_hide_stationary_objects.checkState() == Qt.CheckState.Checked else '') + self.settings.setValue(self.checkBox_use_MOT.objectName(), + True if self.checkBox_use_MOT.checkState() == Qt.CheckState.Checked else '') + classes = {} + for index in range(self.listWidget_list_classes.count()): + item = self.listWidget_list_classes.item(index) + widget: ListItemClass = self.listWidget_list_classes.itemWidget( + item) + classes[widget.checkbox.text()] = widget.checkbox.isChecked() + self.settings.setValue( + self.listWidget_list_classes.objectName(), classes) + + def add_class(self, class_name: Callable[[], str], check_state, isAddedFromLineEdit=False): + if class_name(): + widget = ListItemClass(class_name(), check_state) + list_item = QListWidgetItem() + list_item.setFlags(list_item.flags() & ~ + Qt.ItemFlag.ItemIsSelectable) + list_item.setSizeHint(QSize(0, 40)) + self.listWidget_list_classes.addItem(list_item) + self.listWidget_list_classes.setItemWidget(list_item, widget) + widget.toolButton.clicked.connect( + partial(self.remove_class, list_item)) + if isAddedFromLineEdit: + self.lineEdit_add_new_class.setText("") + + def remove_class(self, item): + self.listWidget_list_classes.takeItem( + self.listWidget_list_classes.row(item)) + + +class ListItemClass(QWidget): + def __init__(self, class_name, check_state): + super().__init__() + self.layout = QHBoxLayout(self) + self.checkbox = QCheckBox(class_name) + self.checkbox.setChecked(check_state) + self.toolButton = QToolButton() + self.toolButton.setText('-') + self.spacer = QSpacerItem( + 0, 0, QSizePolicy.Policy.Expanding, QSizePolicy.Policy.Minimum) + self.layout.addWidget(self.checkbox) + self.layout.addItem(self.spacer) + self.layout.addWidget(self.toolButton) + + +if __name__ == '__main__': + _path = Path(__file__).parent + app = QApplication(sys.argv) + app.setWindowIcon(QtGui.QIcon(_path.joinpath('icon.png').__str__())) + window = MainWindow() + window.setWindowTitle("GUI for tester tracker") + window.show() + app.exec() diff --git a/gui-for-tester-tracker/icon.png b/gui-for-tester-tracker/icon.png new file mode 100644 index 0000000..8c715c8 Binary files /dev/null and b/gui-for-tester-tracker/icon.png differ diff --git "a/gui-for-tester-tracker/styles/\320\235\320\276\321\207\320\275\320\276\320\271 \321\201\321\202\320\270\320\273\321\214.qss" "b/gui-for-tester-tracker/styles/\320\235\320\276\321\207\320\275\320\276\320\271 \321\201\321\202\320\270\320\273\321\214.qss" new file mode 100644 index 0000000..cee7a63 --- /dev/null +++ "b/gui-for-tester-tracker/styles/\320\235\320\276\321\207\320\275\320\276\320\271 \321\201\321\202\320\270\320\273\321\214.qss" @@ -0,0 +1,70 @@ +QWidget { + background-color: #111; +} + +QLabel, QCheckBox { + color: #aec0d4; + font-weight: 600; +} +QCheckBox { + background: transparent +} + +QLineEdit { + border-radius: 8px; + border: 1px solid #e0e4e7; + padding: 5px 5px; + background: #baa +} +QLineEdit:focus { + border: 1px solid #d0e3ff; +} + +QPushButton { + font-weight: 600; + border-radius: 8px; + padding: 5px 15px; +} +QPushButton:disabled { + background-color: #183055; + color: #999; + border: 1px solid #183055; +} +QPushButton:enabled { + background-color: #0e2952; + color: #fff; + border: 1px solid #0e2952; +} +QPushButton:hover{ + background-color: #2d6bc9; + border: 3px solid #73a9f5; + padding: 3px; +} + +QMenuBar:item { + padding: 1px 4px; + background: transparent; + color: #000000; + background-color: #fff; +} +QMenuBar:item:selected { + background-color: #afcaf3; +} +QMenuBar:item:pressed { + background-color: #5e99f3; +} + +QMenu { + background-color: #ffffff; + color: #000; + border: 1px solid #000000; +} +QMenu:item { + font-weight: 600; + padding: 5px 15px; + padding-left: 10px; +} +QMenu:item:selected { + background-color: #5e99f3; +} + diff --git "a/gui-for-tester-tracker/styles/\320\241\321\202\320\260\320\275\320\264\320\260\321\200\321\202\320\275\321\213\320\271 \321\201\321\202\320\270\320\273\321\214.qss" "b/gui-for-tester-tracker/styles/\320\241\321\202\320\260\320\275\320\264\320\260\321\200\321\202\320\275\321\213\320\271 \321\201\321\202\320\270\320\273\321\214.qss" new file mode 100644 index 0000000..e69de29 diff --git "a/gui-for-tester-tracker/styles/\320\247\321\202\320\276-\321\202\320\276 \320\275\320\260 CSS'\320\275\320\276\320\274.qss" "b/gui-for-tester-tracker/styles/\320\247\321\202\320\276-\321\202\320\276 \320\275\320\260 CSS'\320\275\320\276\320\274.qss" new file mode 100644 index 0000000..481e1de --- /dev/null +++ "b/gui-for-tester-tracker/styles/\320\247\321\202\320\276-\321\202\320\276 \320\275\320\260 CSS'\320\275\320\276\320\274.qss" @@ -0,0 +1,69 @@ +QWidget { + background-color: #fff; +} + +QLabel, QCheckBox { + color: #464d55; + font-weight: 600; +} +QCheckBox { + background: transparent +} + +QLineEdit { + border-radius: 8px; + border: 1px solid #e0e4e7; + padding: 5px 5px; +} +QLineEdit:focus { + border: 1px solid #d0e3ff; +} + +QPushButton { + font-weight: 600; + border-radius: 8px; + padding: 5px 15px; +} +QPushButton:disabled { + background-color: #183055; + color: #999; + border: 1px solid #183055; +} +QPushButton:enabled { + background-color: #0d6efd; + color: #fff; + border: 1px solid #0d6efd; +} +QPushButton:hover{ + background-color: #0b5ed7; + border: 3px solid #9ac3fe; + padding: 3px; +} + +QMenuBar:item { + padding: 1px 4px; + background: transparent; + color: #000000; + background-color: #fff; +} +QMenuBar:item:selected { + background-color: #afcaf3; +} +QMenuBar:item:pressed { + background-color: #5e99f3; +} + +QMenu { + background-color: #ffffff; + color: #000; + border: 1px solid #000000; +} +QMenu:item { + font-weight: 600; + padding: 5px 15px; + padding-left: 10px; +} +QMenu:item:selected { + background-color: #5e99f3; +} + diff --git a/gui-for-tester-tracker/tester.py b/gui-for-tester-tracker/tester.py new file mode 100644 index 0000000..8258959 --- /dev/null +++ b/gui-for-tester-tracker/tester.py @@ -0,0 +1,31 @@ + + +def defaultOnProgressCallback(completed: int, all: int, curNet: str, curVideo: str): + if curNet and curVideo: + print(f"[{completed}/{all}] Work with net {curNet} and video {curVideo}") + + +def defaultOnErrorCallback(message: str): + print(f"[E] {message}") + + +from typing import Tuple, Optional, Callable + +def main( + netsDir: str, + videosDir: str, + resDir: str, + targetClasses: Tuple[str, ...], + path2Epf: Optional[str] = None, + useMot: bool = False, + motIouThr: float = 0.3, + framerate: int = 13, + hideStillObjects: bool = False, + hideStillObjectsSensitivity: float = 0.5, + minDetectionTriggers: int = 6, + confThreshold: float = 0.3, + siameseFile: str = "", + onProgressCallback: Callable[[int, int, str, str], None] = defaultOnProgressCallback, + onErrorCallback: Callable[[str], None] = defaultOnErrorCallback +): + pass diff --git a/xgtf_to_excel/__pycache__/xgtf_to_excel.cpython-311.pyc b/xgtf_to_excel/__pycache__/xgtf_to_excel.cpython-311.pyc deleted file mode 100644 index 0e933ea..0000000 Binary files a/xgtf_to_excel/__pycache__/xgtf_to_excel.cpython-311.pyc and /dev/null differ diff --git a/xgtf_to_excel/requirements.txt b/xgtf_to_excel/requirements.txt deleted file mode 100644 index f1e5be5..0000000 Binary files a/xgtf_to_excel/requirements.txt and /dev/null differ diff --git a/xgtf_to_excel/xgtf_to_excel.py b/xgtf_to_excel/xgtf_to_excel.py deleted file mode 100644 index 4737828..0000000 --- a/xgtf_to_excel/xgtf_to_excel.py +++ /dev/null @@ -1,163 +0,0 @@ -import os -import pandas as pd -import xml.etree.ElementTree as ET -from argparse import ArgumentParser -import cv2 -from dataclasses import dataclass, field -from typing import Optional, Tuple -from math import isnan -from numpy import sum as npsum - - -# Константы -VIPER = "{http://lamp.cfar.umd.edu/viper#}" -VIPERDATA = "{http://lamp.cfar.umd.edu/viperdata#}" -# - -def get_fps_and_numframes_from_video(work_dir:str, file_name:str) -> Tuple[float, float]: - extensions = ["mkv", "mp4", "mpeg", "mov", "avi"] - file_name = file_name.removesuffix(".xgtf") - video_path = None - for video_name in [f"{file_name}.{extension}" for extension in extensions]: - if os.path.isfile(os.path.join(work_dir, video_name)): - video_path = os.path.join(work_dir, video_name) - break - if video_path is not None: - video = cv2.VideoCapture(video_path) - return video.get(cv2.CAP_PROP_FRAME_COUNT), video.get(cv2.CAP_PROP_FPS) - else: - return 0.0, 0.0 - -def calculate_time(time:float) -> str: - hours = int(time // 3600) - time -= 3600*hours - minutes = int(time//60) - time -= 60*minutes - seconds = int(time) - return f"{hours}:{minutes}:{seconds}" - -def get_default_value_for_class(tree:ET.ElementTree) -> str: - default_value = "None" - for attribute in tree.getroot().findall(f'./{VIPER}config/{VIPER}descriptor/{VIPER}attribute[@name="Class"]/{VIPER}default/{VIPERDATA}svalue'): - default_value = attribute.attrib['value'] - return default_value - -def painting_errors(element): - if isinstance(element, int): - if element == 0: - return 'background-color: #ff4c5b;' - elif isinstance(element, str): - if "None" in element or element == "": - return 'background-color: #ff4c5b;' - elif element == "0:0:0": - return 'background-color: #ff4c5b;' - elif isinstance(element, float): - if element == 0.0: - return 'background-color: #ff4c5b;' - elif isnan(element): - return 'background-color: #ff4c5b;' - elif element is None: - return 'background-color: #ff4c5b;' - return None - - - -@dataclass -class XgtfData: - fileName:str - objectsCount:int=0 - objectsFramesCount:int=0 - videoDuration:float=0.0 - framesCount:float=0.0 - classes:Optional[set[Optional[str]]]=field(default_factory=set) - - def to_excel(self) -> list: - return [self.fileName, - self.objectsCount, - calculate_time(self.videoDuration), - self.framesCount, - self.objectsFramesCount/self.framesCount if self.framesCount != 0 else 0.0, - ",".join(self.classes)] - pass - -@dataclass -class AllXgtfData: - _xgtfData:list[XgtfData] = field(default_factory=list) - - def to_excel(self) -> list: - statistics = XgtfData("Итого") - statistics.objectsCount, statistics.videoDuration, statistics.framesCount, statistics.objectsFramesCount = npsum([[xgtf.objectsFramesCount, xgtf.videoDuration, xgtf.framesCount, xgtf.objectsFramesCount] for xgtf in self._xgtfData], axis=0) - statistics.classes = set.union(*[xgtf.classes for xgtf in self._xgtfData]) - return [xgtf.to_excel() for xgtf in self._xgtfData] + [statistics.to_excel()] - def append(self, element:XgtfData): - self._xgtfData.append(element) - pass - pass - - - -if __name__ == "__main__": - # Аргументы - parser = ArgumentParser() - parser.add_argument('--work-dir', required=True) - parser.add_argument('--result-dir',nargs="?", default='result.xlsx') - namespace = parser.parse_args() - # - allData = AllXgtfData() - for file_name in os.listdir(namespace.work_dir): - # Условие для обработки .xgtf - if file_name.find(".xgtf") == -1: - continue - # Подготовка - # Имя - data = XgtfData(file_name) - - try: - tree = ET.parse(os.path.join(namespace.work_dir, file_name)) - except ET.ParseError: - allData.append(data) - continue - print(os.path.join(namespace.work_dir, file_name)) - root_data_sourcefile = tree.getroot().find(f'./{VIPER}data/{VIPER}sourcefile') - - # Количество рамок объектов - for v_object in root_data_sourcefile.findall(f'./{VIPER}object'): - data.objectsCount += 1 - for bbox in v_object.findall(f'./{VIPER}attribute[@name="Position"]/{VIPERDATA}bbox'): - data.objectsFramesCount += sum([right-left+1 for splited_bbox in bbox.attrib["framespan"].split(" ") for left, right in [map(int, splited_bbox.split(":"))]]) - - # Классы - try: - data.classes.add(v_object.find(f'./{VIPER}attribute[@name="Class"]/{VIPERDATA}svalue').attrib['value']) - except AttributeError: - data.classes.add(get_default_value_for_class(tree)) - - root_data_sourcefile_file = root_data_sourcefile.find(f'./{VIPER}file') - try: - # Длинна видео (кадры) - data.framesCount = float(root_data_sourcefile_file.find(f'./{VIPER}attribute[@name="NUMFRAMES"]/').attrib['value']) # NUMFRAMES - framerate = float(root_data_sourcefile_file.find(f'.//{VIPER}attribute[@name="FRAMERATE"]/').attrib['value']) # FRAMERATE - if data.framesCount == 0 or framerate == 0: - raise AttributeError - except AttributeError: - data.framesCount,framerate = get_fps_and_numframes_from_video(namespace.work_dir, file_name) - - if framerate != 0: - # Расчет времени - data.videoDuration = data.framesCount / framerate - - - # Сохраняем в общий массив - allData.append(data) - - # Вывод в файл - df = pd.DataFrame(allData.to_excel(), columns=['Имя', 'Количество объектов', 'Длинна видео (секунд)', 'Длинна видео (кадры)', 'Среднее кол-во рамок объектов на кадре', 'Классы']) - writer = pd.ExcelWriter(namespace.result_dir, engine='xlsxwriter') - df.style.applymap(painting_errors).to_excel(writer, sheet_name='Sheet1', index=False, na_rep='NaN') - - for column in df: - column_length = max(df[column].astype(str).map(len).max(), len(column)) + 1 - col_idx = df.columns.get_loc(column) - writer.sheets['Sheet1'].set_column(col_idx, col_idx, column_length) - - writer.close()