mirror of
https://github.com/283375/arcaea-offline-pyside-ui.git
synced 2025-07-02 04:46:26 +00:00
Compare commits
18 Commits
v0.3.0b
...
86b1653fe3
Author | SHA1 | Date | |
---|---|---|---|
86b1653fe3
|
|||
3e2e96b00b
|
|||
9bb6f5b3d9
|
|||
8628399469
|
|||
cf913d296e
|
|||
1060590e03
|
|||
858abe3415
|
|||
cd4ed51826
|
|||
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.db
|
||||||
arcaea_offline.ini
|
arcaea_offline.ini
|
||||||
|
/data
|
||||||
|
|
||||||
ui/resources/VERSION
|
ui/resources/VERSION
|
||||||
|
|
||||||
|
@ -29,9 +29,9 @@
|
|||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QRadioButton" name="iccIgnoreRadioButton">
|
<widget class="QRadioButton" name="iccUseQtRadioButton">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>icc.ignore</string>
|
<string>icc.useQt</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
@ -38,10 +38,10 @@ class Ui_OcrQueue(object):
|
|||||||
self.groupBox.setObjectName(u"groupBox")
|
self.groupBox.setObjectName(u"groupBox")
|
||||||
self.verticalLayout = QVBoxLayout(self.groupBox)
|
self.verticalLayout = QVBoxLayout(self.groupBox)
|
||||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
self.verticalLayout.setObjectName(u"verticalLayout")
|
||||||
self.iccIgnoreRadioButton = QRadioButton(self.groupBox)
|
self.iccUseQtRadioButton = QRadioButton(self.groupBox)
|
||||||
self.iccIgnoreRadioButton.setObjectName(u"iccIgnoreRadioButton")
|
self.iccUseQtRadioButton.setObjectName(u"iccUseQtRadioButton")
|
||||||
|
|
||||||
self.verticalLayout.addWidget(self.iccIgnoreRadioButton)
|
self.verticalLayout.addWidget(self.iccUseQtRadioButton)
|
||||||
|
|
||||||
self.iccUsePILRadioButton = QRadioButton(self.groupBox)
|
self.iccUsePILRadioButton = QRadioButton(self.groupBox)
|
||||||
self.iccUsePILRadioButton.setObjectName(u"iccUsePILRadioButton")
|
self.iccUsePILRadioButton.setObjectName(u"iccUsePILRadioButton")
|
||||||
@ -155,7 +155,7 @@ class Ui_OcrQueue(object):
|
|||||||
def retranslateUi(self, OcrQueue):
|
def retranslateUi(self, OcrQueue):
|
||||||
self.groupBox_3.setTitle(QCoreApplication.translate("OcrQueue", u"queue.title", None))
|
self.groupBox_3.setTitle(QCoreApplication.translate("OcrQueue", u"queue.title", None))
|
||||||
self.groupBox.setTitle(QCoreApplication.translate("OcrQueue", u"iccOptionsGroupBox", None))
|
self.groupBox.setTitle(QCoreApplication.translate("OcrQueue", u"iccOptionsGroupBox", None))
|
||||||
self.iccIgnoreRadioButton.setText(QCoreApplication.translate("OcrQueue", u"icc.ignore", None))
|
self.iccUseQtRadioButton.setText(QCoreApplication.translate("OcrQueue", u"icc.useQt", None))
|
||||||
self.iccUsePILRadioButton.setText(QCoreApplication.translate("OcrQueue", u"icc.usePIL", None))
|
self.iccUsePILRadioButton.setText(QCoreApplication.translate("OcrQueue", u"icc.usePIL", None))
|
||||||
self.iccTryFixRadioButton.setText(QCoreApplication.translate("OcrQueue", u"icc.tryFix", None))
|
self.iccTryFixRadioButton.setText(QCoreApplication.translate("OcrQueue", u"icc.tryFix", None))
|
||||||
self.ocr_addImageButton.setText(QCoreApplication.translate("OcrQueue", u"queue.addImageButton", None))
|
self.ocr_addImageButton.setText(QCoreApplication.translate("OcrQueue", u"queue.addImageButton", None))
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string notr="true">TabOcr_B30</string>
|
<string notr="true">TabOcr_B30</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
@ -27,60 +27,87 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<widget class="QGroupBox" name="groupBox_6">
|
||||||
<item>
|
<property name="title">
|
||||||
<widget class="QGroupBox" name="groupBox_3">
|
<string>dependencies.title</string>
|
||||||
<property name="title">
|
</property>
|
||||||
<string>knnModelSelector.title</string>
|
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0,0,1">
|
||||||
</property>
|
<item row="0" column="0">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
<widget class="QLabel" name="label">
|
||||||
<item>
|
<property name="text">
|
||||||
<widget class="FileSelector" name="knnModelSelector" native="true"/>
|
<string>dependencies.knnModel</string>
|
||||||
</item>
|
</property>
|
||||||
</layout>
|
<property name="alignment">
|
||||||
</widget>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
</item>
|
</property>
|
||||||
<item>
|
</widget>
|
||||||
<widget class="QGroupBox" name="groupBox_5">
|
</item>
|
||||||
<property name="title">
|
<item row="0" column="2">
|
||||||
<string>b30KnnModelSelector.title</string>
|
<widget class="QLabel" name="dependencies_knnModelStatusLabel">
|
||||||
</property>
|
<property name="text">
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
<string notr="true">...</string>
|
||||||
<item>
|
</property>
|
||||||
<widget class="FileSelector" name="b30KnnModelSelector" native="true"/>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
<item row="0" column="3" rowspan="3">
|
||||||
</widget>
|
<widget class="Line" name="line_2">
|
||||||
</item>
|
<property name="orientation">
|
||||||
</layout>
|
<enum>Qt::Vertical</enum>
|
||||||
</item>
|
</property>
|
||||||
<item>
|
</widget>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
</item>
|
||||||
<item>
|
<item row="1" column="0">
|
||||||
<widget class="QGroupBox" name="groupBox_4">
|
<widget class="QLabel" name="label_2">
|
||||||
<property name="title">
|
<property name="text">
|
||||||
<string>phashDatabaseSelector.title</string>
|
<string>dependencies.b30KnnModel</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
<property name="alignment">
|
||||||
<item>
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
<widget class="FileSelector" name="phashDatabaseSelector" native="true"/>
|
</property>
|
||||||
</item>
|
</widget>
|
||||||
</layout>
|
</item>
|
||||||
</widget>
|
<item row="2" column="2">
|
||||||
</item>
|
<widget class="QLabel" name="dependencies_phashDatabaseStatusLabel">
|
||||||
<item>
|
<property name="text">
|
||||||
<widget class="QGroupBox" name="groupBox_2">
|
<string notr="true">...</string>
|
||||||
<property name="title">
|
</property>
|
||||||
<string>imageSelector.title</string>
|
</widget>
|
||||||
</property>
|
</item>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
<item row="0" column="1" rowspan="3">
|
||||||
<item>
|
<widget class="Line" name="line">
|
||||||
<widget class="FileSelector" name="imageSelector" native="true"/>
|
<property name="orientation">
|
||||||
</item>
|
<enum>Qt::Vertical</enum>
|
||||||
</layout>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string>dependencies.phashDatabase</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="2">
|
||||||
|
<widget class="QLabel" name="dependencies_b30KnnModelStatusLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="4">
|
||||||
|
<widget class="FileSelector" name="dependencies_knnModelSelector" native="true"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="4">
|
||||||
|
<widget class="FileSelector" name="dependencies_b30KnnModelSelector" native="true"/>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="4">
|
||||||
|
<widget class="FileSelector" name="dependencies_phashDatabaseSelector" native="true"/>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="OcrQueue" name="ocrQueue" native="true">
|
<widget class="OcrQueue" name="ocrQueue" native="true">
|
||||||
|
@ -15,8 +15,9 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
|||||||
QFont, QFontDatabase, QGradient, QIcon,
|
QFont, QFontDatabase, QGradient, QIcon,
|
||||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||||
from PySide6.QtWidgets import (QApplication, QComboBox, QGroupBox, QHBoxLayout,
|
from PySide6.QtWidgets import (QApplication, QComboBox, QFrame, QGridLayout,
|
||||||
QSizePolicy, QVBoxLayout, QWidget)
|
QGroupBox, QLabel, QSizePolicy, QVBoxLayout,
|
||||||
|
QWidget)
|
||||||
|
|
||||||
from ui.implements.components.fileSelector import FileSelector
|
from ui.implements.components.fileSelector import FileSelector
|
||||||
from ui.implements.components.ocrQueue import OcrQueue
|
from ui.implements.components.ocrQueue import OcrQueue
|
||||||
@ -27,8 +28,8 @@ class Ui_TabOcr_B30(object):
|
|||||||
TabOcr_B30.setObjectName(u"TabOcr_B30")
|
TabOcr_B30.setObjectName(u"TabOcr_B30")
|
||||||
TabOcr_B30.resize(555, 461)
|
TabOcr_B30.resize(555, 461)
|
||||||
TabOcr_B30.setWindowTitle(u"TabOcr_B30")
|
TabOcr_B30.setWindowTitle(u"TabOcr_B30")
|
||||||
self.verticalLayout_3 = QVBoxLayout(TabOcr_B30)
|
self.verticalLayout_2 = QVBoxLayout(TabOcr_B30)
|
||||||
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
|
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||||
self.groupBox = QGroupBox(TabOcr_B30)
|
self.groupBox = QGroupBox(TabOcr_B30)
|
||||||
self.groupBox.setObjectName(u"groupBox")
|
self.groupBox.setObjectName(u"groupBox")
|
||||||
self.verticalLayout = QVBoxLayout(self.groupBox)
|
self.verticalLayout = QVBoxLayout(self.groupBox)
|
||||||
@ -39,65 +40,80 @@ class Ui_TabOcr_B30(object):
|
|||||||
self.verticalLayout.addWidget(self.b30TypeComboBox)
|
self.verticalLayout.addWidget(self.b30TypeComboBox)
|
||||||
|
|
||||||
|
|
||||||
self.verticalLayout_3.addWidget(self.groupBox)
|
self.verticalLayout_2.addWidget(self.groupBox)
|
||||||
|
|
||||||
self.horizontalLayout = QHBoxLayout()
|
self.groupBox_6 = QGroupBox(TabOcr_B30)
|
||||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
self.groupBox_6.setObjectName(u"groupBox_6")
|
||||||
self.groupBox_3 = QGroupBox(TabOcr_B30)
|
self.gridLayout = QGridLayout(self.groupBox_6)
|
||||||
self.groupBox_3.setObjectName(u"groupBox_3")
|
self.gridLayout.setObjectName(u"gridLayout")
|
||||||
self.verticalLayout_4 = QVBoxLayout(self.groupBox_3)
|
self.label = QLabel(self.groupBox_6)
|
||||||
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
|
self.label.setObjectName(u"label")
|
||||||
self.knnModelSelector = FileSelector(self.groupBox_3)
|
self.label.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||||
self.knnModelSelector.setObjectName(u"knnModelSelector")
|
|
||||||
|
|
||||||
self.verticalLayout_4.addWidget(self.knnModelSelector)
|
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
|
||||||
|
|
||||||
|
self.dependencies_knnModelStatusLabel = QLabel(self.groupBox_6)
|
||||||
|
self.dependencies_knnModelStatusLabel.setObjectName(u"dependencies_knnModelStatusLabel")
|
||||||
|
self.dependencies_knnModelStatusLabel.setText(u"...")
|
||||||
|
|
||||||
self.horizontalLayout.addWidget(self.groupBox_3)
|
self.gridLayout.addWidget(self.dependencies_knnModelStatusLabel, 0, 2, 1, 1)
|
||||||
|
|
||||||
self.groupBox_5 = QGroupBox(TabOcr_B30)
|
self.line_2 = QFrame(self.groupBox_6)
|
||||||
self.groupBox_5.setObjectName(u"groupBox_5")
|
self.line_2.setObjectName(u"line_2")
|
||||||
self.verticalLayout_6 = QVBoxLayout(self.groupBox_5)
|
self.line_2.setFrameShape(QFrame.VLine)
|
||||||
self.verticalLayout_6.setObjectName(u"verticalLayout_6")
|
self.line_2.setFrameShadow(QFrame.Sunken)
|
||||||
self.b30KnnModelSelector = FileSelector(self.groupBox_5)
|
|
||||||
self.b30KnnModelSelector.setObjectName(u"b30KnnModelSelector")
|
|
||||||
|
|
||||||
self.verticalLayout_6.addWidget(self.b30KnnModelSelector)
|
self.gridLayout.addWidget(self.line_2, 0, 3, 3, 1)
|
||||||
|
|
||||||
|
self.label_2 = QLabel(self.groupBox_6)
|
||||||
|
self.label_2.setObjectName(u"label_2")
|
||||||
|
self.label_2.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||||
|
|
||||||
self.horizontalLayout.addWidget(self.groupBox_5)
|
self.gridLayout.addWidget(self.label_2, 1, 0, 1, 1)
|
||||||
|
|
||||||
|
self.dependencies_phashDatabaseStatusLabel = QLabel(self.groupBox_6)
|
||||||
|
self.dependencies_phashDatabaseStatusLabel.setObjectName(u"dependencies_phashDatabaseStatusLabel")
|
||||||
|
self.dependencies_phashDatabaseStatusLabel.setText(u"...")
|
||||||
|
|
||||||
self.verticalLayout_3.addLayout(self.horizontalLayout)
|
self.gridLayout.addWidget(self.dependencies_phashDatabaseStatusLabel, 2, 2, 1, 1)
|
||||||
|
|
||||||
self.horizontalLayout_3 = QHBoxLayout()
|
self.line = QFrame(self.groupBox_6)
|
||||||
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
|
self.line.setObjectName(u"line")
|
||||||
self.groupBox_4 = QGroupBox(TabOcr_B30)
|
self.line.setFrameShape(QFrame.VLine)
|
||||||
self.groupBox_4.setObjectName(u"groupBox_4")
|
self.line.setFrameShadow(QFrame.Sunken)
|
||||||
self.verticalLayout_5 = QVBoxLayout(self.groupBox_4)
|
|
||||||
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
|
|
||||||
self.phashDatabaseSelector = FileSelector(self.groupBox_4)
|
|
||||||
self.phashDatabaseSelector.setObjectName(u"phashDatabaseSelector")
|
|
||||||
|
|
||||||
self.verticalLayout_5.addWidget(self.phashDatabaseSelector)
|
self.gridLayout.addWidget(self.line, 0, 1, 3, 1)
|
||||||
|
|
||||||
|
self.label_3 = QLabel(self.groupBox_6)
|
||||||
|
self.label_3.setObjectName(u"label_3")
|
||||||
|
self.label_3.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||||
|
|
||||||
self.horizontalLayout_3.addWidget(self.groupBox_4)
|
self.gridLayout.addWidget(self.label_3, 2, 0, 1, 1)
|
||||||
|
|
||||||
self.groupBox_2 = QGroupBox(TabOcr_B30)
|
self.dependencies_b30KnnModelStatusLabel = QLabel(self.groupBox_6)
|
||||||
self.groupBox_2.setObjectName(u"groupBox_2")
|
self.dependencies_b30KnnModelStatusLabel.setObjectName(u"dependencies_b30KnnModelStatusLabel")
|
||||||
self.verticalLayout_2 = QVBoxLayout(self.groupBox_2)
|
self.dependencies_b30KnnModelStatusLabel.setText(u"...")
|
||||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
|
||||||
self.imageSelector = FileSelector(self.groupBox_2)
|
|
||||||
self.imageSelector.setObjectName(u"imageSelector")
|
|
||||||
|
|
||||||
self.verticalLayout_2.addWidget(self.imageSelector)
|
self.gridLayout.addWidget(self.dependencies_b30KnnModelStatusLabel, 1, 2, 1, 1)
|
||||||
|
|
||||||
|
self.dependencies_knnModelSelector = FileSelector(self.groupBox_6)
|
||||||
|
self.dependencies_knnModelSelector.setObjectName(u"dependencies_knnModelSelector")
|
||||||
|
|
||||||
self.horizontalLayout_3.addWidget(self.groupBox_2)
|
self.gridLayout.addWidget(self.dependencies_knnModelSelector, 0, 4, 1, 1)
|
||||||
|
|
||||||
|
self.dependencies_b30KnnModelSelector = FileSelector(self.groupBox_6)
|
||||||
|
self.dependencies_b30KnnModelSelector.setObjectName(u"dependencies_b30KnnModelSelector")
|
||||||
|
|
||||||
self.verticalLayout_3.addLayout(self.horizontalLayout_3)
|
self.gridLayout.addWidget(self.dependencies_b30KnnModelSelector, 1, 4, 1, 1)
|
||||||
|
|
||||||
|
self.dependencies_phashDatabaseSelector = FileSelector(self.groupBox_6)
|
||||||
|
self.dependencies_phashDatabaseSelector.setObjectName(u"dependencies_phashDatabaseSelector")
|
||||||
|
|
||||||
|
self.gridLayout.addWidget(self.dependencies_phashDatabaseSelector, 2, 4, 1, 1)
|
||||||
|
|
||||||
|
self.gridLayout.setColumnStretch(4, 1)
|
||||||
|
|
||||||
|
self.verticalLayout_2.addWidget(self.groupBox_6)
|
||||||
|
|
||||||
self.ocrQueue = OcrQueue(TabOcr_B30)
|
self.ocrQueue = OcrQueue(TabOcr_B30)
|
||||||
self.ocrQueue.setObjectName(u"ocrQueue")
|
self.ocrQueue.setObjectName(u"ocrQueue")
|
||||||
@ -107,7 +123,7 @@ class Ui_TabOcr_B30(object):
|
|||||||
sizePolicy.setHeightForWidth(self.ocrQueue.sizePolicy().hasHeightForWidth())
|
sizePolicy.setHeightForWidth(self.ocrQueue.sizePolicy().hasHeightForWidth())
|
||||||
self.ocrQueue.setSizePolicy(sizePolicy)
|
self.ocrQueue.setSizePolicy(sizePolicy)
|
||||||
|
|
||||||
self.verticalLayout_3.addWidget(self.ocrQueue)
|
self.verticalLayout_2.addWidget(self.ocrQueue)
|
||||||
|
|
||||||
|
|
||||||
self.retranslateUi(TabOcr_B30)
|
self.retranslateUi(TabOcr_B30)
|
||||||
@ -117,10 +133,10 @@ class Ui_TabOcr_B30(object):
|
|||||||
|
|
||||||
def retranslateUi(self, TabOcr_B30):
|
def retranslateUi(self, TabOcr_B30):
|
||||||
self.groupBox.setTitle(QCoreApplication.translate("TabOcr_B30", u"b30type", None))
|
self.groupBox.setTitle(QCoreApplication.translate("TabOcr_B30", u"b30type", None))
|
||||||
self.groupBox_3.setTitle(QCoreApplication.translate("TabOcr_B30", u"knnModelSelector.title", None))
|
self.groupBox_6.setTitle(QCoreApplication.translate("TabOcr_B30", u"dependencies.title", None))
|
||||||
self.groupBox_5.setTitle(QCoreApplication.translate("TabOcr_B30", u"b30KnnModelSelector.title", None))
|
self.label.setText(QCoreApplication.translate("TabOcr_B30", u"dependencies.knnModel", None))
|
||||||
self.groupBox_4.setTitle(QCoreApplication.translate("TabOcr_B30", u"phashDatabaseSelector.title", None))
|
self.label_2.setText(QCoreApplication.translate("TabOcr_B30", u"dependencies.b30KnnModel", None))
|
||||||
self.groupBox_2.setTitle(QCoreApplication.translate("TabOcr_B30", u"imageSelector.title", None))
|
self.label_3.setText(QCoreApplication.translate("TabOcr_B30", u"dependencies.phashDatabase", None))
|
||||||
pass
|
pass
|
||||||
# retranslateUi
|
# retranslateUi
|
||||||
|
|
||||||
|
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,249 @@
|
|||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="groupBox">
|
<widget class="QGroupBox" name="groupBox">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>deviceSelector.title</string>
|
<string>options.title</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QHBoxLayout" name="horizontalLayout" stretch="0,0,0">
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="deviceUseAutoFactorCheckBox">
|
<widget class="QCheckBox" name="options_usePresetCheckBox">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>deviceSelector.useAutoFactor</string>
|
<string>options.usePreset</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QCheckBox" name="deviceSizesV2CheckBox">
|
<widget class="QComboBox" name="options_presetComboBox">
|
||||||
<property name="text">
|
<property name="enabled">
|
||||||
<string notr="true">SizesV2</string>
|
<bool>false</bool>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<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>
|
||||||
<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="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<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="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<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>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QWidget" name="horizontalWidget" native="true">
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
<property name="sizePolicy">
|
<property name="title">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Maximum">
|
<string>dependencies.title</string>
|
||||||
<horstretch>0</horstretch>
|
|
||||||
<verstretch>0</verstretch>
|
|
||||||
</sizepolicy>
|
|
||||||
</property>
|
</property>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_2">
|
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0,0,1">
|
||||||
<property name="leftMargin">
|
<item row="0" column="0">
|
||||||
<number>0</number>
|
<widget class="QLabel" name="label_3">
|
||||||
</property>
|
<property name="text">
|
||||||
<property name="topMargin">
|
<string>dependencies.knnModel</string>
|
||||||
<number>0</number>
|
</property>
|
||||||
</property>
|
<property name="alignment">
|
||||||
<property name="rightMargin">
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
<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>
|
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
|
||||||
<item>
|
|
||||||
<widget class="FileSelector" name="knnModelSelector" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="2">
|
||||||
<widget class="QStackedWidget" name="deviceDependenciesStackedWidget">
|
<widget class="QLabel" name="dependencies_knnModelStatusLabel">
|
||||||
<property name="currentIndex">
|
<property name="text">
|
||||||
<number>0</number>
|
<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>
|
</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>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@ -178,12 +297,24 @@
|
|||||||
<header>ui.implements.components.ocrQueue</header>
|
<header>ui.implements.components.ocrQueue</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
<customwidget>
|
|
||||||
<class>DevicesComboBox</class>
|
|
||||||
<extends>QComboBox</extends>
|
|
||||||
<header>ui.implements.components.devicesComboBox</header>
|
|
||||||
</customwidget>
|
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<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>
|
</ui>
|
||||||
|
@ -15,11 +15,11 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
|||||||
QFont, QFontDatabase, QGradient, QIcon,
|
QFont, QFontDatabase, QGradient, QIcon,
|
||||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
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,
|
QPushButton, QSizePolicy, QStackedWidget, QVBoxLayout,
|
||||||
QWidget)
|
QWidget)
|
||||||
|
|
||||||
from ui.implements.components.devicesComboBox import DevicesComboBox
|
|
||||||
from ui.implements.components.fileSelector import FileSelector
|
from ui.implements.components.fileSelector import FileSelector
|
||||||
from ui.implements.components.ocrQueue import OcrQueue
|
from ui.implements.components.ocrQueue import OcrQueue
|
||||||
|
|
||||||
@ -38,102 +38,181 @@ class Ui_TabOcr_Device(object):
|
|||||||
|
|
||||||
self.groupBox = QGroupBox(TabOcr_Device)
|
self.groupBox = QGroupBox(TabOcr_Device)
|
||||||
self.groupBox.setObjectName(u"groupBox")
|
self.groupBox.setObjectName(u"groupBox")
|
||||||
self.verticalLayout = QVBoxLayout(self.groupBox)
|
self.horizontalLayout = QHBoxLayout(self.groupBox)
|
||||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
|
||||||
self.horizontalLayout = QHBoxLayout()
|
|
||||||
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
self.horizontalLayout.setObjectName(u"horizontalLayout")
|
||||||
self.deviceUseAutoFactorCheckBox = QCheckBox(self.groupBox)
|
self.verticalLayout = QVBoxLayout()
|
||||||
self.deviceUseAutoFactorCheckBox.setObjectName(u"deviceUseAutoFactorCheckBox")
|
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.options_presetComboBox = QComboBox(self.groupBox)
|
||||||
self.deviceSizesV2CheckBox.setObjectName(u"deviceSizesV2CheckBox")
|
self.options_presetComboBox.setObjectName(u"options_presetComboBox")
|
||||||
self.deviceSizesV2CheckBox.setText(u"SizesV2")
|
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.line_3 = QFrame(self.groupBox)
|
||||||
self.deviceFileSelector.setObjectName(u"deviceFileSelector")
|
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.options_preciseControlWidget = QWidget(self.groupBox)
|
||||||
self.deviceComboBox.setObjectName(u"deviceComboBox")
|
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")
|
||||||
|
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.options_roisStackedWidget.sizePolicy().hasHeightForWidth())
|
||||||
|
self.options_roisStackedWidget.setSizePolicy(sizePolicy)
|
||||||
|
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")
|
||||||
|
sizePolicy.setHeightForWidth(self.options_maskerStackedWidget.sizePolicy().hasHeightForWidth())
|
||||||
|
self.options_maskerStackedWidget.setSizePolicy(sizePolicy)
|
||||||
|
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.verticalLayout_3.addWidget(self.groupBox)
|
||||||
|
|
||||||
self.horizontalWidget = QWidget(TabOcr_Device)
|
self.groupBox_2 = QGroupBox(TabOcr_Device)
|
||||||
self.horizontalWidget.setObjectName(u"horizontalWidget")
|
self.groupBox_2.setObjectName(u"groupBox_2")
|
||||||
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
|
self.gridLayout = QGridLayout(self.groupBox_2)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
self.gridLayout.setObjectName(u"gridLayout")
|
||||||
sizePolicy.setVerticalStretch(0)
|
self.label_3 = QLabel(self.groupBox_2)
|
||||||
sizePolicy.setHeightForWidth(self.horizontalWidget.sizePolicy().hasHeightForWidth())
|
self.label_3.setObjectName(u"label_3")
|
||||||
self.horizontalWidget.setSizePolicy(sizePolicy)
|
self.label_3.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||||
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.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.dependencies_phashDatabaseStatusLabel = QLabel(self.groupBox_2)
|
||||||
self.deviceDependenciesStackedWidget.setObjectName(u"deviceDependenciesStackedWidget")
|
self.dependencies_phashDatabaseStatusLabel.setObjectName(u"dependencies_phashDatabaseStatusLabel")
|
||||||
self.deviceV1 = QWidget()
|
self.dependencies_phashDatabaseStatusLabel.setText(u"...")
|
||||||
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.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.line = QFrame(self.groupBox_2)
|
||||||
self.deviceV2 = QWidget()
|
self.line.setObjectName(u"line")
|
||||||
self.deviceV2.setObjectName(u"deviceV2")
|
self.line.setFrameShape(QFrame.VLine)
|
||||||
self.verticalLayout_4 = QVBoxLayout(self.deviceV2)
|
self.line.setFrameShadow(QFrame.Sunken)
|
||||||
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.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 = OcrQueue(TabOcr_Device)
|
||||||
self.ocrQueue.setObjectName(u"ocrQueue")
|
self.ocrQueue.setObjectName(u"ocrQueue")
|
||||||
@ -147,8 +226,10 @@ class Ui_TabOcr_Device(object):
|
|||||||
|
|
||||||
|
|
||||||
self.retranslateUi(TabOcr_Device)
|
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)
|
QMetaObject.connectSlotsByName(TabOcr_Device)
|
||||||
@ -156,11 +237,15 @@ class Ui_TabOcr_Device(object):
|
|||||||
|
|
||||||
def retranslateUi(self, TabOcr_Device):
|
def retranslateUi(self, TabOcr_Device):
|
||||||
self.openWizardButton.setText(QCoreApplication.translate("TabOcr_Device", u"openWizardButton", None))
|
self.openWizardButton.setText(QCoreApplication.translate("TabOcr_Device", u"openWizardButton", None))
|
||||||
self.groupBox.setTitle(QCoreApplication.translate("TabOcr_Device", u"deviceSelector.title", None))
|
self.groupBox.setTitle(QCoreApplication.translate("TabOcr_Device", u"options.title", None))
|
||||||
self.deviceUseAutoFactorCheckBox.setText(QCoreApplication.translate("TabOcr_Device", u"deviceSelector.useAutoFactor", None))
|
self.options_usePresetCheckBox.setText(QCoreApplication.translate("TabOcr_Device", u"options.usePreset", None))
|
||||||
self.groupBox_6.setTitle(QCoreApplication.translate("TabOcr_Device", u"knnModelSelector.title", None))
|
self.label.setText(QCoreApplication.translate("TabOcr_Device", u"options.rois", None))
|
||||||
self.groupBox_4.setTitle(QCoreApplication.translate("TabOcr_Device", u"tesseractSelector.title", None))
|
self.label_2.setText(QCoreApplication.translate("TabOcr_Device", u"options.masker", None))
|
||||||
self.groupBox_5.setTitle(QCoreApplication.translate("TabOcr_Device", u"phashDatabaseSelector.title", 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
|
pass
|
||||||
# retranslateUi
|
# retranslateUi
|
||||||
|
|
||||||
|
@ -29,6 +29,11 @@
|
|||||||
<string>tab.b30</string>
|
<string>tab.b30</string>
|
||||||
</attribute>
|
</attribute>
|
||||||
</widget>
|
</widget>
|
||||||
|
<widget class="TabOcr_BuildPHashDatabase" name="tab_3">
|
||||||
|
<attribute name="title">
|
||||||
|
<string>tab.buildPHashDatabase</string>
|
||||||
|
</attribute>
|
||||||
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
@ -46,6 +51,12 @@
|
|||||||
<header>ui.implements.tabs.tabOcr.tabOcr_B30</header>
|
<header>ui.implements.tabs.tabOcr.tabOcr_B30</header>
|
||||||
<container>1</container>
|
<container>1</container>
|
||||||
</customwidget>
|
</customwidget>
|
||||||
|
<customwidget>
|
||||||
|
<class>TabOcr_BuildPHashDatabase</class>
|
||||||
|
<extends>QWidget</extends>
|
||||||
|
<header>ui.implements.tabs.tabOcr.tabOcr_BuildPHashDatabase</header>
|
||||||
|
<container>1</container>
|
||||||
|
</customwidget>
|
||||||
</customwidgets>
|
</customwidgets>
|
||||||
<resources/>
|
<resources/>
|
||||||
<connections/>
|
<connections/>
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
################################################################################
|
################################################################################
|
||||||
## Form generated from reading UI file 'tabOcrEntry.ui'
|
## 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!
|
## 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)
|
QWidget)
|
||||||
|
|
||||||
from ui.implements.tabs.tabOcr.tabOcr_B30 import TabOcr_B30
|
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
|
from ui.implements.tabs.tabOcr.tabOcr_Device import TabOcr_Device
|
||||||
|
|
||||||
class Ui_TabOcrEntry(object):
|
class Ui_TabOcrEntry(object):
|
||||||
@ -37,6 +38,9 @@ class Ui_TabOcrEntry(object):
|
|||||||
self.tab_2 = TabOcr_B30()
|
self.tab_2 = TabOcr_B30()
|
||||||
self.tab_2.setObjectName(u"tab_2")
|
self.tab_2.setObjectName(u"tab_2")
|
||||||
self.tabWidget.addTab(self.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)
|
self.verticalLayout.addWidget(self.tabWidget)
|
||||||
|
|
||||||
@ -52,6 +56,7 @@ class Ui_TabOcrEntry(object):
|
|||||||
def retranslateUi(self, TabOcrEntry):
|
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), 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_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
|
pass
|
||||||
# retranslateUi
|
# retranslateUi
|
||||||
|
|
||||||
|
@ -6,113 +6,15 @@
|
|||||||
<rect>
|
<rect>
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>668</width>
|
<width>616</width>
|
||||||
<height>546</height>
|
<height>500</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
<string notr="true">TabTools_ChartRecommend</string>
|
<string notr="true">TabTools_ChartRecommend</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QGridLayout" name="gridLayout">
|
||||||
<item>
|
<item row="0" column="1">
|
||||||
<widget class="QGroupBox" name="groupBox">
|
|
||||||
<property name="title">
|
|
||||||
<string>constantRangeFromPlayRating</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="QDoubleSpinBox" name="rangeFromPlayRating_playRatingSpinBox">
|
|
||||||
<property name="minimumSize">
|
|
||||||
<size>
|
|
||||||
<width>100</width>
|
|
||||||
<height>0</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="maximumSize">
|
|
||||||
<size>
|
|
||||||
<width>100</width>
|
|
||||||
<height>16777215</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
<property name="decimals">
|
|
||||||
<number>3</number>
|
|
||||||
</property>
|
|
||||||
<property name="maximum">
|
|
||||||
<double>100.000000000000000</double>
|
|
||||||
</property>
|
|
||||||
<property name="singleStep">
|
|
||||||
<double>0.100000000000000</double>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QGridLayout" name="gridLayout_3">
|
|
||||||
<item row="0" column="2">
|
|
||||||
<widget class="QLabel" name="label_3">
|
|
||||||
<property name="text">
|
|
||||||
<string notr="true">AA</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="1">
|
|
||||||
<widget class="QLabel" name="label_2">
|
|
||||||
<property name="text">
|
|
||||||
<string notr="true">EX</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="0" column="0">
|
|
||||||
<widget class="QLabel" name="label">
|
|
||||||
<property name="text">
|
|
||||||
<string notr="true">EX+</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="0">
|
|
||||||
<widget class="QLabel" name="rangeFromPlayRating_ExPlusLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string notr="true">...</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="1">
|
|
||||||
<widget class="QLabel" name="rangeFromPlayRating_ExLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string notr="true">...</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item row="1" column="2">
|
|
||||||
<widget class="QLabel" name="rangeFromPlayRating_AaLabel">
|
|
||||||
<property name="text">
|
|
||||||
<string notr="true">...</string>
|
|
||||||
</property>
|
|
||||||
<property name="alignment">
|
|
||||||
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_2">
|
<widget class="QGroupBox" name="groupBox_2">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>chartsByConstant</string>
|
<string>chartsByConstant</string>
|
||||||
@ -147,51 +49,197 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="chartsByConstant_numLabel">
|
<widget class="QLabel" name="chartsByConstant_numLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">...</string>
|
<string notr="true">...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<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="chartsByConstant_refreshButton">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>refreshButton</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QWidget" name="widget" native="true">
|
<widget class="QListView" name="chartsByConstant_modelView">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="chartsByConstant_gridLayout"/>
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>150</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::NoSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="verticalScrollMode">
|
||||||
|
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollMode">
|
||||||
|
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="0">
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>constantRangeFromPlayRating</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QDoubleSpinBox" name="rangeFromPlayRating_playRatingSpinBox">
|
||||||
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="maximumSize">
|
||||||
|
<size>
|
||||||
|
<width>100</width>
|
||||||
|
<height>16777215</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="decimals">
|
||||||
|
<number>3</number>
|
||||||
|
</property>
|
||||||
|
<property name="maximum">
|
||||||
|
<double>100.000000000000000</double>
|
||||||
|
</property>
|
||||||
|
<property name="singleStep">
|
||||||
|
<double>0.100000000000000</double>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QFormLayout" name="formLayout">
|
||||||
|
<property name="labelAlignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<property name="formAlignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">EX+</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QLabel" name="rangeFromPlayRating_ExPlusLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">...</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">EX</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1">
|
||||||
|
<widget class="QLabel" name="rangeFromPlayRating_ExLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">...</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="label_3">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">AA</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignBottom|Qt::AlignLeading|Qt::AlignLeft</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="rangeFromPlayRating_AaLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">...</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="0">
|
||||||
|
<widget class="QLabel" name="label_5">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">A</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="3" column="1">
|
||||||
|
<widget class="QLabel" name="rangeFromPlayRating_ALabel">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="0">
|
||||||
|
<widget class="QLabel" name="label_8">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">B</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="4" column="1">
|
||||||
|
<widget class="QLabel" name="rangeFromPlayRating_BLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="0">
|
||||||
|
<widget class="QLabel" name="label_10">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">C</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="5" column="1">
|
||||||
|
<widget class="QLabel" name="rangeFromPlayRating_CLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0" colspan="2">
|
||||||
<widget class="QGroupBox" name="groupBox_3">
|
<widget class="QGroupBox" name="groupBox_3">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>chartsRecommendFromPlayRating</string>
|
<string>chartsRecommendFromPlayRating</string>
|
||||||
@ -246,45 +294,48 @@
|
|||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="chartsRecommendFromPlayRating_numLabel">
|
<widget class="QLabel" name="chartsRecommendFromPlayRating_numLabel">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string notr="true">...</string>
|
<string notr="true">...</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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>
|
|
||||||
<item>
|
|
||||||
<widget class="QPushButton" name="chartsRecommendFromPlayRating_refreshButton">
|
|
||||||
<property name="enabled">
|
|
||||||
<bool>false</bool>
|
|
||||||
</property>
|
|
||||||
<property name="text">
|
|
||||||
<string>refreshButton</string>
|
|
||||||
</property>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
</layout>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QWidget" name="widget_2" native="true">
|
<widget class="QTableView" name="chartsRecommendFromPlayRating_modelView">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||||
<horstretch>0</horstretch>
|
<horstretch>0</horstretch>
|
||||||
<verstretch>0</verstretch>
|
<verstretch>0</verstretch>
|
||||||
</sizepolicy>
|
</sizepolicy>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QGridLayout" name="chartsRecommendFromPlayRating_gridLayout"/>
|
<property name="minimumSize">
|
||||||
|
<size>
|
||||||
|
<width>200</width>
|
||||||
|
<height>0</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
<property name="editTriggers">
|
||||||
|
<set>QAbstractItemView::NoEditTriggers</set>
|
||||||
|
</property>
|
||||||
|
<property name="selectionMode">
|
||||||
|
<enum>QAbstractItemView::SingleSelection</enum>
|
||||||
|
</property>
|
||||||
|
<property name="selectionBehavior">
|
||||||
|
<enum>QAbstractItemView::SelectRows</enum>
|
||||||
|
</property>
|
||||||
|
<property name="verticalScrollMode">
|
||||||
|
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||||
|
</property>
|
||||||
|
<property name="horizontalScrollMode">
|
||||||
|
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
|
@ -15,82 +15,19 @@ from PySide6.QtGui import (QBrush, QColor, QConicalGradient, QCursor,
|
|||||||
QFont, QFontDatabase, QGradient, QIcon,
|
QFont, QFontDatabase, QGradient, QIcon,
|
||||||
QImage, QKeySequence, QLinearGradient, QPainter,
|
QImage, QKeySequence, QLinearGradient, QPainter,
|
||||||
QPalette, QPixmap, QRadialGradient, QTransform)
|
QPalette, QPixmap, QRadialGradient, QTransform)
|
||||||
from PySide6.QtWidgets import (QApplication, QDoubleSpinBox, QGridLayout, QGroupBox,
|
from PySide6.QtWidgets import (QAbstractItemView, QApplication, QDoubleSpinBox, QFormLayout,
|
||||||
QHBoxLayout, QLabel, QPushButton, QSizePolicy,
|
QGridLayout, QGroupBox, QHBoxLayout, QHeaderView,
|
||||||
QSpacerItem, QVBoxLayout, QWidget)
|
QLabel, QListView, QSizePolicy, QTableView,
|
||||||
|
QVBoxLayout, QWidget)
|
||||||
|
|
||||||
class Ui_TabTools_ChartRecommend(object):
|
class Ui_TabTools_ChartRecommend(object):
|
||||||
def setupUi(self, TabTools_ChartRecommend):
|
def setupUi(self, TabTools_ChartRecommend):
|
||||||
if not TabTools_ChartRecommend.objectName():
|
if not TabTools_ChartRecommend.objectName():
|
||||||
TabTools_ChartRecommend.setObjectName(u"TabTools_ChartRecommend")
|
TabTools_ChartRecommend.setObjectName(u"TabTools_ChartRecommend")
|
||||||
TabTools_ChartRecommend.resize(668, 546)
|
TabTools_ChartRecommend.resize(616, 500)
|
||||||
TabTools_ChartRecommend.setWindowTitle(u"TabTools_ChartRecommend")
|
TabTools_ChartRecommend.setWindowTitle(u"TabTools_ChartRecommend")
|
||||||
self.verticalLayout = QVBoxLayout(TabTools_ChartRecommend)
|
self.gridLayout = QGridLayout(TabTools_ChartRecommend)
|
||||||
self.verticalLayout.setObjectName(u"verticalLayout")
|
self.gridLayout.setObjectName(u"gridLayout")
|
||||||
self.groupBox = QGroupBox(TabTools_ChartRecommend)
|
|
||||||
self.groupBox.setObjectName(u"groupBox")
|
|
||||||
self.verticalLayout_2 = QVBoxLayout(self.groupBox)
|
|
||||||
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
|
||||||
self.rangeFromPlayRating_playRatingSpinBox = QDoubleSpinBox(self.groupBox)
|
|
||||||
self.rangeFromPlayRating_playRatingSpinBox.setObjectName(u"rangeFromPlayRating_playRatingSpinBox")
|
|
||||||
self.rangeFromPlayRating_playRatingSpinBox.setMinimumSize(QSize(100, 0))
|
|
||||||
self.rangeFromPlayRating_playRatingSpinBox.setMaximumSize(QSize(100, 16777215))
|
|
||||||
self.rangeFromPlayRating_playRatingSpinBox.setDecimals(3)
|
|
||||||
self.rangeFromPlayRating_playRatingSpinBox.setMaximum(100.000000000000000)
|
|
||||||
self.rangeFromPlayRating_playRatingSpinBox.setSingleStep(0.100000000000000)
|
|
||||||
|
|
||||||
self.verticalLayout_2.addWidget(self.rangeFromPlayRating_playRatingSpinBox)
|
|
||||||
|
|
||||||
self.gridLayout_3 = QGridLayout()
|
|
||||||
self.gridLayout_3.setObjectName(u"gridLayout_3")
|
|
||||||
self.label_3 = QLabel(self.groupBox)
|
|
||||||
self.label_3.setObjectName(u"label_3")
|
|
||||||
self.label_3.setText(u"AA")
|
|
||||||
self.label_3.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
|
|
||||||
|
|
||||||
self.gridLayout_3.addWidget(self.label_3, 0, 2, 1, 1)
|
|
||||||
|
|
||||||
self.label_2 = QLabel(self.groupBox)
|
|
||||||
self.label_2.setObjectName(u"label_2")
|
|
||||||
self.label_2.setText(u"EX")
|
|
||||||
self.label_2.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
|
|
||||||
|
|
||||||
self.gridLayout_3.addWidget(self.label_2, 0, 1, 1, 1)
|
|
||||||
|
|
||||||
self.label = QLabel(self.groupBox)
|
|
||||||
self.label.setObjectName(u"label")
|
|
||||||
self.label.setText(u"EX+")
|
|
||||||
self.label.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
|
|
||||||
|
|
||||||
self.gridLayout_3.addWidget(self.label, 0, 0, 1, 1)
|
|
||||||
|
|
||||||
self.rangeFromPlayRating_ExPlusLabel = QLabel(self.groupBox)
|
|
||||||
self.rangeFromPlayRating_ExPlusLabel.setObjectName(u"rangeFromPlayRating_ExPlusLabel")
|
|
||||||
self.rangeFromPlayRating_ExPlusLabel.setText(u"...")
|
|
||||||
self.rangeFromPlayRating_ExPlusLabel.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)
|
|
||||||
|
|
||||||
self.gridLayout_3.addWidget(self.rangeFromPlayRating_ExPlusLabel, 1, 0, 1, 1)
|
|
||||||
|
|
||||||
self.rangeFromPlayRating_ExLabel = QLabel(self.groupBox)
|
|
||||||
self.rangeFromPlayRating_ExLabel.setObjectName(u"rangeFromPlayRating_ExLabel")
|
|
||||||
self.rangeFromPlayRating_ExLabel.setText(u"...")
|
|
||||||
self.rangeFromPlayRating_ExLabel.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)
|
|
||||||
|
|
||||||
self.gridLayout_3.addWidget(self.rangeFromPlayRating_ExLabel, 1, 1, 1, 1)
|
|
||||||
|
|
||||||
self.rangeFromPlayRating_AaLabel = QLabel(self.groupBox)
|
|
||||||
self.rangeFromPlayRating_AaLabel.setObjectName(u"rangeFromPlayRating_AaLabel")
|
|
||||||
self.rangeFromPlayRating_AaLabel.setText(u"...")
|
|
||||||
self.rangeFromPlayRating_AaLabel.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)
|
|
||||||
|
|
||||||
self.gridLayout_3.addWidget(self.rangeFromPlayRating_AaLabel, 1, 2, 1, 1)
|
|
||||||
|
|
||||||
|
|
||||||
self.verticalLayout_2.addLayout(self.gridLayout_3)
|
|
||||||
|
|
||||||
|
|
||||||
self.verticalLayout.addWidget(self.groupBox)
|
|
||||||
|
|
||||||
self.groupBox_2 = QGroupBox(TabTools_ChartRecommend)
|
self.groupBox_2 = QGroupBox(TabTools_ChartRecommend)
|
||||||
self.groupBox_2.setObjectName(u"groupBox_2")
|
self.groupBox_2.setObjectName(u"groupBox_2")
|
||||||
self.verticalLayout_3 = QVBoxLayout(self.groupBox_2)
|
self.verticalLayout_3 = QVBoxLayout(self.groupBox_2)
|
||||||
@ -109,37 +46,137 @@ class Ui_TabTools_ChartRecommend(object):
|
|||||||
|
|
||||||
self.chartsByConstant_numLabel = QLabel(self.groupBox_2)
|
self.chartsByConstant_numLabel = QLabel(self.groupBox_2)
|
||||||
self.chartsByConstant_numLabel.setObjectName(u"chartsByConstant_numLabel")
|
self.chartsByConstant_numLabel.setObjectName(u"chartsByConstant_numLabel")
|
||||||
|
sizePolicy = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Preferred)
|
||||||
|
sizePolicy.setHorizontalStretch(0)
|
||||||
|
sizePolicy.setVerticalStretch(0)
|
||||||
|
sizePolicy.setHeightForWidth(self.chartsByConstant_numLabel.sizePolicy().hasHeightForWidth())
|
||||||
|
self.chartsByConstant_numLabel.setSizePolicy(sizePolicy)
|
||||||
self.chartsByConstant_numLabel.setText(u"...")
|
self.chartsByConstant_numLabel.setText(u"...")
|
||||||
|
|
||||||
self.horizontalLayout_3.addWidget(self.chartsByConstant_numLabel)
|
self.horizontalLayout_3.addWidget(self.chartsByConstant_numLabel)
|
||||||
|
|
||||||
self.horizontalSpacer = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
|
||||||
|
|
||||||
self.horizontalLayout_3.addItem(self.horizontalSpacer)
|
|
||||||
|
|
||||||
self.chartsByConstant_refreshButton = QPushButton(self.groupBox_2)
|
|
||||||
self.chartsByConstant_refreshButton.setObjectName(u"chartsByConstant_refreshButton")
|
|
||||||
self.chartsByConstant_refreshButton.setEnabled(False)
|
|
||||||
|
|
||||||
self.horizontalLayout_3.addWidget(self.chartsByConstant_refreshButton)
|
|
||||||
|
|
||||||
|
|
||||||
self.verticalLayout_3.addLayout(self.horizontalLayout_3)
|
self.verticalLayout_3.addLayout(self.horizontalLayout_3)
|
||||||
|
|
||||||
self.widget = QWidget(self.groupBox_2)
|
self.chartsByConstant_modelView = QListView(self.groupBox_2)
|
||||||
self.widget.setObjectName(u"widget")
|
self.chartsByConstant_modelView.setObjectName(u"chartsByConstant_modelView")
|
||||||
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
|
sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
|
||||||
sizePolicy.setHorizontalStretch(0)
|
sizePolicy1.setHorizontalStretch(0)
|
||||||
sizePolicy.setVerticalStretch(0)
|
sizePolicy1.setVerticalStretch(0)
|
||||||
sizePolicy.setHeightForWidth(self.widget.sizePolicy().hasHeightForWidth())
|
sizePolicy1.setHeightForWidth(self.chartsByConstant_modelView.sizePolicy().hasHeightForWidth())
|
||||||
self.widget.setSizePolicy(sizePolicy)
|
self.chartsByConstant_modelView.setSizePolicy(sizePolicy1)
|
||||||
self.chartsByConstant_gridLayout = QGridLayout(self.widget)
|
self.chartsByConstant_modelView.setMinimumSize(QSize(150, 0))
|
||||||
self.chartsByConstant_gridLayout.setObjectName(u"chartsByConstant_gridLayout")
|
self.chartsByConstant_modelView.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
||||||
|
self.chartsByConstant_modelView.setSelectionMode(QAbstractItemView.NoSelection)
|
||||||
|
self.chartsByConstant_modelView.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||||
|
self.chartsByConstant_modelView.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||||
|
|
||||||
self.verticalLayout_3.addWidget(self.widget)
|
self.verticalLayout_3.addWidget(self.chartsByConstant_modelView)
|
||||||
|
|
||||||
|
|
||||||
self.verticalLayout.addWidget(self.groupBox_2)
|
self.gridLayout.addWidget(self.groupBox_2, 0, 1, 1, 1)
|
||||||
|
|
||||||
|
self.groupBox = QGroupBox(TabTools_ChartRecommend)
|
||||||
|
self.groupBox.setObjectName(u"groupBox")
|
||||||
|
self.verticalLayout_2 = QVBoxLayout(self.groupBox)
|
||||||
|
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
|
||||||
|
self.rangeFromPlayRating_playRatingSpinBox = QDoubleSpinBox(self.groupBox)
|
||||||
|
self.rangeFromPlayRating_playRatingSpinBox.setObjectName(u"rangeFromPlayRating_playRatingSpinBox")
|
||||||
|
self.rangeFromPlayRating_playRatingSpinBox.setMinimumSize(QSize(100, 0))
|
||||||
|
self.rangeFromPlayRating_playRatingSpinBox.setMaximumSize(QSize(100, 16777215))
|
||||||
|
self.rangeFromPlayRating_playRatingSpinBox.setDecimals(3)
|
||||||
|
self.rangeFromPlayRating_playRatingSpinBox.setMaximum(100.000000000000000)
|
||||||
|
self.rangeFromPlayRating_playRatingSpinBox.setSingleStep(0.100000000000000)
|
||||||
|
|
||||||
|
self.verticalLayout_2.addWidget(self.rangeFromPlayRating_playRatingSpinBox)
|
||||||
|
|
||||||
|
self.formLayout = QFormLayout()
|
||||||
|
self.formLayout.setObjectName(u"formLayout")
|
||||||
|
self.formLayout.setLabelAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
|
||||||
|
self.formLayout.setFormAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignVCenter)
|
||||||
|
self.label = QLabel(self.groupBox)
|
||||||
|
self.label.setObjectName(u"label")
|
||||||
|
self.label.setText(u"EX+")
|
||||||
|
self.label.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
|
||||||
|
|
||||||
|
self.formLayout.setWidget(0, QFormLayout.LabelRole, self.label)
|
||||||
|
|
||||||
|
self.rangeFromPlayRating_ExPlusLabel = QLabel(self.groupBox)
|
||||||
|
self.rangeFromPlayRating_ExPlusLabel.setObjectName(u"rangeFromPlayRating_ExPlusLabel")
|
||||||
|
self.rangeFromPlayRating_ExPlusLabel.setText(u"...")
|
||||||
|
self.rangeFromPlayRating_ExPlusLabel.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)
|
||||||
|
|
||||||
|
self.formLayout.setWidget(0, QFormLayout.FieldRole, self.rangeFromPlayRating_ExPlusLabel)
|
||||||
|
|
||||||
|
self.label_2 = QLabel(self.groupBox)
|
||||||
|
self.label_2.setObjectName(u"label_2")
|
||||||
|
self.label_2.setText(u"EX")
|
||||||
|
self.label_2.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
|
||||||
|
|
||||||
|
self.formLayout.setWidget(1, QFormLayout.LabelRole, self.label_2)
|
||||||
|
|
||||||
|
self.rangeFromPlayRating_ExLabel = QLabel(self.groupBox)
|
||||||
|
self.rangeFromPlayRating_ExLabel.setObjectName(u"rangeFromPlayRating_ExLabel")
|
||||||
|
self.rangeFromPlayRating_ExLabel.setText(u"...")
|
||||||
|
self.rangeFromPlayRating_ExLabel.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)
|
||||||
|
|
||||||
|
self.formLayout.setWidget(1, QFormLayout.FieldRole, self.rangeFromPlayRating_ExLabel)
|
||||||
|
|
||||||
|
self.label_3 = QLabel(self.groupBox)
|
||||||
|
self.label_3.setObjectName(u"label_3")
|
||||||
|
self.label_3.setText(u"AA")
|
||||||
|
self.label_3.setAlignment(Qt.AlignBottom|Qt.AlignLeading|Qt.AlignLeft)
|
||||||
|
|
||||||
|
self.formLayout.setWidget(2, QFormLayout.LabelRole, self.label_3)
|
||||||
|
|
||||||
|
self.rangeFromPlayRating_AaLabel = QLabel(self.groupBox)
|
||||||
|
self.rangeFromPlayRating_AaLabel.setObjectName(u"rangeFromPlayRating_AaLabel")
|
||||||
|
self.rangeFromPlayRating_AaLabel.setText(u"...")
|
||||||
|
self.rangeFromPlayRating_AaLabel.setAlignment(Qt.AlignLeading|Qt.AlignLeft|Qt.AlignTop)
|
||||||
|
|
||||||
|
self.formLayout.setWidget(2, QFormLayout.FieldRole, self.rangeFromPlayRating_AaLabel)
|
||||||
|
|
||||||
|
self.label_5 = QLabel(self.groupBox)
|
||||||
|
self.label_5.setObjectName(u"label_5")
|
||||||
|
self.label_5.setText(u"A")
|
||||||
|
|
||||||
|
self.formLayout.setWidget(3, QFormLayout.LabelRole, self.label_5)
|
||||||
|
|
||||||
|
self.rangeFromPlayRating_ALabel = QLabel(self.groupBox)
|
||||||
|
self.rangeFromPlayRating_ALabel.setObjectName(u"rangeFromPlayRating_ALabel")
|
||||||
|
self.rangeFromPlayRating_ALabel.setText(u"...")
|
||||||
|
|
||||||
|
self.formLayout.setWidget(3, QFormLayout.FieldRole, self.rangeFromPlayRating_ALabel)
|
||||||
|
|
||||||
|
self.label_8 = QLabel(self.groupBox)
|
||||||
|
self.label_8.setObjectName(u"label_8")
|
||||||
|
self.label_8.setText(u"B")
|
||||||
|
|
||||||
|
self.formLayout.setWidget(4, QFormLayout.LabelRole, self.label_8)
|
||||||
|
|
||||||
|
self.rangeFromPlayRating_BLabel = QLabel(self.groupBox)
|
||||||
|
self.rangeFromPlayRating_BLabel.setObjectName(u"rangeFromPlayRating_BLabel")
|
||||||
|
self.rangeFromPlayRating_BLabel.setText(u"...")
|
||||||
|
|
||||||
|
self.formLayout.setWidget(4, QFormLayout.FieldRole, self.rangeFromPlayRating_BLabel)
|
||||||
|
|
||||||
|
self.label_10 = QLabel(self.groupBox)
|
||||||
|
self.label_10.setObjectName(u"label_10")
|
||||||
|
self.label_10.setText(u"C")
|
||||||
|
|
||||||
|
self.formLayout.setWidget(5, QFormLayout.LabelRole, self.label_10)
|
||||||
|
|
||||||
|
self.rangeFromPlayRating_CLabel = QLabel(self.groupBox)
|
||||||
|
self.rangeFromPlayRating_CLabel.setObjectName(u"rangeFromPlayRating_CLabel")
|
||||||
|
self.rangeFromPlayRating_CLabel.setText(u"...")
|
||||||
|
|
||||||
|
self.formLayout.setWidget(5, QFormLayout.FieldRole, self.rangeFromPlayRating_CLabel)
|
||||||
|
|
||||||
|
|
||||||
|
self.verticalLayout_2.addLayout(self.formLayout)
|
||||||
|
|
||||||
|
|
||||||
|
self.gridLayout.addWidget(self.groupBox, 0, 0, 1, 1)
|
||||||
|
|
||||||
self.groupBox_3 = QGroupBox(TabTools_ChartRecommend)
|
self.groupBox_3 = QGroupBox(TabTools_ChartRecommend)
|
||||||
self.groupBox_3.setObjectName(u"groupBox_3")
|
self.groupBox_3.setObjectName(u"groupBox_3")
|
||||||
@ -173,34 +210,33 @@ class Ui_TabTools_ChartRecommend(object):
|
|||||||
|
|
||||||
self.chartsRecommendFromPlayRating_numLabel = QLabel(self.groupBox_3)
|
self.chartsRecommendFromPlayRating_numLabel = QLabel(self.groupBox_3)
|
||||||
self.chartsRecommendFromPlayRating_numLabel.setObjectName(u"chartsRecommendFromPlayRating_numLabel")
|
self.chartsRecommendFromPlayRating_numLabel.setObjectName(u"chartsRecommendFromPlayRating_numLabel")
|
||||||
|
sizePolicy.setHeightForWidth(self.chartsRecommendFromPlayRating_numLabel.sizePolicy().hasHeightForWidth())
|
||||||
|
self.chartsRecommendFromPlayRating_numLabel.setSizePolicy(sizePolicy)
|
||||||
self.chartsRecommendFromPlayRating_numLabel.setText(u"...")
|
self.chartsRecommendFromPlayRating_numLabel.setText(u"...")
|
||||||
|
|
||||||
self.horizontalLayout_2.addWidget(self.chartsRecommendFromPlayRating_numLabel)
|
self.horizontalLayout_2.addWidget(self.chartsRecommendFromPlayRating_numLabel)
|
||||||
|
|
||||||
self.horizontalSpacer_2 = QSpacerItem(40, 20, QSizePolicy.Expanding, QSizePolicy.Minimum)
|
|
||||||
|
|
||||||
self.horizontalLayout_2.addItem(self.horizontalSpacer_2)
|
|
||||||
|
|
||||||
self.chartsRecommendFromPlayRating_refreshButton = QPushButton(self.groupBox_3)
|
|
||||||
self.chartsRecommendFromPlayRating_refreshButton.setObjectName(u"chartsRecommendFromPlayRating_refreshButton")
|
|
||||||
self.chartsRecommendFromPlayRating_refreshButton.setEnabled(False)
|
|
||||||
|
|
||||||
self.horizontalLayout_2.addWidget(self.chartsRecommendFromPlayRating_refreshButton)
|
|
||||||
|
|
||||||
|
|
||||||
self.verticalLayout_4.addLayout(self.horizontalLayout_2)
|
self.verticalLayout_4.addLayout(self.horizontalLayout_2)
|
||||||
|
|
||||||
self.widget_2 = QWidget(self.groupBox_3)
|
self.chartsRecommendFromPlayRating_modelView = QTableView(self.groupBox_3)
|
||||||
self.widget_2.setObjectName(u"widget_2")
|
self.chartsRecommendFromPlayRating_modelView.setObjectName(u"chartsRecommendFromPlayRating_modelView")
|
||||||
sizePolicy.setHeightForWidth(self.widget_2.sizePolicy().hasHeightForWidth())
|
sizePolicy2 = QSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
|
||||||
self.widget_2.setSizePolicy(sizePolicy)
|
sizePolicy2.setHorizontalStretch(0)
|
||||||
self.chartsRecommendFromPlayRating_gridLayout = QGridLayout(self.widget_2)
|
sizePolicy2.setVerticalStretch(0)
|
||||||
self.chartsRecommendFromPlayRating_gridLayout.setObjectName(u"chartsRecommendFromPlayRating_gridLayout")
|
sizePolicy2.setHeightForWidth(self.chartsRecommendFromPlayRating_modelView.sizePolicy().hasHeightForWidth())
|
||||||
|
self.chartsRecommendFromPlayRating_modelView.setSizePolicy(sizePolicy2)
|
||||||
|
self.chartsRecommendFromPlayRating_modelView.setMinimumSize(QSize(200, 0))
|
||||||
|
self.chartsRecommendFromPlayRating_modelView.setEditTriggers(QAbstractItemView.NoEditTriggers)
|
||||||
|
self.chartsRecommendFromPlayRating_modelView.setSelectionMode(QAbstractItemView.SingleSelection)
|
||||||
|
self.chartsRecommendFromPlayRating_modelView.setSelectionBehavior(QAbstractItemView.SelectRows)
|
||||||
|
self.chartsRecommendFromPlayRating_modelView.setVerticalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||||
|
self.chartsRecommendFromPlayRating_modelView.setHorizontalScrollMode(QAbstractItemView.ScrollPerPixel)
|
||||||
|
|
||||||
self.verticalLayout_4.addWidget(self.widget_2)
|
self.verticalLayout_4.addWidget(self.chartsRecommendFromPlayRating_modelView)
|
||||||
|
|
||||||
|
|
||||||
self.verticalLayout.addWidget(self.groupBox_3)
|
self.gridLayout.addWidget(self.groupBox_3, 1, 0, 1, 2)
|
||||||
|
|
||||||
|
|
||||||
self.retranslateUi(TabTools_ChartRecommend)
|
self.retranslateUi(TabTools_ChartRecommend)
|
||||||
@ -209,11 +245,9 @@ class Ui_TabTools_ChartRecommend(object):
|
|||||||
# setupUi
|
# setupUi
|
||||||
|
|
||||||
def retranslateUi(self, TabTools_ChartRecommend):
|
def retranslateUi(self, TabTools_ChartRecommend):
|
||||||
self.groupBox.setTitle(QCoreApplication.translate("TabTools_ChartRecommend", u"constantRangeFromPlayRating", None))
|
|
||||||
self.groupBox_2.setTitle(QCoreApplication.translate("TabTools_ChartRecommend", u"chartsByConstant", None))
|
self.groupBox_2.setTitle(QCoreApplication.translate("TabTools_ChartRecommend", u"chartsByConstant", None))
|
||||||
self.chartsByConstant_refreshButton.setText(QCoreApplication.translate("TabTools_ChartRecommend", u"refreshButton", None))
|
self.groupBox.setTitle(QCoreApplication.translate("TabTools_ChartRecommend", u"constantRangeFromPlayRating", None))
|
||||||
self.groupBox_3.setTitle(QCoreApplication.translate("TabTools_ChartRecommend", u"chartsRecommendFromPlayRating", None))
|
self.groupBox_3.setTitle(QCoreApplication.translate("TabTools_ChartRecommend", u"chartsRecommendFromPlayRating", None))
|
||||||
self.chartsRecommendFromPlayRating_refreshButton.setText(QCoreApplication.translate("TabTools_ChartRecommend", u"refreshButton", None))
|
|
||||||
pass
|
pass
|
||||||
# retranslateUi
|
# retranslateUi
|
||||||
|
|
||||||
|
@ -6,8 +6,7 @@ from arcaea_offline.calculate import calculate_score_range
|
|||||||
from arcaea_offline.database import Database
|
from arcaea_offline.database import Database
|
||||||
from arcaea_offline.models import Chart, Score
|
from arcaea_offline.models import Chart, Score
|
||||||
from arcaea_offline_ocr.b30.shared import B30OcrResultItem
|
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 import Image
|
||||||
from PIL.ImageQt import ImageQt
|
from PIL.ImageQt import ImageQt
|
||||||
from PySide6.QtCore import (
|
from PySide6.QtCore import (
|
||||||
@ -25,6 +24,7 @@ from PySide6.QtCore import (
|
|||||||
)
|
)
|
||||||
from PySide6.QtGui import QImage, QPixmap
|
from PySide6.QtGui import QImage, QPixmap
|
||||||
|
|
||||||
|
from ui.extends.ocr import convert_to_srgb
|
||||||
from ui.extends.shared.delegates.chartDelegate import ChartDelegate
|
from ui.extends.shared.delegates.chartDelegate import ChartDelegate
|
||||||
from ui.extends.shared.delegates.imageDelegate import ImageDelegate
|
from ui.extends.shared.delegates.imageDelegate import ImageDelegate
|
||||||
from ui.extends.shared.delegates.scoreDelegate import ScoreDelegate
|
from ui.extends.shared.delegates.scoreDelegate import ScoreDelegate
|
||||||
@ -46,7 +46,7 @@ class OcrRunnable(QRunnable):
|
|||||||
|
|
||||||
|
|
||||||
class IccOption(IntEnum):
|
class IccOption(IntEnum):
|
||||||
Ignore = 0
|
UseQt = 0
|
||||||
UsePIL = 1
|
UsePIL = 1
|
||||||
TryFix = 2
|
TryFix = 2
|
||||||
|
|
||||||
|
@ -1,26 +0,0 @@
|
|||||||
try:
|
|
||||||
import json
|
|
||||||
|
|
||||||
from arcaea_offline_ocr.device.v1.definition import DeviceV1
|
|
||||||
from arcaea_offline_ocr.device.v2.definition import DeviceV2
|
|
||||||
|
|
||||||
def load_devices_json(filepath: str) -> list[DeviceV1]:
|
|
||||||
with open(filepath, "r", encoding="utf-8") as f:
|
|
||||||
file_content = f.read()
|
|
||||||
if len(file_content) == 0:
|
|
||||||
return []
|
|
||||||
content = json.loads(file_content)
|
|
||||||
assert isinstance(content, list)
|
|
||||||
devices = []
|
|
||||||
for item in content:
|
|
||||||
version = item["version"]
|
|
||||||
if version == 1:
|
|
||||||
devices.append(DeviceV1(**item))
|
|
||||||
elif version == 2:
|
|
||||||
devices.append(DeviceV2(**item))
|
|
||||||
return devices
|
|
||||||
|
|
||||||
except Exception:
|
|
||||||
|
|
||||||
def load_devices_json(*args, **kwargs):
|
|
||||||
pass
|
|
27
ui/extends/ocr/__init__.py
Normal file
27
ui/extends/ocr/__init__.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
import io
|
||||||
|
|
||||||
|
from PIL import Image, ImageCms
|
||||||
|
|
||||||
|
from .build_phash import build_image_phash_database
|
||||||
|
|
||||||
|
|
||||||
|
def convert_to_srgb(pil_img: Image.Image):
|
||||||
|
"""
|
||||||
|
Convert PIL image to sRGB color space (if possible)
|
||||||
|
and save the converted file.
|
||||||
|
|
||||||
|
https://stackoverflow.com/a/65667797/16484891
|
||||||
|
|
||||||
|
CC BY-SA 4.0
|
||||||
|
"""
|
||||||
|
icc = pil_img.info.get("icc_profile", "")
|
||||||
|
icc_conv = ""
|
||||||
|
|
||||||
|
if icc:
|
||||||
|
io_handle = io.BytesIO(icc) # virtual file
|
||||||
|
src_profile = ImageCms.ImageCmsProfile(io_handle)
|
||||||
|
dst_profile = ImageCms.createProfile("sRGB")
|
||||||
|
img_conv = ImageCms.profileToProfile(pil_img, src_profile, dst_profile)
|
||||||
|
icc_conv = img_conv.info.get("icc_profile", "")
|
||||||
|
|
||||||
|
return img_conv if icc != icc_conv else pil_img
|
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
|
28
ui/extends/ocr/dependencies.py
Normal file
28
ui/extends/ocr/dependencies.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import cv2
|
||||||
|
from arcaea_offline_ocr.phash_db import ImagePhashDatabase
|
||||||
|
|
||||||
|
|
||||||
|
def getCv2StatModelStatusText(model: cv2.ml.StatModel):
|
||||||
|
if not isinstance(model, cv2.ml.StatModel):
|
||||||
|
return '<font color="red">ERROR</font>'
|
||||||
|
|
||||||
|
varCount = model.getVarCount()
|
||||||
|
if varCount != 81:
|
||||||
|
return f'<font color="darkorange">WARN</font>, varCount {varCount}'
|
||||||
|
else:
|
||||||
|
return f'<font color="green">OK</font>, varCount {varCount}'
|
||||||
|
|
||||||
|
|
||||||
|
def getPhashDatabaseStatusText(db: ImagePhashDatabase):
|
||||||
|
if not isinstance(db, ImagePhashDatabase):
|
||||||
|
return '<font color="red">ERROR</font>'
|
||||||
|
|
||||||
|
jacketCount = len(db.jacket_hashes)
|
||||||
|
partnerIconCount = len(db.partner_icon_hashes)
|
||||||
|
|
||||||
|
statusText = f"J{jacketCount} PI{partnerIconCount}"
|
||||||
|
|
||||||
|
if partnerIconCount <= 0:
|
||||||
|
return f'<font color="darkorange">WARN</font>, {statusText}'
|
||||||
|
else:
|
||||||
|
return f'<font color="green">OK</font>, {statusText}'
|
@ -1,28 +0,0 @@
|
|||||||
import cv2
|
|
||||||
import numpy as np
|
|
||||||
from PySide6.QtGui import QImage
|
|
||||||
|
|
||||||
|
|
||||||
def cv2BgrMatToQImage(mat) -> QImage:
|
|
||||||
arr = np.ascontiguousarray(mat)
|
|
||||||
return QImage(
|
|
||||||
arr.data,
|
|
||||||
arr.shape[1],
|
|
||||||
arr.shape[0],
|
|
||||||
arr.strides[0],
|
|
||||||
QImage.Format.Format_RGB888,
|
|
||||||
).rgbSwapped()
|
|
||||||
|
|
||||||
|
|
||||||
def qImageToCvMatBgr(qImg: QImage):
|
|
||||||
# from Bing AI, references
|
|
||||||
# 1: https://stackoverflow.com/q/384759/16484891 | CC BY-SA 4.0
|
|
||||||
# 2: https://stackoverflow.com/q/37552924/16484891 | CC BY-SA 3.0
|
|
||||||
qImg = qImg.convertToFormat(QImage.Format.Format_RGB888)
|
|
||||||
qImg = qImg.copy().rgbSwapped()
|
|
||||||
return np.ndarray(
|
|
||||||
(qImg.height(), qImg.width(), 3),
|
|
||||||
buffer=qImg.constBits(),
|
|
||||||
strides=[qImg.bytesPerLine(), 3, 1],
|
|
||||||
dtype=np.uint8,
|
|
||||||
)
|
|
86
ui/extends/shared/data.py
Normal file
86
ui/extends/shared/data.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
import json
|
||||||
|
import sys
|
||||||
|
from functools import cached_property
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Literal, Optional, overload
|
||||||
|
|
||||||
|
from arcaea_offline.models import Chart, Difficulty, Song
|
||||||
|
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"
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def getJacketPath(self, chart: Chart, /) -> Path | None:
|
||||||
|
...
|
||||||
|
|
||||||
|
@overload
|
||||||
|
def getJacketPath(
|
||||||
|
self, song: Song, difficulty: Optional[Difficulty] = None, /
|
||||||
|
) -> Path | None:
|
||||||
|
...
|
||||||
|
|
||||||
|
def getJacketPath(self, *args) -> Path | None:
|
||||||
|
if isinstance(args[0], Chart):
|
||||||
|
chart = args[0]
|
||||||
|
ratingSpecified = f"{chart.song_id}_{chart.rating_class}"
|
||||||
|
base = chart.song_id
|
||||||
|
elif isinstance(args[0], Song):
|
||||||
|
song = args[0]
|
||||||
|
difficulty = args[1]
|
||||||
|
ratingSpecified = (
|
||||||
|
f"{song.id}_{difficulty.rating_class}"
|
||||||
|
if isinstance(difficulty, Difficulty)
|
||||||
|
else song.id
|
||||||
|
)
|
||||||
|
base = song.id
|
||||||
|
else:
|
||||||
|
raise ValueError()
|
||||||
|
|
||||||
|
ratingSpecified += ".jpg"
|
||||||
|
base += ".jpg"
|
||||||
|
|
||||||
|
jacketsPath = self.arcaeaPath / "Song"
|
||||||
|
if (jacketsPath / ratingSpecified).exists():
|
||||||
|
return jacketsPath / ratingSpecified
|
||||||
|
elif (jacketsPath / base).exists():
|
||||||
|
return jacketsPath / base
|
||||||
|
else:
|
||||||
|
return None
|
@ -1,8 +1,15 @@
|
|||||||
from typing import Callable
|
from enum import IntEnum
|
||||||
|
from typing import Callable, Literal
|
||||||
|
|
||||||
from PySide6.QtCore import QEvent, QModelIndex, QObject, QPoint, QSize, Qt
|
from PySide6.QtCore import QModelIndex, QPoint, QSize, Qt
|
||||||
from PySide6.QtGui import QBrush, QColor, QFont, QFontMetrics, QLinearGradient, QPainter
|
from PySide6.QtGui import QBrush, QColor, QFont, QFontMetrics, QLinearGradient, QPainter
|
||||||
from PySide6.QtWidgets import QApplication, QStyledItemDelegate, QStyleOptionViewItem
|
from PySide6.QtWidgets import QStyledItemDelegate, QStyleOptionViewItem
|
||||||
|
|
||||||
|
|
||||||
|
class TextSegmentDelegateVerticalAlign(IntEnum):
|
||||||
|
Top = 0
|
||||||
|
Middle = 1
|
||||||
|
Bottom = 2
|
||||||
|
|
||||||
|
|
||||||
class TextSegmentDelegate(QStyledItemDelegate):
|
class TextSegmentDelegate(QStyledItemDelegate):
|
||||||
@ -15,6 +22,44 @@ class TextSegmentDelegate(QStyledItemDelegate):
|
|||||||
GradientWrapperRole = TextRole + 3
|
GradientWrapperRole = TextRole + 3
|
||||||
FontRole = TextRole + 20
|
FontRole = TextRole + 20
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self.baseXOffsets: dict[str, int] = {}
|
||||||
|
self.baseYOffsets: dict[str, int] = {}
|
||||||
|
|
||||||
|
self.verticalAlign = TextSegmentDelegateVerticalAlign.Middle
|
||||||
|
|
||||||
|
def indexOffsetKey(self, index: QModelIndex):
|
||||||
|
return f"{index.row()},{index.column()}"
|
||||||
|
|
||||||
|
def setBaseXOffset(self, index: QModelIndex, offset: int):
|
||||||
|
key = self.indexOffsetKey(index)
|
||||||
|
if not offset:
|
||||||
|
self.baseXOffsets.pop(key, None)
|
||||||
|
else:
|
||||||
|
self.baseXOffsets[key] = offset
|
||||||
|
|
||||||
|
def setBaseYOffset(self, index: QModelIndex, offset: int):
|
||||||
|
key = self.indexOffsetKey(index)
|
||||||
|
if not offset:
|
||||||
|
self.baseYOffsets.pop(key, None)
|
||||||
|
else:
|
||||||
|
self.baseYOffsets[key] = offset
|
||||||
|
|
||||||
|
def setVerticalAlign(self, align: Literal["top", "middle", "bottom"]):
|
||||||
|
if not isinstance(align, str) and align not in ["top", "middle", "bottom"]:
|
||||||
|
raise ValueError(
|
||||||
|
"TextSegment only supports top/middle/bottom vertical aligning."
|
||||||
|
)
|
||||||
|
|
||||||
|
if align == "top":
|
||||||
|
self.verticalAlign = TextSegmentDelegateVerticalAlign.Top
|
||||||
|
elif align == "middle":
|
||||||
|
self.verticalAlign = TextSegmentDelegateVerticalAlign.Middle
|
||||||
|
elif align == "bottom":
|
||||||
|
self.verticalAlign = TextSegmentDelegateVerticalAlign.Bottom
|
||||||
|
|
||||||
def getTextSegments(
|
def getTextSegments(
|
||||||
self, index: QModelIndex, option
|
self, index: QModelIndex, option
|
||||||
) -> list[
|
) -> list[
|
||||||
@ -31,12 +76,14 @@ class TextSegmentDelegate(QStyledItemDelegate):
|
|||||||
]:
|
]:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
def sizeHint(self, option, index) -> QSize:
|
def textsSizeHint(self, option: QStyleOptionViewItem, index: QModelIndex) -> QSize:
|
||||||
width = 0
|
width = 0
|
||||||
height = self.VerticalPadding
|
height = 0
|
||||||
fm: QFontMetrics = option.fontMetrics
|
fm: QFontMetrics = option.fontMetrics
|
||||||
for line in self.getTextSegments(index, option):
|
segments = self.getTextSegments(index, option)
|
||||||
lineWidth = 4 * self.HorizontalPadding
|
for i in range(len(segments)):
|
||||||
|
line = segments[i]
|
||||||
|
lineWidth = 2 * self.HorizontalPadding
|
||||||
lineHeight = 0
|
lineHeight = 0
|
||||||
for textFrag in line:
|
for textFrag in line:
|
||||||
font = textFrag.get(self.FontRole)
|
font = textFrag.get(self.FontRole)
|
||||||
@ -47,17 +94,55 @@ class TextSegmentDelegate(QStyledItemDelegate):
|
|||||||
lineWidth += textWidth
|
lineWidth += textWidth
|
||||||
lineHeight = max(lineHeight, textHeight)
|
lineHeight = max(lineHeight, textHeight)
|
||||||
width = max(lineWidth, width)
|
width = max(lineWidth, width)
|
||||||
height += lineHeight + self.VerticalPadding
|
height += lineHeight
|
||||||
|
if i != len(segments) - 1:
|
||||||
|
height += self.VerticalPadding
|
||||||
return QSize(width, height)
|
return QSize(width, height)
|
||||||
|
|
||||||
|
def sizeHint(self, option: QStyleOptionViewItem, index: QModelIndex) -> QSize:
|
||||||
|
width = self.HorizontalPadding * 2
|
||||||
|
height = self.VerticalPadding * 2
|
||||||
|
textsSizeHint = self.textsSizeHint(option, index)
|
||||||
|
return QSize(textsSizeHint.width() + width, textsSizeHint.height() + height)
|
||||||
|
|
||||||
|
def baseX(self, option: QStyleOptionViewItem, index: QModelIndex):
|
||||||
|
return (
|
||||||
|
option.rect.x()
|
||||||
|
+ self.HorizontalPadding
|
||||||
|
+ self.baseXOffsets.get(self.indexOffsetKey(index), 0)
|
||||||
|
)
|
||||||
|
|
||||||
|
def baseY(self, option: QStyleOptionViewItem, index: QModelIndex):
|
||||||
|
baseY = (
|
||||||
|
option.rect.y()
|
||||||
|
+ self.VerticalPadding
|
||||||
|
+ self.baseYOffsets.get(self.indexOffsetKey(index), 0)
|
||||||
|
)
|
||||||
|
if self.verticalAlign != TextSegmentDelegateVerticalAlign.Top:
|
||||||
|
paintAreaSize: QSize = option.rect.size()
|
||||||
|
delegateSize = self.sizeHint(option, index)
|
||||||
|
if self.verticalAlign == TextSegmentDelegateVerticalAlign.Middle:
|
||||||
|
baseY += round((paintAreaSize.height() - delegateSize.height()) / 2)
|
||||||
|
elif self.verticalAlign == TextSegmentDelegateVerticalAlign.Bottom:
|
||||||
|
baseY += paintAreaSize.height() - delegateSize.height()
|
||||||
|
return baseY
|
||||||
|
|
||||||
|
def textMaxWidth(self, option: QStyleOptionViewItem, index: QModelIndex):
|
||||||
|
return (
|
||||||
|
option.rect.width()
|
||||||
|
- (2 * self.HorizontalPadding)
|
||||||
|
- self.baseXOffsets.get(self.indexOffsetKey(index), 0)
|
||||||
|
)
|
||||||
|
|
||||||
def paint(
|
def paint(
|
||||||
self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex
|
self, painter: QPainter, option: QStyleOptionViewItem, index: QModelIndex
|
||||||
):
|
):
|
||||||
self.initStyleOption(option, index)
|
self.initStyleOption(option, index)
|
||||||
# draw text only
|
|
||||||
baseX = option.rect.x() + self.HorizontalPadding
|
baseX = self.baseX(option, index)
|
||||||
baseY = option.rect.y() + self.VerticalPadding
|
baseY = self.baseY(option, index)
|
||||||
maxWidth = option.rect.width() - (2 * self.HorizontalPadding)
|
maxWidth = self.textMaxWidth(option, index)
|
||||||
|
|
||||||
fm: QFontMetrics = option.fontMetrics
|
fm: QFontMetrics = option.fontMetrics
|
||||||
painter.save()
|
painter.save()
|
||||||
for line in self.getTextSegments(index, option):
|
for line in self.getTextSegments(index, option):
|
||||||
@ -69,8 +154,7 @@ class TextSegmentDelegate(QStyledItemDelegate):
|
|||||||
# elide text, get font values
|
# elide text, get font values
|
||||||
text = textFrag[self.TextRole]
|
text = textFrag[self.TextRole]
|
||||||
fragMaxWidth = maxWidth - (lineBaseX - baseX)
|
fragMaxWidth = maxWidth - (lineBaseX - baseX)
|
||||||
font = textFrag.get(self.FontRole)
|
if font := textFrag.get(self.FontRole):
|
||||||
if font:
|
|
||||||
painter.setFont(font)
|
painter.setFont(font)
|
||||||
_fm = QFontMetrics(font)
|
_fm = QFontMetrics(font)
|
||||||
else:
|
else:
|
||||||
@ -116,37 +200,3 @@ class TextSegmentDelegate(QStyledItemDelegate):
|
|||||||
|
|
||||||
def super_styledItemDelegate_paint(self, painter, option, index):
|
def super_styledItemDelegate_paint(self, painter, option, index):
|
||||||
return super().paint(painter, option, index)
|
return super().paint(painter, option, index)
|
||||||
|
|
||||||
|
|
||||||
class NoCommitWhenFocusOutEventFilter(QObject):
|
|
||||||
"""
|
|
||||||
--DEPRECATED--
|
|
||||||
|
|
||||||
The default QAbstractItemDelegate implementation has a private function
|
|
||||||
`editorEventFilter()`, when editor sends focusOut/hide event, it emits the
|
|
||||||
`commitData(editor)` signal. We don't want this since we need to validate
|
|
||||||
the input, so we filter the event out and handle it by ourselves.
|
|
||||||
|
|
||||||
Reimplement `checkIsEditor(self, val) -> bool` to ensure this filter is
|
|
||||||
working. The default implementation always return `False`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
def checkIsEditor(self, val) -> bool:
|
|
||||||
return False
|
|
||||||
|
|
||||||
def eventFilter(self, object: QObject, event: QEvent) -> bool:
|
|
||||||
if self.checkIsEditor(object) and event.type() in [
|
|
||||||
QEvent.Type.FocusOut,
|
|
||||||
QEvent.Type.Hide,
|
|
||||||
]:
|
|
||||||
widget = QApplication.focusWidget()
|
|
||||||
while widget:
|
|
||||||
# check if focus changed into editor's child
|
|
||||||
if self.checkIsEditor(widget):
|
|
||||||
return False
|
|
||||||
widget = widget.parentWidget()
|
|
||||||
|
|
||||||
object.hide()
|
|
||||||
object.deleteLater()
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
from arcaea_offline.models import Chart
|
from arcaea_offline.models import Chart, Difficulty, Song
|
||||||
from arcaea_offline.utils.rating import rating_class_to_short_text, rating_class_to_text
|
from arcaea_offline.utils.rating import rating_class_to_short_text, rating_class_to_text
|
||||||
from PySide6.QtCore import QModelIndex, Qt, Signal
|
from PIL import Image
|
||||||
from PySide6.QtGui import QColor
|
from PySide6.QtCore import QModelIndex, QRect, Qt, Signal
|
||||||
|
from PySide6.QtGui import QColor, QPainter, QPixmap
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import (
|
||||||
QFrame,
|
QFrame,
|
||||||
QHBoxLayout,
|
QHBoxLayout,
|
||||||
@ -13,6 +14,7 @@ from PySide6.QtWidgets import (
|
|||||||
QWidget,
|
QWidget,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
from ui.extends.shared.data import Data
|
||||||
from ui.implements.components.chartSelector import ChartSelector
|
from ui.implements.components.chartSelector import ChartSelector
|
||||||
|
|
||||||
from ..utils import keepWidgetInScreen
|
from ..utils import keepWidgetInScreen
|
||||||
@ -86,51 +88,152 @@ class ChartDelegate(TextSegmentDelegate):
|
|||||||
def getChart(self, index: QModelIndex) -> Chart | None:
|
def getChart(self, index: QModelIndex) -> Chart | None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def getSong(self, index: QModelIndex) -> Song | None:
|
||||||
|
return None
|
||||||
|
|
||||||
|
def getDifficulty(self, index: QModelIndex) -> Difficulty | None:
|
||||||
|
return None
|
||||||
|
|
||||||
def getTextSegments(self, index: QModelIndex, option):
|
def getTextSegments(self, index: QModelIndex, option):
|
||||||
chart = self.getChart(index)
|
chart = self.getChart(index)
|
||||||
if not isinstance(chart, Chart):
|
song = self.getSong(index)
|
||||||
|
difficulty = self.getDifficulty(index)
|
||||||
|
|
||||||
|
chartValid = isinstance(chart, Chart)
|
||||||
|
songValid = isinstance(song, Song)
|
||||||
|
difficultyValid = isinstance(difficulty, Difficulty)
|
||||||
|
|
||||||
|
if not chartValid and not songValid:
|
||||||
return [
|
return [
|
||||||
[{self.TextRole: "Chart Invalid", self.ColorRole: QColor("#ff0000")}]
|
[
|
||||||
|
{
|
||||||
|
self.TextRole: "Chart/Song not set",
|
||||||
|
self.ColorRole: QColor("#ff0000"),
|
||||||
|
}
|
||||||
|
]
|
||||||
]
|
]
|
||||||
|
|
||||||
chartConstantString = (
|
# get texts
|
||||||
f"{chart.constant / 10:.1f}"
|
if chartValid:
|
||||||
if chart.constant is not None and chart.constant > 0
|
title = chart.title
|
||||||
else "?"
|
else:
|
||||||
|
title = (
|
||||||
|
difficulty.title if difficultyValid and difficulty.title else song.title
|
||||||
|
)
|
||||||
|
|
||||||
|
if chartValid and chart.constant is not None:
|
||||||
|
chartConstantString = f"{chart.constant / 10:.1f}"
|
||||||
|
elif difficultyValid:
|
||||||
|
chartConstantString = str(difficulty.rating)
|
||||||
|
if difficulty.rating_plus:
|
||||||
|
chartConstantString += "+"
|
||||||
|
else:
|
||||||
|
chartConstantString = "?"
|
||||||
|
|
||||||
|
if chartValid:
|
||||||
|
ratingClass = chart.rating_class
|
||||||
|
elif difficultyValid:
|
||||||
|
ratingClass = difficulty.rating_class
|
||||||
|
else:
|
||||||
|
ratingClass = None
|
||||||
|
|
||||||
|
ratingText = (
|
||||||
|
f"{rating_class_to_text(ratingClass)} {chartConstantString}"
|
||||||
|
if ratingClass is not None
|
||||||
|
else "Unknown ?"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if chartValid:
|
||||||
|
descText = f"({chart.song_id}, {chart.set})"
|
||||||
|
else:
|
||||||
|
descText = f"({song.id}, {song.set})"
|
||||||
|
|
||||||
|
# get attributes
|
||||||
|
ratingClassColor = (
|
||||||
|
self.RatingClassColors[ratingClass] if ratingClass is not None else None
|
||||||
|
)
|
||||||
|
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
{self.TextRole: f"{chart.title}"},
|
{self.TextRole: str(title)},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
self.TextRole: f"{rating_class_to_text(chart.rating_class)} {chartConstantString}",
|
self.TextRole: ratingText,
|
||||||
self.ColorRole: self.RatingClassColors[chart.rating_class],
|
self.ColorRole: ratingClassColor,
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
self.TextRole: f"({chart.song_id}, {chart.set})",
|
self.TextRole: descText,
|
||||||
self.ColorRole: option.widget.palette().placeholderText().color(),
|
self.ColorRole: option.widget.palette().placeholderText().color(),
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
|
|
||||||
def paintWarningBackground(self, index: QModelIndex) -> bool:
|
def sizeHint(self, option, index):
|
||||||
return True
|
size = super().sizeHint(option, index)
|
||||||
|
minWidth = size.height() + 2 * self.HorizontalPadding # jacket size
|
||||||
|
width = size.width() + self.HorizontalPadding + size.height()
|
||||||
|
size.setWidth(max(minWidth, width))
|
||||||
|
return size
|
||||||
|
|
||||||
def paint(self, painter, option, index):
|
def paint(self, painter, option, index):
|
||||||
# draw chartInvalid warning background
|
|
||||||
chart = self.getChart(index)
|
|
||||||
if not isinstance(chart, Chart) and self.paintWarningBackground(index):
|
|
||||||
painter.save()
|
|
||||||
painter.setPen(Qt.PenStyle.NoPen)
|
|
||||||
bgColor = QColor(self.ChartInvalidBackgroundColor)
|
|
||||||
bgColor.setAlpha(50)
|
|
||||||
painter.setBrush(bgColor)
|
|
||||||
painter.drawRect(option.rect)
|
|
||||||
painter.restore()
|
|
||||||
option.text = ""
|
option.text = ""
|
||||||
|
|
||||||
|
data = Data()
|
||||||
|
|
||||||
|
chart = self.getChart(index)
|
||||||
|
song = self.getSong(index)
|
||||||
|
difficulty = self.getDifficulty(index)
|
||||||
|
|
||||||
|
if isinstance(chart, Chart):
|
||||||
|
jacketPath = data.getJacketPath(chart)
|
||||||
|
elif isinstance(song, Song):
|
||||||
|
jacketPath = data.getJacketPath(song, difficulty)
|
||||||
|
else:
|
||||||
|
jacketPath = "__TEXT_ONLY__"
|
||||||
|
|
||||||
|
if jacketPath == "__TEXT_ONLY__":
|
||||||
|
self.setBaseXOffset(index, 0)
|
||||||
|
super().paint(painter, option, index)
|
||||||
|
return
|
||||||
|
|
||||||
|
textsSizeHint = super().textsSizeHint(option, index)
|
||||||
|
jacketSize = textsSizeHint.height()
|
||||||
|
self.setBaseXOffset(index, self.HorizontalPadding + jacketSize)
|
||||||
|
|
||||||
|
jacketSizeTuple = (jacketSize, jacketSize)
|
||||||
|
if jacketPath:
|
||||||
|
pixmap = (
|
||||||
|
Image.open(str(jacketPath.resolve()))
|
||||||
|
.resize(jacketSizeTuple, Image.BICUBIC)
|
||||||
|
.toqpixmap()
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
pixmap = (
|
||||||
|
Image.fromqpixmap(QPixmap(":/images/jacket-placeholder.png"))
|
||||||
|
.resize(jacketSizeTuple, Image.BICUBIC)
|
||||||
|
.toqpixmap()
|
||||||
|
)
|
||||||
|
|
||||||
|
pixmapAvailableWidth = option.rect.width() - self.HorizontalPadding
|
||||||
|
pixmapAvailableHeight = option.rect.height()
|
||||||
|
|
||||||
|
if pixmapAvailableWidth < jacketSize or pixmapAvailableHeight < jacketSize:
|
||||||
|
cropRect = QRect(0, 0, pixmapAvailableWidth, pixmapAvailableHeight)
|
||||||
|
pixmap = pixmap.copy(cropRect)
|
||||||
|
|
||||||
|
painter.save()
|
||||||
|
painter.setRenderHint(QPainter.RenderHint.LosslessImageRendering, True)
|
||||||
|
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
|
||||||
|
pixmapBaseY = self.baseY(option, index)
|
||||||
|
painter.drawPixmap(
|
||||||
|
option.rect.x() + self.HorizontalPadding,
|
||||||
|
pixmapBaseY,
|
||||||
|
pixmap,
|
||||||
|
)
|
||||||
|
painter.restore()
|
||||||
super().paint(painter, option, index)
|
super().paint(painter, option, index)
|
||||||
|
|
||||||
def checkIsEditor(self, val):
|
def checkIsEditor(self, val):
|
||||||
|
@ -1,19 +1,15 @@
|
|||||||
from typing import Union
|
|
||||||
|
|
||||||
from arcaea_offline.calculate import calculate_score_range
|
from arcaea_offline.calculate import calculate_score_range
|
||||||
from arcaea_offline.models import Chart, Score
|
from arcaea_offline.models import Chart, Score, ScoreBest
|
||||||
from arcaea_offline.utils.rating import rating_class_to_text
|
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.QtCore import QAbstractItemModel, QDateTime, QModelIndex, Qt, Signal
|
||||||
from PySide6.QtGui import QColor, QFont, QLinearGradient
|
from PySide6.QtGui import QColor, QFont, QLinearGradient
|
||||||
from PySide6.QtWidgets import (
|
from PySide6.QtWidgets import QHBoxLayout, QLabel, QPushButton, QSizePolicy, QWidget
|
||||||
QFrame,
|
|
||||||
QHBoxLayout,
|
|
||||||
QLabel,
|
|
||||||
QPushButton,
|
|
||||||
QSizePolicy,
|
|
||||||
QWidget,
|
|
||||||
)
|
|
||||||
|
|
||||||
from ui.implements.components.scoreEditor import ScoreEditor
|
from ui.implements.components.scoreEditor import ScoreEditor
|
||||||
|
|
||||||
@ -27,12 +23,6 @@ class ScoreEditorDelegateWrapper(ScoreEditor):
|
|||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
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.delegateHeader = QWidget(self)
|
||||||
self.delegateHeaderHBoxLayout = QHBoxLayout(self.delegateHeader)
|
self.delegateHeaderHBoxLayout = QHBoxLayout(self.delegateHeader)
|
||||||
self.delegateHeaderHBoxLayout.setContentsMargins(0, 0, 0, 0)
|
self.delegateHeaderHBoxLayout.setContentsMargins(0, 0, 0, 0)
|
||||||
@ -55,7 +45,9 @@ class ScoreEditorDelegateWrapper(ScoreEditor):
|
|||||||
text = "Editing "
|
text = "Editing "
|
||||||
text += _extra or ""
|
text += _extra or ""
|
||||||
text += f"score {score.score}"
|
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)
|
self.editorLabel.setText(text)
|
||||||
|
|
||||||
|
|
||||||
@ -86,18 +78,21 @@ class ScoreDelegate(TextSegmentDelegate):
|
|||||||
createGradeGradientWrapper(QColor("#5d1d35"), QColor("#9f3c55")),
|
createGradeGradientWrapper(QColor("#5d1d35"), QColor("#9f3c55")),
|
||||||
]
|
]
|
||||||
|
|
||||||
def getScore(self, index: QModelIndex) -> Score | None:
|
def getScore(self, index: QModelIndex) -> Score | ScoreBest | None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def getChart(self, index: QModelIndex) -> Chart | None:
|
def getChart(self, index: QModelIndex) -> Chart | None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def isScoreInstance(self, index: QModelIndex) -> bool:
|
||||||
|
return isinstance(self.getScore(index), (Score, ScoreBest))
|
||||||
|
|
||||||
def getScoreValidateOk(self, index: QModelIndex) -> bool | None:
|
def getScoreValidateOk(self, index: QModelIndex) -> bool | None:
|
||||||
score = self.getScore(index)
|
score = self.getScore(index)
|
||||||
chart = self.getChart(index)
|
chart = self.getChart(index)
|
||||||
|
|
||||||
if (
|
if (
|
||||||
isinstance(score, Score)
|
self.isScoreInstance(index)
|
||||||
and isinstance(chart, Chart)
|
and isinstance(chart, Chart)
|
||||||
and chart.notes is not None
|
and chart.notes is not None
|
||||||
and score.pure is not None
|
and score.pure is not None
|
||||||
@ -111,12 +106,12 @@ class ScoreDelegate(TextSegmentDelegate):
|
|||||||
|
|
||||||
def getTextSegments(self, index, option):
|
def getTextSegments(self, index, option):
|
||||||
score = self.getScore(index)
|
score = self.getScore(index)
|
||||||
chart = self.getChart(index)
|
|
||||||
if not (isinstance(score, Score) and isinstance(chart, Chart)):
|
if not self.isScoreInstance(index):
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
self.TextRole: "Chart/Score Invalid",
|
self.TextRole: "Score Invalid",
|
||||||
self.ColorRole: QColor("#ff0000"),
|
self.ColorRole: QColor("#ff0000"),
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -128,7 +123,9 @@ class ScoreDelegate(TextSegmentDelegate):
|
|||||||
score_font.setPointSize(12)
|
score_font.setPointSize(12)
|
||||||
score_grade_font = QFont(score_font)
|
score_grade_font = QFont(score_font)
|
||||||
score_grade_font.setBold(True)
|
score_grade_font.setBold(True)
|
||||||
return [
|
placeholderColor = option.widget.palette().placeholderText().color()
|
||||||
|
|
||||||
|
segments = [
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
self.TextRole: score_to_grade_text(score.score),
|
self.TextRole: score_to_grade_text(score.score),
|
||||||
@ -156,19 +153,47 @@ class ScoreDelegate(TextSegmentDelegate):
|
|||||||
self.ColorRole: self.PureFarLostColors[2],
|
self.ColorRole: self.PureFarLostColors[2],
|
||||||
},
|
},
|
||||||
{self.TextRole: " | "},
|
{self.TextRole: " | "},
|
||||||
{self.TextRole: f"MAX RECALL {score.max_recall}"},
|
{self.TextRole: f"MR {score.max_recall}"},
|
||||||
],
|
|
||||||
[
|
|
||||||
{
|
|
||||||
self.TextRole: QDateTime.fromSecsSinceEpoch(score.date).toString(
|
|
||||||
"yyyy-MM-dd hh:mm:ss"
|
|
||||||
)
|
|
||||||
if score.date
|
|
||||||
else "-- No Date --"
|
|
||||||
}
|
|
||||||
],
|
],
|
||||||
]
|
]
|
||||||
|
|
||||||
|
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:
|
def paintWarningBackground(self, index: QModelIndex) -> bool:
|
||||||
return True
|
return True
|
||||||
|
|
||||||
@ -177,7 +202,7 @@ class ScoreDelegate(TextSegmentDelegate):
|
|||||||
score = self.getScore(index)
|
score = self.getScore(index)
|
||||||
chart = self.getChart(index)
|
chart = self.getChart(index)
|
||||||
if (
|
if (
|
||||||
isinstance(score, Score)
|
self.isScoreInstance(index)
|
||||||
and isinstance(chart, Chart)
|
and isinstance(chart, Chart)
|
||||||
and self.paintWarningBackground(index)
|
and self.paintWarningBackground(index)
|
||||||
):
|
):
|
||||||
@ -217,7 +242,7 @@ class ScoreDelegate(TextSegmentDelegate):
|
|||||||
else:
|
else:
|
||||||
editor.setWindowTitle("-")
|
editor.setWindowTitle("-")
|
||||||
|
|
||||||
if isinstance(score, Score):
|
if self.isScoreInstance(index):
|
||||||
editor.setText(score)
|
editor.setText(score)
|
||||||
|
|
||||||
editor.setValidateBeforeAccept(False)
|
editor.setValidateBeforeAccept(False)
|
||||||
@ -238,7 +263,7 @@ class ScoreDelegate(TextSegmentDelegate):
|
|||||||
chart = self.getChart(index)
|
chart = self.getChart(index)
|
||||||
if isinstance(chart, Chart):
|
if isinstance(chart, Chart):
|
||||||
editor.setChart(chart)
|
editor.setChart(chart)
|
||||||
if isinstance(score, Score):
|
if self.isScoreInstance(index):
|
||||||
editor.setValue(score)
|
editor.setValue(score)
|
||||||
|
|
||||||
def confirmSetModelData(self, editor: ScoreEditorDelegateWrapper):
|
def confirmSetModelData(self, editor: ScoreEditorDelegateWrapper):
|
||||||
|
@ -5,12 +5,11 @@ from PySide6.QtCore import QFileInfo, QSettings, Signal
|
|||||||
from .singleton import QObjectSingleton
|
from .singleton import QObjectSingleton
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
|
"LANGUAGE",
|
||||||
"DATABASE_URL",
|
"DATABASE_URL",
|
||||||
"DEVICES_JSON_FILE",
|
|
||||||
"DEVICE_UUID",
|
|
||||||
"TESSERACT_FILE",
|
|
||||||
"KNN_MODEL_FILE",
|
"KNN_MODEL_FILE",
|
||||||
"SIFT_DATABASE_FILE",
|
"B30_KNN_MODEL_FILE",
|
||||||
|
"PHASH_DATABASE_FILE",
|
||||||
"ANDREAL_FOLDER",
|
"ANDREAL_FOLDER",
|
||||||
"ANDREAL_EXECUTABLE",
|
"ANDREAL_EXECUTABLE",
|
||||||
"Settings",
|
"Settings",
|
||||||
@ -21,12 +20,8 @@ __all__ = [
|
|||||||
LANGUAGE = "Language"
|
LANGUAGE = "Language"
|
||||||
DATABASE_URL = "DatabaseUrl"
|
DATABASE_URL = "DatabaseUrl"
|
||||||
|
|
||||||
DEVICES_JSON_FILE = "Ocr/DevicesJsonFile"
|
|
||||||
DEVICE_UUID = "Ocr/DeviceUuid"
|
|
||||||
TESSERACT_FILE = "Ocr/TesseractFile"
|
|
||||||
KNN_MODEL_FILE = "Ocr/KnnModelFile"
|
KNN_MODEL_FILE = "Ocr/KnnModelFile"
|
||||||
B30_KNN_MODEL_FILE = "Ocr/B30KnnModelFile"
|
B30_KNN_MODEL_FILE = "Ocr/B30KnnModelFile"
|
||||||
SIFT_DATABASE_FILE = "Ocr/SiftDatabaseFile"
|
|
||||||
PHASH_DATABASE_FILE = "Ocr/PHashDatabaseFile"
|
PHASH_DATABASE_FILE = "Ocr/PHashDatabaseFile"
|
||||||
|
|
||||||
ANDREAL_FOLDER = "Andreal/AndrealFolder"
|
ANDREAL_FOLDER = "Andreal/AndrealFolder"
|
||||||
@ -70,33 +65,6 @@ class Settings(QSettings, metaclass=QObjectSingleton):
|
|||||||
def setDatabaseUrl(self, value: str):
|
def setDatabaseUrl(self, value: str):
|
||||||
self._setStrItem(DATABASE_URL, value)
|
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):
|
def knnModelFile(self):
|
||||||
return self._strItem(KNN_MODEL_FILE)
|
return self._strItem(KNN_MODEL_FILE)
|
||||||
|
|
||||||
@ -115,15 +83,6 @@ class Settings(QSettings, metaclass=QObjectSingleton):
|
|||||||
def resetB30KnnModelFile(self):
|
def resetB30KnnModelFile(self):
|
||||||
self._resetStrItem(B30_KNN_MODEL_FILE)
|
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):
|
def phashDatabaseFile(self):
|
||||||
return self._strItem(PHASH_DATABASE_FILE)
|
return self._strItem(PHASH_DATABASE_FILE)
|
||||||
|
|
||||||
|
@ -1,69 +1,58 @@
|
|||||||
import contextlib
|
import contextlib
|
||||||
import logging
|
import logging
|
||||||
from typing import Tuple
|
from typing import Tuple, Type
|
||||||
|
|
||||||
import cv2
|
import cv2
|
||||||
|
import exif
|
||||||
from arcaea_offline.database import Database
|
from arcaea_offline.database import Database
|
||||||
from arcaea_offline.models import Chart, Score
|
from arcaea_offline.models import Chart, Score
|
||||||
from arcaea_offline_ocr.device.shared import DeviceOcrResult
|
from arcaea_offline.utils.partner import KanaeDayNight, kanae_day_night
|
||||||
from arcaea_offline_ocr.device.v2 import DeviceV2AutoRois, DeviceV2Ocr, DeviceV2Rois
|
from arcaea_offline_ocr.device import DeviceOcr, DeviceOcrResult
|
||||||
from arcaea_offline_ocr.device.v2.sizes import SizesV1, SizesV2
|
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 arcaea_offline_ocr.utils import imread_unicode
|
||||||
from PySide6.QtCore import QDateTime, QFileInfo
|
from PySide6.QtCore import QDateTime, QFileInfo
|
||||||
|
|
||||||
from ui.extends.components.ocrQueue import OcrRunnable
|
from ui.extends.components.ocrQueue import OcrRunnable
|
||||||
|
from ui.extends.shared.data import Data
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
import exif
|
|
||||||
|
|
||||||
|
class TabDeviceOcrRunnable(OcrRunnable):
|
||||||
class TabDeviceV2OcrRunnable(OcrRunnable):
|
def __init__(
|
||||||
def __init__(self, imagePath, device, knnModel, phashDb, *, sizesV2: bool):
|
self,
|
||||||
|
imagePath: str,
|
||||||
|
rois: DeviceRois | Type[DeviceRoisAuto],
|
||||||
|
masker: DeviceRoisMasker,
|
||||||
|
knnModel: cv2.ml.KNearest,
|
||||||
|
phashDb: ImagePhashDatabase,
|
||||||
|
):
|
||||||
super().__init__()
|
super().__init__()
|
||||||
self.imagePath = imagePath
|
self.imagePath = imagePath
|
||||||
self.device = device
|
self.rois = rois
|
||||||
|
self.masker = masker
|
||||||
self.knnModel = knnModel
|
self.knnModel = knnModel
|
||||||
self.phashDb = phashDb
|
self.phashDb = phashDb
|
||||||
self.sizesV2 = sizesV2
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
try:
|
||||||
rois = DeviceV2Rois(
|
img = imread_unicode(self.imagePath, cv2.IMREAD_COLOR)
|
||||||
self.device, 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])
|
||||||
rois.sizes = (
|
else:
|
||||||
SizesV2(self.device.factor)
|
rois = self.rois
|
||||||
if self.sizesV2
|
extractor = DeviceRoisExtractor(img, rois)
|
||||||
else SizesV1(self.device.factor)
|
ocr = DeviceOcr(extractor, self.masker, self.knnModel, self.phashDb)
|
||||||
)
|
result = ocr.ocr()
|
||||||
ocr = DeviceV2Ocr(self.knnModel, self.phashDb)
|
|
||||||
result = ocr.ocr(rois)
|
|
||||||
self.signals.resultReady.emit(result)
|
self.signals.resultReady.emit(result)
|
||||||
except Exception:
|
except Exception:
|
||||||
logger.exception(f"DeviceV2 ocr {self.imagePath} error")
|
logger.exception("DeviceOcr 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")
|
|
||||||
finally:
|
finally:
|
||||||
self.signals.finished.emit()
|
self.signals.finished.emit()
|
||||||
|
|
||||||
@ -83,7 +72,24 @@ def getImageDate(imagePath: str) -> QDateTime:
|
|||||||
|
|
||||||
class ScoreConverter:
|
class ScoreConverter:
|
||||||
@staticmethod
|
@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()
|
db = Database()
|
||||||
score = Score(
|
score = Score(
|
||||||
song_id=result.song_id,
|
song_id=result.song_id,
|
||||||
@ -92,16 +98,16 @@ class ScoreConverter:
|
|||||||
pure=result.pure,
|
pure=result.pure,
|
||||||
far=result.far,
|
far=result.far,
|
||||||
lost=result.lost,
|
lost=result.lost,
|
||||||
date=getImageDate(imagePath).toSecsSinceEpoch(),
|
date=imageDate.toSecsSinceEpoch(),
|
||||||
max_recall=result.max_recall,
|
max_recall=result.max_recall,
|
||||||
|
modifier=modifier,
|
||||||
|
clear_type=clearType,
|
||||||
comment=f"OCR {QFileInfo(imagePath).fileName()}",
|
comment=f"OCR {QFileInfo(imagePath).fileName()}",
|
||||||
)
|
)
|
||||||
chart = db.get_chart(score.song_id, score.rating_class)
|
chart = db.get_chart(score.song_id, score.rating_class) or Chart(
|
||||||
if not chart:
|
song_id=result.song_id,
|
||||||
chart = Chart(
|
rating_class=result.rating_class,
|
||||||
song_id=result.song_id,
|
title=result.song_id,
|
||||||
rating_class=result.rating_class,
|
constant=0.0,
|
||||||
title=result.song_id,
|
)
|
||||||
constant=0.0,
|
|
||||||
)
|
|
||||||
return (chart, score)
|
return (chart, score)
|
||||||
|
@ -2,6 +2,7 @@ import base64
|
|||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
import re
|
import re
|
||||||
|
import subprocess
|
||||||
|
|
||||||
from PySide6.QtCore import QObject, QProcess, QRunnable, QThreadPool, Signal
|
from PySide6.QtCore import QObject, QProcess, QRunnable, QThreadPool, Signal
|
||||||
|
|
||||||
@ -24,7 +25,12 @@ class AndrealExecuteRunnable(QRunnable):
|
|||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
try:
|
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]
|
b64Result = [s for s in result.split("\n") if s]
|
||||||
imageBytes = base64.b64decode(
|
imageBytes = base64.b64decode(
|
||||||
re.sub(r"data:image/.*;base64,", "", b64Result[-1])
|
re.sub(r"data:image/.*;base64,", "", b64Result[-1])
|
||||||
|
120
ui/extends/tabs/tabTools/tabTools_ChartRecommend.py
Normal file
120
ui/extends/tabs/tabTools/tabTools_ChartRecommend.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
import re
|
||||||
|
from typing import Any
|
||||||
|
|
||||||
|
from arcaea_offline.database import Database
|
||||||
|
from arcaea_offline.models import Chart, ScoreBest
|
||||||
|
from arcaea_offline.utils.rating import rating_class_to_text
|
||||||
|
from PySide6.QtCore import QAbstractListModel, QModelIndex, Qt
|
||||||
|
from PySide6.QtGui import QStandardItem, QStandardItemModel
|
||||||
|
|
||||||
|
from ui.extends.shared.delegates.chartDelegate import ChartDelegate
|
||||||
|
from ui.extends.shared.delegates.scoreDelegate import ScoreDelegate
|
||||||
|
|
||||||
|
|
||||||
|
class ChartsModel(QAbstractListModel):
|
||||||
|
ChartRole = Qt.ItemDataRole.UserRole
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
self.__data: list[dict[int, Any]] = []
|
||||||
|
|
||||||
|
def rowCount(self, *args) -> int:
|
||||||
|
return len(self.__data)
|
||||||
|
|
||||||
|
def columnCount(self, *args) -> int:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def headerData(self, *args):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def data(self, index: QModelIndex, role: int):
|
||||||
|
if not self.checkIndex(index):
|
||||||
|
return None
|
||||||
|
|
||||||
|
return self.__data[index.row()].get(role, None)
|
||||||
|
|
||||||
|
def clear(self):
|
||||||
|
self.beginResetModel()
|
||||||
|
self.beginRemoveRows(QModelIndex(), 0, self.rowCount())
|
||||||
|
self.__data.clear()
|
||||||
|
self.endRemoveRows()
|
||||||
|
self.endResetModel()
|
||||||
|
|
||||||
|
def setCharts(self, charts: list[Chart]):
|
||||||
|
self.clear()
|
||||||
|
|
||||||
|
db = Database()
|
||||||
|
self.beginInsertRows(QModelIndex(), 0, len(charts))
|
||||||
|
for chart in charts:
|
||||||
|
pack = db.get_pack(chart.set)
|
||||||
|
if re.search(r"_append_.*$", pack.id):
|
||||||
|
basePackId = re.sub(r"_append_.*$", "", pack.id)
|
||||||
|
basePackName = db.get_pack(basePackId).name
|
||||||
|
packName = f"{basePackName} - {pack.name}"
|
||||||
|
else:
|
||||||
|
packName = pack.name
|
||||||
|
|
||||||
|
tooltip = (
|
||||||
|
f"{chart.title}@{packName} [{rating_class_to_text(chart.rating_class)}]"
|
||||||
|
)
|
||||||
|
self.__data.append(
|
||||||
|
{
|
||||||
|
Qt.ItemDataRole.ToolTipRole: tooltip,
|
||||||
|
self.ChartRole: chart,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
self.endInsertRows()
|
||||||
|
|
||||||
|
|
||||||
|
class CustomChartDelegate(ChartDelegate):
|
||||||
|
def getChart(self, index: QModelIndex) -> Chart | None:
|
||||||
|
return index.data(ChartsModel.ChartRole)
|
||||||
|
|
||||||
|
|
||||||
|
class ChartsWithScoreBestModel(QStandardItemModel):
|
||||||
|
ChartRole = Qt.ItemDataRole.UserRole
|
||||||
|
ScoreBestRole = Qt.ItemDataRole.UserRole + 10
|
||||||
|
|
||||||
|
def columnCount(self, *args) -> int:
|
||||||
|
return 3
|
||||||
|
|
||||||
|
def headerData(self, *args):
|
||||||
|
return None
|
||||||
|
|
||||||
|
def setChartAndScore(self, charts: list[Chart], scoreBests: list[ScoreBest]):
|
||||||
|
self.clear()
|
||||||
|
|
||||||
|
db = Database()
|
||||||
|
self.beginInsertRows(QModelIndex(), 0, len(charts))
|
||||||
|
for chart, scoreBest in zip(charts, scoreBests):
|
||||||
|
pack = db.get_pack(chart.set)
|
||||||
|
if re.search(r"_append_.*$", pack.id):
|
||||||
|
basePackId = re.sub(r"_append_.*$", "", pack.id)
|
||||||
|
basePackName = db.get_pack(basePackId).name
|
||||||
|
packName = f"{basePackName} - {pack.name}"
|
||||||
|
else:
|
||||||
|
packName = pack.name
|
||||||
|
|
||||||
|
tooltip = (
|
||||||
|
f"{chart.title}@{packName} [{rating_class_to_text(chart.rating_class)}]\n"
|
||||||
|
f"{scoreBest.score} > {scoreBest.potential}"
|
||||||
|
)
|
||||||
|
|
||||||
|
chartItem = QStandardItem()
|
||||||
|
chartItem.setData(tooltip, Qt.ItemDataRole.ToolTipRole)
|
||||||
|
chartItem.setData(chart, self.ChartRole)
|
||||||
|
|
||||||
|
scoreBestItem = QStandardItem()
|
||||||
|
scoreBestItem.setData(tooltip, Qt.ItemDataRole.ToolTipRole)
|
||||||
|
scoreBestItem.setData(scoreBest, self.ScoreBestRole)
|
||||||
|
|
||||||
|
potentialTextItem = QStandardItem()
|
||||||
|
potentialTextItem.setText(f"{scoreBest.potential}")
|
||||||
|
|
||||||
|
self.appendRow([chartItem, scoreBestItem, potentialTextItem])
|
||||||
|
|
||||||
|
|
||||||
|
class CustomScoreBestDelegate(ScoreDelegate):
|
||||||
|
def getScore(self, index: QModelIndex):
|
||||||
|
return index.data(ChartsWithScoreBestModel.ScoreBestRole)
|
@ -27,6 +27,9 @@ class ChartSelector(Ui_ChartSelector, QWidget):
|
|||||||
|
|
||||||
self.valueChanged.connect(self.updateResultLabel)
|
self.valueChanged.connect(self.updateResultLabel)
|
||||||
self.songIdSelector.valueChanged.connect(self.updateRatingClassEnabled)
|
self.songIdSelector.valueChanged.connect(self.updateRatingClassEnabled)
|
||||||
|
self.songIdSelector.quickSearchActivated.connect(
|
||||||
|
self.__songIdSelectedQuickSearchActivated
|
||||||
|
)
|
||||||
|
|
||||||
self.songIdSelector.valueChanged.connect(self.valueChanged)
|
self.songIdSelector.valueChanged.connect(self.valueChanged)
|
||||||
self.ratingClassSelector.valueChanged.connect(self.valueChanged)
|
self.ratingClassSelector.valueChanged.connect(self.valueChanged)
|
||||||
@ -85,15 +88,17 @@ class ChartSelector(Ui_ChartSelector, QWidget):
|
|||||||
texts = [" | ".join(t) for t in texts]
|
texts = [" | ".join(t) for t in texts]
|
||||||
text = f'{texts[0]}<br><font color="gray">{texts[1]}</font>'
|
text = f'{texts[0]}<br><font color="gray">{texts[1]}</font>'
|
||||||
else:
|
else:
|
||||||
text = f'No chart data<br><font color="gray">{chart.set} | {chart.song_id} | {chart.rating_class}</font>'
|
text = (
|
||||||
|
"No chart data<br>"
|
||||||
|
f'<font color="gray">{chart.set} | {chart.song_id} | {chart.rating_class}</font>'
|
||||||
|
)
|
||||||
self.resultLabel.setText(text)
|
self.resultLabel.setText(text)
|
||||||
else:
|
else:
|
||||||
self.resultLabel.setText("...")
|
self.resultLabel.setText("...")
|
||||||
|
|
||||||
def updateRatingClassEnabled(self):
|
def updateRatingClassEnabled(self):
|
||||||
ratingClasses = []
|
ratingClasses = []
|
||||||
songId = self.songIdSelector.songId()
|
if songId := self.songIdSelector.songId():
|
||||||
if songId:
|
|
||||||
if self.songIdSelector.mode == SongIdSelectorMode.Chart:
|
if self.songIdSelector.mode == SongIdSelectorMode.Chart:
|
||||||
items = self.db.get_charts_by_song_id(songId)
|
items = self.db.get_charts_by_song_id(songId)
|
||||||
else:
|
else:
|
||||||
@ -106,9 +111,8 @@ class ChartSelector(Ui_ChartSelector, QWidget):
|
|||||||
self.songIdSelector.reset()
|
self.songIdSelector.reset()
|
||||||
|
|
||||||
def selectChart(self, chart: Chart):
|
def selectChart(self, chart: Chart):
|
||||||
if not self.songIdSelector.selectPack(chart.set):
|
self.songIdSelector.selectChart(chart)
|
||||||
return False
|
self.ratingClassSelector.select(chart.rating_class)
|
||||||
if not self.songIdSelector.selectSongId(chart.song_id):
|
|
||||||
return False
|
def __songIdSelectedQuickSearchActivated(self, chart: Chart):
|
||||||
self.ratingClassSelector.select(chart.rating_class)
|
self.ratingClassSelector.select(chart.rating_class)
|
||||||
return True
|
|
||||||
|
@ -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)
|
|
@ -43,7 +43,7 @@ class OcrQueue(Ui_OcrQueue, QWidget):
|
|||||||
|
|
||||||
self.iccOptionButtonGroup = QButtonGroup(self)
|
self.iccOptionButtonGroup = QButtonGroup(self)
|
||||||
self.iccOptionButtonGroup.buttonToggled.connect(self.updateIccOption)
|
self.iccOptionButtonGroup.buttonToggled.connect(self.updateIccOption)
|
||||||
self.iccOptionButtonGroup.addButton(self.iccIgnoreRadioButton, 0)
|
self.iccOptionButtonGroup.addButton(self.iccUseQtRadioButton, 0)
|
||||||
self.iccOptionButtonGroup.addButton(self.iccUsePILRadioButton, 1)
|
self.iccOptionButtonGroup.addButton(self.iccUsePILRadioButton, 1)
|
||||||
self.iccOptionButtonGroup.addButton(self.iccTryFixRadioButton, 2)
|
self.iccOptionButtonGroup.addButton(self.iccTryFixRadioButton, 2)
|
||||||
self.updateIccOption()
|
self.updateIccOption()
|
||||||
|
@ -1,11 +1,10 @@
|
|||||||
import logging
|
import logging
|
||||||
import re
|
import re
|
||||||
from enum import IntEnum
|
from enum import IntEnum
|
||||||
from typing import Literal
|
|
||||||
|
|
||||||
from arcaea_offline.database import Database
|
from arcaea_offline.database import Database
|
||||||
from arcaea_offline.models import Chart
|
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 PySide6.QtWidgets import QCompleter, QWidget
|
||||||
|
|
||||||
from ui.designer.components.songIdSelector_ui import Ui_SongIdSelector
|
from ui.designer.components.songIdSelector_ui import Ui_SongIdSelector
|
||||||
@ -24,6 +23,7 @@ class SongIdSelectorMode(IntEnum):
|
|||||||
|
|
||||||
class SongIdSelector(Ui_SongIdSelector, QWidget):
|
class SongIdSelector(Ui_SongIdSelector, QWidget):
|
||||||
valueChanged = Signal()
|
valueChanged = Signal()
|
||||||
|
quickSearchActivated = Signal(Chart)
|
||||||
|
|
||||||
def __init__(self, parent=None):
|
def __init__(self, parent=None):
|
||||||
super().__init__(parent)
|
super().__init__(parent)
|
||||||
@ -33,18 +33,22 @@ class SongIdSelector(Ui_SongIdSelector, QWidget):
|
|||||||
self.languageChangeEventFilter = LanguageChangeEventFilter(self)
|
self.languageChangeEventFilter = LanguageChangeEventFilter(self)
|
||||||
self.installEventFilter(self.languageChangeEventFilter)
|
self.installEventFilter(self.languageChangeEventFilter)
|
||||||
|
|
||||||
self.previousPackageButton.clicked.connect(
|
# quick switch bindings
|
||||||
lambda: self.quickSwitchSelection("previous", "package")
|
self.quickSwitchSignalMapper = QSignalMapper(self)
|
||||||
|
self.previousPackageButton.clicked.connect(self.quickSwitchSignalMapper.map)
|
||||||
|
self.quickSwitchSignalMapper.setMapping(
|
||||||
|
self.previousPackageButton, "package||previous"
|
||||||
)
|
)
|
||||||
self.previousSongIdButton.clicked.connect(
|
self.nextPackageButton.clicked.connect(self.quickSwitchSignalMapper.map)
|
||||||
lambda: self.quickSwitchSelection("previous", "songId")
|
self.quickSwitchSignalMapper.setMapping(self.nextPackageButton, "package||next")
|
||||||
)
|
self.previousSongIdButton.clicked.connect(self.quickSwitchSignalMapper.map)
|
||||||
self.nextSongIdButton.clicked.connect(
|
self.quickSwitchSignalMapper.setMapping(
|
||||||
lambda: self.quickSwitchSelection("next", "songId")
|
self.previousSongIdButton, "songId||previous"
|
||||||
)
|
|
||||||
self.nextPackageButton.clicked.connect(
|
|
||||||
lambda: self.quickSwitchSelection("next", "package")
|
|
||||||
)
|
)
|
||||||
|
self.nextSongIdButton.clicked.connect(self.quickSwitchSignalMapper.map)
|
||||||
|
self.quickSwitchSignalMapper.setMapping(self.nextSongIdButton, "songId||next")
|
||||||
|
|
||||||
|
self.quickSwitchSignalMapper.mappedString.connect(self.quickSwitchSlot)
|
||||||
|
|
||||||
self.mode = SongIdSelectorMode.SongId
|
self.mode = SongIdSelectorMode.SongId
|
||||||
|
|
||||||
@ -73,12 +77,11 @@ class SongIdSelector(Ui_SongIdSelector, QWidget):
|
|||||||
def setMode(self, mode: SongIdSelectorMode):
|
def setMode(self, mode: SongIdSelectorMode):
|
||||||
self.mode = mode
|
self.mode = mode
|
||||||
|
|
||||||
def quickSwitchSelection(
|
@Slot(str)
|
||||||
self,
|
def quickSwitchSlot(self, action: str):
|
||||||
direction: Literal["previous", "next"],
|
model, direction = action.split("||")
|
||||||
model: Literal["package", "songId"],
|
|
||||||
):
|
minIndex = -1
|
||||||
minIndex = 0
|
|
||||||
if model == "package":
|
if model == "package":
|
||||||
maxIndex = self.packComboBox.count() - 1
|
maxIndex = self.packComboBox.count() - 1
|
||||||
currentIndex = self.packComboBox.currentIndex() + (
|
currentIndex = self.packComboBox.currentIndex() + (
|
||||||
@ -124,8 +127,7 @@ class SongIdSelector(Ui_SongIdSelector, QWidget):
|
|||||||
self.packComboBox.clear()
|
self.packComboBox.clear()
|
||||||
packs = self.db.get_packs()
|
packs = self.db.get_packs()
|
||||||
for pack in packs:
|
for pack in packs:
|
||||||
isAppendPack = re.search(r"_append_.*$", pack.id)
|
if isAppendPack := re.search(r"_append_.*$", pack.id):
|
||||||
if isAppendPack:
|
|
||||||
basePackId = re.sub(r"_append_.*$", "", pack.id)
|
basePackId = re.sub(r"_append_.*$", "", pack.id)
|
||||||
basePackName = self.db.get_pack(basePackId).name
|
basePackName = self.db.get_pack(basePackId).name
|
||||||
packName = f"{basePackName} - {pack.name}"
|
packName = f"{basePackName} - {pack.name}"
|
||||||
@ -144,8 +146,7 @@ class SongIdSelector(Ui_SongIdSelector, QWidget):
|
|||||||
|
|
||||||
def fillSongIdComboBox(self):
|
def fillSongIdComboBox(self):
|
||||||
self.songIdComboBox.clear()
|
self.songIdComboBox.clear()
|
||||||
packId = self.packComboBox.currentData()
|
if packId := self.packComboBox.currentData():
|
||||||
if packId:
|
|
||||||
if self.mode == SongIdSelectorMode.SongId:
|
if self.mode == SongIdSelectorMode.SongId:
|
||||||
items = self.db.get_songs_by_pack_id(packId)
|
items = self.db.get_songs_by_pack_id(packId)
|
||||||
elif self.mode == SongIdSelectorMode.Chart:
|
elif self.mode == SongIdSelectorMode.Chart:
|
||||||
@ -174,7 +175,7 @@ class SongIdSelector(Ui_SongIdSelector, QWidget):
|
|||||||
self.songIdComboBox.setCurrentIndex(-1)
|
self.songIdComboBox.setCurrentIndex(-1)
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def on_packComboBox_activated(self):
|
def on_packComboBox_currentIndexChanged(self):
|
||||||
self.fillSongIdComboBox()
|
self.fillSongIdComboBox()
|
||||||
|
|
||||||
@Slot(str)
|
@Slot(str)
|
||||||
@ -206,14 +207,15 @@ class SongIdSelector(Ui_SongIdSelector, QWidget):
|
|||||||
return False
|
return False
|
||||||
|
|
||||||
def selectChart(self, chart: Chart):
|
def selectChart(self, chart: Chart):
|
||||||
if not self.selectPack(chart.set):
|
packSelected = self.selectPack(chart.set)
|
||||||
return False
|
songIdSelected = self.selectSongId(chart.song_id)
|
||||||
return self.selectSongId(chart.song_id)
|
return packSelected and songIdSelected
|
||||||
|
|
||||||
@Slot(QModelIndex)
|
@Slot(QModelIndex)
|
||||||
def searchCompleterSetSelection(self, index: QModelIndex):
|
def searchCompleterSetSelection(self, index: QModelIndex):
|
||||||
chart = index.data(Qt.ItemDataRole.UserRole + 10) # type: Chart
|
chart: Chart = index.data(Qt.ItemDataRole.UserRole + 10)
|
||||||
self.selectChart(chart)
|
self.selectChart(chart)
|
||||||
|
self.quickSearchActivated.emit(chart)
|
||||||
|
|
||||||
self.searchLineEdit.clear()
|
self.searchLineEdit.clear()
|
||||||
self.searchLineEdit.clearFocus()
|
self.searchLineEdit.clearFocus()
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
from PySide6.QtCore import QCoreApplication
|
from PySide6.QtCore import QCoreApplication
|
||||||
from PySide6.QtWidgets import QLabel, QPushButton
|
from PySide6.QtWidgets import QLabel, QPushButton
|
||||||
|
|
||||||
from ui.implements.components.devicesComboBox import DevicesComboBox
|
|
||||||
from ui.implements.components.fileSelector import FileSelector
|
from ui.implements.components.fileSelector import FileSelector
|
||||||
from ui.implements.settings.settingsBaseWidget import SettingsBaseWidget
|
from ui.implements.settings.settingsBaseWidget import SettingsBaseWidget
|
||||||
|
|
||||||
@ -12,28 +11,6 @@ class SettingsOcr(SettingsBaseWidget):
|
|||||||
|
|
||||||
self.setupUi(self)
|
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():
|
if self.settings.knnModelFile():
|
||||||
self.knnModelFileValueWidget.selectFile(self.settings.knnModelFile())
|
self.knnModelFileValueWidget.selectFile(self.settings.knnModelFile())
|
||||||
self.knnModelFileValueWidget.filesSelected.connect(self.setKnnModelFile)
|
self.knnModelFileValueWidget.filesSelected.connect(self.setKnnModelFile)
|
||||||
@ -56,19 +33,6 @@ class SettingsOcr(SettingsBaseWidget):
|
|||||||
self.b30KnnModelFileResetButton,
|
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():
|
if self.settings.phashDatabaseFile():
|
||||||
self.phashDatabaseFileValueWidget.selectFile(
|
self.phashDatabaseFileValueWidget.selectFile(
|
||||||
self.settings.phashDatabaseFile()
|
self.settings.phashDatabaseFile()
|
||||||
@ -84,34 +48,6 @@ class SettingsOcr(SettingsBaseWidget):
|
|||||||
self.phashDatabaseFileResetButton,
|
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):
|
def setKnnModelFile(self):
|
||||||
selectedFile = self.knnModelFileValueWidget.selectedFiles()
|
selectedFile = self.knnModelFileValueWidget.selectedFiles()
|
||||||
if selectedFile and selectedFile[0]:
|
if selectedFile and selectedFile[0]:
|
||||||
@ -132,16 +68,6 @@ class SettingsOcr(SettingsBaseWidget):
|
|||||||
self.b30KnnModelFileValueWidget.reset()
|
self.b30KnnModelFileValueWidget.reset()
|
||||||
self.settings.resetB30KnnModelFile()
|
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):
|
def setPHashDatabaseFile(self):
|
||||||
selectedFile = self.phashDatabaseFileValueWidget.selectedFiles()
|
selectedFile = self.phashDatabaseFileValueWidget.selectedFiles()
|
||||||
if selectedFile and selectedFile[0]:
|
if selectedFile and selectedFile[0]:
|
||||||
@ -153,14 +79,6 @@ class SettingsOcr(SettingsBaseWidget):
|
|||||||
self.settings.resetPHashDatabaseFile()
|
self.settings.resetPHashDatabaseFile()
|
||||||
|
|
||||||
def setupUi(self, *args):
|
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.knnModelFileLabel = QLabel(self)
|
||||||
self.knnModelFileValueWidget = FileSelector(self)
|
self.knnModelFileValueWidget = FileSelector(self)
|
||||||
self.knnModelFileResetButton = QPushButton(self)
|
self.knnModelFileResetButton = QPushButton(self)
|
||||||
@ -169,10 +87,6 @@ class SettingsOcr(SettingsBaseWidget):
|
|||||||
self.b30KnnModelFileValueWidget = FileSelector(self)
|
self.b30KnnModelFileValueWidget = FileSelector(self)
|
||||||
self.b30KnnModelFileResetButton = QPushButton(self)
|
self.b30KnnModelFileResetButton = QPushButton(self)
|
||||||
|
|
||||||
self.siftDatabaseFileLabel = QLabel(self)
|
|
||||||
self.siftDatabaseFileValueWidget = FileSelector(self)
|
|
||||||
self.siftDatabaseFileResetButton = QPushButton(self)
|
|
||||||
|
|
||||||
self.phashDatabaseFileLabel = QLabel(self)
|
self.phashDatabaseFileLabel = QLabel(self)
|
||||||
self.phashDatabaseFileValueWidget = FileSelector(self)
|
self.phashDatabaseFileValueWidget = FileSelector(self)
|
||||||
self.phashDatabaseFileResetButton = QPushButton(self)
|
self.phashDatabaseFileResetButton = QPushButton(self)
|
||||||
@ -186,21 +100,12 @@ class SettingsOcr(SettingsBaseWidget):
|
|||||||
# fmt: off
|
# fmt: off
|
||||||
self.setTitle(QCoreApplication.translate("Settings", "ocr.title"))
|
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.knnModelFileLabel.setText(QCoreApplication.translate("Settings", "ocr.knnModelFile.label"))
|
||||||
self.knnModelFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton"))
|
self.knnModelFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton"))
|
||||||
|
|
||||||
self.b30KnnModelFileLabel.setText(QCoreApplication.translate("Settings", "ocr.b30KnnModelFile.label"))
|
self.b30KnnModelFileLabel.setText(QCoreApplication.translate("Settings", "ocr.b30KnnModelFile.label"))
|
||||||
self.b30KnnModelFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton"))
|
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.phashDatabaseFileLabel.setText(QCoreApplication.translate("Settings", "ocr.phashDatabaseFile.label"))
|
||||||
self.phashDatabaseFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton"))
|
self.phashDatabaseFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton"))
|
||||||
# fmt: on
|
# fmt: on
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
import logging
|
import logging
|
||||||
|
|
||||||
import cv2
|
import cv2
|
||||||
|
import numpy as np
|
||||||
from arcaea_offline_ocr.b30.chieri.v4.ocr import ChieriBotV4Ocr
|
from arcaea_offline_ocr.b30.chieri.v4.ocr import ChieriBotV4Ocr
|
||||||
from arcaea_offline_ocr.phash_db import ImagePHashDatabase
|
from arcaea_offline_ocr.phash_db import ImagePhashDatabase
|
||||||
from arcaea_offline_ocr.sift_db import SIFTDatabase
|
|
||||||
from arcaea_offline_ocr.utils import imread_unicode
|
from arcaea_offline_ocr.utils import imread_unicode
|
||||||
|
from PIL import Image
|
||||||
from PySide6.QtCore import Signal, Slot
|
from PySide6.QtCore import Signal, Slot
|
||||||
from PySide6.QtWidgets import QWidget
|
from PySide6.QtWidgets import QFileDialog, QMessageBox, QWidget
|
||||||
|
|
||||||
from ui.designer.tabs.tabOcr.tabOcr_B30_ui import Ui_TabOcr_B30
|
from ui.designer.tabs.tabOcr.tabOcr_B30_ui import Ui_TabOcr_B30
|
||||||
from ui.extends.components.ocrQueue import OcrQueueModel
|
from ui.extends.components.ocrQueue import OcrQueueModel
|
||||||
from ui.extends.shared.cv2_utils import cv2BgrMatToQImage, qImageToCvMatBgr
|
from ui.extends.ocr.dependencies import (
|
||||||
|
getCv2StatModelStatusText,
|
||||||
|
getPhashDatabaseStatusText,
|
||||||
|
)
|
||||||
from ui.extends.shared.language import LanguageChangeEventFilter
|
from ui.extends.shared.language import LanguageChangeEventFilter
|
||||||
from ui.extends.shared.settings import (
|
from ui.extends.shared.settings import (
|
||||||
B30_KNN_MODEL_FILE,
|
B30_KNN_MODEL_FILE,
|
||||||
@ -36,97 +40,119 @@ class TabOcr_B30(Ui_TabOcr_B30, QWidget):
|
|||||||
self.b30TypeComboBox.setCurrentIndex(0)
|
self.b30TypeComboBox.setCurrentIndex(0)
|
||||||
self.b30TypeComboBox.setEnabled(False)
|
self.b30TypeComboBox.setEnabled(False)
|
||||||
|
|
||||||
self.imageSelector.filesSelected.connect(self.imageSelected)
|
self.dependencies_knnModelSelector.filesSelected.connect(self.knnModelSelected)
|
||||||
self.knnModelSelector.filesSelected.connect(self.knnModelSelected)
|
self.dependencies_b30KnnModelSelector.filesSelected.connect(
|
||||||
self.b30KnnModelSelector.filesSelected.connect(self.b30KnnModelSelected)
|
self.b30KnnModelSelected
|
||||||
self.phashDatabaseSelector.filesSelected.connect(self.phashDatabaseSelected)
|
)
|
||||||
|
self.dependencies_phashDatabaseSelector.filesSelected.connect(
|
||||||
|
self.phashDatabaseSelected
|
||||||
|
)
|
||||||
|
|
||||||
self.imagePath = None # for checking only
|
|
||||||
self.img = None
|
|
||||||
self.paddleFolder = None
|
|
||||||
self.paddle = None
|
|
||||||
self.knnModel = None
|
self.knnModel = None
|
||||||
self.b30KnnModel = None
|
self.b30KnnModel = None
|
||||||
# self.siftDatabase = None
|
|
||||||
self.phashDatabase = None
|
self.phashDatabase = None
|
||||||
|
|
||||||
self.ocr = None
|
self.ocr = None
|
||||||
|
|
||||||
self.tryPrepareOcr.connect(self.prepareOcr)
|
|
||||||
|
|
||||||
logger.info("Applying settings...")
|
logger.info("Applying settings...")
|
||||||
self.knnModelSelector.connectSettings(KNN_MODEL_FILE)
|
self.dependencies_knnModelSelector.connectSettings(KNN_MODEL_FILE)
|
||||||
self.b30KnnModelSelector.connectSettings(B30_KNN_MODEL_FILE)
|
self.dependencies_b30KnnModelSelector.connectSettings(B30_KNN_MODEL_FILE)
|
||||||
self.phashDatabaseSelector.connectSettings(PHASH_DATABASE_FILE)
|
self.dependencies_phashDatabaseSelector.connectSettings(PHASH_DATABASE_FILE)
|
||||||
|
|
||||||
self.ocrQueueModel = OcrQueueModel(self)
|
self.ocrQueueModel = OcrQueueModel(self)
|
||||||
self.ocrQueue.setModel(self.ocrQueueModel)
|
self.ocrQueue.setModel(self.ocrQueueModel)
|
||||||
|
|
||||||
def imageSelected(self):
|
# def imageSelected(self):
|
||||||
if selectedFiles := self.imageSelector.selectedFiles():
|
# if selectedFiles := self.imageSelector.selectedFiles():
|
||||||
imagePath = selectedFiles[0]
|
# imagePath = selectedFiles[0]
|
||||||
self.imagePath = imagePath
|
# self.imagePath = imagePath
|
||||||
self.img = imread_unicode(imagePath)
|
# self.img = imread_unicode(imagePath)
|
||||||
self.tryPrepareOcr.emit()
|
# self.tryPrepareOcr.emit()
|
||||||
|
|
||||||
def knnModelSelected(self):
|
def knnModelSelected(self):
|
||||||
if selectedFiles := self.knnModelSelector.selectedFiles():
|
try:
|
||||||
knnModelPath = selectedFiles[0]
|
filePath = self.dependencies_knnModelSelector.selectedFiles()[0]
|
||||||
self.knnModel = cv2.ml.KNearest.load(knnModelPath)
|
self.knnModel = cv2.ml.KNearest.load(filePath)
|
||||||
self.tryPrepareOcr.emit()
|
except Exception:
|
||||||
|
self.knnModel = None
|
||||||
|
logger.exception("Error loading knn model:")
|
||||||
|
finally:
|
||||||
|
self.dependencies_knnModelStatusLabel.setText(
|
||||||
|
getCv2StatModelStatusText(self.knnModel)
|
||||||
|
)
|
||||||
|
|
||||||
def b30KnnModelSelected(self):
|
def b30KnnModelSelected(self):
|
||||||
if selectedFiles := self.b30KnnModelSelector.selectedFiles():
|
try:
|
||||||
b30KnnModelPath = selectedFiles[0]
|
filePath = self.dependencies_b30KnnModelSelector.selectedFiles()[0]
|
||||||
self.b30KnnModel = cv2.ml.KNearest.load(b30KnnModelPath)
|
self.b30KnnModel = cv2.ml.KNearest.load(filePath)
|
||||||
self.tryPrepareOcr.emit()
|
except Exception:
|
||||||
|
self.b30KnnModel = None
|
||||||
|
logger.exception("Error loading b30 knn model:")
|
||||||
|
finally:
|
||||||
|
self.dependencies_b30KnnModelStatusLabel.setText(
|
||||||
|
getCv2StatModelStatusText(self.b30KnnModel)
|
||||||
|
)
|
||||||
|
|
||||||
def phashDatabaseSelected(self):
|
def phashDatabaseSelected(self):
|
||||||
if selectedFiles := self.phashDatabaseSelector.selectedFiles():
|
try:
|
||||||
phashDatabasePath = selectedFiles[0]
|
filePath = self.dependencies_phashDatabaseSelector.selectedFiles()[0]
|
||||||
self.phashDatabase = ImagePHashDatabase(phashDatabasePath)
|
self.phashDatabase = ImagePhashDatabase(filePath)
|
||||||
self.tryPrepareOcr.emit()
|
except Exception:
|
||||||
|
self.phashDatabase = None
|
||||||
|
logger.exception("Error loading phash database:")
|
||||||
|
finally:
|
||||||
|
self.dependencies_phashDatabaseStatusLabel.setText(
|
||||||
|
getPhashDatabaseStatusText(self.phashDatabase)
|
||||||
|
)
|
||||||
|
|
||||||
def prepareOcr(self):
|
def checkDependencies(self):
|
||||||
b30Type = self.b30TypeComboBox.currentData()
|
b30Type = self.b30TypeComboBox.currentData()
|
||||||
if not b30Type:
|
if not b30Type:
|
||||||
|
return False
|
||||||
|
elif b30Type == "chieri_v4":
|
||||||
|
return (
|
||||||
|
self.knnModel is not None
|
||||||
|
and self.b30KnnModel is not None
|
||||||
|
and self.phashDatabase is not None
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
@Slot()
|
||||||
|
def on_ocr_addImageButton_clicked(self):
|
||||||
|
if not self.checkDependencies():
|
||||||
|
QMessageBox.critical(self, None, "Dependencies not configured.")
|
||||||
return
|
return
|
||||||
|
|
||||||
if b30Type == "chieri_v4":
|
imagePath, _ = QFileDialog.getOpenFileName(
|
||||||
if (
|
self, None, "", "Image Files (*.png *.jpg *.jpeg *.bmp *.webp);;*"
|
||||||
not self.imagePath
|
)
|
||||||
or not self.knnModel
|
|
||||||
or not self.b30KnnModel
|
|
||||||
or not self.phashDatabase
|
|
||||||
):
|
|
||||||
return
|
|
||||||
|
|
||||||
self.ocrQueueModel.clear()
|
if not imagePath:
|
||||||
|
return
|
||||||
|
|
||||||
ocr = ChieriBotV4Ocr(self.knnModel, self.b30KnnModel, self.phashDatabase)
|
self.ocrQueueModel.clear()
|
||||||
ocr.set_factor(self.img)
|
|
||||||
self.ocr = ocr
|
|
||||||
|
|
||||||
roi = ocr.rois
|
img = imread_unicode(imagePath, cv2.IMREAD_COLOR)
|
||||||
for component in roi.components(self.img):
|
ocr = ChieriBotV4Ocr(self.knnModel, self.b30KnnModel, self.phashDatabase)
|
||||||
qImage = cv2BgrMatToQImage(component.copy())
|
ocr.set_factor(img)
|
||||||
self.ocrQueueModel.addItem(qImage)
|
self.ocr = ocr
|
||||||
|
|
||||||
|
roi = ocr.rois
|
||||||
|
for component in roi.components(img):
|
||||||
|
qImage = Image.fromarray(component.copy()).toqimage()
|
||||||
|
self.ocrQueueModel.addItem(qImage)
|
||||||
self.ocrQueue.resizeTableView()
|
self.ocrQueue.resizeTableView()
|
||||||
|
|
||||||
@Slot()
|
@Slot()
|
||||||
def on_ocr_startButton_clicked(self):
|
def on_ocr_startButton_clicked(self):
|
||||||
if (
|
if not self.ocr:
|
||||||
not self.imagePath
|
|
||||||
or not self.knnModel
|
|
||||||
or not self.b30KnnModel
|
|
||||||
or not self.phashDatabase
|
|
||||||
):
|
|
||||||
return
|
return
|
||||||
|
|
||||||
for row in range(self.ocrQueueModel.rowCount()):
|
for row in range(self.ocrQueueModel.rowCount()):
|
||||||
index = self.ocrQueueModel.index(row, 0)
|
index = self.ocrQueueModel.index(row, 0)
|
||||||
qImage = index.data(OcrQueueModel.ImageQImageRole)
|
qImage = index.data(OcrQueueModel.ImageQImageRole)
|
||||||
cv2Mat = qImageToCvMatBgr(qImage)
|
cv2Mat = np.array(Image.fromqimage(qImage))
|
||||||
runnable = ChieriV4OcrRunnable(self.ocr, cv2Mat)
|
runnable = ChieriV4OcrRunnable(self.ocr, cv2Mat)
|
||||||
self.ocrQueueModel.setData(index, runnable, OcrQueueModel.OcrRunnableRole)
|
self.ocrQueueModel.setData(index, runnable, OcrQueueModel.OcrRunnableRole)
|
||||||
self.ocrQueueModel.setData(
|
self.ocrQueueModel.setData(
|
||||||
|
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 logging
|
||||||
|
|
||||||
import cv2
|
import cv2
|
||||||
|
from arcaea_offline_ocr.device.rois import (
|
||||||
# from arcaea_offline_ocr_device_creation_wizard.implements.wizard import Wizard
|
DeviceRoisAutoT1,
|
||||||
from arcaea_offline_ocr.device.v1.definition import DeviceV1
|
DeviceRoisAutoT2,
|
||||||
from arcaea_offline_ocr.device.v2.definition import DeviceV2
|
DeviceRoisMaskerAutoT1,
|
||||||
from arcaea_offline_ocr.phash_db import ImagePHashDatabase
|
DeviceRoisMaskerAutoT2,
|
||||||
from arcaea_offline_ocr.sift_db import SIFTDatabase
|
)
|
||||||
from PySide6.QtCore import Qt, Slot
|
from arcaea_offline_ocr.phash_db import ImagePhashDatabase
|
||||||
from PySide6.QtWidgets import QApplication, QFileDialog, QWidget
|
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.designer.tabs.tabOcr.tabOcr_Device_ui import Ui_TabOcr_Device
|
||||||
from ui.extends.components.ocrQueue import OcrQueueModel
|
from ui.extends.components.ocrQueue import OcrQueueModel
|
||||||
from ui.extends.shared.language import LanguageChangeEventFilter
|
from ui.extends.shared.language import LanguageChangeEventFilter
|
||||||
from ui.extends.shared.settings import (
|
from ui.extends.shared.settings import KNN_MODEL_FILE, PHASH_DATABASE_FILE
|
||||||
DEVICES_JSON_FILE,
|
from ui.extends.tabs.tabOcr.tabOcr_Device import ScoreConverter, TabDeviceOcrRunnable
|
||||||
KNN_MODEL_FILE,
|
|
||||||
PHASH_DATABASE_FILE,
|
|
||||||
TESSERACT_FILE,
|
|
||||||
Settings,
|
|
||||||
)
|
|
||||||
from ui.extends.tabs.tabOcr.tabOcr_Device import (
|
|
||||||
ScoreConverter,
|
|
||||||
TabDeviceV2AutoRoisOcrRunnable,
|
|
||||||
TabDeviceV2OcrRunnable,
|
|
||||||
)
|
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -38,17 +29,36 @@ class TabOcr_Device(Ui_TabOcr_Device, QWidget):
|
|||||||
self.languageChangeEventFilter = LanguageChangeEventFilter(self)
|
self.languageChangeEventFilter = LanguageChangeEventFilter(self)
|
||||||
self.installEventFilter(self.languageChangeEventFilter)
|
self.installEventFilter(self.languageChangeEventFilter)
|
||||||
|
|
||||||
self.deviceFileSelector.filesSelected.connect(self.deviceFileSelected)
|
# connect options checkBoxes & comboBoxes
|
||||||
self.knnModelSelector.filesSelected.connect(self.knnModelFileSelected)
|
self.options_roisUseCustomCheckBox.toggled.connect(
|
||||||
self.phashDatabaseSelector.filesSelected.connect(self.phashDatabaseFileSelected)
|
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...")
|
logger.info("Applying settings...")
|
||||||
self.deviceFileSelector.connectSettings(DEVICES_JSON_FILE)
|
self.dependencies_knnModelSelector.connectSettings(KNN_MODEL_FILE)
|
||||||
self.knnModelSelector.connectSettings(KNN_MODEL_FILE)
|
self.dependencies_phashDatabaseSelector.connectSettings(PHASH_DATABASE_FILE)
|
||||||
self.tesseractFileSelector.connectSettings(TESSERACT_FILE)
|
|
||||||
self.phashDatabaseSelector.connectSettings(PHASH_DATABASE_FILE)
|
self.options_usePresetCheckBox.setChecked(True)
|
||||||
settings = Settings()
|
self.options_usePresetCheckBox.setEnabled(False)
|
||||||
self.deviceComboBox.selectDevice(settings.deviceUuid())
|
|
||||||
|
|
||||||
self.ocrQueueModel = OcrQueueModel(self)
|
self.ocrQueueModel = OcrQueueModel(self)
|
||||||
self.ocrQueue.setModel(self.ocrQueueModel)
|
self.ocrQueue.setModel(self.ocrQueueModel)
|
||||||
@ -60,43 +70,76 @@ class TabOcr_Device(Ui_TabOcr_Device, QWidget):
|
|||||||
# wizard.open()
|
# wizard.open()
|
||||||
pass
|
pass
|
||||||
|
|
||||||
@Slot()
|
@Slot(bool)
|
||||||
def on_deviceUseAutoFactorCheckBox_stateChanged(self):
|
def options_setUsePreset(self, usePreset: bool):
|
||||||
checkState = self.deviceUseAutoFactorCheckBox.checkState()
|
self.options_roisUseCustomCheckBox.setChecked(not usePreset)
|
||||||
if checkState == Qt.CheckState.Checked:
|
self.options_maskerUseCustomCheckBox.setChecked(not usePreset)
|
||||||
self.deviceDependenciesStackedWidget.setCurrentIndex(1)
|
self.options_preciseControlWidget.setEnabled(not usePreset)
|
||||||
self.deviceComboBox.setCurrentIndex(-1)
|
if not usePreset:
|
||||||
self.deviceFileSelector.setEnabled(False)
|
self.options_presetComboBox.setCurrentIndex(-1)
|
||||||
self.deviceComboBox.setEnabled(False)
|
|
||||||
else:
|
|
||||||
self.deviceFileSelector.setEnabled(True)
|
|
||||||
self.deviceComboBox.setEnabled(True)
|
|
||||||
|
|
||||||
@Slot()
|
@Slot(int)
|
||||||
def on_deviceComboBox_currentIndexChanged(self):
|
def options_presetSelected(self, index: int):
|
||||||
self.changeDeviceDepStackedWidget()
|
if index < 0:
|
||||||
|
self.options_roisComboBox.setCurrentIndex(-1)
|
||||||
|
self.options_maskerComboBox.setCurrentIndex(-1)
|
||||||
|
|
||||||
def changeDeviceDepStackedWidget(self):
|
autoTypeString = self.options_presetComboBox.currentData()
|
||||||
device = self.deviceComboBox.currentData()
|
roisAutoTypeIndex = self.options_roisComboBox.findData(autoTypeString)
|
||||||
if isinstance(device, (DeviceV1, DeviceV2)):
|
maskerAutoTypeIndex = self.options_maskerComboBox.findData(autoTypeString)
|
||||||
self.deviceDependenciesStackedWidget.setCurrentIndex(device.version - 1)
|
self.options_roisComboBox.setCurrentIndex(roisAutoTypeIndex)
|
||||||
|
self.options_maskerComboBox.setCurrentIndex(maskerAutoTypeIndex)
|
||||||
|
|
||||||
def deviceFileSelected(self):
|
def options_fillComboBoxes(self):
|
||||||
if selectedFiles := self.deviceFileSelector.selectedFiles():
|
self.options_roisComboBox.addItem("RoisAutoT1", "AutoT1")
|
||||||
file = selectedFiles[0]
|
self.options_roisComboBox.addItem("RoisAutoT2", "AutoT2")
|
||||||
self.deviceComboBox.loadDevicesJson(file)
|
self.options_roisComboBox.setCurrentIndex(-1)
|
||||||
|
|
||||||
def knnModelFileSelected(self):
|
self.options_maskerComboBox.addItem("MaskerAutoT1", "AutoT1")
|
||||||
if selectedFiles := self.knnModelSelector.selectedFiles():
|
self.options_maskerComboBox.addItem("MaskerAutoT2", "AutoT2")
|
||||||
self.knnModel = cv2.ml.KNearest.load(selectedFiles[0])
|
self.options_maskerComboBox.setCurrentIndex(-1)
|
||||||
|
|
||||||
def phashDatabaseFileSelected(self):
|
self.options_presetComboBox.addItem("AutoT1 (ver <= 4.7.2)", "AutoT1")
|
||||||
if selectedFiles := self.phashDatabaseSelector.selectedFiles():
|
self.options_presetComboBox.addItem("AutoT2 (ver >= 5.0.0)", "AutoT2")
|
||||||
self.phashDatabase = ImagePHashDatabase(selectedFiles[0])
|
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()
|
@Slot()
|
||||||
def on_ocr_addImageButton_clicked(self):
|
def on_ocr_addImageButton_clicked(self):
|
||||||
files, _filter = QFileDialog.getOpenFileNames(
|
files, _ = QFileDialog.getOpenFileNames(
|
||||||
self, None, "", "Image Files (*.png *.jpg *.jpeg *.bmp *.webp);;*"
|
self, None, "", "Image Files (*.png *.jpg *.jpeg *.bmp *.webp);;*"
|
||||||
)
|
)
|
||||||
filesNum = len(files)
|
filesNum = len(files)
|
||||||
@ -114,30 +157,51 @@ class TabOcr_Device(Ui_TabOcr_Device, QWidget):
|
|||||||
QApplication.processEvents()
|
QApplication.processEvents()
|
||||||
self.ocrQueue.resizeTableView()
|
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()
|
@Slot()
|
||||||
def on_ocr_startButton_clicked(self):
|
def on_ocr_startButton_clicked(self):
|
||||||
for row in range(self.ocrQueueModel.rowCount()):
|
for row in range(self.ocrQueueModel.rowCount()):
|
||||||
index = self.ocrQueueModel.index(row, 0)
|
index = self.ocrQueueModel.index(row, 0)
|
||||||
imagePath = index.data(OcrQueueModel.ImagePathRole)
|
imagePath = index.data(OcrQueueModel.ImagePathRole)
|
||||||
if self.deviceUseAutoFactorCheckBox.checkState() == Qt.CheckState.Checked:
|
|
||||||
runnable = TabDeviceV2AutoRoisOcrRunnable(
|
rois = self.deviceRois()
|
||||||
imagePath,
|
masker = self.deviceRoisMasker()
|
||||||
self.knnModel,
|
|
||||||
self.phashDatabase,
|
if rois is None or masker is None:
|
||||||
sizesV2=self.deviceSizesV2CheckBox.isChecked(),
|
return
|
||||||
)
|
|
||||||
else:
|
runnable = TabDeviceOcrRunnable(
|
||||||
runnable = TabDeviceV2OcrRunnable(
|
imagePath, rois, masker, self.knnModel, self.phashDatabase
|
||||||
imagePath,
|
)
|
||||||
self.deviceComboBox.currentData(),
|
|
||||||
self.knnModel,
|
|
||||||
self.phashDatabase,
|
|
||||||
sizesV2=self.deviceSizesV2CheckBox.isChecked(),
|
|
||||||
)
|
|
||||||
self.ocrQueueModel.setData(index, runnable, OcrQueueModel.OcrRunnableRole)
|
self.ocrQueueModel.setData(index, runnable, OcrQueueModel.OcrRunnableRole)
|
||||||
self.ocrQueueModel.setData(
|
self.ocrQueueModel.setData(
|
||||||
index,
|
index,
|
||||||
ScoreConverter.deviceV2,
|
ScoreConverter.device,
|
||||||
OcrQueueModel.ProcessOcrResultFuncRole,
|
OcrQueueModel.ProcessOcrResultFuncRole,
|
||||||
)
|
)
|
||||||
self.ocrQueueModel.startQueue()
|
self.ocrQueueModel.startQueue()
|
||||||
|
@ -180,19 +180,20 @@ class TabTools_Andreal(Ui_TabTools_Andreal, QWidget):
|
|||||||
|
|
||||||
arguments = [
|
arguments = [
|
||||||
str(self.imageType()),
|
str(self.imageType()),
|
||||||
f'--json-file="{jsonFile}"',
|
"--json-file",
|
||||||
f"--img-version={self.imageVersion()}",
|
jsonFile,
|
||||||
|
"--img-version",
|
||||||
|
str(self.imageVersion()),
|
||||||
]
|
]
|
||||||
if self.andrealFolderSelector.selectedFiles():
|
if self.andrealFolderSelector.selectedFiles():
|
||||||
arguments.append(
|
arguments.append("--path")
|
||||||
f'--path="{self.andrealFolderSelector.selectedFiles()[0]}"'
|
arguments.append(self.andrealFolderSelector.selectedFiles()[0])
|
||||||
)
|
|
||||||
if preview:
|
if preview:
|
||||||
arguments.extend(["--img-format=jpg", "--img-quality=20"])
|
arguments.extend(["--img-format", "jpg", "--img-quality", "20"])
|
||||||
else:
|
else:
|
||||||
arguments.append(f"--img-format={self.imageFormat()}")
|
arguments.extend(["--img-format", self.imageFormat()])
|
||||||
if self.imageFormat() == "jpg":
|
if self.imageFormat() == "jpg":
|
||||||
arguments.append(f"--img-quality={self.jpgQualitySpinBox.value()}")
|
arguments.extend(["--img-quality", str(self.jpgQualitySpinBox.value())])
|
||||||
return arguments
|
return arguments
|
||||||
|
|
||||||
def getAndrealJsonContent(self):
|
def getAndrealJsonContent(self):
|
||||||
|
@ -1,5 +1,4 @@
|
|||||||
import logging
|
import logging
|
||||||
import random
|
|
||||||
|
|
||||||
from arcaea_offline.calculate import calculate_constants_from_play_rating
|
from arcaea_offline.calculate import calculate_constants_from_play_rating
|
||||||
from arcaea_offline.database import Database
|
from arcaea_offline.database import Database
|
||||||
@ -7,11 +6,17 @@ from arcaea_offline.models import Chart, ScoreBest
|
|||||||
from arcaea_offline.utils.rating import rating_class_to_text
|
from arcaea_offline.utils.rating import rating_class_to_text
|
||||||
from arcaea_offline.utils.score import score_to_grade_text
|
from arcaea_offline.utils.score import score_to_grade_text
|
||||||
from PySide6.QtCore import Slot
|
from PySide6.QtCore import Slot
|
||||||
from PySide6.QtWidgets import QLabel, QWidget
|
from PySide6.QtWidgets import QWidget
|
||||||
|
|
||||||
from ui.designer.tabs.tabTools.tabTools_ChartRecommend_ui import (
|
from ui.designer.tabs.tabTools.tabTools_ChartRecommend_ui import (
|
||||||
Ui_TabTools_ChartRecommend,
|
Ui_TabTools_ChartRecommend,
|
||||||
)
|
)
|
||||||
|
from ui.extends.tabs.tabTools.tabTools_ChartRecommend import (
|
||||||
|
ChartsModel,
|
||||||
|
ChartsWithScoreBestModel,
|
||||||
|
CustomChartDelegate,
|
||||||
|
CustomScoreBestDelegate,
|
||||||
|
)
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -31,11 +36,25 @@ class TabTools_ChartRecommend(Ui_TabTools_ChartRecommend, QWidget):
|
|||||||
|
|
||||||
self.db = Database()
|
self.db = Database()
|
||||||
|
|
||||||
self.chartsByConstant = []
|
self.chartsByConstantModel = ChartsModel(self)
|
||||||
self.chartsRecommendFromPlayRating = []
|
self.chartsRecommendFromPlayRatingModel = ChartsWithScoreBestModel(self)
|
||||||
|
|
||||||
self.numLabelFormatString = "{} charts"
|
self.numLabelFormatString = "{} charts"
|
||||||
|
|
||||||
|
self.chartDelegate = CustomChartDelegate(self)
|
||||||
|
self.scoreBestDelegate = CustomScoreBestDelegate(self)
|
||||||
|
self.chartsByConstant_modelView.setModel(self.chartsByConstantModel)
|
||||||
|
self.chartsByConstant_modelView.setItemDelegate(self.chartDelegate)
|
||||||
|
self.chartsRecommendFromPlayRating_modelView.setModel(
|
||||||
|
self.chartsRecommendFromPlayRatingModel
|
||||||
|
)
|
||||||
|
self.chartsRecommendFromPlayRating_modelView.setItemDelegateForColumn(
|
||||||
|
0, self.chartDelegate
|
||||||
|
)
|
||||||
|
self.chartsRecommendFromPlayRating_modelView.setItemDelegateForColumn(
|
||||||
|
1, self.scoreBestDelegate
|
||||||
|
)
|
||||||
|
|
||||||
self.chartsRecommendFromPlayRating_playRatingSpinBox.valueChanged.connect(
|
self.chartsRecommendFromPlayRating_playRatingSpinBox.valueChanged.connect(
|
||||||
self.updateChartsRecommendFromPlayRating
|
self.updateChartsRecommendFromPlayRating
|
||||||
)
|
)
|
||||||
@ -43,81 +62,61 @@ class TabTools_ChartRecommend(Ui_TabTools_ChartRecommend, QWidget):
|
|||||||
self.updateChartsRecommendFromPlayRating
|
self.updateChartsRecommendFromPlayRating
|
||||||
)
|
)
|
||||||
|
|
||||||
self.chartsByConstant_refreshButton.clicked.connect(self.fillChartsByConstant)
|
|
||||||
self.chartsRecommendFromPlayRating_refreshButton.clicked.connect(
|
|
||||||
self.fillChartsRecommendFromPlayRating
|
|
||||||
)
|
|
||||||
|
|
||||||
@Slot(float)
|
@Slot(float)
|
||||||
def on_rangeFromPlayRating_playRatingSpinBox_valueChanged(self, value: float):
|
def on_rangeFromPlayRating_playRatingSpinBox_valueChanged(self, value: float):
|
||||||
try:
|
try:
|
||||||
result = calculate_constants_from_play_rating(value)
|
constant = round(
|
||||||
exPlusLower, exPlusUpper = result.EXPlus
|
value, self.rangeFromPlayRating_playRatingSpinBox.decimals()
|
||||||
exLower, exUpper = result.EX
|
|
||||||
aaLower, aaUpper = result.AA
|
|
||||||
|
|
||||||
self.rangeFromPlayRating_ExPlusLabel.setText(
|
|
||||||
f"{exPlusLower:.3f}~{exPlusUpper:.3f}"
|
|
||||||
)
|
)
|
||||||
self.rangeFromPlayRating_ExLabel.setText(f"{exLower:.3f}~{exUpper:.3f}")
|
result = calculate_constants_from_play_rating(constant)
|
||||||
self.rangeFromPlayRating_AaLabel.setText(f"{aaLower:.3f}~{aaUpper:.3f}")
|
labels = [
|
||||||
|
self.rangeFromPlayRating_ExPlusLabel,
|
||||||
|
self.rangeFromPlayRating_ExLabel,
|
||||||
|
self.rangeFromPlayRating_AaLabel,
|
||||||
|
self.rangeFromPlayRating_ALabel,
|
||||||
|
self.rangeFromPlayRating_BLabel,
|
||||||
|
self.rangeFromPlayRating_CLabel,
|
||||||
|
]
|
||||||
|
|
||||||
|
for label, constantRange in zip(
|
||||||
|
labels,
|
||||||
|
[result.EXPlus, result.EX, result.AA, result.A, result.B, result.C],
|
||||||
|
):
|
||||||
|
label.setText(f"{constantRange[0]:.3f}~{constantRange[1]:.3f}")
|
||||||
except Exception:
|
except Exception:
|
||||||
logging.exception("cannot calculate constant from play rating")
|
logging.exception("Cannot calculate constant from play rating:")
|
||||||
self.rangeFromPlayRating_ExPlusLabel.setText("...")
|
self.rangeFromPlayRating_ExPlusLabel.setText("...")
|
||||||
self.rangeFromPlayRating_ExLabel.setText("...")
|
self.rangeFromPlayRating_ExLabel.setText("...")
|
||||||
self.rangeFromPlayRating_AaLabel.setText("...")
|
self.rangeFromPlayRating_AaLabel.setText("...")
|
||||||
|
|
||||||
def fillChartsByConstant(self):
|
|
||||||
while item := self.chartsByConstant_gridLayout.takeAt(0):
|
|
||||||
item.widget().deleteLater()
|
|
||||||
|
|
||||||
charts = random.sample(
|
|
||||||
self.chartsByConstant, k=min(len(self.chartsByConstant), 6)
|
|
||||||
)
|
|
||||||
row = 0
|
|
||||||
for i, chart in enumerate(charts):
|
|
||||||
if i % 3 == 0:
|
|
||||||
row += 1
|
|
||||||
label = QLabel(self)
|
|
||||||
label.setText(chartToText(chart))
|
|
||||||
self.chartsByConstant_gridLayout.addWidget(label, row, i % 3)
|
|
||||||
|
|
||||||
@Slot(float)
|
@Slot(float)
|
||||||
def on_chartsByConstant_constantSpinBox_valueChanged(self, value: float):
|
def on_chartsByConstant_constantSpinBox_valueChanged(self, value: float):
|
||||||
self.chartsByConstant = self.db.get_charts_by_constant(int(value * 10))
|
constant = round(value, self.chartsByConstant_constantSpinBox.decimals())
|
||||||
chartsNum = len(self.chartsByConstant)
|
charts = self.db.get_charts_by_constant(int(constant * 10))
|
||||||
self.chartsByConstant_refreshButton.setEnabled(chartsNum > 6)
|
chartsNum = len(charts)
|
||||||
self.chartsByConstant_numLabel.setText(
|
self.chartsByConstant_numLabel.setText(
|
||||||
self.numLabelFormatString.format(chartsNum)
|
self.numLabelFormatString.format(chartsNum)
|
||||||
)
|
)
|
||||||
self.fillChartsByConstant()
|
self.chartsByConstantModel.setCharts(charts)
|
||||||
|
|
||||||
def fillChartsRecommendFromPlayRating(self):
|
|
||||||
while item := self.chartsRecommendFromPlayRating_gridLayout.takeAt(0):
|
|
||||||
item.widget().deleteLater()
|
|
||||||
|
|
||||||
charts = random.sample(
|
|
||||||
self.chartsRecommendFromPlayRating,
|
|
||||||
k=min(len(self.chartsRecommendFromPlayRating), 6),
|
|
||||||
)
|
|
||||||
row = 0
|
|
||||||
for i, chart in enumerate(charts):
|
|
||||||
if i % 3 == 0:
|
|
||||||
row += 1
|
|
||||||
scoreBest = self.db.get_score_best(chart.song_id, chart.rating_class)
|
|
||||||
label = QLabel(self)
|
|
||||||
label.setText(f"{chartToText(chart)}<br>-<br>{scoreBestToText(scoreBest)}")
|
|
||||||
self.chartsRecommendFromPlayRating_gridLayout.addWidget(label, row, i % 3)
|
|
||||||
|
|
||||||
def updateChartsRecommendFromPlayRating(self):
|
def updateChartsRecommendFromPlayRating(self):
|
||||||
playRating = self.chartsRecommendFromPlayRating_playRatingSpinBox.value()
|
playRating = self.chartsRecommendFromPlayRating_playRatingSpinBox.value()
|
||||||
bounds = self.chartsRecommendFromPlayRating_boundsSpinBox.value()
|
bounds = self.chartsRecommendFromPlayRating_boundsSpinBox.value()
|
||||||
self.chartsRecommendFromPlayRating = self.db.recommend_charts(
|
charts = self.db.recommend_charts(
|
||||||
playRating, bounds
|
round(
|
||||||
|
playRating,
|
||||||
|
self.chartsRecommendFromPlayRating_playRatingSpinBox.decimals(),
|
||||||
|
),
|
||||||
|
round(
|
||||||
|
bounds,
|
||||||
|
self.chartsRecommendFromPlayRating_boundsSpinBox.decimals(),
|
||||||
|
),
|
||||||
)
|
)
|
||||||
chartsNum = len(self.chartsRecommendFromPlayRating)
|
chartsNum = len(charts)
|
||||||
self.chartsRecommendFromPlayRating_refreshButton.setEnabled(chartsNum > 6)
|
|
||||||
self.chartsRecommendFromPlayRating_numLabel.setText(
|
self.chartsRecommendFromPlayRating_numLabel.setText(
|
||||||
self.numLabelFormatString.format(chartsNum)
|
self.numLabelFormatString.format(chartsNum)
|
||||||
)
|
)
|
||||||
self.fillChartsRecommendFromPlayRating()
|
scores = [self.db.get_score_best(c.song_id, c.rating_class) for c in charts]
|
||||||
|
self.chartsRecommendFromPlayRatingModel.setChartAndScore(charts, scores)
|
||||||
|
self.chartsRecommendFromPlayRating_modelView.resizeRowsToContents()
|
||||||
|
self.chartsRecommendFromPlayRating_modelView.resizeColumnsToContents()
|
||||||
|
BIN
ui/resources/images/jacket-placeholder.png
Normal file
BIN
ui/resources/images/jacket-placeholder.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 212 KiB |
@ -89,12 +89,12 @@
|
|||||||
<translation>Continue</translation>
|
<translation>Continue</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../startup/databaseChecker.py" line="115"/>
|
<location filename="../../startup/databaseChecker.py" line="117"/>
|
||||||
<source>dialog.tryInitExistingDatabase</source>
|
<source>dialog.tryInitExistingDatabase</source>
|
||||||
<translation>The existing database doesn't seem to be initialized properly, try initialize again?</translation>
|
<translation>The existing database doesn't seem to be initialized properly, try initialize again?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../startup/databaseChecker.py" line="131"/>
|
<location filename="../../startup/databaseChecker.py" line="133"/>
|
||||||
<source>dialog.confirmNewDatabase</source>
|
<source>dialog.confirmNewDatabase</source>
|
||||||
<translation>Database file does not exist. Create now?</translation>
|
<translation>Database file does not exist. Create now?</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -225,8 +225,8 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/components/ocrQueue.ui" line="34"/>
|
<location filename="../../designer/components/ocrQueue.ui" line="34"/>
|
||||||
<source>icc.ignore</source>
|
<source>icc.useQt</source>
|
||||||
<translation>Ignore</translation>
|
<translation>Use Qt</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/components/ocrQueue.ui" line="41"/>
|
<location filename="../../designer/components/ocrQueue.ui" line="41"/>
|
||||||
@ -477,12 +477,9 @@ validation</translation>
|
|||||||
<location filename="../../implements/settings/settingsAndreal.py" line="82"/>
|
<location filename="../../implements/settings/settingsAndreal.py" line="82"/>
|
||||||
<location filename="../../implements/settings/settingsAndreal.py" line="85"/>
|
<location filename="../../implements/settings/settingsAndreal.py" line="85"/>
|
||||||
<location filename="../../implements/settings/settingsGeneral.py" line="107"/>
|
<location filename="../../implements/settings/settingsGeneral.py" line="107"/>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="190"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="104"/>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="193"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="107"/>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="196"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="110"/>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="199"/>
|
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="202"/>
|
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="205"/>
|
|
||||||
<source>resetButton</source>
|
<source>resetButton</source>
|
||||||
<translation>Reset</translation>
|
<translation>Reset</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -517,37 +514,22 @@ validation</translation>
|
|||||||
<translation>Database URL</translation>
|
<translation>Database URL</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="187"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="101"/>
|
||||||
<source>ocr.title</source>
|
<source>ocr.title</source>
|
||||||
<translation>OCR</translation>
|
<translation>OCR</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="189"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="103"/>
|
||||||
<source>ocr.devicesJson.label</source>
|
|
||||||
<translation>Default devices.json</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="192"/>
|
|
||||||
<source>ocr.deviceUuid.label</source>
|
|
||||||
<translation>Default device</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="195"/>
|
|
||||||
<source>ocr.knnModelFile.label</source>
|
<source>ocr.knnModelFile.label</source>
|
||||||
<translation>Default KNearest model</translation>
|
<translation>Default KNearest model</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="198"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="106"/>
|
||||||
<source>ocr.b30KnnModelFile.label</source>
|
<source>ocr.b30KnnModelFile.label</source>
|
||||||
<translation>Default B30 KNearest model</translation>
|
<translation>Default B30 KNearest model</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="201"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="109"/>
|
||||||
<source>ocr.siftDatabaseFile.label</source>
|
|
||||||
<translation>Default SIFT database file</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="204"/>
|
|
||||||
<source>ocr.phashDatabaseFile.label</source>
|
<source>ocr.phashDatabaseFile.label</source>
|
||||||
<translation>Default image PHash database</translation>
|
<translation>Default image PHash database</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -696,6 +678,11 @@ validation</translation>
|
|||||||
<source>tab.b30</source>
|
<source>tab.b30</source>
|
||||||
<translation>B30</translation>
|
<translation>B30</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../designer/tabs/tabOcrEntry.ui" line="34"/>
|
||||||
|
<source>tab.buildPHashDatabase</source>
|
||||||
|
<translation>Build pHash Database</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>TabOcr_B30</name>
|
<name>TabOcr_B30</name>
|
||||||
@ -705,24 +692,72 @@ validation</translation>
|
|||||||
<translation>B30 Image Type</translation>
|
<translation>B30 Image Type</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="34"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="32"/>
|
||||||
<source>knnModelSelector.title</source>
|
<source>dependencies.title</source>
|
||||||
<translation>Select KNearest Model</translation>
|
<translation>OCR Dependencies</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="46"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="38"/>
|
||||||
<source>b30KnnModelSelector.title</source>
|
<source>dependencies.knnModel</source>
|
||||||
<translation>Select B30 Specialized KNearest Model</translation>
|
<translation>KNearest model</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="62"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="62"/>
|
||||||
<source>phashDatabaseSelector.title</source>
|
<source>dependencies.b30KnnModel</source>
|
||||||
<translation>Select Image PHash Database</translation>
|
<translation>B30 KNearest model</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="74"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="86"/>
|
||||||
<source>imageSelector.title</source>
|
<source>dependencies.phashDatabase</source>
|
||||||
<translation>Select Image</translation>
|
<translation>Image pHash database</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>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -734,28 +769,44 @@ validation</translation>
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="27"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="27"/>
|
||||||
<source>deviceSelector.title</source>
|
<source>options.title</source>
|
||||||
<translation>Select Device</translation>
|
<translation>Options</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="35"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="35"/>
|
||||||
<source>deviceSelector.useAutoFactor</source>
|
<source>options.usePreset</source>
|
||||||
<translation>Auto calculate factor</translation>
|
<translation>Use preset</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="81"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="73"/>
|
||||||
<source>knnModelSelector.title</source>
|
<source>options.rois</source>
|
||||||
<translation>Select KNearest Model</translation>
|
<translation>Rois</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="112"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="128"/>
|
||||||
<source>tesseractSelector.title</source>
|
<source>options.masker</source>
|
||||||
<translation>Select tesseract Path</translation>
|
<translation>Masker</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="140"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="138"/>
|
||||||
<source>phashDatabaseSelector.title</source>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="145"/>
|
||||||
<translation>Select Image PHash Database</translation>
|
<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>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -1132,17 +1183,17 @@ validation</translation>
|
|||||||
<translation>Calculate to Step</translation>
|
<translation>Calculate to Step</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="386"/>
|
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="367"/>
|
||||||
<source>calculate.toStep.playResultLabel</source>
|
<source>calculate.toStep.playResultLabel</source>
|
||||||
<translation>Play result</translation>
|
<translation>Play result</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="419"/>
|
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="393"/>
|
||||||
<source>calculate.toStep.calculatePlayResultFromScoreButton</source>
|
<source>calculate.toStep.calculatePlayResultFromScoreButton</source>
|
||||||
<translation>Calculate from Score</translation>
|
<translation>Calculate from Score</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="399"/>
|
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="406"/>
|
||||||
<source>calculate.toStep.resultLabel</source>
|
<source>calculate.toStep.resultLabel</source>
|
||||||
<translation>Result</translation>
|
<translation>Result</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -1152,17 +1203,17 @@ validation</translation>
|
|||||||
<translation>Detailed log output</translation>
|
<translation>Detailed log output</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="429"/>
|
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="448"/>
|
||||||
<source>calculate.fromStep</source>
|
<source>calculate.fromStep</source>
|
||||||
<translation>Calculate from Step</translation>
|
<translation>Calculate from Step</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="438"/>
|
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="457"/>
|
||||||
<source>calculate.fromStep.targetStepLabel</source>
|
<source>calculate.fromStep.targetStepLabel</source>
|
||||||
<translation>Target step value</translation>
|
<translation>Target step value</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="461"/>
|
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="480"/>
|
||||||
<source>calculate.fromStep.resultLabel</source>
|
<source>calculate.fromStep.resultLabel</source>
|
||||||
<translation>Result (play rating)</translation>
|
<translation>Result (play rating)</translation>
|
||||||
</message>
|
</message>
|
||||||
|
@ -89,12 +89,12 @@
|
|||||||
<translation>继续</translation>
|
<translation>继续</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../startup/databaseChecker.py" line="115"/>
|
<location filename="../../startup/databaseChecker.py" line="117"/>
|
||||||
<source>dialog.tryInitExistingDatabase</source>
|
<source>dialog.tryInitExistingDatabase</source>
|
||||||
<translation>现有的数据库似乎没有正确初始化,是否尝试再次初始化?</translation>
|
<translation>现有的数据库似乎没有正确初始化,是否尝试再次初始化?</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../startup/databaseChecker.py" line="131"/>
|
<location filename="../../startup/databaseChecker.py" line="133"/>
|
||||||
<source>dialog.confirmNewDatabase</source>
|
<source>dialog.confirmNewDatabase</source>
|
||||||
<translation>数据库文件不存在,是否创建?</translation>
|
<translation>数据库文件不存在,是否创建?</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -225,13 +225,13 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/components/ocrQueue.ui" line="34"/>
|
<location filename="../../designer/components/ocrQueue.ui" line="34"/>
|
||||||
<source>icc.ignore</source>
|
<source>icc.useQt</source>
|
||||||
<translation>忽略</translation>
|
<translation>使用 Qt</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/components/ocrQueue.ui" line="41"/>
|
<location filename="../../designer/components/ocrQueue.ui" line="41"/>
|
||||||
<source>icc.usePIL</source>
|
<source>icc.usePIL</source>
|
||||||
<translation>使用 PIL 读取</translation>
|
<translation>使用 PIL</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/components/ocrQueue.ui" line="51"/>
|
<location filename="../../designer/components/ocrQueue.ui" line="51"/>
|
||||||
@ -476,12 +476,9 @@
|
|||||||
<location filename="../../implements/settings/settingsAndreal.py" line="82"/>
|
<location filename="../../implements/settings/settingsAndreal.py" line="82"/>
|
||||||
<location filename="../../implements/settings/settingsAndreal.py" line="85"/>
|
<location filename="../../implements/settings/settingsAndreal.py" line="85"/>
|
||||||
<location filename="../../implements/settings/settingsGeneral.py" line="107"/>
|
<location filename="../../implements/settings/settingsGeneral.py" line="107"/>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="190"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="104"/>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="193"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="107"/>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="196"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="110"/>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="199"/>
|
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="202"/>
|
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="205"/>
|
|
||||||
<source>resetButton</source>
|
<source>resetButton</source>
|
||||||
<translation>重置</translation>
|
<translation>重置</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -516,37 +513,22 @@
|
|||||||
<translation>数据库 URL</translation>
|
<translation>数据库 URL</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="187"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="101"/>
|
||||||
<source>ocr.title</source>
|
<source>ocr.title</source>
|
||||||
<translation>OCR</translation>
|
<translation>OCR</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="189"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="103"/>
|
||||||
<source>ocr.devicesJson.label</source>
|
|
||||||
<translation>默认设备定义文件</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="192"/>
|
|
||||||
<source>ocr.deviceUuid.label</source>
|
|
||||||
<translation>默认设备</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="195"/>
|
|
||||||
<source>ocr.knnModelFile.label</source>
|
<source>ocr.knnModelFile.label</source>
|
||||||
<translation>默认 KNearest 模型</translation>
|
<translation>默认 KNearest 模型</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="198"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="106"/>
|
||||||
<source>ocr.b30KnnModelFile.label</source>
|
<source>ocr.b30KnnModelFile.label</source>
|
||||||
<translation>默认 B30 KNearest 模型</translation>
|
<translation>默认 B30 KNearest 模型</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="201"/>
|
<location filename="../../implements/settings/settingsOcr.py" line="109"/>
|
||||||
<source>ocr.siftDatabaseFile.label</source>
|
|
||||||
<translation>默认 SIFT 特征值数据库</translation>
|
|
||||||
</message>
|
|
||||||
<message>
|
|
||||||
<location filename="../../implements/settings/settingsOcr.py" line="204"/>
|
|
||||||
<source>ocr.phashDatabaseFile.label</source>
|
<source>ocr.phashDatabaseFile.label</source>
|
||||||
<translation>默认图像 PHash 数据库</translation>
|
<translation>默认图像 PHash 数据库</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -695,6 +677,11 @@
|
|||||||
<source>tab.b30</source>
|
<source>tab.b30</source>
|
||||||
<translation>B30</translation>
|
<translation>B30</translation>
|
||||||
</message>
|
</message>
|
||||||
|
<message>
|
||||||
|
<location filename="../../designer/tabs/tabOcrEntry.ui" line="34"/>
|
||||||
|
<source>tab.buildPHashDatabase</source>
|
||||||
|
<translation>构建 pHash 数据库</translation>
|
||||||
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
<name>TabOcr_B30</name>
|
<name>TabOcr_B30</name>
|
||||||
@ -704,24 +691,72 @@
|
|||||||
<translation>B30 图片类型</translation>
|
<translation>B30 图片类型</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="34"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="32"/>
|
||||||
<source>knnModelSelector.title</source>
|
<source>dependencies.title</source>
|
||||||
<translation>选择 KNearest 模型</translation>
|
<translation>OCR 依赖</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="46"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="38"/>
|
||||||
<source>b30KnnModelSelector.title</source>
|
<source>dependencies.knnModel</source>
|
||||||
<translation>选择 B30 特别版 KNearest 模型</translation>
|
<translation>KNearest 模型</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="62"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="62"/>
|
||||||
<source>phashDatabaseSelector.title</source>
|
<source>dependencies.b30KnnModel</source>
|
||||||
<translation>选择图像 PHash 数据库</translation>
|
<translation>B30 KNearest 模型</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="74"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="86"/>
|
||||||
<source>imageSelector.title</source>
|
<source>dependencies.phashDatabase</source>
|
||||||
<translation>选择图片</translation>
|
<translation>图像 pHash 数据库</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>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -733,28 +768,44 @@
|
|||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="27"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="27"/>
|
||||||
<source>deviceSelector.title</source>
|
<source>options.title</source>
|
||||||
<translation>选择设备</translation>
|
<translation>选项</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="35"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="35"/>
|
||||||
<source>deviceSelector.useAutoFactor</source>
|
<source>options.usePreset</source>
|
||||||
<translation>自动计算 factor</translation>
|
<translation>使用预设</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="81"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="73"/>
|
||||||
<source>knnModelSelector.title</source>
|
<source>options.rois</source>
|
||||||
<translation>选择 KNearest 模型</translation>
|
<translation>定位器</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="112"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="128"/>
|
||||||
<source>tesseractSelector.title</source>
|
<source>options.masker</source>
|
||||||
<translation>选择 tesseract 路径</translation>
|
<translation>遮罩器</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="140"/>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="138"/>
|
||||||
<source>phashDatabaseSelector.title</source>
|
<location filename="../../designer/tabs/tabOcr/tabOcr_Device.ui" line="145"/>
|
||||||
<translation>选择图像 PHash 数据库</translation>
|
<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>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
@ -1131,17 +1182,17 @@
|
|||||||
<translation>正算</translation>
|
<translation>正算</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="386"/>
|
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="367"/>
|
||||||
<source>calculate.toStep.playResultLabel</source>
|
<source>calculate.toStep.playResultLabel</source>
|
||||||
<translation>单曲 PTT</translation>
|
<translation>单曲 PTT</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="419"/>
|
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="393"/>
|
||||||
<source>calculate.toStep.calculatePlayResultFromScoreButton</source>
|
<source>calculate.toStep.calculatePlayResultFromScoreButton</source>
|
||||||
<translation>从分数计算</translation>
|
<translation>从分数计算</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="399"/>
|
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="406"/>
|
||||||
<source>calculate.toStep.resultLabel</source>
|
<source>calculate.toStep.resultLabel</source>
|
||||||
<translation>结果</translation>
|
<translation>结果</translation>
|
||||||
</message>
|
</message>
|
||||||
@ -1151,17 +1202,17 @@
|
|||||||
<translation>详细日志输出</translation>
|
<translation>详细日志输出</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="429"/>
|
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="448"/>
|
||||||
<source>calculate.fromStep</source>
|
<source>calculate.fromStep</source>
|
||||||
<translation>逆算</translation>
|
<translation>逆算</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="438"/>
|
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="457"/>
|
||||||
<source>calculate.fromStep.targetStepLabel</source>
|
<source>calculate.fromStep.targetStepLabel</source>
|
||||||
<translation>目标 STEP 值</translation>
|
<translation>目标 STEP 值</translation>
|
||||||
</message>
|
</message>
|
||||||
<message>
|
<message>
|
||||||
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="461"/>
|
<location filename="../../designer/tabs/tabTools/tabTools_StepCalculator.ui" line="480"/>
|
||||||
<source>calculate.fromStep.resultLabel</source>
|
<source>calculate.fromStep.resultLabel</source>
|
||||||
<translation>结果(单曲 PTT)</translation>
|
<translation>结果(单曲 PTT)</translation>
|
||||||
</message>
|
</message>
|
||||||
|
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,8 +4,11 @@
|
|||||||
<file>VERSION</file>
|
<file>VERSION</file>
|
||||||
<file>LICENSE</file>
|
<file>LICENSE</file>
|
||||||
|
|
||||||
|
<file>partnerModifiers.json</file>
|
||||||
|
|
||||||
<file>images/icon.png</file>
|
<file>images/icon.png</file>
|
||||||
<file>images/logo.png</file>
|
<file>images/logo.png</file>
|
||||||
|
<file>images/jacket-placeholder.png</file>
|
||||||
<file>images/stepCalculator/stamina.png</file>
|
<file>images/stepCalculator/stamina.png</file>
|
||||||
<file>images/stepCalculator/play.png</file>
|
<file>images/stepCalculator/play.png</file>
|
||||||
<file>images/stepCalculator/memory-boost.png</file>
|
<file>images/stepCalculator/memory-boost.png</file>
|
||||||
|
@ -74,6 +74,7 @@ class DatabaseChecker(Ui_DatabaseChecker, QDialog):
|
|||||||
db = Database(create_engine(dbSqliteUrl))
|
db = Database(create_engine(dbSqliteUrl))
|
||||||
if db.check_init():
|
if db.check_init():
|
||||||
flags |= DatabaseCheckerResult.Initted
|
flags |= DatabaseCheckerResult.Initted
|
||||||
|
self.settings.setDatabaseUrl(self.dbSqliteUrl().toString())
|
||||||
|
|
||||||
return flags
|
return flags
|
||||||
|
|
||||||
@ -102,6 +103,7 @@ class DatabaseChecker(Ui_DatabaseChecker, QDialog):
|
|||||||
@Slot()
|
@Slot()
|
||||||
def on_confirmDbPathButton_clicked(self):
|
def on_confirmDbPathButton_clicked(self):
|
||||||
dbSqliteUrl = self.dbSqliteUrl()
|
dbSqliteUrl = self.dbSqliteUrl()
|
||||||
|
self.settings.setDatabaseUrl(dbSqliteUrl.toString())
|
||||||
|
|
||||||
result = self.confirmDb()
|
result = self.confirmDb()
|
||||||
if result & DatabaseCheckerResult.Initted:
|
if result & DatabaseCheckerResult.Initted:
|
||||||
|
Reference in New Issue
Block a user