mirror of
https://github.com/283375/arcaea-offline-pyside-ui.git
synced 2025-07-02 04:46:26 +00:00
Compare commits
3 Commits
cd4ed51826
...
cf913d296e
Author | SHA1 | Date | |
---|---|---|---|
cf913d296e
|
|||
1060590e03
|
|||
858abe3415
|
@ -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,61 +27,88 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<widget class="QGroupBox" name="groupBox_6">
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_3">
|
|
||||||
<property name="title">
|
<property name="title">
|
||||||
<string>knnModelSelector.title</string>
|
<string>dependencies.title</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0,0,1">
|
||||||
<item>
|
<item row="0" column="0">
|
||||||
<widget class="FileSelector" name="knnModelSelector" native="true"/>
|
<widget class="QLabel" name="label">
|
||||||
|
<property name="text">
|
||||||
|
<string>dependencies.knnModel</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="2">
|
||||||
|
<widget class="QLabel" name="dependencies_knnModelStatusLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="3" rowspan="3">
|
||||||
|
<widget class="Line" name="line_2">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_2">
|
||||||
|
<property name="text">
|
||||||
|
<string>dependencies.b30KnnModel</string>
|
||||||
|
</property>
|
||||||
|
<property name="alignment">
|
||||||
|
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<widget class="QLabel" name="dependencies_phashDatabaseStatusLabel">
|
||||||
|
<property name="text">
|
||||||
|
<string notr="true">...</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1" rowspan="3">
|
||||||
|
<widget class="Line" name="line">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Vertical</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<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>
|
</item>
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_5">
|
|
||||||
<property name="title">
|
|
||||||
<string>b30KnnModelSelector.title</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
|
||||||
<item>
|
|
||||||
<widget class="FileSelector" name="b30KnnModelSelector" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_4">
|
|
||||||
<property name="title">
|
|
||||||
<string>phashDatabaseSelector.title</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
|
||||||
<item>
|
|
||||||
<widget class="FileSelector" name="phashDatabaseSelector" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QGroupBox" name="groupBox_2">
|
|
||||||
<property name="title">
|
|
||||||
<string>imageSelector.title</string>
|
|
||||||
</property>
|
|
||||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
|
||||||
<item>
|
|
||||||
<widget class="FileSelector" name="imageSelector" native="true"/>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</widget>
|
|
||||||
</item>
|
|
||||||
</layout>
|
|
||||||
</item>
|
|
||||||
<item>
|
<item>
|
||||||
<widget class="OcrQueue" name="ocrQueue" native="true">
|
<widget class="OcrQueue" name="ocrQueue" native="true">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -79,6 +79,12 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="0" column="1">
|
<item row="0" column="1">
|
||||||
<widget class="QStackedWidget" name="options_roisStackedWidget">
|
<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">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
@ -148,6 +154,12 @@
|
|||||||
</item>
|
</item>
|
||||||
<item row="1" column="1">
|
<item row="1" column="1">
|
||||||
<widget class="QStackedWidget" name="options_maskerStackedWidget">
|
<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">
|
<property name="currentIndex">
|
||||||
<number>0</number>
|
<number>0</number>
|
||||||
</property>
|
</property>
|
||||||
|
@ -76,6 +76,11 @@ class Ui_TabOcr_Device(object):
|
|||||||
|
|
||||||
self.options_roisStackedWidget = QStackedWidget(self.options_preciseControlWidget)
|
self.options_roisStackedWidget = QStackedWidget(self.options_preciseControlWidget)
|
||||||
self.options_roisStackedWidget.setObjectName(u"options_roisStackedWidget")
|
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 = QWidget()
|
||||||
self.page.setObjectName(u"page")
|
self.page.setObjectName(u"page")
|
||||||
self.verticalLayout_2 = QVBoxLayout(self.page)
|
self.verticalLayout_2 = QVBoxLayout(self.page)
|
||||||
@ -119,6 +124,8 @@ class Ui_TabOcr_Device(object):
|
|||||||
|
|
||||||
self.options_maskerStackedWidget = QStackedWidget(self.options_preciseControlWidget)
|
self.options_maskerStackedWidget = QStackedWidget(self.options_preciseControlWidget)
|
||||||
self.options_maskerStackedWidget.setObjectName(u"options_maskerStackedWidget")
|
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 = QWidget()
|
||||||
self.page_3.setObjectName(u"page_3")
|
self.page_3.setObjectName(u"page_3")
|
||||||
self.verticalLayout_5 = QVBoxLayout(self.page_3)
|
self.verticalLayout_5 = QVBoxLayout(self.page_3)
|
||||||
@ -209,11 +216,11 @@ class Ui_TabOcr_Device(object):
|
|||||||
|
|
||||||
self.ocrQueue = OcrQueue(TabOcr_Device)
|
self.ocrQueue = OcrQueue(TabOcr_Device)
|
||||||
self.ocrQueue.setObjectName(u"ocrQueue")
|
self.ocrQueue.setObjectName(u"ocrQueue")
|
||||||
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.ocrQueue.sizePolicy().hasHeightForWidth())
|
sizePolicy1.setHeightForWidth(self.ocrQueue.sizePolicy().hasHeightForWidth())
|
||||||
self.ocrQueue.setSizePolicy(sizePolicy)
|
self.ocrQueue.setSizePolicy(sizePolicy1)
|
||||||
|
|
||||||
self.verticalLayout_3.addWidget(self.ocrQueue)
|
self.verticalLayout_3.addWidget(self.ocrQueue)
|
||||||
|
|
||||||
|
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,
|
|
||||||
)
|
|
@ -2,8 +2,9 @@ import json
|
|||||||
import sys
|
import sys
|
||||||
from functools import cached_property
|
from functools import cached_property
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Literal
|
from typing import Literal, Optional, overload
|
||||||
|
|
||||||
|
from arcaea_offline.models import Chart, Difficulty, Song
|
||||||
from PySide6.QtCore import QFile
|
from PySide6.QtCore import QFile
|
||||||
|
|
||||||
from .singleton import Singleton
|
from .singleton import Singleton
|
||||||
@ -45,3 +46,41 @@ class Data(metaclass=Singleton):
|
|||||||
@property
|
@property
|
||||||
def arcaeaPath(self):
|
def arcaeaPath(self):
|
||||||
return self.dataPath / "Arcaea"
|
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,28 @@ class TextSegmentDelegate(QStyledItemDelegate):
|
|||||||
GradientWrapperRole = TextRole + 3
|
GradientWrapperRole = TextRole + 3
|
||||||
FontRole = TextRole + 20
|
FontRole = TextRole + 20
|
||||||
|
|
||||||
|
def __init__(self, parent=None):
|
||||||
|
super().__init__(parent)
|
||||||
|
|
||||||
|
# TODO: make this differ by index
|
||||||
|
self.baseXOffset = 0
|
||||||
|
self.baseYOffset = 0
|
||||||
|
|
||||||
|
self.verticalAlign = TextSegmentDelegateVerticalAlign.Middle
|
||||||
|
|
||||||
|
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[
|
||||||
@ -50,14 +79,32 @@ class TextSegmentDelegate(QStyledItemDelegate):
|
|||||||
height += lineHeight + self.VerticalPadding
|
height += lineHeight + self.VerticalPadding
|
||||||
return QSize(width, height)
|
return QSize(width, height)
|
||||||
|
|
||||||
|
def baseX(self, option: QStyleOptionViewItem, index: QModelIndex):
|
||||||
|
return option.rect.x() + self.HorizontalPadding + self.baseXOffset
|
||||||
|
|
||||||
|
def baseY(self, option: QStyleOptionViewItem, index: QModelIndex):
|
||||||
|
baseY = option.rect.y() + self.VerticalPadding + self.baseYOffset
|
||||||
|
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.baseXOffset
|
||||||
|
|
||||||
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 +116,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 +162,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 PIL import Image
|
||||||
from PySide6.QtCore import QModelIndex, Qt, Signal
|
from PySide6.QtCore import QModelIndex, Qt, Signal
|
||||||
from PySide6.QtGui import QColor
|
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,139 @@ 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)
|
||||||
return [
|
difficulty = self.getDifficulty(index)
|
||||||
[{self.TextRole: "Chart Invalid", self.ColorRole: QColor("#ff0000")}]
|
|
||||||
]
|
|
||||||
|
|
||||||
chartConstantString = (
|
chartValid = isinstance(chart, Chart)
|
||||||
f"{chart.constant / 10:.1f}"
|
songValid = isinstance(song, Song)
|
||||||
if chart.constant is not None and chart.constant > 0
|
difficultyValid = isinstance(difficulty, Difficulty)
|
||||||
else "?"
|
|
||||||
)
|
if not chartValid and not songValid:
|
||||||
return [
|
return [
|
||||||
[
|
[
|
||||||
{self.TextRole: f"{chart.title}"},
|
{
|
||||||
|
self.TextRole: "Chart/Song not set",
|
||||||
|
self.ColorRole: QColor("#ff0000"),
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
|
||||||
|
# get texts
|
||||||
|
if chartValid:
|
||||||
|
title = chart.title
|
||||||
|
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(chart.rating_class)} {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 [
|
||||||
|
[
|
||||||
|
{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)
|
||||||
|
size.setWidth(size.width() + self.HorizontalPadding + size.height())
|
||||||
|
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__":
|
||||||
|
super().paint(painter, option, index)
|
||||||
|
return
|
||||||
|
|
||||||
|
textSizeHint = super().sizeHint(option, index)
|
||||||
|
jacketSize = textSizeHint.height()
|
||||||
|
self.baseXOffset = 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()
|
||||||
|
)
|
||||||
|
|
||||||
|
painter.save()
|
||||||
|
painter.setRenderHint(QPainter.RenderHint.LosslessImageRendering, True)
|
||||||
|
painter.setRenderHint(QPainter.RenderHint.Antialiasing, True)
|
||||||
|
painter.drawPixmap(
|
||||||
|
option.rect.x() + self.HorizontalPadding, self.baseY(option, index), pixmap
|
||||||
|
)
|
||||||
|
painter.restore()
|
||||||
super().paint(painter, option, index)
|
super().paint(painter, option, index)
|
||||||
|
|
||||||
def checkIsEditor(self, val):
|
def checkIsEditor(self, val):
|
||||||
|
@ -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
|
if not imagePath:
|
||||||
or not self.phashDatabase
|
|
||||||
):
|
|
||||||
return
|
return
|
||||||
|
|
||||||
self.ocrQueueModel.clear()
|
self.ocrQueueModel.clear()
|
||||||
|
|
||||||
|
img = imread_unicode(imagePath, cv2.IMREAD_COLOR)
|
||||||
ocr = ChieriBotV4Ocr(self.knnModel, self.b30KnnModel, self.phashDatabase)
|
ocr = ChieriBotV4Ocr(self.knnModel, self.b30KnnModel, self.phashDatabase)
|
||||||
ocr.set_factor(self.img)
|
ocr.set_factor(img)
|
||||||
self.ocr = ocr
|
self.ocr = ocr
|
||||||
|
|
||||||
roi = ocr.rois
|
roi = ocr.rois
|
||||||
for component in roi.components(self.img):
|
for component in roi.components(img):
|
||||||
qImage = cv2BgrMatToQImage(component.copy())
|
qImage = Image.fromarray(component.copy()).toqimage()
|
||||||
self.ocrQueueModel.addItem(qImage)
|
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(
|
||||||
|
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 |
@ -692,24 +692,24 @@ 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>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
@ -691,24 +691,24 @@
|
|||||||
<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>
|
</message>
|
||||||
</context>
|
</context>
|
||||||
<context>
|
<context>
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
<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>
|
||||||
|
Reference in New Issue
Block a user