mirror of
https://github.com/283375/arcaea-offline-pyside-ui.git
synced 2025-07-01 20:36:26 +00:00
Compare commits
10 Commits
v0.3.0b
...
ad5e5ec694
Author | SHA1 | Date | |
---|---|---|---|
ad5e5ec694
|
|||
5c5c1a227d
|
|||
cde8a047a7
|
|||
19cd526814
|
|||
8b6f64e041
|
|||
6dbb7cbfef
|
|||
94e4d73a95
|
|||
4a1e20a45f
|
|||
de8c5d28a7
|
|||
bce48a03a7
|
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@ __debug*
|
||||
|
||||
arcaea_offline.db
|
||||
arcaea_offline.ini
|
||||
/data
|
||||
|
||||
ui/resources/VERSION
|
||||
|
||||
|
281
ui/designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui
Normal file
281
ui/designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui
Normal file
@ -0,0 +1,281 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>TabOcr_BuildPHashDatabase</class>
|
||||
<widget class="QWidget" name="TabOcr_BuildPHashDatabase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>632</width>
|
||||
<height>551</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">TabOcr_BuildPHashDatabase</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>folders.title</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>folders.songDir</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="FileSelector" name="songDirSelector" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>folders.charIconDir</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="FileSelector" name="charIconDirSelector" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="MinimumExpanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>options.title</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string notr="true">hash_size</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="hashSizeSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>2</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>64</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>16</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_7">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string notr="true">highfreq_factor</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="highfreqFactorSpinBox">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Maximum" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>32</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>4</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="preprocessCharIconCheckBox">
|
||||
<property name="text">
|
||||
<string>options.preprocessCharIcon</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="optionsResetButton">
|
||||
<property name="text">
|
||||
<string>resetButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="readImageProgressBar">
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="format">
|
||||
<string>[Reading images] %v/%m - %p%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="calculateHashProgressBar">
|
||||
<property name="maximum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignCenter</set>
|
||||
</property>
|
||||
<property name="format">
|
||||
<string>[Calculate hashes] %v/%m - %p%</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_5">
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="buildButton">
|
||||
<property name="text">
|
||||
<string>buildButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>40</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>FileSelector</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.components.fileSelector</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
209
ui/designer/tabs/tabOcr/tabOcr_BuildPHashDatabase_ui.py
Normal file
209
ui/designer/tabs/tabOcr/tabOcr_BuildPHashDatabase_ui.py
Normal file
@ -0,0 +1,209 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'tabOcr_BuildPHashDatabase.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
|
||||
from PySide6.QtCore import (QCoreApplication, QDate, QDateTime, QLocale,
|
||||
QMetaObject, QObject, QPoint, QRect,
|
||||
QSize, QTime, QUrl, Qt)
|
||||
from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||
QFont, QFontDatabase, QGradient, QIcon,
|
||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||
from PySide6.QtWidgets import (QApplication, QCheckBox, QGroupBox, QHBoxLayout,
|
||||
QLabel, QProgressBar, QPushButton, QSizePolicy,
|
||||
QSpacerItem, QSpinBox, QVBoxLayout, QWidget)
|
||||
|
||||
from ui.implements.components.fileSelector import FileSelector
|
||||
|
||||
class Ui_TabOcr_BuildPHashDatabase(object):
|
||||
def setupUi(self, TabOcr_BuildPHashDatabase):
|
||||
if not TabOcr_BuildPHashDatabase.objectName():
|
||||
TabOcr_BuildPHashDatabase.setObjectName(u"TabOcr_BuildPHashDatabase")
|
||||
TabOcr_BuildPHashDatabase.resize(632, 551)
|
||||
TabOcr_BuildPHashDatabase.setWindowTitle(u"TabOcr_BuildPHashDatabase")
|
||||
self.verticalLayout_3 = QVBoxLayout(TabOcr_BuildPHashDatabase)
|
||||
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
|
||||
self.verticalSpacer = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
|
||||
self.verticalLayout_3.addItem(self.verticalSpacer)
|
||||
|
||||
self.groupBox = QGroupBox(TabOcr_BuildPHashDatabase)
|
||||
self.groupBox.setObjectName(u"groupBox")
|
||||
self.verticalLayout = QVBoxLayout(self.groupBox)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.label = QLabel(self.groupBox)
|
||||
self.label.setObjectName(u"label")
|
||||
|
||||
self.horizontalLayout.addWidget(self.label)
|
||||
|
||||
self.songDirSelector = FileSelector(self.groupBox)
|
||||
self.songDirSelector.setObjectName(u"songDirSelector")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Preferred)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.songDirSelector.sizePolicy().hasHeightForWidth())
|
||||
self.songDirSelector.setSizePolicy(sizePolicy)
|
||||
|
||||
self.horizontalLayout.addWidget(self.songDirSelector)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
|
||||
self.horizontalLayout_2 = QHBoxLayout()
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
self.label_2 = QLabel(self.groupBox)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.label_2)
|
||||
|
||||
self.charIconDirSelector = FileSelector(self.groupBox)
|
||||
self.charIconDirSelector.setObjectName(u"charIconDirSelector")
|
||||
sizePolicy.setHeightForWidth(self.charIconDirSelector.sizePolicy().hasHeightForWidth())
|
||||
self.charIconDirSelector.setSizePolicy(sizePolicy)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.charIconDirSelector)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout_2)
|
||||
|
||||
|
||||
self.verticalLayout_3.addWidget(self.groupBox)
|
||||
|
||||
self.groupBox_2 = QGroupBox(TabOcr_BuildPHashDatabase)
|
||||
self.groupBox_2.setObjectName(u"groupBox_2")
|
||||
self.horizontalLayout_3 = QHBoxLayout(self.groupBox_2)
|
||||
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
||||
self.verticalLayout_2 = QVBoxLayout()
|
||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||
self.horizontalLayout_6 = QHBoxLayout()
|
||||
self.horizontalLayout_6.setObjectName(u"horizontalLayout_6")
|
||||
self.label_3 = QLabel(self.groupBox_2)
|
||||
self.label_3.setObjectName(u"label_3")
|
||||
self.label_3.setText(u"hash_size")
|
||||
self.label_3.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||
|
||||
self.horizontalLayout_6.addWidget(self.label_3)
|
||||
|
||||
self.hashSizeSpinBox = QSpinBox(self.groupBox_2)
|
||||
self.hashSizeSpinBox.setObjectName(u"hashSizeSpinBox")
|
||||
sizePolicy1 = QSizePolicy(QSizePolicy.Maximum, QSizePolicy.Fixed)
|
||||
sizePolicy1.setHorizontalStretch(0)
|
||||
sizePolicy1.setVerticalStretch(0)
|
||||
sizePolicy1.setHeightForWidth(self.hashSizeSpinBox.sizePolicy().hasHeightForWidth())
|
||||
self.hashSizeSpinBox.setSizePolicy(sizePolicy1)
|
||||
self.hashSizeSpinBox.setMinimum(2)
|
||||
self.hashSizeSpinBox.setMaximum(64)
|
||||
self.hashSizeSpinBox.setValue(16)
|
||||
|
||||
self.horizontalLayout_6.addWidget(self.hashSizeSpinBox)
|
||||
|
||||
|
||||
self.verticalLayout_2.addLayout(self.horizontalLayout_6)
|
||||
|
||||
self.horizontalLayout_7 = QHBoxLayout()
|
||||
self.horizontalLayout_7.setObjectName(u"horizontalLayout_7")
|
||||
self.label_4 = QLabel(self.groupBox_2)
|
||||
self.label_4.setObjectName(u"label_4")
|
||||
self.label_4.setText(u"highfreq_factor")
|
||||
self.label_4.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||
|
||||
self.horizontalLayout_7.addWidget(self.label_4)
|
||||
|
||||
self.highfreqFactorSpinBox = QSpinBox(self.groupBox_2)
|
||||
self.highfreqFactorSpinBox.setObjectName(u"highfreqFactorSpinBox")
|
||||
sizePolicy1.setHeightForWidth(self.highfreqFactorSpinBox.sizePolicy().hasHeightForWidth())
|
||||
self.highfreqFactorSpinBox.setSizePolicy(sizePolicy1)
|
||||
self.highfreqFactorSpinBox.setMaximum(32)
|
||||
self.highfreqFactorSpinBox.setValue(4)
|
||||
|
||||
self.horizontalLayout_7.addWidget(self.highfreqFactorSpinBox)
|
||||
|
||||
|
||||
self.verticalLayout_2.addLayout(self.horizontalLayout_7)
|
||||
|
||||
|
||||
self.horizontalLayout_3.addLayout(self.verticalLayout_2)
|
||||
|
||||
self.preprocessCharIconCheckBox = QCheckBox(self.groupBox_2)
|
||||
self.preprocessCharIconCheckBox.setObjectName(u"preprocessCharIconCheckBox")
|
||||
self.preprocessCharIconCheckBox.setChecked(True)
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.preprocessCharIconCheckBox)
|
||||
|
||||
self.horizontalSpacer_3 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
|
||||
self.horizontalLayout_3.addItem(self.horizontalSpacer_3)
|
||||
|
||||
self.optionsResetButton = QPushButton(self.groupBox_2)
|
||||
self.optionsResetButton.setObjectName(u"optionsResetButton")
|
||||
|
||||
self.horizontalLayout_3.addWidget(self.optionsResetButton)
|
||||
|
||||
|
||||
self.verticalLayout_3.addWidget(self.groupBox_2)
|
||||
|
||||
self.readImageProgressBar = QProgressBar(TabOcr_BuildPHashDatabase)
|
||||
self.readImageProgressBar.setObjectName(u"readImageProgressBar")
|
||||
self.readImageProgressBar.setMaximum(0)
|
||||
self.readImageProgressBar.setValue(0)
|
||||
self.readImageProgressBar.setAlignment(Qt.AlignCenter)
|
||||
|
||||
self.verticalLayout_3.addWidget(self.readImageProgressBar)
|
||||
|
||||
self.calculateHashProgressBar = QProgressBar(TabOcr_BuildPHashDatabase)
|
||||
self.calculateHashProgressBar.setObjectName(u"calculateHashProgressBar")
|
||||
self.calculateHashProgressBar.setMaximum(0)
|
||||
self.calculateHashProgressBar.setValue(0)
|
||||
self.calculateHashProgressBar.setAlignment(Qt.AlignCenter)
|
||||
|
||||
self.verticalLayout_3.addWidget(self.calculateHashProgressBar)
|
||||
|
||||
self.horizontalLayout_5 = QHBoxLayout()
|
||||
self.horizontalLayout_5.setObjectName(u"horizontalLayout_5")
|
||||
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
|
||||
self.horizontalLayout_5.addItem(self.horizontalSpacer)
|
||||
|
||||
self.buildButton = QPushButton(TabOcr_BuildPHashDatabase)
|
||||
self.buildButton.setObjectName(u"buildButton")
|
||||
|
||||
self.horizontalLayout_5.addWidget(self.buildButton)
|
||||
|
||||
self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
||||
|
||||
self.horizontalLayout_5.addItem(self.horizontalSpacer_2)
|
||||
|
||||
|
||||
self.verticalLayout_3.addLayout(self.horizontalLayout_5)
|
||||
|
||||
self.verticalSpacer_2 = QSpacerItem(20, 40, QSizePolicy.Minimum, QSizePolicy.Expanding)
|
||||
|
||||
self.verticalLayout_3.addItem(self.verticalSpacer_2)
|
||||
|
||||
|
||||
self.retranslateUi(TabOcr_BuildPHashDatabase)
|
||||
|
||||
QMetaObject.connectSlotsByName(TabOcr_BuildPHashDatabase)
|
||||
# setupUi
|
||||
|
||||
def retranslateUi(self, TabOcr_BuildPHashDatabase):
|
||||
self.groupBox.setTitle(QCoreApplication.translate("TabOcr_BuildPHashDatabase", u"folders.title", None))
|
||||
self.label.setText(QCoreApplication.translate("TabOcr_BuildPHashDatabase", u"folders.songDir", None))
|
||||
self.label_2.setText(QCoreApplication.translate("TabOcr_BuildPHashDatabase", u"folders.charIconDir", None))
|
||||
self.groupBox_2.setTitle(QCoreApplication.translate("TabOcr_BuildPHashDatabase", u"options.title", None))
|
||||
self.preprocessCharIconCheckBox.setText(QCoreApplication.translate("TabOcr_BuildPHashDatabase", u"options.preprocessCharIcon", None))
|
||||
self.optionsResetButton.setText(QCoreApplication.translate("TabOcr_BuildPHashDatabase", u"resetButton", None))
|
||||
self.readImageProgressBar.setFormat(QCoreApplication.translate("TabOcr_BuildPHashDatabase", u"[Reading images] %v/%m - %p%", None))
|
||||
self.calculateHashProgressBar.setFormat(QCoreApplication.translate("TabOcr_BuildPHashDatabase", u"[Calculate hashes] %v/%m - %p%", None))
|
||||
self.buildButton.setText(QCoreApplication.translate("TabOcr_BuildPHashDatabase", u"buildButton", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
@ -24,130 +24,237 @@
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string>deviceSelector.title</string>
|
||||
<string>options.title</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QCheckBox" name="deviceUseAutoFactorCheckBox">
|
||||
<widget class="QCheckBox" name="options_usePresetCheckBox">
|
||||
<property name="text">
|
||||
<string>deviceSelector.useAutoFactor</string>
|
||||
<string>options.usePreset</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="deviceSizesV2CheckBox">
|
||||
<property name="text">
|
||||
<string notr="true">SizesV2</string>
|
||||
<widget class="QComboBox" name="options_presetComboBox">
|
||||
<property name="enabled">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="FileSelector" name="deviceFileSelector" native="true"/>
|
||||
<widget class="Line" name="line_3">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="DevicesComboBox" name="deviceComboBox"/>
|
||||
<widget class="QWidget" name="options_preciseControlWidget" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout_2" columnstretch="0,1,0">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>options.rois</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QStackedWidget" name="options_roisStackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="options_roisComboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="FileSelector" name="options_roisCustomSelector" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_2">
|
||||
<property name="text">
|
||||
<string>options.masker</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="2">
|
||||
<widget class="QCheckBox" name="options_roisUseCustomCheckBox">
|
||||
<property name="text">
|
||||
<string>options.useCustom</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QCheckBox" name="options_maskerUseCustomCheckBox">
|
||||
<property name="text">
|
||||
<string>options.useCustom</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QStackedWidget" name="options_maskerStackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="page_3">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QComboBox" name="options_maskerComboBox"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="page_4">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="FileSelector" name="options_maskerCustomSelector" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="horizontalWidget" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
<widget class="QGroupBox" name="groupBox_2">
|
||||
<property name="title">
|
||||
<string>dependencies.title</string>
|
||||
</property>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_6">
|
||||
<property name="title">
|
||||
<string>knnModelSelector.title</string>
|
||||
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0,0,1">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>dependencies.knnModel</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="FileSelector" name="knnModelSelector" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QStackedWidget" name="deviceDependenciesStackedWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
<item row="0" column="2">
|
||||
<widget class="QLabel" name="dependencies_knnModelStatusLabel">
|
||||
<property name="text">
|
||||
<string notr="true">...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="2">
|
||||
<widget class="QLabel" name="dependencies_phashDatabaseStatusLabel">
|
||||
<property name="text">
|
||||
<string notr="true">...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="4">
|
||||
<widget class="FileSelector" name="dependencies_phashDatabaseSelector" native="true"/>
|
||||
</item>
|
||||
<item row="0" column="1" rowspan="2">
|
||||
<widget class="Line" name="line">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="4">
|
||||
<widget class="FileSelector" name="dependencies_knnModelSelector" native="true"/>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="text">
|
||||
<string>dependencies.phashDatabase</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="3" rowspan="2">
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<widget class="QWidget" name="deviceV1">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_4">
|
||||
<property name="title">
|
||||
<string>tesseractSelector.title</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="FileSelector" name="tesseractFileSelector" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="deviceV2">
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<property name="leftMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="topMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="rightMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="bottomMargin">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox_5">
|
||||
<property name="title">
|
||||
<string>phashDatabaseSelector.title</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<widget class="FileSelector" name="phashDatabaseSelector" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -178,12 +285,24 @@
|
||||
<header>ui.implements.components.ocrQueue</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>DevicesComboBox</class>
|
||||
<extends>QComboBox</extends>
|
||||
<header>ui.implements.components.devicesComboBox</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>options_usePresetCheckBox</sender>
|
||||
<signal>toggled(bool)</signal>
|
||||
<receiver>options_presetComboBox</receiver>
|
||||
<slot>setEnabled(bool)</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>82</x>
|
||||
<y>111</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>82</x>
|
||||
<y>175</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
|
@ -15,11 +15,11 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
||||
QFont, QFontDatabase, QGradient, QIcon,
|
||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||
from PySide6.QtWidgets import (QApplication, QCheckBox, QGroupBox, QHBoxLayout,
|
||||
from PySide6.QtWidgets import (QApplication, QCheckBox, QComboBox, QFrame,
|
||||
QGridLayout, QGroupBox, QHBoxLayout, QLabel,
|
||||
QPushButton, QSizePolicy, QStackedWidget, QVBoxLayout,
|
||||
QWidget)
|
||||
|
||||
from ui.implements.components.devicesComboBox import DevicesComboBox
|
||||
from ui.implements.components.fileSelector import FileSelector
|
||||
from ui.implements.components.ocrQueue import OcrQueue
|
||||
|
||||
@ -38,117 +38,191 @@ class Ui_TabOcr_Device(object):
|
||||
|
||||
self.groupBox = QGroupBox(TabOcr_Device)
|
||||
self.groupBox.setObjectName(u"groupBox")
|
||||
self.verticalLayout = QVBoxLayout(self.groupBox)
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.horizontalLayout = QHBoxLayout()
|
||||
self.horizontalLayout = QHBoxLayout(self.groupBox)
|
||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||
self.deviceUseAutoFactorCheckBox = QCheckBox(self.groupBox)
|
||||
self.deviceUseAutoFactorCheckBox.setObjectName(u"deviceUseAutoFactorCheckBox")
|
||||
self.verticalLayout = QVBoxLayout()
|
||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||
self.options_usePresetCheckBox = QCheckBox(self.groupBox)
|
||||
self.options_usePresetCheckBox.setObjectName(u"options_usePresetCheckBox")
|
||||
|
||||
self.horizontalLayout.addWidget(self.deviceUseAutoFactorCheckBox)
|
||||
self.verticalLayout.addWidget(self.options_usePresetCheckBox)
|
||||
|
||||
self.deviceSizesV2CheckBox = QCheckBox(self.groupBox)
|
||||
self.deviceSizesV2CheckBox.setObjectName(u"deviceSizesV2CheckBox")
|
||||
self.deviceSizesV2CheckBox.setText(u"SizesV2")
|
||||
self.options_presetComboBox = QComboBox(self.groupBox)
|
||||
self.options_presetComboBox.setObjectName(u"options_presetComboBox")
|
||||
self.options_presetComboBox.setEnabled(False)
|
||||
|
||||
self.horizontalLayout.addWidget(self.deviceSizesV2CheckBox)
|
||||
self.verticalLayout.addWidget(self.options_presetComboBox)
|
||||
|
||||
|
||||
self.verticalLayout.addLayout(self.horizontalLayout)
|
||||
self.horizontalLayout.addLayout(self.verticalLayout)
|
||||
|
||||
self.deviceFileSelector = FileSelector(self.groupBox)
|
||||
self.deviceFileSelector.setObjectName(u"deviceFileSelector")
|
||||
self.line_3 = QFrame(self.groupBox)
|
||||
self.line_3.setObjectName(u"line_3")
|
||||
self.line_3.setFrameShape(QFrame.VLine)
|
||||
self.line_3.setFrameShadow(QFrame.Sunken)
|
||||
|
||||
self.verticalLayout.addWidget(self.deviceFileSelector)
|
||||
self.horizontalLayout.addWidget(self.line_3)
|
||||
|
||||
self.deviceComboBox = DevicesComboBox(self.groupBox)
|
||||
self.deviceComboBox.setObjectName(u"deviceComboBox")
|
||||
self.options_preciseControlWidget = QWidget(self.groupBox)
|
||||
self.options_preciseControlWidget.setObjectName(u"options_preciseControlWidget")
|
||||
self.gridLayout_2 = QGridLayout(self.options_preciseControlWidget)
|
||||
self.gridLayout_2.setObjectName(u"gridLayout_2")
|
||||
self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.label = QLabel(self.options_preciseControlWidget)
|
||||
self.label.setObjectName(u"label")
|
||||
self.label.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||
|
||||
self.verticalLayout.addWidget(self.deviceComboBox)
|
||||
self.gridLayout_2.addWidget(self.label, 0, 0, 1, 1)
|
||||
|
||||
self.options_roisStackedWidget = QStackedWidget(self.options_preciseControlWidget)
|
||||
self.options_roisStackedWidget.setObjectName(u"options_roisStackedWidget")
|
||||
self.page = QWidget()
|
||||
self.page.setObjectName(u"page")
|
||||
self.verticalLayout_2 = QVBoxLayout(self.page)
|
||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.options_roisComboBox = QComboBox(self.page)
|
||||
self.options_roisComboBox.setObjectName(u"options_roisComboBox")
|
||||
|
||||
self.verticalLayout_2.addWidget(self.options_roisComboBox)
|
||||
|
||||
self.options_roisStackedWidget.addWidget(self.page)
|
||||
self.page_2 = QWidget()
|
||||
self.page_2.setObjectName(u"page_2")
|
||||
self.verticalLayout_4 = QVBoxLayout(self.page_2)
|
||||
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
|
||||
self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)
|
||||
self.options_roisCustomSelector = FileSelector(self.page_2)
|
||||
self.options_roisCustomSelector.setObjectName(u"options_roisCustomSelector")
|
||||
|
||||
self.verticalLayout_4.addWidget(self.options_roisCustomSelector)
|
||||
|
||||
self.options_roisStackedWidget.addWidget(self.page_2)
|
||||
|
||||
self.gridLayout_2.addWidget(self.options_roisStackedWidget, 0, 1, 1, 1)
|
||||
|
||||
self.label_2 = QLabel(self.options_preciseControlWidget)
|
||||
self.label_2.setObjectName(u"label_2")
|
||||
self.label_2.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||
|
||||
self.gridLayout_2.addWidget(self.label_2, 1, 0, 1, 1)
|
||||
|
||||
self.options_roisUseCustomCheckBox = QCheckBox(self.options_preciseControlWidget)
|
||||
self.options_roisUseCustomCheckBox.setObjectName(u"options_roisUseCustomCheckBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.options_roisUseCustomCheckBox, 0, 2, 1, 1)
|
||||
|
||||
self.options_maskerUseCustomCheckBox = QCheckBox(self.options_preciseControlWidget)
|
||||
self.options_maskerUseCustomCheckBox.setObjectName(u"options_maskerUseCustomCheckBox")
|
||||
|
||||
self.gridLayout_2.addWidget(self.options_maskerUseCustomCheckBox, 1, 2, 1, 1)
|
||||
|
||||
self.options_maskerStackedWidget = QStackedWidget(self.options_preciseControlWidget)
|
||||
self.options_maskerStackedWidget.setObjectName(u"options_maskerStackedWidget")
|
||||
self.page_3 = QWidget()
|
||||
self.page_3.setObjectName(u"page_3")
|
||||
self.verticalLayout_5 = QVBoxLayout(self.page_3)
|
||||
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
|
||||
self.verticalLayout_5.setContentsMargins(0, 0, 0, 0)
|
||||
self.options_maskerComboBox = QComboBox(self.page_3)
|
||||
self.options_maskerComboBox.setObjectName(u"options_maskerComboBox")
|
||||
|
||||
self.verticalLayout_5.addWidget(self.options_maskerComboBox)
|
||||
|
||||
self.options_maskerStackedWidget.addWidget(self.page_3)
|
||||
self.page_4 = QWidget()
|
||||
self.page_4.setObjectName(u"page_4")
|
||||
self.verticalLayout_6 = QVBoxLayout(self.page_4)
|
||||
self.verticalLayout_6.setObjectName(u"verticalLayout_6")
|
||||
self.verticalLayout_6.setContentsMargins(0, 0, 0, 0)
|
||||
self.options_maskerCustomSelector = FileSelector(self.page_4)
|
||||
self.options_maskerCustomSelector.setObjectName(u"options_maskerCustomSelector")
|
||||
|
||||
self.verticalLayout_6.addWidget(self.options_maskerCustomSelector)
|
||||
|
||||
self.options_maskerStackedWidget.addWidget(self.page_4)
|
||||
|
||||
self.gridLayout_2.addWidget(self.options_maskerStackedWidget, 1, 1, 1, 1)
|
||||
|
||||
self.gridLayout_2.setColumnStretch(1, 1)
|
||||
|
||||
self.horizontalLayout.addWidget(self.options_preciseControlWidget)
|
||||
|
||||
|
||||
self.verticalLayout_3.addWidget(self.groupBox)
|
||||
|
||||
self.horizontalWidget = QWidget(TabOcr_Device)
|
||||
self.horizontalWidget.setObjectName(u"horizontalWidget")
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.horizontalWidget.sizePolicy().hasHeightForWidth())
|
||||
self.horizontalWidget.setSizePolicy(sizePolicy)
|
||||
self.horizontalLayout_2 = QHBoxLayout(self.horizontalWidget)
|
||||
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
|
||||
self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.groupBox_6 = QGroupBox(self.horizontalWidget)
|
||||
self.groupBox_6.setObjectName(u"groupBox_6")
|
||||
self.verticalLayout_6 = QVBoxLayout(self.groupBox_6)
|
||||
self.verticalLayout_6.setObjectName(u"verticalLayout_6")
|
||||
self.knnModelSelector = FileSelector(self.groupBox_6)
|
||||
self.knnModelSelector.setObjectName(u"knnModelSelector")
|
||||
self.groupBox_2 = QGroupBox(TabOcr_Device)
|
||||
self.groupBox_2.setObjectName(u"groupBox_2")
|
||||
self.gridLayout = QGridLayout(self.groupBox_2)
|
||||
self.gridLayout.setObjectName(u"gridLayout")
|
||||
self.label_3 = QLabel(self.groupBox_2)
|
||||
self.label_3.setObjectName(u"label_3")
|
||||
self.label_3.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||
|
||||
self.verticalLayout_6.addWidget(self.knnModelSelector)
|
||||
self.gridLayout.addWidget(self.label_3, 0, 0, 1, 1)
|
||||
|
||||
self.dependencies_knnModelStatusLabel = QLabel(self.groupBox_2)
|
||||
self.dependencies_knnModelStatusLabel.setObjectName(u"dependencies_knnModelStatusLabel")
|
||||
self.dependencies_knnModelStatusLabel.setText(u"...")
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.groupBox_6)
|
||||
self.gridLayout.addWidget(self.dependencies_knnModelStatusLabel, 0, 2, 1, 1)
|
||||
|
||||
self.deviceDependenciesStackedWidget = QStackedWidget(self.horizontalWidget)
|
||||
self.deviceDependenciesStackedWidget.setObjectName(u"deviceDependenciesStackedWidget")
|
||||
self.deviceV1 = QWidget()
|
||||
self.deviceV1.setObjectName(u"deviceV1")
|
||||
self.verticalLayout_2 = QVBoxLayout(self.deviceV1)
|
||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||
self.verticalLayout_2.setContentsMargins(0, 0, 0, 0)
|
||||
self.groupBox_4 = QGroupBox(self.deviceV1)
|
||||
self.groupBox_4.setObjectName(u"groupBox_4")
|
||||
self.verticalLayout_5 = QVBoxLayout(self.groupBox_4)
|
||||
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
|
||||
self.tesseractFileSelector = FileSelector(self.groupBox_4)
|
||||
self.tesseractFileSelector.setObjectName(u"tesseractFileSelector")
|
||||
self.dependencies_phashDatabaseStatusLabel = QLabel(self.groupBox_2)
|
||||
self.dependencies_phashDatabaseStatusLabel.setObjectName(u"dependencies_phashDatabaseStatusLabel")
|
||||
self.dependencies_phashDatabaseStatusLabel.setText(u"...")
|
||||
|
||||
self.verticalLayout_5.addWidget(self.tesseractFileSelector)
|
||||
self.gridLayout.addWidget(self.dependencies_phashDatabaseStatusLabel, 1, 2, 1, 1)
|
||||
|
||||
self.dependencies_phashDatabaseSelector = FileSelector(self.groupBox_2)
|
||||
self.dependencies_phashDatabaseSelector.setObjectName(u"dependencies_phashDatabaseSelector")
|
||||
|
||||
self.verticalLayout_2.addWidget(self.groupBox_4)
|
||||
self.gridLayout.addWidget(self.dependencies_phashDatabaseSelector, 1, 4, 1, 1)
|
||||
|
||||
self.deviceDependenciesStackedWidget.addWidget(self.deviceV1)
|
||||
self.deviceV2 = QWidget()
|
||||
self.deviceV2.setObjectName(u"deviceV2")
|
||||
self.verticalLayout_4 = QVBoxLayout(self.deviceV2)
|
||||
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
|
||||
self.verticalLayout_4.setContentsMargins(0, 0, 0, 0)
|
||||
self.groupBox_5 = QGroupBox(self.deviceV2)
|
||||
self.groupBox_5.setObjectName(u"groupBox_5")
|
||||
self.verticalLayout_7 = QVBoxLayout(self.groupBox_5)
|
||||
self.verticalLayout_7.setObjectName(u"verticalLayout_7")
|
||||
self.phashDatabaseSelector = FileSelector(self.groupBox_5)
|
||||
self.phashDatabaseSelector.setObjectName(u"phashDatabaseSelector")
|
||||
self.line = QFrame(self.groupBox_2)
|
||||
self.line.setObjectName(u"line")
|
||||
self.line.setFrameShape(QFrame.VLine)
|
||||
self.line.setFrameShadow(QFrame.Sunken)
|
||||
|
||||
self.verticalLayout_7.addWidget(self.phashDatabaseSelector)
|
||||
self.gridLayout.addWidget(self.line, 0, 1, 2, 1)
|
||||
|
||||
self.dependencies_knnModelSelector = FileSelector(self.groupBox_2)
|
||||
self.dependencies_knnModelSelector.setObjectName(u"dependencies_knnModelSelector")
|
||||
|
||||
self.verticalLayout_4.addWidget(self.groupBox_5)
|
||||
self.gridLayout.addWidget(self.dependencies_knnModelSelector, 0, 4, 1, 1)
|
||||
|
||||
self.deviceDependenciesStackedWidget.addWidget(self.deviceV2)
|
||||
self.label_4 = QLabel(self.groupBox_2)
|
||||
self.label_4.setObjectName(u"label_4")
|
||||
self.label_4.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||
|
||||
self.horizontalLayout_2.addWidget(self.deviceDependenciesStackedWidget)
|
||||
self.gridLayout.addWidget(self.label_4, 1, 0, 1, 1)
|
||||
|
||||
self.line_2 = QFrame(self.groupBox_2)
|
||||
self.line_2.setObjectName(u"line_2")
|
||||
self.line_2.setFrameShape(QFrame.VLine)
|
||||
self.line_2.setFrameShadow(QFrame.Sunken)
|
||||
|
||||
self.verticalLayout_3.addWidget(self.horizontalWidget)
|
||||
self.gridLayout.addWidget(self.line_2, 0, 3, 2, 1)
|
||||
|
||||
self.gridLayout.setColumnStretch(4, 1)
|
||||
|
||||
self.verticalLayout_3.addWidget(self.groupBox_2)
|
||||
|
||||
self.ocrQueue = OcrQueue(TabOcr_Device)
|
||||
self.ocrQueue.setObjectName(u"ocrQueue")
|
||||
sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
|
||||
sizePolicy1.setHorizontalStretch(0)
|
||||
sizePolicy1.setVerticalStretch(0)
|
||||
sizePolicy1.setHeightForWidth(self.ocrQueue.sizePolicy().hasHeightForWidth())
|
||||
self.ocrQueue.setSizePolicy(sizePolicy1)
|
||||
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
|
||||
sizePolicy.setHorizontalStretch(0)
|
||||
sizePolicy.setVerticalStretch(0)
|
||||
sizePolicy.setHeightForWidth(self.ocrQueue.sizePolicy().hasHeightForWidth())
|
||||
self.ocrQueue.setSizePolicy(sizePolicy)
|
||||
|
||||
self.verticalLayout_3.addWidget(self.ocrQueue)
|
||||
|
||||
|
||||
self.retranslateUi(TabOcr_Device)
|
||||
self.options_usePresetCheckBox.toggled.connect(self.options_presetComboBox.setEnabled)
|
||||
|
||||
self.deviceDependenciesStackedWidget.setCurrentIndex(0)
|
||||
self.options_roisStackedWidget.setCurrentIndex(0)
|
||||
self.options_maskerStackedWidget.setCurrentIndex(0)
|
||||
|
||||
|
||||
QMetaObject.connectSlotsByName(TabOcr_Device)
|
||||
@ -156,11 +230,15 @@ class Ui_TabOcr_Device(object):
|
||||
|
||||
def retranslateUi(self, TabOcr_Device):
|
||||
self.openWizardButton.setText(QCoreApplication.translate("TabOcr_Device", u"openWizardButton", None))
|
||||
self.groupBox.setTitle(QCoreApplication.translate("TabOcr_Device", u"deviceSelector.title", None))
|
||||
self.deviceUseAutoFactorCheckBox.setText(QCoreApplication.translate("TabOcr_Device", u"deviceSelector.useAutoFactor", None))
|
||||
self.groupBox_6.setTitle(QCoreApplication.translate("TabOcr_Device", u"knnModelSelector.title", None))
|
||||
self.groupBox_4.setTitle(QCoreApplication.translate("TabOcr_Device", u"tesseractSelector.title", None))
|
||||
self.groupBox_5.setTitle(QCoreApplication.translate("TabOcr_Device", u"phashDatabaseSelector.title", None))
|
||||
self.groupBox.setTitle(QCoreApplication.translate("TabOcr_Device", u"options.title", None))
|
||||
self.options_usePresetCheckBox.setText(QCoreApplication.translate("TabOcr_Device", u"options.usePreset", None))
|
||||
self.label.setText(QCoreApplication.translate("TabOcr_Device", u"options.rois", None))
|
||||
self.label_2.setText(QCoreApplication.translate("TabOcr_Device", u"options.masker", None))
|
||||
self.options_roisUseCustomCheckBox.setText(QCoreApplication.translate("TabOcr_Device", u"options.useCustom", None))
|
||||
self.options_maskerUseCustomCheckBox.setText(QCoreApplication.translate("TabOcr_Device", u"options.useCustom", None))
|
||||
self.groupBox_2.setTitle(QCoreApplication.translate("TabOcr_Device", u"dependencies.title", None))
|
||||
self.label_3.setText(QCoreApplication.translate("TabOcr_Device", u"dependencies.knnModel", None))
|
||||
self.label_4.setText(QCoreApplication.translate("TabOcr_Device", u"dependencies.phashDatabase", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
||||
|
@ -29,6 +29,11 @@
|
||||
<string>tab.b30</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="TabOcr_BuildPHashDatabase" name="tab_3">
|
||||
<attribute name="title">
|
||||
<string>tab.buildPHashDatabase</string>
|
||||
</attribute>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
@ -46,6 +51,12 @@
|
||||
<header>ui.implements.tabs.tabOcr.tabOcr_B30</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>TabOcr_BuildPHashDatabase</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>ui.implements.tabs.tabOcr.tabOcr_BuildPHashDatabase</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
@ -3,7 +3,7 @@
|
||||
################################################################################
|
||||
## Form generated from reading UI file 'tabOcrEntry.ui'
|
||||
##
|
||||
## Created by: Qt User Interface Compiler version 6.5.1
|
||||
## Created by: Qt User Interface Compiler version 6.5.2
|
||||
##
|
||||
## WARNING! All changes made in this file will be lost when recompiling UI file!
|
||||
################################################################################
|
||||
@ -19,6 +19,7 @@ from PySide6.QtWidgets import (QApplication, QSizePolicy, QTabWidget, QVBoxLayou
|
||||
QWidget)
|
||||
|
||||
from ui.implements.tabs.tabOcr.tabOcr_B30 import TabOcr_B30
|
||||
from ui.implements.tabs.tabOcr.tabOcr_BuildPHashDatabase import TabOcr_BuildPHashDatabase
|
||||
from ui.implements.tabs.tabOcr.tabOcr_Device import TabOcr_Device
|
||||
|
||||
class Ui_TabOcrEntry(object):
|
||||
@ -37,6 +38,9 @@ class Ui_TabOcrEntry(object):
|
||||
self.tab_2 = TabOcr_B30()
|
||||
self.tab_2.setObjectName(u"tab_2")
|
||||
self.tabWidget.addTab(self.tab_2, "")
|
||||
self.tab_3 = TabOcr_BuildPHashDatabase()
|
||||
self.tab_3.setObjectName(u"tab_3")
|
||||
self.tabWidget.addTab(self.tab_3, "")
|
||||
|
||||
self.verticalLayout.addWidget(self.tabWidget)
|
||||
|
||||
@ -52,6 +56,7 @@ class Ui_TabOcrEntry(object):
|
||||
def retranslateUi(self, TabOcrEntry):
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), QCoreApplication.translate("TabOcrEntry", u"tab.device", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QCoreApplication.translate("TabOcrEntry", u"tab.b30", None))
|
||||
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_3), QCoreApplication.translate("TabOcrEntry", u"tab.buildPHashDatabase", None))
|
||||
pass
|
||||
# retranslateUi
|
||||
|
||||
|
@ -6,7 +6,7 @@ from arcaea_offline.calculate import calculate_score_range
|
||||
from arcaea_offline.database import Database
|
||||
from arcaea_offline.models import Chart, Score
|
||||
from arcaea_offline_ocr.b30.shared import B30OcrResultItem
|
||||
from arcaea_offline_ocr.device.shared import DeviceOcrResult
|
||||
from arcaea_offline_ocr.device.common import DeviceOcrResult
|
||||
from arcaea_offline_ocr.utils import convert_to_srgb
|
||||
from PIL import Image
|
||||
from PIL.ImageQt import ImageQt
|
||||
|
@ -1,3 +1,5 @@
|
||||
from .build_phash import build_image_phash_database
|
||||
|
||||
try:
|
||||
import json
|
||||
|
76
ui/extends/ocr/build_phash.py
Normal file
76
ui/extends/ocr/build_phash.py
Normal file
@ -0,0 +1,76 @@
|
||||
import sqlite3
|
||||
import time
|
||||
from typing import Any, Callable, Optional
|
||||
|
||||
import cv2
|
||||
import numpy as np
|
||||
from arcaea_offline_ocr.phash_db import phash_opencv
|
||||
|
||||
|
||||
def preprocess_char_icon(img_gray: cv2.Mat):
|
||||
h, w = img_gray.shape[:2]
|
||||
img = cv2.fillPoly(
|
||||
img_gray,
|
||||
[
|
||||
np.array([[0, 0], [round(w / 2), 0], [0, round(h / 2)]], np.int32),
|
||||
np.array([[w, 0], [round(w / 2), 0], [w, round(h / 2)]], np.int32),
|
||||
np.array([[0, h], [round(w / 2), h], [0, round(h / 2)]], np.int32),
|
||||
np.array([[w, h], [round(w / 2), h], [w, round(h / 2)]], np.int32),
|
||||
],
|
||||
(128),
|
||||
)
|
||||
return img
|
||||
|
||||
|
||||
def build_image_phash_database(
|
||||
images: list[cv2.Mat],
|
||||
labels: list[str],
|
||||
*,
|
||||
hash_size: int = 16,
|
||||
highfreq_factor: int = 4,
|
||||
progress_func: Optional[Callable[[int, int], Any]] = None,
|
||||
):
|
||||
assert len(images) == len(labels)
|
||||
|
||||
conn = sqlite3.connect(":memory:", check_same_thread=False)
|
||||
|
||||
with conn:
|
||||
cursor = conn.cursor()
|
||||
|
||||
cursor.execute("CREATE TABLE properties (key TEXT, value TEXT)")
|
||||
cursor.executemany(
|
||||
"INSERT INTO properties VALUES (?, ?)",
|
||||
[
|
||||
("hash_size", hash_size),
|
||||
("highfreq_factor", highfreq_factor),
|
||||
],
|
||||
)
|
||||
|
||||
image_num = len(images)
|
||||
id_hashes = []
|
||||
for i, label, image in zip(range(image_num), labels, images):
|
||||
image_hash = phash_opencv(
|
||||
image,
|
||||
hash_size=hash_size,
|
||||
highfreq_factor=highfreq_factor,
|
||||
)
|
||||
image_hash_bytes = image_hash.flatten().tobytes()
|
||||
|
||||
id_hashes.append([label, image_hash_bytes])
|
||||
if progress_func:
|
||||
progress_func(i + 1, image_num)
|
||||
|
||||
hash_length = len(id_hashes[0][1])
|
||||
cursor.execute(f"CREATE TABLE hashes (id TEXT, hash BLOB({hash_length}))")
|
||||
|
||||
cursor.executemany(
|
||||
"INSERT INTO hashes VALUES (?, ?)",
|
||||
id_hashes,
|
||||
)
|
||||
cursor.executemany(
|
||||
"INSERT INTO properties VALUES (?, ?)",
|
||||
[("built_timestamp", int(time.time()))],
|
||||
)
|
||||
conn.commit()
|
||||
|
||||
return conn
|
47
ui/extends/shared/data.py
Normal file
47
ui/extends/shared/data.py
Normal file
@ -0,0 +1,47 @@
|
||||
import json
|
||||
import sys
|
||||
from functools import cached_property
|
||||
from pathlib import Path
|
||||
from typing import Literal
|
||||
|
||||
from PySide6.QtCore import QFile
|
||||
|
||||
from .singleton import Singleton
|
||||
|
||||
TPartnerModifier = dict[str, Literal[0, 1, 2]]
|
||||
|
||||
|
||||
class Data(metaclass=Singleton):
|
||||
def __init__(self):
|
||||
root = Path(sys.argv[0]).parent
|
||||
self.__dataPath = (root / "data").resolve()
|
||||
|
||||
@property
|
||||
def dataPath(self):
|
||||
return self.__dataPath
|
||||
|
||||
@cached_property
|
||||
def partnerModifiers(self) -> TPartnerModifier:
|
||||
data = {}
|
||||
builtinFile = QFile(":/partnerModifiers.json")
|
||||
builtinFile.open(QFile.OpenModeFlag.ReadOnly)
|
||||
builtinData = json.loads(str(builtinFile.readAll(), encoding="utf-8"))
|
||||
builtinFile.close()
|
||||
data |= builtinData
|
||||
|
||||
customFile = self.dataPath / "partnerModifiers.json"
|
||||
if customFile.exists():
|
||||
with open(customFile, "r", encoding="utf-8") as f:
|
||||
customData = json.loads(f.read())
|
||||
data |= customData
|
||||
|
||||
return data
|
||||
|
||||
def expirePartnerModifiersCache(self):
|
||||
# expire property caches
|
||||
# https://stackoverflow.com/a/69367025/16484891, CC BY-SA 4.0
|
||||
self.__dict__.pop("partnerModifiers", None)
|
||||
|
||||
@property
|
||||
def arcaeaPath(self):
|
||||
return self.dataPath / "Arcaea"
|
@ -1,19 +1,15 @@
|
||||
from typing import Union
|
||||
|
||||
from arcaea_offline.calculate import calculate_score_range
|
||||
from arcaea_offline.models import Chart, Score
|
||||
from arcaea_offline.utils.rating import rating_class_to_text
|
||||
from arcaea_offline.utils.score import score_to_grade_text, zip_score_grade
|
||||
from arcaea_offline.utils.score import (
|
||||
clear_type_to_text,
|
||||
modifier_to_text,
|
||||
score_to_grade_text,
|
||||
zip_score_grade,
|
||||
)
|
||||
from PySide6.QtCore import QAbstractItemModel, QDateTime, QModelIndex, Qt, Signal
|
||||
from PySide6.QtGui import QColor, QFont, QLinearGradient
|
||||
from PySide6.QtWidgets import (
|
||||
QFrame,
|
||||
QHBoxLayout,
|
||||
QLabel,
|
||||
QPushButton,
|
||||
QSizePolicy,
|
||||
QWidget,
|
||||
)
|
||||
from PySide6.QtWidgets import QHBoxLayout, QLabel, QPushButton, QSizePolicy, QWidget
|
||||
|
||||
from ui.implements.components.scoreEditor import ScoreEditor
|
||||
|
||||
@ -27,12 +23,6 @@ class ScoreEditorDelegateWrapper(ScoreEditor):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
|
||||
# self.hLine = QFrame(self)
|
||||
# self.hLine.setFrameShape(QFrame.Shape.HLine)
|
||||
# self.hLine.setFrameShadow(QFrame.Shadow.Plain)
|
||||
# self.hLine.setFixedHeight(5)
|
||||
# self.gridLayout.addWidget(self.hLine, self.gridLayout.rowCount(), 0, -1, -1)
|
||||
|
||||
self.delegateHeader = QWidget(self)
|
||||
self.delegateHeaderHBoxLayout = QHBoxLayout(self.delegateHeader)
|
||||
self.delegateHeaderHBoxLayout.setContentsMargins(0, 0, 0, 0)
|
||||
@ -55,7 +45,9 @@ class ScoreEditorDelegateWrapper(ScoreEditor):
|
||||
text = "Editing "
|
||||
text += _extra or ""
|
||||
text += f"score {score.score}"
|
||||
text += f"<br>(P{score.pure} F{score.far} L{score.lost} | MR{score.max_recall})"
|
||||
text += (
|
||||
f"<br>(P{score.pure} F{score.far} L{score.lost} | MR {score.max_recall})"
|
||||
)
|
||||
self.editorLabel.setText(text)
|
||||
|
||||
|
||||
@ -111,8 +103,8 @@ class ScoreDelegate(TextSegmentDelegate):
|
||||
|
||||
def getTextSegments(self, index, option):
|
||||
score = self.getScore(index)
|
||||
chart = self.getChart(index)
|
||||
if not (isinstance(score, Score) and isinstance(chart, Chart)):
|
||||
|
||||
if not isinstance(score, Score):
|
||||
return [
|
||||
[
|
||||
{
|
||||
@ -128,7 +120,9 @@ class ScoreDelegate(TextSegmentDelegate):
|
||||
score_font.setPointSize(12)
|
||||
score_grade_font = QFont(score_font)
|
||||
score_grade_font.setBold(True)
|
||||
return [
|
||||
placeholderColor = option.widget.palette().placeholderText().color()
|
||||
|
||||
segments = [
|
||||
[
|
||||
{
|
||||
self.TextRole: score_to_grade_text(score.score),
|
||||
@ -156,19 +150,47 @@ class ScoreDelegate(TextSegmentDelegate):
|
||||
self.ColorRole: self.PureFarLostColors[2],
|
||||
},
|
||||
{self.TextRole: " | "},
|
||||
{self.TextRole: f"MAX RECALL {score.max_recall}"},
|
||||
],
|
||||
[
|
||||
{
|
||||
self.TextRole: QDateTime.fromSecsSinceEpoch(score.date).toString(
|
||||
"yyyy-MM-dd hh:mm:ss"
|
||||
)
|
||||
if score.date
|
||||
else "-- No Date --"
|
||||
}
|
||||
{self.TextRole: f"MR {score.max_recall}"},
|
||||
],
|
||||
]
|
||||
|
||||
if score.date is not None:
|
||||
segments.append(
|
||||
[
|
||||
{
|
||||
self.TextRole: QDateTime.fromSecsSinceEpoch(
|
||||
score.date
|
||||
).toString("yyyy-MM-dd hh:mm:ss")
|
||||
}
|
||||
],
|
||||
)
|
||||
else:
|
||||
segments.append(
|
||||
[{self.TextRole: "-- No Date --", self.ColorRole: placeholderColor}],
|
||||
)
|
||||
|
||||
modifierClearTypeSegments = []
|
||||
if score.modifier is not None:
|
||||
modifierClearTypeSegments.append(
|
||||
{self.TextRole: modifier_to_text(score.modifier)}
|
||||
)
|
||||
else:
|
||||
modifierClearTypeSegments.append(
|
||||
{self.TextRole: "Modifier None", self.ColorRole: placeholderColor}
|
||||
)
|
||||
modifierClearTypeSegments.append({self.TextRole: ", "})
|
||||
if score.clear_type is not None:
|
||||
modifierClearTypeSegments.append(
|
||||
{self.TextRole: clear_type_to_text(score.clear_type)}
|
||||
)
|
||||
else:
|
||||
modifierClearTypeSegments.append(
|
||||
{self.TextRole: "Clear Type None", self.ColorRole: placeholderColor}
|
||||
)
|
||||
segments.append(modifierClearTypeSegments)
|
||||
|
||||
return segments
|
||||
|
||||
def paintWarningBackground(self, index: QModelIndex) -> bool:
|
||||
return True
|
||||
|
||||
|
@ -5,12 +5,11 @@ from PySide6.QtCore import QFileInfo, QSettings, Signal
|
||||
from .singleton import QObjectSingleton
|
||||
|
||||
__all__ = [
|
||||
"LANGUAGE",
|
||||
"DATABASE_URL",
|
||||
"DEVICES_JSON_FILE",
|
||||
"DEVICE_UUID",
|
||||
"TESSERACT_FILE",
|
||||
"KNN_MODEL_FILE",
|
||||
"SIFT_DATABASE_FILE",
|
||||
"B30_KNN_MODEL_FILE",
|
||||
"PHASH_DATABASE_FILE",
|
||||
"ANDREAL_FOLDER",
|
||||
"ANDREAL_EXECUTABLE",
|
||||
"Settings",
|
||||
@ -21,12 +20,8 @@ __all__ = [
|
||||
LANGUAGE = "Language"
|
||||
DATABASE_URL = "DatabaseUrl"
|
||||
|
||||
DEVICES_JSON_FILE = "Ocr/DevicesJsonFile"
|
||||
DEVICE_UUID = "Ocr/DeviceUuid"
|
||||
TESSERACT_FILE = "Ocr/TesseractFile"
|
||||
KNN_MODEL_FILE = "Ocr/KnnModelFile"
|
||||
B30_KNN_MODEL_FILE = "Ocr/B30KnnModelFile"
|
||||
SIFT_DATABASE_FILE = "Ocr/SiftDatabaseFile"
|
||||
PHASH_DATABASE_FILE = "Ocr/PHashDatabaseFile"
|
||||
|
||||
ANDREAL_FOLDER = "Andreal/AndrealFolder"
|
||||
@ -70,33 +65,6 @@ class Settings(QSettings, metaclass=QObjectSingleton):
|
||||
def setDatabaseUrl(self, value: str):
|
||||
self._setStrItem(DATABASE_URL, value)
|
||||
|
||||
def devicesJsonFile(self):
|
||||
return self._strItem(DEVICES_JSON_FILE)
|
||||
|
||||
def setDevicesJsonFile(self, value: str):
|
||||
self._setStrItem(DEVICES_JSON_FILE, value)
|
||||
|
||||
def resetDevicesJsonFile(self):
|
||||
self._resetStrItem(DEVICES_JSON_FILE)
|
||||
|
||||
def deviceUuid(self):
|
||||
return self._strItem(DEVICE_UUID)
|
||||
|
||||
def setDeviceUuid(self, value: str):
|
||||
self._setStrItem(DEVICE_UUID, value)
|
||||
|
||||
def resetDeviceUuid(self):
|
||||
self._resetStrItem(DEVICE_UUID)
|
||||
|
||||
def tesseractPath(self):
|
||||
return self._strItem(TESSERACT_FILE)
|
||||
|
||||
def setTesseractPath(self, value: str):
|
||||
self._setStrItem(TESSERACT_FILE, value)
|
||||
|
||||
def resetTesseractPath(self):
|
||||
self._resetStrItem(TESSERACT_FILE)
|
||||
|
||||
def knnModelFile(self):
|
||||
return self._strItem(KNN_MODEL_FILE)
|
||||
|
||||
@ -115,15 +83,6 @@ class Settings(QSettings, metaclass=QObjectSingleton):
|
||||
def resetB30KnnModelFile(self):
|
||||
self._resetStrItem(B30_KNN_MODEL_FILE)
|
||||
|
||||
def siftDatabaseFile(self):
|
||||
return self._strItem(SIFT_DATABASE_FILE)
|
||||
|
||||
def setSiftDatabaseFile(self, value: str):
|
||||
self._setStrItem(SIFT_DATABASE_FILE, value)
|
||||
|
||||
def resetSiftDatabaseFile(self):
|
||||
self._resetStrItem(SIFT_DATABASE_FILE)
|
||||
|
||||
def phashDatabaseFile(self):
|
||||
return self._strItem(PHASH_DATABASE_FILE)
|
||||
|
||||
|
@ -1,69 +1,58 @@
|
||||
import contextlib
|
||||
import logging
|
||||
from typing import Tuple
|
||||
from typing import Tuple, Type
|
||||
|
||||
import cv2
|
||||
import exif
|
||||
from arcaea_offline.database import Database
|
||||
from arcaea_offline.models import Chart, Score
|
||||
from arcaea_offline_ocr.device.shared import DeviceOcrResult
|
||||
from arcaea_offline_ocr.device.v2 import DeviceV2AutoRois, DeviceV2Ocr, DeviceV2Rois
|
||||
from arcaea_offline_ocr.device.v2.sizes import SizesV1, SizesV2
|
||||
from arcaea_offline.utils.partner import KanaeDayNight, kanae_day_night
|
||||
from arcaea_offline_ocr.device import DeviceOcr, DeviceOcrResult
|
||||
from arcaea_offline_ocr.device.rois import (
|
||||
DeviceRois,
|
||||
DeviceRoisAuto,
|
||||
DeviceRoisExtractor,
|
||||
DeviceRoisMasker,
|
||||
)
|
||||
from arcaea_offline_ocr.phash_db import ImagePhashDatabase
|
||||
from arcaea_offline_ocr.utils import imread_unicode
|
||||
from PySide6.QtCore import QDateTime, QFileInfo
|
||||
|
||||
from ui.extends.components.ocrQueue import OcrRunnable
|
||||
from ui.extends.shared.data import Data
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
import exif
|
||||
|
||||
|
||||
class TabDeviceV2OcrRunnable(OcrRunnable):
|
||||
def __init__(self, imagePath, device, knnModel, phashDb, *, sizesV2: bool):
|
||||
class TabDeviceOcrRunnable(OcrRunnable):
|
||||
def __init__(
|
||||
self,
|
||||
imagePath: str,
|
||||
rois: DeviceRois | Type[DeviceRoisAuto],
|
||||
masker: DeviceRoisMasker,
|
||||
knnModel: cv2.ml.KNearest,
|
||||
phashDb: ImagePhashDatabase,
|
||||
):
|
||||
super().__init__()
|
||||
self.imagePath = imagePath
|
||||
self.device = device
|
||||
self.rois = rois
|
||||
self.masker = masker
|
||||
self.knnModel = knnModel
|
||||
self.phashDb = phashDb
|
||||
self.sizesV2 = sizesV2
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
rois = DeviceV2Rois(
|
||||
self.device, imread_unicode(self.imagePath, cv2.IMREAD_COLOR)
|
||||
)
|
||||
rois.sizes = (
|
||||
SizesV2(self.device.factor)
|
||||
if self.sizesV2
|
||||
else SizesV1(self.device.factor)
|
||||
)
|
||||
ocr = DeviceV2Ocr(self.knnModel, self.phashDb)
|
||||
result = ocr.ocr(rois)
|
||||
img = imread_unicode(self.imagePath, cv2.IMREAD_COLOR)
|
||||
if isinstance(self.rois, type) and issubclass(self.rois, DeviceRoisAuto):
|
||||
rois = self.rois(img.shape[1], img.shape[0])
|
||||
else:
|
||||
rois = self.rois
|
||||
extractor = DeviceRoisExtractor(img, rois)
|
||||
ocr = DeviceOcr(extractor, self.masker, self.knnModel, self.phashDb)
|
||||
result = ocr.ocr()
|
||||
self.signals.resultReady.emit(result)
|
||||
except Exception:
|
||||
logger.exception(f"DeviceV2 ocr {self.imagePath} error")
|
||||
finally:
|
||||
self.signals.finished.emit()
|
||||
|
||||
|
||||
class TabDeviceV2AutoRoisOcrRunnable(OcrRunnable):
|
||||
def __init__(self, imagePath, knnModel, phashDb, *, sizesV2: bool):
|
||||
super().__init__()
|
||||
self.imagePath = imagePath
|
||||
self.knnModel = knnModel
|
||||
self.phashDb = phashDb
|
||||
self.sizesV2 = sizesV2
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
rois = DeviceV2AutoRois(imread_unicode(self.imagePath, cv2.IMREAD_COLOR))
|
||||
factor = rois.sizes.factor
|
||||
rois.sizes = SizesV2(factor) if self.sizesV2 else SizesV1(factor)
|
||||
ocr = DeviceV2Ocr(self.knnModel, self.phashDb)
|
||||
result = ocr.ocr(rois)
|
||||
self.signals.resultReady.emit(result)
|
||||
except Exception:
|
||||
logger.exception(f"DeviceV2AutoRois ocr {self.imagePath} error")
|
||||
logger.exception("DeviceOcr error:")
|
||||
finally:
|
||||
self.signals.finished.emit()
|
||||
|
||||
@ -83,7 +72,24 @@ def getImageDate(imagePath: str) -> QDateTime:
|
||||
|
||||
class ScoreConverter:
|
||||
@staticmethod
|
||||
def deviceV2(imagePath: str, _, result: DeviceOcrResult) -> Tuple[Chart, Score]:
|
||||
def device(imagePath: str, _, result: DeviceOcrResult) -> Tuple[Chart, Score]:
|
||||
partnerModifiers = Data().partnerModifiers
|
||||
imageDate = getImageDate(imagePath)
|
||||
|
||||
# calculate clear type
|
||||
if result.partner_id == "50":
|
||||
dayNight = kanae_day_night(imageDate)
|
||||
modifier = 1 if dayNight == KanaeDayNight.Day else 2
|
||||
else:
|
||||
modifier = partnerModifiers.get(result.partner_id, 0)
|
||||
|
||||
if result.clear_status == 1 and modifier == 1:
|
||||
clearType = 4
|
||||
elif result.clear_status == 1 and modifier == 2:
|
||||
clearType = 5
|
||||
else:
|
||||
clearType = result.clear_status
|
||||
|
||||
db = Database()
|
||||
score = Score(
|
||||
song_id=result.song_id,
|
||||
@ -92,16 +98,16 @@ class ScoreConverter:
|
||||
pure=result.pure,
|
||||
far=result.far,
|
||||
lost=result.lost,
|
||||
date=getImageDate(imagePath).toSecsSinceEpoch(),
|
||||
date=imageDate.toSecsSinceEpoch(),
|
||||
max_recall=result.max_recall,
|
||||
modifier=modifier,
|
||||
clear_type=clearType,
|
||||
comment=f"OCR {QFileInfo(imagePath).fileName()}",
|
||||
)
|
||||
chart = db.get_chart(score.song_id, score.rating_class)
|
||||
if not chart:
|
||||
chart = Chart(
|
||||
song_id=result.song_id,
|
||||
rating_class=result.rating_class,
|
||||
title=result.song_id,
|
||||
constant=0.0,
|
||||
)
|
||||
chart = db.get_chart(score.song_id, score.rating_class) or Chart(
|
||||
song_id=result.song_id,
|
||||
rating_class=result.rating_class,
|
||||
title=result.song_id,
|
||||
constant=0.0,
|
||||
)
|
||||
return (chart, score)
|
||||
|
@ -2,6 +2,7 @@ import base64
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
|
||||
from PySide6.QtCore import QObject, QProcess, QRunnable, QThreadPool, Signal
|
||||
|
||||
@ -24,7 +25,12 @@ class AndrealExecuteRunnable(QRunnable):
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
result = os.popen(f"{self.executePath} {' '.join(self.arguments)}").read()
|
||||
subp = subprocess.run(
|
||||
[self.executePath, *self.arguments],
|
||||
capture_output=True,
|
||||
encoding="utf-8",
|
||||
)
|
||||
result = subp.stdout
|
||||
b64Result = [s for s in result.split("\n") if s]
|
||||
imageBytes = base64.b64decode(
|
||||
re.sub(r"data:image/.*;base64,", "", b64Result[-1])
|
||||
|
@ -1,32 +0,0 @@
|
||||
from arcaea_offline_ocr.device.v1.definition import DeviceV1
|
||||
from PySide6.QtCore import Qt
|
||||
from PySide6.QtWidgets import QComboBox
|
||||
|
||||
from ui.extends.ocr import load_devices_json
|
||||
from ui.extends.shared.delegates.descriptionDelegate import DescriptionDelegate
|
||||
|
||||
|
||||
class DevicesComboBox(QComboBox):
|
||||
DeviceUuidRole = Qt.ItemDataRole.UserRole + 10
|
||||
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setItemDelegate(DescriptionDelegate(self))
|
||||
|
||||
def setDevices(self, devices: list[DeviceV1]):
|
||||
self.clear()
|
||||
for device in devices:
|
||||
self.addItem(f"{device.name} ({device.uuid})", device)
|
||||
row = self.count() - 1
|
||||
self.setItemData(row, device.uuid, self.DeviceUuidRole)
|
||||
self.setItemData(row, device.name, DescriptionDelegate.MainTextRole)
|
||||
self.setItemData(row, device.uuid, DescriptionDelegate.DescriptionTextRole)
|
||||
self.setCurrentIndex(-1)
|
||||
|
||||
def loadDevicesJson(self, path: str):
|
||||
devices = load_devices_json(path)
|
||||
self.setDevices(devices)
|
||||
|
||||
def selectDevice(self, deviceUuid: str):
|
||||
index = self.findData(deviceUuid, self.DeviceUuidRole)
|
||||
self.setCurrentIndex(index)
|
@ -1,11 +1,10 @@
|
||||
import logging
|
||||
import re
|
||||
from enum import IntEnum
|
||||
from typing import Literal
|
||||
|
||||
from arcaea_offline.database import Database
|
||||
from arcaea_offline.models import Chart
|
||||
from PySide6.QtCore import QModelIndex, Qt, Signal, Slot
|
||||
from PySide6.QtCore import QModelIndex, QSignalMapper, Qt, Signal, Slot
|
||||
from PySide6.QtWidgets import QCompleter, QWidget
|
||||
|
||||
from ui.designer.components.songIdSelector_ui import Ui_SongIdSelector
|
||||
@ -33,18 +32,22 @@ class SongIdSelector(Ui_SongIdSelector, QWidget):
|
||||
self.languageChangeEventFilter = LanguageChangeEventFilter(self)
|
||||
self.installEventFilter(self.languageChangeEventFilter)
|
||||
|
||||
self.previousPackageButton.clicked.connect(
|
||||
lambda: self.quickSwitchSelection("previous", "package")
|
||||
# quick switch bindings
|
||||
self.quickSwitchSignalMapper = QSignalMapper(self)
|
||||
self.previousPackageButton.clicked.connect(self.quickSwitchSignalMapper.map)
|
||||
self.quickSwitchSignalMapper.setMapping(
|
||||
self.previousPackageButton, "package||previous"
|
||||
)
|
||||
self.previousSongIdButton.clicked.connect(
|
||||
lambda: self.quickSwitchSelection("previous", "songId")
|
||||
)
|
||||
self.nextSongIdButton.clicked.connect(
|
||||
lambda: self.quickSwitchSelection("next", "songId")
|
||||
)
|
||||
self.nextPackageButton.clicked.connect(
|
||||
lambda: self.quickSwitchSelection("next", "package")
|
||||
self.nextPackageButton.clicked.connect(self.quickSwitchSignalMapper.map)
|
||||
self.quickSwitchSignalMapper.setMapping(self.nextPackageButton, "package||next")
|
||||
self.previousSongIdButton.clicked.connect(self.quickSwitchSignalMapper.map)
|
||||
self.quickSwitchSignalMapper.setMapping(
|
||||
self.previousSongIdButton, "songId||previous"
|
||||
)
|
||||
self.nextSongIdButton.clicked.connect(self.quickSwitchSignalMapper.map)
|
||||
self.quickSwitchSignalMapper.setMapping(self.nextSongIdButton, "songId||next")
|
||||
|
||||
self.quickSwitchSignalMapper.mappedString.connect(self.quickSwitchSlot)
|
||||
|
||||
self.mode = SongIdSelectorMode.SongId
|
||||
|
||||
@ -73,12 +76,11 @@ class SongIdSelector(Ui_SongIdSelector, QWidget):
|
||||
def setMode(self, mode: SongIdSelectorMode):
|
||||
self.mode = mode
|
||||
|
||||
def quickSwitchSelection(
|
||||
self,
|
||||
direction: Literal["previous", "next"],
|
||||
model: Literal["package", "songId"],
|
||||
):
|
||||
minIndex = 0
|
||||
@Slot(str)
|
||||
def quickSwitchSlot(self, action: str):
|
||||
model, direction = action.split("||")
|
||||
|
||||
minIndex = -1
|
||||
if model == "package":
|
||||
maxIndex = self.packComboBox.count() - 1
|
||||
currentIndex = self.packComboBox.currentIndex() + (
|
||||
@ -174,7 +176,7 @@ class SongIdSelector(Ui_SongIdSelector, QWidget):
|
||||
self.songIdComboBox.setCurrentIndex(-1)
|
||||
|
||||
@Slot()
|
||||
def on_packComboBox_activated(self):
|
||||
def on_packComboBox_currentIndexChanged(self):
|
||||
self.fillSongIdComboBox()
|
||||
|
||||
@Slot(str)
|
||||
|
@ -1,7 +1,6 @@
|
||||
from PySide6.QtCore import QCoreApplication
|
||||
from PySide6.QtWidgets import QLabel, QPushButton
|
||||
|
||||
from ui.implements.components.devicesComboBox import DevicesComboBox
|
||||
from ui.implements.components.fileSelector import FileSelector
|
||||
from ui.implements.settings.settingsBaseWidget import SettingsBaseWidget
|
||||
|
||||
@ -12,28 +11,6 @@ class SettingsOcr(SettingsBaseWidget):
|
||||
|
||||
self.setupUi(self)
|
||||
|
||||
if self.settings.devicesJsonFile():
|
||||
self.devicesJsonValueWidget.selectFile(self.settings.devicesJsonFile())
|
||||
self.devicesJsonValueWidget.filesSelected.connect(self.setDevicesJson)
|
||||
self.devicesJsonResetButton.clicked.connect(self.resetDevicesJson)
|
||||
self.insertItem(
|
||||
"devicesJson",
|
||||
self.devicesJsonLabel,
|
||||
self.devicesJsonValueWidget,
|
||||
self.devicesJsonResetButton,
|
||||
)
|
||||
|
||||
if self.settings.deviceUuid():
|
||||
self.deviceUuidValueWidget.selectDevice(self.settings.deviceUuid())
|
||||
self.deviceUuidValueWidget.activated.connect(self.setDeviceUuid)
|
||||
self.deviceUuidResetButton.clicked.connect(self.resetDeviceUuid)
|
||||
self.insertItem(
|
||||
"deviceUuid",
|
||||
self.deviceUuidLabel,
|
||||
self.deviceUuidValueWidget,
|
||||
self.deviceUuidResetButton,
|
||||
)
|
||||
|
||||
if self.settings.knnModelFile():
|
||||
self.knnModelFileValueWidget.selectFile(self.settings.knnModelFile())
|
||||
self.knnModelFileValueWidget.filesSelected.connect(self.setKnnModelFile)
|
||||
@ -56,19 +33,6 @@ class SettingsOcr(SettingsBaseWidget):
|
||||
self.b30KnnModelFileResetButton,
|
||||
)
|
||||
|
||||
if self.settings.siftDatabaseFile():
|
||||
self.siftDatabaseFileValueWidget.selectFile(
|
||||
self.settings.siftDatabaseFile()
|
||||
)
|
||||
self.siftDatabaseFileValueWidget.filesSelected.connect(self.setSiftDatabaseFile)
|
||||
self.siftDatabaseFileResetButton.clicked.connect(self.resetSiftDatabaseFile)
|
||||
self.insertItem(
|
||||
"siftDatabaseFile",
|
||||
self.siftDatabaseFileLabel,
|
||||
self.siftDatabaseFileValueWidget,
|
||||
self.siftDatabaseFileResetButton,
|
||||
)
|
||||
|
||||
if self.settings.phashDatabaseFile():
|
||||
self.phashDatabaseFileValueWidget.selectFile(
|
||||
self.settings.phashDatabaseFile()
|
||||
@ -84,34 +48,6 @@ class SettingsOcr(SettingsBaseWidget):
|
||||
self.phashDatabaseFileResetButton,
|
||||
)
|
||||
|
||||
def setDevicesJson(self):
|
||||
selectedFile = self.devicesJsonValueWidget.selectedFiles()
|
||||
if selectedFile and selectedFile[0]:
|
||||
file = selectedFile[0]
|
||||
self.settings.setDevicesJsonFile(file)
|
||||
self.fillDeviceUuidComboBox()
|
||||
|
||||
def fillDeviceUuidComboBox(self):
|
||||
devicesJsonPath = self.devicesJsonValueWidget.selectedFiles()[0]
|
||||
self.deviceUuidValueWidget.loadDevicesJson(devicesJsonPath)
|
||||
|
||||
storedDeviceUuid = self.settings.deviceUuid()
|
||||
self.deviceUuidValueWidget.selectDevice(storedDeviceUuid)
|
||||
|
||||
def resetDevicesJson(self):
|
||||
self.deviceUuidValueWidget.clear()
|
||||
self.devicesJsonValueWidget.reset()
|
||||
self.settings.resetDeviceUuid()
|
||||
self.settings.resetDevicesJsonFile()
|
||||
|
||||
def setDeviceUuid(self):
|
||||
if device := self.deviceUuidValueWidget.currentData():
|
||||
self.settings.setDeviceUuid(device.uuid)
|
||||
|
||||
def resetDeviceUuid(self):
|
||||
self.deviceUuidValueWidget.setCurrentIndex(-1)
|
||||
self.settings.resetDeviceUuid()
|
||||
|
||||
def setKnnModelFile(self):
|
||||
selectedFile = self.knnModelFileValueWidget.selectedFiles()
|
||||
if selectedFile and selectedFile[0]:
|
||||
@ -132,16 +68,6 @@ class SettingsOcr(SettingsBaseWidget):
|
||||
self.b30KnnModelFileValueWidget.reset()
|
||||
self.settings.resetB30KnnModelFile()
|
||||
|
||||
def setSiftDatabaseFile(self):
|
||||
selectedFile = self.siftDatabaseFileValueWidget.selectedFiles()
|
||||
if selectedFile and selectedFile[0]:
|
||||
file = selectedFile[0]
|
||||
self.settings.setSiftDatabaseFile(file)
|
||||
|
||||
def resetSiftDatabaseFile(self):
|
||||
self.siftDatabaseFileValueWidget.reset()
|
||||
self.settings.resetSiftDatabaseFile()
|
||||
|
||||
def setPHashDatabaseFile(self):
|
||||
selectedFile = self.phashDatabaseFileValueWidget.selectedFiles()
|
||||
if selectedFile and selectedFile[0]:
|
||||
@ -153,14 +79,6 @@ class SettingsOcr(SettingsBaseWidget):
|
||||
self.settings.resetPHashDatabaseFile()
|
||||
|
||||
def setupUi(self, *args):
|
||||
self.devicesJsonLabel = QLabel(self)
|
||||
self.devicesJsonValueWidget = FileSelector(self)
|
||||
self.devicesJsonResetButton = QPushButton(self)
|
||||
|
||||
self.deviceUuidLabel = QLabel(self)
|
||||
self.deviceUuidValueWidget = DevicesComboBox(self)
|
||||
self.deviceUuidResetButton = QPushButton(self)
|
||||
|
||||
self.knnModelFileLabel = QLabel(self)
|
||||
self.knnModelFileValueWidget = FileSelector(self)
|
||||
self.knnModelFileResetButton = QPushButton(self)
|
||||
@ -169,10 +87,6 @@ class SettingsOcr(SettingsBaseWidget):
|
||||
self.b30KnnModelFileValueWidget = FileSelector(self)
|
||||
self.b30KnnModelFileResetButton = QPushButton(self)
|
||||
|
||||
self.siftDatabaseFileLabel = QLabel(self)
|
||||
self.siftDatabaseFileValueWidget = FileSelector(self)
|
||||
self.siftDatabaseFileResetButton = QPushButton(self)
|
||||
|
||||
self.phashDatabaseFileLabel = QLabel(self)
|
||||
self.phashDatabaseFileValueWidget = FileSelector(self)
|
||||
self.phashDatabaseFileResetButton = QPushButton(self)
|
||||
@ -186,21 +100,12 @@ class SettingsOcr(SettingsBaseWidget):
|
||||
# fmt: off
|
||||
self.setTitle(QCoreApplication.translate("Settings", "ocr.title"))
|
||||
|
||||
self.devicesJsonLabel.setText(QCoreApplication.translate("Settings", "ocr.devicesJson.label"))
|
||||
self.devicesJsonResetButton.setText(QCoreApplication.translate("Settings", "resetButton"))
|
||||
|
||||
self.deviceUuidLabel.setText(QCoreApplication.translate("Settings", "ocr.deviceUuid.label"))
|
||||
self.deviceUuidResetButton.setText(QCoreApplication.translate("Settings", "resetButton"))
|
||||
|
||||
self.knnModelFileLabel.setText(QCoreApplication.translate("Settings", "ocr.knnModelFile.label"))
|
||||
self.knnModelFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton"))
|
||||
|
||||
self.b30KnnModelFileLabel.setText(QCoreApplication.translate("Settings", "ocr.b30KnnModelFile.label"))
|
||||
self.b30KnnModelFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton"))
|
||||
|
||||
self.siftDatabaseFileLabel.setText(QCoreApplication.translate("Settings", "ocr.siftDatabaseFile.label"))
|
||||
self.siftDatabaseFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton"))
|
||||
|
||||
self.phashDatabaseFileLabel.setText(QCoreApplication.translate("Settings", "ocr.phashDatabaseFile.label"))
|
||||
self.phashDatabaseFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton"))
|
||||
# fmt: on
|
||||
|
164
ui/implements/tabs/tabOcr/tabOcr_BuildPHashDatabase.py
Normal file
164
ui/implements/tabs/tabOcr/tabOcr_BuildPHashDatabase.py
Normal file
@ -0,0 +1,164 @@
|
||||
import logging
|
||||
import re
|
||||
import sqlite3
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
||||
import cv2
|
||||
from PySide6.QtCore import QThread, Signal, Slot
|
||||
from PySide6.QtWidgets import QFileDialog, QMessageBox, QWidget
|
||||
|
||||
from ui.designer.tabs.tabOcr.tabOcr_BuildPHashDatabase_ui import (
|
||||
Ui_TabOcr_BuildPHashDatabase,
|
||||
)
|
||||
from ui.extends.ocr.build_phash import build_image_phash_database, preprocess_char_icon
|
||||
from ui.extends.shared.language import LanguageChangeEventFilter
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class BuildDatabaseThread(QThread):
|
||||
conn: sqlite3.Connection
|
||||
|
||||
progress = Signal(int, int)
|
||||
success = Signal()
|
||||
error = Signal(str)
|
||||
finished = Signal()
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
images: list[Path],
|
||||
labels: list[str],
|
||||
*,
|
||||
hashSize: int | None = None,
|
||||
highfreqFactor: int | None = None,
|
||||
):
|
||||
super().__init__()
|
||||
self.images = images
|
||||
self.labels = labels
|
||||
self.hashSize = hashSize
|
||||
self.highfreqFactor = highfreqFactor
|
||||
|
||||
def run(self):
|
||||
try:
|
||||
progressFunc = lambda i, total: self.progress.emit(i, total)
|
||||
|
||||
kwargsDict = {}
|
||||
if self.hashSize is not None:
|
||||
kwargsDict["hash_size"] = self.hashSize
|
||||
if self.highfreqFactor is not None:
|
||||
kwargsDict["highfreq_factor"] = self.highfreqFactor
|
||||
self.conn = build_image_phash_database(
|
||||
self.images, self.labels, progress_func=progressFunc, **kwargsDict
|
||||
)
|
||||
self.success.emit()
|
||||
except Exception as e:
|
||||
logger.exception("Error during pHash database build")
|
||||
self.error.emit(str(e))
|
||||
finally:
|
||||
self.finished.emit()
|
||||
|
||||
|
||||
class TabOcr_BuildPHashDatabase(Ui_TabOcr_BuildPHashDatabase, QWidget):
|
||||
def __init__(self, parent=None):
|
||||
super().__init__(parent)
|
||||
self.setupUi(self)
|
||||
|
||||
self.languageChangeEventFilter = LanguageChangeEventFilter(self)
|
||||
self.installEventFilter(self.languageChangeEventFilter)
|
||||
|
||||
self.songDirSelector.setMode(self.songDirSelector.getExistingDirectory)
|
||||
self.charIconDirSelector.setMode(self.charIconDirSelector.getExistingDirectory)
|
||||
|
||||
self.buildButton.clicked.connect(self.databaseBuildStart)
|
||||
|
||||
@Slot()
|
||||
def on_optionsResetButton_clicked(self):
|
||||
self.hashSizeSpinBox.setValue(16)
|
||||
self.highfreqFactorSpinBox.setValue(4)
|
||||
|
||||
def databaseFileName(self):
|
||||
return f"image-phash-{int(time.time() * 1000)}.db"
|
||||
|
||||
def databaseBuildStart(self):
|
||||
if not self.songDirSelector.selectedFiles():
|
||||
QMessageBox.critical(self, None, "Song directory not selected.")
|
||||
return
|
||||
if not self.charIconDirSelector.selectedFiles():
|
||||
QMessageBox.critical(self, None, "Char icon directory not selected.")
|
||||
return
|
||||
|
||||
songDir = self.songDirSelector.selectedFiles()[0]
|
||||
charIconDir = self.charIconDirSelector.selectedFiles()[0]
|
||||
|
||||
acceptExts = [".jpg", ".png"]
|
||||
songFilePaths = [
|
||||
p for p in Path(songDir).glob("**/*") if p.suffix in acceptExts
|
||||
]
|
||||
charIconFilePaths = [
|
||||
p for p in Path(charIconDir).glob("**/*") if p.suffix in acceptExts
|
||||
]
|
||||
|
||||
self.readImageProgressBar.setMaximum(
|
||||
len(songFilePaths) + len(charIconFilePaths)
|
||||
)
|
||||
i = 0
|
||||
songMats = []
|
||||
charIconMats = []
|
||||
for image_path in songFilePaths:
|
||||
songMats.append(cv2.imread(str(image_path.resolve()), cv2.IMREAD_GRAYSCALE))
|
||||
i += 1
|
||||
self.readImageProgressBar.setValue(i)
|
||||
for image_path in charIconFilePaths:
|
||||
mat = cv2.imread(str(image_path.resolve()), cv2.IMREAD_GRAYSCALE)
|
||||
if self.preprocessCharIconCheckBox.isChecked():
|
||||
mat = preprocess_char_icon(mat)
|
||||
charIconMats.append(mat)
|
||||
i += 1
|
||||
self.readImageProgressBar.setValue(i)
|
||||
|
||||
songLabels = [re.sub(r"_.*$", "", p.stem) for p in songFilePaths]
|
||||
charLabels = [f"partner_icon||{p.stem}" for p in charIconFilePaths]
|
||||
|
||||
self.databaseBuildThread = BuildDatabaseThread(
|
||||
songMats + charIconMats, songLabels + charLabels
|
||||
)
|
||||
self.databaseBuildThread.progress.connect(self.databaseBuildProgress)
|
||||
self.databaseBuildThread.success.connect(self.databaseBuildSuccess)
|
||||
self.databaseBuildThread.error.connect(self.databaseBuildError)
|
||||
self.buildButton.setEnabled(False)
|
||||
self.databaseBuildThread.start()
|
||||
|
||||
@Slot(int, int)
|
||||
def databaseBuildProgress(self, i: int, total: int):
|
||||
if i < 5:
|
||||
self.calculateHashProgressBar.setMaximum(total)
|
||||
self.calculateHashProgressBar.setValue(i)
|
||||
|
||||
@Slot(str)
|
||||
def databaseBuildError(self, msg: str):
|
||||
QMessageBox.critical(self, "Error", msg)
|
||||
self.databaseBuildCleanUp()
|
||||
|
||||
@Slot()
|
||||
def databaseBuildSuccess(self):
|
||||
dbMemory = self.databaseBuildThread.conn
|
||||
|
||||
dbFileName, _ = QFileDialog.getSaveFileName(self, None, self.databaseFileName())
|
||||
if not dbFileName:
|
||||
self.databaseBuildCleanUp()
|
||||
QMessageBox.information(self, None, "User canceled operation.")
|
||||
return
|
||||
|
||||
dbDisk = sqlite3.connect(dbFileName)
|
||||
dbMemory.backup(dbDisk)
|
||||
self.databaseBuildCleanUp()
|
||||
|
||||
def databaseBuildCleanUp(self):
|
||||
self.databaseBuildThread.deleteLater()
|
||||
self.databaseBuildThread = None
|
||||
self.readImageProgressBar.setMaximum(0)
|
||||
self.readImageProgressBar.setValue(0)
|
||||
self.calculateHashProgressBar.setMaximum(0)
|
||||
self.calculateHashProgressBar.setValue(0)
|
||||
self.buildButton.setEnabled(True)
|
@ -1,30 +1,21 @@
|
||||
import logging
|
||||
|
||||
import cv2
|
||||
|
||||
# from arcaea_offline_ocr_device_creation_wizard.implements.wizard import Wizard
|
||||
from arcaea_offline_ocr.device.v1.definition import DeviceV1
|
||||
from arcaea_offline_ocr.device.v2.definition import DeviceV2
|
||||
from arcaea_offline_ocr.phash_db import ImagePHashDatabase
|
||||
from arcaea_offline_ocr.sift_db import SIFTDatabase
|
||||
from PySide6.QtCore import Qt, Slot
|
||||
from PySide6.QtWidgets import QApplication, QFileDialog, QWidget
|
||||
from arcaea_offline_ocr.device.rois import (
|
||||
DeviceRoisAutoT1,
|
||||
DeviceRoisAutoT2,
|
||||
DeviceRoisMaskerAutoT1,
|
||||
DeviceRoisMaskerAutoT2,
|
||||
)
|
||||
from arcaea_offline_ocr.phash_db import ImagePhashDatabase
|
||||
from PySide6.QtCore import Slot
|
||||
from PySide6.QtWidgets import QApplication, QFileDialog, QMessageBox, QWidget
|
||||
|
||||
from ui.designer.tabs.tabOcr.tabOcr_Device_ui import Ui_TabOcr_Device
|
||||
from ui.extends.components.ocrQueue import OcrQueueModel
|
||||
from ui.extends.shared.language import LanguageChangeEventFilter
|
||||
from ui.extends.shared.settings import (
|
||||
DEVICES_JSON_FILE,
|
||||
KNN_MODEL_FILE,
|
||||
PHASH_DATABASE_FILE,
|
||||
TESSERACT_FILE,
|
||||
Settings,
|
||||
)
|
||||
from ui.extends.tabs.tabOcr.tabOcr_Device import (
|
||||
ScoreConverter,
|
||||
TabDeviceV2AutoRoisOcrRunnable,
|
||||
TabDeviceV2OcrRunnable,
|
||||
)
|
||||
from ui.extends.shared.settings import KNN_MODEL_FILE, PHASH_DATABASE_FILE
|
||||
from ui.extends.tabs.tabOcr.tabOcr_Device import ScoreConverter, TabDeviceOcrRunnable
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
@ -38,17 +29,36 @@ class TabOcr_Device(Ui_TabOcr_Device, QWidget):
|
||||
self.languageChangeEventFilter = LanguageChangeEventFilter(self)
|
||||
self.installEventFilter(self.languageChangeEventFilter)
|
||||
|
||||
self.deviceFileSelector.filesSelected.connect(self.deviceFileSelected)
|
||||
self.knnModelSelector.filesSelected.connect(self.knnModelFileSelected)
|
||||
self.phashDatabaseSelector.filesSelected.connect(self.phashDatabaseFileSelected)
|
||||
# connect options checkBoxes & comboBoxes
|
||||
self.options_roisUseCustomCheckBox.toggled.connect(
|
||||
lambda useCustom: self.options_roisStackedWidget.setCurrentIndex(
|
||||
1 if useCustom else 0
|
||||
)
|
||||
)
|
||||
self.options_maskerUseCustomCheckBox.toggled.connect(
|
||||
lambda useCustom: self.options_maskerStackedWidget.setCurrentIndex(
|
||||
1 if useCustom else 0
|
||||
)
|
||||
)
|
||||
self.options_usePresetCheckBox.toggled.connect(self.options_setUsePreset)
|
||||
|
||||
self.options_presetComboBox.currentIndexChanged.connect(
|
||||
self.options_presetSelected
|
||||
)
|
||||
# fill option values
|
||||
self.options_fillComboBoxes()
|
||||
|
||||
self.dependencies_knnModelSelector.filesSelected.connect(self.knnModelSelected)
|
||||
self.dependencies_phashDatabaseSelector.filesSelected.connect(
|
||||
self.phashDatabaseSelected
|
||||
)
|
||||
|
||||
logger.info("Applying settings...")
|
||||
self.deviceFileSelector.connectSettings(DEVICES_JSON_FILE)
|
||||
self.knnModelSelector.connectSettings(KNN_MODEL_FILE)
|
||||
self.tesseractFileSelector.connectSettings(TESSERACT_FILE)
|
||||
self.phashDatabaseSelector.connectSettings(PHASH_DATABASE_FILE)
|
||||
settings = Settings()
|
||||
self.deviceComboBox.selectDevice(settings.deviceUuid())
|
||||
self.dependencies_knnModelSelector.connectSettings(KNN_MODEL_FILE)
|
||||
self.dependencies_phashDatabaseSelector.connectSettings(PHASH_DATABASE_FILE)
|
||||
|
||||
self.options_usePresetCheckBox.setChecked(True)
|
||||
self.options_usePresetCheckBox.setEnabled(False)
|
||||
|
||||
self.ocrQueueModel = OcrQueueModel(self)
|
||||
self.ocrQueue.setModel(self.ocrQueueModel)
|
||||
@ -60,43 +70,76 @@ class TabOcr_Device(Ui_TabOcr_Device, QWidget):
|
||||
# wizard.open()
|
||||
pass
|
||||
|
||||
@Slot()
|
||||
def on_deviceUseAutoFactorCheckBox_stateChanged(self):
|
||||
checkState = self.deviceUseAutoFactorCheckBox.checkState()
|
||||
if checkState == Qt.CheckState.Checked:
|
||||
self.deviceDependenciesStackedWidget.setCurrentIndex(1)
|
||||
self.deviceComboBox.setCurrentIndex(-1)
|
||||
self.deviceFileSelector.setEnabled(False)
|
||||
self.deviceComboBox.setEnabled(False)
|
||||
else:
|
||||
self.deviceFileSelector.setEnabled(True)
|
||||
self.deviceComboBox.setEnabled(True)
|
||||
@Slot(bool)
|
||||
def options_setUsePreset(self, usePreset: bool):
|
||||
self.options_roisUseCustomCheckBox.setChecked(not usePreset)
|
||||
self.options_maskerUseCustomCheckBox.setChecked(not usePreset)
|
||||
self.options_preciseControlWidget.setEnabled(not usePreset)
|
||||
if not usePreset:
|
||||
self.options_presetComboBox.setCurrentIndex(-1)
|
||||
|
||||
@Slot()
|
||||
def on_deviceComboBox_currentIndexChanged(self):
|
||||
self.changeDeviceDepStackedWidget()
|
||||
@Slot(int)
|
||||
def options_presetSelected(self, index: int):
|
||||
if index < 0:
|
||||
self.options_roisComboBox.setCurrentIndex(-1)
|
||||
self.options_maskerComboBox.setCurrentIndex(-1)
|
||||
|
||||
def changeDeviceDepStackedWidget(self):
|
||||
device = self.deviceComboBox.currentData()
|
||||
if isinstance(device, (DeviceV1, DeviceV2)):
|
||||
self.deviceDependenciesStackedWidget.setCurrentIndex(device.version - 1)
|
||||
autoTypeString = self.options_presetComboBox.currentData()
|
||||
roisAutoTypeIndex = self.options_roisComboBox.findData(autoTypeString)
|
||||
maskerAutoTypeIndex = self.options_maskerComboBox.findData(autoTypeString)
|
||||
self.options_roisComboBox.setCurrentIndex(roisAutoTypeIndex)
|
||||
self.options_maskerComboBox.setCurrentIndex(maskerAutoTypeIndex)
|
||||
|
||||
def deviceFileSelected(self):
|
||||
if selectedFiles := self.deviceFileSelector.selectedFiles():
|
||||
file = selectedFiles[0]
|
||||
self.deviceComboBox.loadDevicesJson(file)
|
||||
def options_fillComboBoxes(self):
|
||||
self.options_roisComboBox.addItem("RoisAutoT1", "AutoT1")
|
||||
self.options_roisComboBox.addItem("RoisAutoT2", "AutoT2")
|
||||
self.options_roisComboBox.setCurrentIndex(-1)
|
||||
|
||||
def knnModelFileSelected(self):
|
||||
if selectedFiles := self.knnModelSelector.selectedFiles():
|
||||
self.knnModel = cv2.ml.KNearest.load(selectedFiles[0])
|
||||
self.options_maskerComboBox.addItem("MaskerAutoT1", "AutoT1")
|
||||
self.options_maskerComboBox.addItem("MaskerAutoT2", "AutoT2")
|
||||
self.options_maskerComboBox.setCurrentIndex(-1)
|
||||
|
||||
def phashDatabaseFileSelected(self):
|
||||
if selectedFiles := self.phashDatabaseSelector.selectedFiles():
|
||||
self.phashDatabase = ImagePHashDatabase(selectedFiles[0])
|
||||
self.options_presetComboBox.addItem("AutoT1 (ver <= 4.7.2)", "AutoT1")
|
||||
self.options_presetComboBox.addItem("AutoT2 (ver >= 5.0.0)", "AutoT2")
|
||||
self.options_presetComboBox.setCurrentIndex(1)
|
||||
|
||||
def knnModelSelected(self):
|
||||
try:
|
||||
knnModelFile = self.dependencies_knnModelSelector.selectedFiles()[0]
|
||||
self.knnModel = cv2.ml.KNearest.load(knnModelFile)
|
||||
varCount = self.knnModel.getVarCount()
|
||||
if varCount != 81:
|
||||
self.dependencies_knnModelStatusLabel.setText(
|
||||
f'<font color="darkorange">WARN</font>, varCount {varCount}'
|
||||
)
|
||||
else:
|
||||
self.dependencies_knnModelStatusLabel.setText(
|
||||
f'<font color="green">OK</font>, varCount {varCount}'
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("Error loading knn model:")
|
||||
self.dependencies_knnModelStatusLabel.setText(
|
||||
'<font color="red">Error</font>'
|
||||
)
|
||||
|
||||
def phashDatabaseSelected(self):
|
||||
try:
|
||||
phashDbFile = self.dependencies_phashDatabaseSelector.selectedFiles()[0]
|
||||
self.phashDatabase = ImagePhashDatabase(phashDbFile)
|
||||
self.dependencies_phashDatabaseStatusLabel.setText(
|
||||
f'<font color="green">OK</font>, '
|
||||
f"J{len(self.phashDatabase.jacket_hashes)} "
|
||||
f"PI{len(self.phashDatabase.partner_icon_hashes)}"
|
||||
)
|
||||
except Exception:
|
||||
logger.exception("Error loading phash database:")
|
||||
self.dependencies_phashDatabaseStatusLabel.setText(
|
||||
'<font color="red">Error</font>'
|
||||
)
|
||||
|
||||
@Slot()
|
||||
def on_ocr_addImageButton_clicked(self):
|
||||
files, _filter = QFileDialog.getOpenFileNames(
|
||||
files, _ = QFileDialog.getOpenFileNames(
|
||||
self, None, "", "Image Files (*.png *.jpg *.jpeg *.bmp *.webp);;*"
|
||||
)
|
||||
filesNum = len(files)
|
||||
@ -114,30 +157,51 @@ class TabOcr_Device(Ui_TabOcr_Device, QWidget):
|
||||
QApplication.processEvents()
|
||||
self.ocrQueue.resizeTableView()
|
||||
|
||||
def deviceRois(self):
|
||||
if self.options_roisUseCustomCheckBox.isChecked():
|
||||
...
|
||||
else:
|
||||
selectedPreset = self.options_roisComboBox.currentData()
|
||||
if selectedPreset == "AutoT1":
|
||||
return DeviceRoisAutoT1
|
||||
elif selectedPreset == "AutoT2":
|
||||
return DeviceRoisAutoT2
|
||||
else:
|
||||
QMessageBox.critical(self, None, "Select a Rois preset first.")
|
||||
return None
|
||||
|
||||
def deviceRoisMasker(self):
|
||||
if self.options_maskerUseCustomCheckBox.isChecked():
|
||||
...
|
||||
else:
|
||||
selectedPreset = self.options_maskerComboBox.currentData()
|
||||
if selectedPreset == "AutoT1":
|
||||
return DeviceRoisMaskerAutoT1()
|
||||
elif selectedPreset == "AutoT2":
|
||||
return DeviceRoisMaskerAutoT2()
|
||||
else:
|
||||
QMessageBox.critical(self, None, "Select a Masker preset first.")
|
||||
return None
|
||||
|
||||
@Slot()
|
||||
def on_ocr_startButton_clicked(self):
|
||||
for row in range(self.ocrQueueModel.rowCount()):
|
||||
index = self.ocrQueueModel.index(row, 0)
|
||||
imagePath = index.data(OcrQueueModel.ImagePathRole)
|
||||
if self.deviceUseAutoFactorCheckBox.checkState() == Qt.CheckState.Checked:
|
||||
runnable = TabDeviceV2AutoRoisOcrRunnable(
|
||||
imagePath,
|
||||
self.knnModel,
|
||||
self.phashDatabase,
|
||||
sizesV2=self.deviceSizesV2CheckBox.isChecked(),
|
||||
)
|
||||
else:
|
||||
runnable = TabDeviceV2OcrRunnable(
|
||||
imagePath,
|
||||
self.deviceComboBox.currentData(),
|
||||
self.knnModel,
|
||||
self.phashDatabase,
|
||||
sizesV2=self.deviceSizesV2CheckBox.isChecked(),
|
||||
)
|
||||
|
||||
rois = self.deviceRois()
|
||||
masker = self.deviceRoisMasker()
|
||||
|
||||
if rois is None or masker is None:
|
||||
return
|
||||
|
||||
runnable = TabDeviceOcrRunnable(
|
||||
imagePath, rois, masker, self.knnModel, self.phashDatabase
|
||||
)
|
||||
self.ocrQueueModel.setData(index, runnable, OcrQueueModel.OcrRunnableRole)
|
||||
self.ocrQueueModel.setData(
|
||||
index,
|
||||
ScoreConverter.deviceV2,
|
||||
ScoreConverter.device,
|
||||
OcrQueueModel.ProcessOcrResultFuncRole,
|
||||
)
|
||||
self.ocrQueueModel.startQueue()
|
||||
|
@ -180,19 +180,20 @@ class TabTools_Andreal(Ui_TabTools_Andreal, QWidget):
|
||||
|
||||
arguments = [
|
||||
str(self.imageType()),
|
||||
f'--json-file="{jsonFile}"',
|
||||
f"--img-version={self.imageVersion()}",
|
||||
"--json-file",
|
||||
jsonFile,
|
||||
"--img-version",
|
||||
str(self.imageVersion()),
|
||||
]
|
||||
if self.andrealFolderSelector.selectedFiles():
|
||||
arguments.append(
|
||||
f'--path="{self.andrealFolderSelector.selectedFiles()[0]}"'
|
||||
)
|
||||
arguments.append("--path")
|
||||
arguments.append(self.andrealFolderSelector.selectedFiles()[0])
|
||||
if preview:
|
||||
arguments.extend(["--img-format=jpg", "--img-quality=20"])
|
||||
arguments.extend(["--img-format", "jpg", "--img-quality", "20"])
|
||||
else:
|
||||
arguments.append(f"--img-format={self.imageFormat()}")
|
||||
arguments.extend(["--img-format", self.imageFormat()])
|
||||
if self.imageFormat() == "jpg":
|
||||
arguments.append(f"--img-quality={self.jpgQualitySpinBox.value()}")
|
||||
arguments.extend(["--img-quality", str(self.jpgQualitySpinBox.value())])
|
||||
return arguments
|
||||
|
||||
def getAndrealJsonContent(self):
|
||||
|
@ -89,12 +89,12 @@
|
||||
<translation>Continue</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.py" line="115"/>
|
||||
<location filename="../../startup/databaseChecker.py" line="117"/>
|
||||
<source>dialog.tryInitExistingDatabase</source>
|
||||
<translation>The existing database doesn't seem to be initialized properly, try initialize again?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.py" line="131"/>
|
||||
<location filename="../../startup/databaseChecker.py" line="133"/>
|
||||
<source>dialog.confirmNewDatabase</source>
|
||||
<translation>Database file does not exist. Create now?</translation>
|
||||
</message>
|
||||
@ -696,6 +696,11 @@ validation</translation>
|
||||
<source>tab.b30</source>
|
||||
<translation>B30</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcrEntry.ui" line="34"/>
|
||||
<source>tab.buildPHashDatabase</source>
|
||||
<translation>Build pHash Database</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabOcr_B30</name>
|
||||
@ -725,6 +730,54 @@ validation</translation>
|
||||
<translation>Select Image</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabOcr_BuildPHashDatabase</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="33"/>
|
||||
<source>folders.title</source>
|
||||
<translation>Data Folders</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="41"/>
|
||||
<source>folders.songDir</source>
|
||||
<translation>Song jackets</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="62"/>
|
||||
<source>folders.charIconDir</source>
|
||||
<translation>Partner icons</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="84"/>
|
||||
<source>options.title</source>
|
||||
<translation>Options</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="157"/>
|
||||
<source>options.preprocessCharIcon</source>
|
||||
<translation>Preprocess partner icons</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="180"/>
|
||||
<source>resetButton</source>
|
||||
<translation>Reset</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="199"/>
|
||||
<source>[Reading images] %v/%m - %p%</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="215"/>
|
||||
<source>[Calculate hashes] %v/%m - %p%</source>
|
||||
<translation></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="237"/>
|
||||
<source>buildButton</source>
|
||||
<translation>Build</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabOcr_Device</name>
|
||||
<message>
|
||||
@ -734,28 +787,44 @@ validation</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="27"/>
|
||||
<source>deviceSelector.title</source>
|
||||
<translation>Select Device</translation>
|
||||
<source>options.title</source>
|
||||
<translation>Options</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="35"/>
|
||||
<source>deviceSelector.useAutoFactor</source>
|
||||
<translation>Auto calculate factor</translation>
|
||||
<source>options.usePreset</source>
|
||||
<translation>Use preset</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="81"/>
|
||||
<source>knnModelSelector.title</source>
|
||||
<translation>Select KNearest Model</translation>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="73"/>
|
||||
<source>options.rois</source>
|
||||
<translation>Rois</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="112"/>
|
||||
<source>tesseractSelector.title</source>
|
||||
<translation>Select tesseract Path</translation>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="128"/>
|
||||
<source>options.masker</source>
|
||||
<translation>Masker</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="140"/>
|
||||
<source>phashDatabaseSelector.title</source>
|
||||
<translation>Select Image PHash Database</translation>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="138"/>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="145"/>
|
||||
<source>options.useCustom</source>
|
||||
<translation>Use custom options</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="203"/>
|
||||
<source>dependencies.title</source>
|
||||
<translation>OCR Dependencies</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="209"/>
|
||||
<source>dependencies.knnModel</source>
|
||||
<translation>KNearest model</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="246"/>
|
||||
<source>dependencies.phashDatabase</source>
|
||||
<translation>Image pHash database</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
@ -89,12 +89,12 @@
|
||||
<translation>继续</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.py" line="115"/>
|
||||
<location filename="../../startup/databaseChecker.py" line="117"/>
|
||||
<source>dialog.tryInitExistingDatabase</source>
|
||||
<translation>现有的数据库似乎没有正确初始化,是否尝试再次初始化?</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../startup/databaseChecker.py" line="131"/>
|
||||
<location filename="../../startup/databaseChecker.py" line="133"/>
|
||||
<source>dialog.confirmNewDatabase</source>
|
||||
<translation>数据库文件不存在,是否创建?</translation>
|
||||
</message>
|
||||
@ -695,6 +695,11 @@
|
||||
<source>tab.b30</source>
|
||||
<translation>B30</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcrEntry.ui" line="34"/>
|
||||
<source>tab.buildPHashDatabase</source>
|
||||
<translation>构建 pHash 数据库</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabOcr_B30</name>
|
||||
@ -724,6 +729,54 @@
|
||||
<translation>选择图片</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabOcr_BuildPHashDatabase</name>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="33"/>
|
||||
<source>folders.title</source>
|
||||
<translation>数据文件夹</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="41"/>
|
||||
<source>folders.songDir</source>
|
||||
<translation>曲封</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="62"/>
|
||||
<source>folders.charIconDir</source>
|
||||
<translation>搭档头像</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="84"/>
|
||||
<source>options.title</source>
|
||||
<translation>选项</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="157"/>
|
||||
<source>options.preprocessCharIcon</source>
|
||||
<translation>预处理搭档头像</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="180"/>
|
||||
<source>resetButton</source>
|
||||
<translation>重置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="199"/>
|
||||
<source>[Reading images] %v/%m - %p%</source>
|
||||
<translation>[读取图片] %v/%m - %p%</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="215"/>
|
||||
<source>[Calculate hashes] %v/%m - %p%</source>
|
||||
<translation>[计算哈希] %v/%m - %p%</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_BuildPHashDatabase.ui" line="237"/>
|
||||
<source>buildButton</source>
|
||||
<translation>构建</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>TabOcr_Device</name>
|
||||
<message>
|
||||
@ -733,28 +786,44 @@
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="27"/>
|
||||
<source>deviceSelector.title</source>
|
||||
<translation>选择设备</translation>
|
||||
<source>options.title</source>
|
||||
<translation>选项</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="35"/>
|
||||
<source>deviceSelector.useAutoFactor</source>
|
||||
<translation>自动计算 factor</translation>
|
||||
<source>options.usePreset</source>
|
||||
<translation>使用预设</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="81"/>
|
||||
<source>knnModelSelector.title</source>
|
||||
<translation>选择 KNearest 模型</translation>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="73"/>
|
||||
<source>options.rois</source>
|
||||
<translation>定位器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="112"/>
|
||||
<source>tesseractSelector.title</source>
|
||||
<translation>选择 tesseract 路径</translation>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="128"/>
|
||||
<source>options.masker</source>
|
||||
<translation>遮罩器</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="140"/>
|
||||
<source>phashDatabaseSelector.title</source>
|
||||
<translation>选择图像 PHash 数据库</translation>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="138"/>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="145"/>
|
||||
<source>options.useCustom</source>
|
||||
<translation>使用自定义设置</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="203"/>
|
||||
<source>dependencies.title</source>
|
||||
<translation>OCR 依赖</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="209"/>
|
||||
<source>dependencies.knnModel</source>
|
||||
<translation>KNearest 模型</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="246"/>
|
||||
<source>dependencies.phashDatabase</source>
|
||||
<translation>图像 pHash 数据库</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
35
ui/resources/partnerModifiers.json
Normal file
35
ui/resources/partnerModifiers.json
Normal file
@ -0,0 +1,35 @@
|
||||
{
|
||||
"__COMMENT__": "1: EASY, 2: HARD",
|
||||
"0": 1,
|
||||
"0u": 1,
|
||||
"7": 2,
|
||||
"9": 1,
|
||||
"10": 2,
|
||||
"10u": 2,
|
||||
"15": 1,
|
||||
"16": 1,
|
||||
"20": 1,
|
||||
"28": 2,
|
||||
"28u": 2,
|
||||
"29": 2,
|
||||
"29u": 2,
|
||||
"35": 2,
|
||||
"36": 2,
|
||||
"36u": 2,
|
||||
"37": 2,
|
||||
"41": 2,
|
||||
"42": 2,
|
||||
"42u": 2,
|
||||
"43": 2,
|
||||
"43u": 2,
|
||||
"54": 2,
|
||||
"55": 2,
|
||||
"57": 2,
|
||||
"61": 2,
|
||||
"64": 2,
|
||||
"66": 2,
|
||||
"66u": 2,
|
||||
"67": 2,
|
||||
"68": 1,
|
||||
"70": 2
|
||||
}
|
@ -4,6 +4,8 @@
|
||||
<file>VERSION</file>
|
||||
<file>LICENSE</file>
|
||||
|
||||
<file>partnerModifiers.json</file>
|
||||
|
||||
<file>images/icon.png</file>
|
||||
<file>images/logo.png</file>
|
||||
<file>images/stepCalculator/stamina.png</file>
|
||||
|
@ -74,6 +74,7 @@ class DatabaseChecker(Ui_DatabaseChecker, QDialog):
|
||||
db = Database(create_engine(dbSqliteUrl))
|
||||
if db.check_init():
|
||||
flags |= DatabaseCheckerResult.Initted
|
||||
self.settings.setDatabaseUrl(self.dbSqliteUrl().toString())
|
||||
|
||||
return flags
|
||||
|
||||
@ -102,6 +103,7 @@ class DatabaseChecker(Ui_DatabaseChecker, QDialog):
|
||||
@Slot()
|
||||
def on_confirmDbPathButton_clicked(self):
|
||||
dbSqliteUrl = self.dbSqliteUrl()
|
||||
self.settings.setDatabaseUrl(dbSqliteUrl.toString())
|
||||
|
||||
result = self.confirmDb()
|
||||
if result & DatabaseCheckerResult.Initted:
|
||||
|
Reference in New Issue
Block a user