wip: b30 ocr tab

This commit is contained in:
283375 2023-08-19 01:21:23 +08:00
parent 9eab7ffc63
commit 38a08a4b17
20 changed files with 726 additions and 97 deletions

View File

@ -7,10 +7,10 @@ from PySide6.QtCore import QLibraryInfo, QLocale, QTranslator
from PySide6.QtGui import QIcon
from PySide6.QtWidgets import QApplication, QDialog, QMessageBox
from ui.startup.databaseChecker import DatabaseChecker
from ui.implements.mainwindow import MainWindow
import ui.resources.images.images_rc
import ui.resources.translations.translations_rc
from ui.implements.mainwindow import MainWindow
from ui.startup.databaseChecker import DatabaseChecker
logging.basicConfig(level=logging.INFO, stream=sys.stdout, force=True)

View File

@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string>OcrQueue</string>
<string notr="true">OcrQueue</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>

View File

@ -25,6 +25,7 @@ class Ui_OcrQueue(object):
if not OcrQueue.objectName():
OcrQueue.setObjectName(u"OcrQueue")
OcrQueue.resize(741, 372)
OcrQueue.setWindowTitle(u"OcrQueue")
self.horizontalLayout_2 = QHBoxLayout(OcrQueue)
self.horizontalLayout_2.setObjectName(u"horizontalLayout_2")
self.groupBox_3 = QGroupBox(OcrQueue)
@ -119,7 +120,6 @@ class Ui_OcrQueue(object):
# setupUi
def retranslateUi(self, OcrQueue):
OcrQueue.setWindowTitle(QCoreApplication.translate("OcrQueue", u"OcrQueue", None))
self.groupBox_3.setTitle(QCoreApplication.translate("OcrQueue", u"ocr.queue.title", None))
self.ocr_addImageButton.setText(QCoreApplication.translate("OcrQueue", u"ocr.queue.addImageButton", None))
self.ocr_removeSelectedButton.setText(QCoreApplication.translate("OcrQueue", u"ocr.queue.removeSelected", None))
@ -129,5 +129,6 @@ class Ui_OcrQueue(object):
self.ocr_acceptSelectedButton.setText(QCoreApplication.translate("OcrQueue", u"ocr.results.acceptSelectedButton", None))
self.ocr_acceptAllButton.setText(QCoreApplication.translate("OcrQueue", u"ocr.results.acceptAllButton", None))
self.ocr_ignoreValidateCheckBox.setText(QCoreApplication.translate("OcrQueue", u"ocr.results.ignoreValidate", None))
pass
# retranslateUi

View File

@ -35,7 +35,7 @@
<string>tab.db</string>
</attribute>
</widget>
<widget class="QWidget" name="tab_ocr">
<widget class="TabOcrEntry" name="tab_ocr">
<attribute name="title">
<string>tab.ocr</string>
</attribute>
@ -86,6 +86,12 @@
<header>ui.implements.tabs.tabDbEntry</header>
<container>1</container>
</customwidget>
<customwidget>
<class>TabOcrEntry</class>
<extends>QWidget</extends>
<header>ui.implements.tabs.tabOcrEntry</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>

View File

@ -3,7 +3,7 @@
################################################################################
## Form generated from reading UI file 'mainwindow.ui'
##
## Created by: Qt User Interface Compiler version 6.5.0
## Created by: Qt User Interface Compiler version 6.5.1
##
## WARNING! All changes made in this file will be lost when recompiling UI file!
################################################################################
@ -21,6 +21,7 @@ from PySide6.QtWidgets import (QApplication, QMainWindow, QSizePolicy, QTabWidge
from ui.implements.tabs.tabAbout import TabAbout
from ui.implements.tabs.tabDbEntry import TabDbEntry
from ui.implements.tabs.tabInputScore import TabInputScore
from ui.implements.tabs.tabOcrEntry import TabOcrEntry
from ui.implements.tabs.tabOverview import TabOverview
from ui.implements.tabs.tabSettings import TabSettings
@ -45,7 +46,7 @@ class Ui_MainWindow(object):
self.tab_db = TabDbEntry()
self.tab_db.setObjectName(u"tab_db")
self.tabWidget.addTab(self.tab_db, "")
self.tab_ocr = QWidget()
self.tab_ocr = TabOcrEntry()
self.tab_ocr.setObjectName(u"tab_ocr")
self.tabWidget.addTab(self.tab_ocr, "")
self.tab_settings = TabSettings()

View File

@ -0,0 +1,113 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TabOcr_B30</class>
<widget class="QWidget" name="TabOcr_B30">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>555</width>
<height>461</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">TabOcr_B30</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>b30type</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QComboBox" name="b30TypeComboBox"/>
</item>
</layout>
</widget>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="QGroupBox" name="groupBox_3">
<property name="title">
<string>knnModelSelector.title</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="FileSelector" name="knnModelSelector" native="true"/>
</item>
</layout>
</widget>
</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>siftDatabaseSelector.title</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_5">
<item>
<widget class="FileSelector" name="siftDatabaseSelector" 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>
<widget class="OcrQueue" name="ocrQueue" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>FileSelector</class>
<extends>QWidget</extends>
<header>ui.implements.components.fileSelector</header>
<container>1</container>
</customwidget>
<customwidget>
<class>OcrQueue</class>
<extends>QWidget</extends>
<header>ui.implements.components.ocrQueue</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,126 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'tabOcr_B30.ui'
##
## Created by: Qt User Interface Compiler version 6.5.1
##
## 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, QComboBox, QGroupBox, QHBoxLayout,
QSizePolicy, QVBoxLayout, QWidget)
from ui.implements.components.fileSelector import FileSelector
from ui.implements.components.ocrQueue import OcrQueue
class Ui_TabOcr_B30(object):
def setupUi(self, TabOcr_B30):
if not TabOcr_B30.objectName():
TabOcr_B30.setObjectName(u"TabOcr_B30")
TabOcr_B30.resize(555, 461)
TabOcr_B30.setWindowTitle(u"TabOcr_B30")
self.verticalLayout_3 = QVBoxLayout(TabOcr_B30)
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
self.groupBox = QGroupBox(TabOcr_B30)
self.groupBox.setObjectName(u"groupBox")
self.verticalLayout = QVBoxLayout(self.groupBox)
self.verticalLayout.setObjectName(u"verticalLayout")
self.b30TypeComboBox = QComboBox(self.groupBox)
self.b30TypeComboBox.setObjectName(u"b30TypeComboBox")
self.verticalLayout.addWidget(self.b30TypeComboBox)
self.verticalLayout_3.addWidget(self.groupBox)
self.horizontalLayout = QHBoxLayout()
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.groupBox_3 = QGroupBox(TabOcr_B30)
self.groupBox_3.setObjectName(u"groupBox_3")
self.verticalLayout_4 = QVBoxLayout(self.groupBox_3)
self.verticalLayout_4.setObjectName(u"verticalLayout_4")
self.knnModelSelector = FileSelector(self.groupBox_3)
self.knnModelSelector.setObjectName(u"knnModelSelector")
self.verticalLayout_4.addWidget(self.knnModelSelector)
self.horizontalLayout.addWidget(self.groupBox_3)
self.groupBox_5 = QGroupBox(TabOcr_B30)
self.groupBox_5.setObjectName(u"groupBox_5")
self.verticalLayout_6 = QVBoxLayout(self.groupBox_5)
self.verticalLayout_6.setObjectName(u"verticalLayout_6")
self.b30KnnModelSelector = FileSelector(self.groupBox_5)
self.b30KnnModelSelector.setObjectName(u"b30KnnModelSelector")
self.verticalLayout_6.addWidget(self.b30KnnModelSelector)
self.horizontalLayout.addWidget(self.groupBox_5)
self.verticalLayout_3.addLayout(self.horizontalLayout)
self.horizontalLayout_3 = QHBoxLayout()
self.horizontalLayout_3.setObjectName(u"horizontalLayout_3")
self.groupBox_4 = QGroupBox(TabOcr_B30)
self.groupBox_4.setObjectName(u"groupBox_4")
self.verticalLayout_5 = QVBoxLayout(self.groupBox_4)
self.verticalLayout_5.setObjectName(u"verticalLayout_5")
self.siftDatabaseSelector = FileSelector(self.groupBox_4)
self.siftDatabaseSelector.setObjectName(u"siftDatabaseSelector")
self.verticalLayout_5.addWidget(self.siftDatabaseSelector)
self.horizontalLayout_3.addWidget(self.groupBox_4)
self.groupBox_2 = QGroupBox(TabOcr_B30)
self.groupBox_2.setObjectName(u"groupBox_2")
self.verticalLayout_2 = QVBoxLayout(self.groupBox_2)
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.horizontalLayout_3.addWidget(self.groupBox_2)
self.verticalLayout_3.addLayout(self.horizontalLayout_3)
self.ocrQueue = OcrQueue(TabOcr_B30)
self.ocrQueue.setObjectName(u"ocrQueue")
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
sizePolicy.setHorizontalStretch(0)
sizePolicy.setVerticalStretch(0)
sizePolicy.setHeightForWidth(self.ocrQueue.sizePolicy().hasHeightForWidth())
self.ocrQueue.setSizePolicy(sizePolicy)
self.verticalLayout_3.addWidget(self.ocrQueue)
self.retranslateUi(TabOcr_B30)
QMetaObject.connectSlotsByName(TabOcr_B30)
# setupUi
def retranslateUi(self, TabOcr_B30):
self.groupBox.setTitle(QCoreApplication.translate("TabOcr_B30", u"b30type", None))
self.groupBox_3.setTitle(QCoreApplication.translate("TabOcr_B30", u"knnModelSelector.title", None))
self.groupBox_5.setTitle(QCoreApplication.translate("TabOcr_B30", u"b30KnnModelSelector.title", None))
self.groupBox_4.setTitle(QCoreApplication.translate("TabOcr_B30", u"siftDatabaseSelector.title", None))
self.groupBox_2.setTitle(QCoreApplication.translate("TabOcr_B30", u"imageSelector.title", None))
pass
# retranslateUi

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TabOcr</class>
<widget class="QWidget" name="TabOcr">
<class>TabOcr_Device</class>
<widget class="QWidget" name="TabOcr_Device">
<property name="geometry">
<rect>
<x>0</x>
@ -11,7 +11,7 @@
</rect>
</property>
<property name="windowTitle">
<string notr="true">TabOcr</string>
<string notr="true">TabOcr_Device</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
@ -136,21 +136,13 @@
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<widget class="OcrQueue" name="ocrQueue" native="true">
<property name="sizePolicy">
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
<horstretch>0</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
<property name="title">
<string>ocr.title</string>
</property>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<widget class="OcrQueue" name="ocrQueue" native="true"/>
</item>
</layout>
</widget>
</item>
</layout>

View File

@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'tabOcr.ui'
## Form generated from reading UI file 'tabOcr_Device.ui'
##
## Created by: Qt User Interface Compiler version 6.5.1
##
@ -22,20 +22,20 @@ from ui.implements.components.devicesComboBox import DevicesComboBox
from ui.implements.components.fileSelector import FileSelector
from ui.implements.components.ocrQueue import OcrQueue
class Ui_TabOcr(object):
def setupUi(self, TabOcr):
if not TabOcr.objectName():
TabOcr.setObjectName(u"TabOcr")
TabOcr.resize(632, 527)
TabOcr.setWindowTitle(u"TabOcr")
self.verticalLayout_3 = QVBoxLayout(TabOcr)
class Ui_TabOcr_Device(object):
def setupUi(self, TabOcr_Device):
if not TabOcr_Device.objectName():
TabOcr_Device.setObjectName(u"TabOcr_Device")
TabOcr_Device.resize(632, 527)
TabOcr_Device.setWindowTitle(u"TabOcr_Device")
self.verticalLayout_3 = QVBoxLayout(TabOcr_Device)
self.verticalLayout_3.setObjectName(u"verticalLayout_3")
self.openWizardButton = QPushButton(TabOcr)
self.openWizardButton = QPushButton(TabOcr_Device)
self.openWizardButton.setObjectName(u"openWizardButton")
self.verticalLayout_3.addWidget(self.openWizardButton)
self.groupBox = QGroupBox(TabOcr)
self.groupBox = QGroupBox(TabOcr_Device)
self.groupBox.setObjectName(u"groupBox")
self.verticalLayout = QVBoxLayout(self.groupBox)
self.verticalLayout.setObjectName(u"verticalLayout")
@ -52,7 +52,7 @@ class Ui_TabOcr(object):
self.verticalLayout_3.addWidget(self.groupBox)
self.horizontalWidget = QWidget(TabOcr)
self.horizontalWidget = QWidget(TabOcr_Device)
self.horizontalWidget.setObjectName(u"horizontalWidget")
sizePolicy = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Maximum)
sizePolicy.setHorizontalStretch(0)
@ -118,39 +118,31 @@ class Ui_TabOcr(object):
self.verticalLayout_3.addWidget(self.horizontalWidget)
self.groupBox_2 = QGroupBox(TabOcr)
self.groupBox_2.setObjectName(u"groupBox_2")
self.ocrQueue = OcrQueue(TabOcr_Device)
self.ocrQueue.setObjectName(u"ocrQueue")
sizePolicy1 = QSizePolicy(QSizePolicy.Preferred, QSizePolicy.Expanding)
sizePolicy1.setHorizontalStretch(0)
sizePolicy1.setVerticalStretch(0)
sizePolicy1.setHeightForWidth(self.groupBox_2.sizePolicy().hasHeightForWidth())
self.groupBox_2.setSizePolicy(sizePolicy1)
self.horizontalLayout = QHBoxLayout(self.groupBox_2)
self.horizontalLayout.setObjectName(u"horizontalLayout")
self.ocrQueue = OcrQueue(self.groupBox_2)
self.ocrQueue.setObjectName(u"ocrQueue")
sizePolicy1.setHeightForWidth(self.ocrQueue.sizePolicy().hasHeightForWidth())
self.ocrQueue.setSizePolicy(sizePolicy1)
self.horizontalLayout.addWidget(self.ocrQueue)
self.verticalLayout_3.addWidget(self.ocrQueue)
self.verticalLayout_3.addWidget(self.groupBox_2)
self.retranslateUi(TabOcr)
self.retranslateUi(TabOcr_Device)
self.deviceDependenciesStackedWidget.setCurrentIndex(0)
QMetaObject.connectSlotsByName(TabOcr)
QMetaObject.connectSlotsByName(TabOcr_Device)
# setupUi
def retranslateUi(self, TabOcr):
self.openWizardButton.setText(QCoreApplication.translate("TabOcr", u"openWizardButton", None))
self.groupBox.setTitle(QCoreApplication.translate("TabOcr", u"deviceSelector.title", None))
self.groupBox_6.setTitle(QCoreApplication.translate("TabOcr", u"knnModelSelector.title", None))
self.groupBox_4.setTitle(QCoreApplication.translate("TabOcr", u"tesseractSelector.title", None))
self.groupBox_5.setTitle(QCoreApplication.translate("TabOcr", u"siftDatabaseSelector.title", None))
self.groupBox_2.setTitle(QCoreApplication.translate("TabOcr", u"ocr.title", None))
def retranslateUi(self, TabOcr_Device):
self.openWizardButton.setText(QCoreApplication.translate("TabOcr_Device", u"openWizardButton", None))
self.groupBox.setTitle(QCoreApplication.translate("TabOcr_Device", u"deviceSelector.title", None))
self.groupBox_6.setTitle(QCoreApplication.translate("TabOcr_Device", u"knnModelSelector.title", None))
self.groupBox_4.setTitle(QCoreApplication.translate("TabOcr_Device", u"tesseractSelector.title", None))
self.groupBox_5.setTitle(QCoreApplication.translate("TabOcr_Device", u"siftDatabaseSelector.title", None))
pass
# retranslateUi

View File

@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>TabOcrEntry</class>
<widget class="QWidget" name="TabOcrEntry">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>600</width>
<height>478</height>
</rect>
</property>
<property name="windowTitle">
<string notr="true">TabOcrEntry</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="TabOcr_Device" name="tab">
<attribute name="title">
<string>tab.device</string>
</attribute>
</widget>
<widget class="TabOcr_B30" name="tab_2">
<attribute name="title">
<string>tab.b30</string>
</attribute>
</widget>
</widget>
</item>
</layout>
</widget>
<customwidgets>
<customwidget>
<class>TabOcr_Device</class>
<extends>QWidget</extends>
<header>ui.implements.tabs.tabOcr.tabOcr_Device</header>
<container>1</container>
</customwidget>
<customwidget>
<class>TabOcr_B30</class>
<extends>QWidget</extends>
<header>ui.implements.tabs.tabOcr.tabOcr_B30</header>
<container>1</container>
</customwidget>
</customwidgets>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,57 @@
# -*- coding: utf-8 -*-
################################################################################
## Form generated from reading UI file 'tabOcrEntry.ui'
##
## Created by: Qt User Interface Compiler version 6.5.1
##
## 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, QSizePolicy, QTabWidget, QVBoxLayout,
QWidget)
from ui.implements.tabs.tabOcr.tabOcr_B30 import TabOcr_B30
from ui.implements.tabs.tabOcr.tabOcr_Device import TabOcr_Device
class Ui_TabOcrEntry(object):
def setupUi(self, TabOcrEntry):
if not TabOcrEntry.objectName():
TabOcrEntry.setObjectName(u"TabOcrEntry")
TabOcrEntry.resize(600, 478)
TabOcrEntry.setWindowTitle(u"TabOcrEntry")
self.verticalLayout = QVBoxLayout(TabOcrEntry)
self.verticalLayout.setObjectName(u"verticalLayout")
self.tabWidget = QTabWidget(TabOcrEntry)
self.tabWidget.setObjectName(u"tabWidget")
self.tab = TabOcr_Device()
self.tab.setObjectName(u"tab")
self.tabWidget.addTab(self.tab, "")
self.tab_2 = TabOcr_B30()
self.tab_2.setObjectName(u"tab_2")
self.tabWidget.addTab(self.tab_2, "")
self.verticalLayout.addWidget(self.tabWidget)
self.retranslateUi(TabOcrEntry)
self.tabWidget.setCurrentIndex(0)
QMetaObject.connectSlotsByName(TabOcrEntry)
# setupUi
def retranslateUi(self, TabOcrEntry):
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), QCoreApplication.translate("TabOcrEntry", u"tab.device", None))
self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), QCoreApplication.translate("TabOcrEntry", u"tab.b30", None))
pass
# retranslateUi

View File

@ -1,9 +1,10 @@
import logging
from typing import Any, Callable
from typing import Any, Callable, Optional, overload
from arcaea_offline.calculate import calculate_score_range
from arcaea_offline.database import Database
from arcaea_offline.models import Chart, ScoreInsert
from arcaea_offline_ocr.b30.shared import B30OcrResultItem
from arcaea_offline_ocr.device.shared import DeviceOcrResult
from PySide6.QtCore import (
QAbstractListModel,
@ -30,7 +31,7 @@ logger = logging.getLogger(__name__)
class OcrRunnableSignals(QObject):
rowId: int = -1
resultReady = Signal(DeviceOcrResult)
resultReady = Signal("QVariant")
finished = Signal()
@ -45,7 +46,7 @@ class OcrQueueModel(QAbstractListModel):
ImageQImageRole = Qt.ItemDataRole.UserRole + 2
ImagePixmapRole = Qt.ItemDataRole.UserRole + 3
DeviceOcrResultRole = Qt.ItemDataRole.UserRole + 10
OcrResultRole = Qt.ItemDataRole.UserRole + 10
ScoreInsertRole = Qt.ItemDataRole.UserRole + 11
ChartRole = Qt.ItemDataRole.UserRole + 12
ScoreValidateOkRole = Qt.ItemDataRole.UserRole + 13
@ -97,55 +98,86 @@ class OcrQueueModel(QAbstractListModel):
item = self.__items[index.row()]
updateRole = None
if role == self.DeviceOcrResultRole and isinstance(value, DeviceOcrResult):
item[self.DeviceOcrResultRole] = value
self.updateRole = role
if role == self.OcrResultRole:
item[self.OcrResultRole] = value
updateRole = role
if role == self.ChartRole and isinstance(value, Chart):
item[self.ChartRole] = value
self.updateScoreValidateOk(index.row())
self.updateRole = role
updateRole = role
if role == self.ScoreInsertRole and isinstance(value, ScoreInsert):
item[self.ScoreInsertRole] = value
self.updateScoreValidateOk(index.row())
self.updateRole = role
updateRole = role
if role == self.ScoreValidateOkRole and isinstance(value, bool):
item[self.ScoreValidateOkRole] = value
self.updateRole = role
updateRole = role
if role == self.OcrRunnableRole and isinstance(value, OcrRunnable):
item[self.OcrRunnableRole] = value
self.updateRole = role
updateRole = role
if role == self.ProcessOcrResultFuncRole and callable(value):
item[self.ProcessOcrResultFuncRole] = value
self.updateRole = role
updateRole = role
if updateRole is not None:
self.dataChanged.emit(index, index, [updateRole])
return True
else:
logger.warning(
f"{repr(self)} setData at row {index.row()} with role {role} and value {value} rejected."
)
return False
@overload
def addItem(
self,
image: str,
runnable: OcrRunnable = None,
process_func: Callable[[Optional[str], QImage, Any], ScoreInsert] = None,
):
...
@overload
def addItem(
self,
image: QImage,
runnable: OcrRunnable = None,
process_func: Callable[[Optional[str], QImage, Any], ScoreInsert] = None,
):
...
def addItem(
self,
imagePath: str,
runnable: OcrRunnable = None,
process_func: Callable = None,
image,
runnable=None,
process_func=None,
):
if imagePath in self.imagePaths or not QFileInfo(imagePath).exists():
logger.warning(f"Attempting to add an invalid file {imagePath}")
if isinstance(image, str):
if image in self.imagePaths or not QFileInfo(image).exists():
logger.warning(f"Attempting to add an invalid file {image}")
return
imagePath = image
qImage = QImage(image)
qPixmap = QPixmap(image)
elif isinstance(image, QImage):
imagePath = None
qImage = image.copy()
qPixmap = QPixmap(qImage)
else:
raise ValueError("Unsupported type for `image`")
self.beginInsertRows(QModelIndex(), self.rowCount(), self.rowCount())
self.__items.append(
{
self.ImagePathRole: imagePath,
self.ImageQImageRole: QImage(imagePath),
self.ImagePixmapRole: QPixmap(imagePath),
self.DeviceOcrResultRole: None,
self.ImageQImageRole: qImage,
self.ImagePixmapRole: qPixmap,
self.OcrResultRole: None,
self.ScoreInsertRole: None,
self.ChartRole: None,
self.ScoreValidateOkRole: False,
@ -155,19 +187,19 @@ class OcrQueueModel(QAbstractListModel):
)
self.endInsertRows()
def updateOcrResult(self, row: int, result: DeviceOcrResult) -> bool:
if not 0 <= row < self.rowCount() or not isinstance(result, DeviceOcrResult):
def updateOcrResult(self, row: int, result: Any) -> bool:
if not 0 <= row < self.rowCount():
return False
index = self.index(row, 0)
imagePath: str = index.data(self.ImagePathRole)
qImage: QImage = index.data(self.ImageQImageRole)
print(row, result)
processOcrResultFunc = index.data(self.ProcessOcrResultFuncRole)
chart, scoreInsert = processOcrResultFunc(imagePath, result)
chart, scoreInsert = processOcrResultFunc(imagePath, qImage, result)
# song_id = self.__db.fuzzy_search_song_id(result.title)[0][0]
self.setData(index, result, self.DeviceOcrResultRole)
self.setData(index, result, self.OcrResultRole)
self.setData(index, chart, self.ChartRole)
self.setData(index, scoreInsert, self.ScoreInsertRole)
return True
@ -175,7 +207,6 @@ class OcrQueueModel(QAbstractListModel):
@Slot(DeviceOcrResult)
def ocrTaskReady(self, result: DeviceOcrResult):
row = self.sender().rowId
print(row)
self.updateOcrResult(row, result)
@Slot()
@ -184,7 +215,6 @@ class OcrQueueModel(QAbstractListModel):
self.progress.emit(self.__taskFinishedNum)
if self.__taskFinishedNum == self.__taskNum:
self.finished.emit()
print("model finished")
def startQueue(self):
self.__taskNum = self.rowCount()
@ -266,11 +296,11 @@ class OcrQueueTableProxyModel(QAbstractTableModel):
OcrQueueModel.ImagePixmapRole,
],
[
OcrQueueModel.DeviceOcrResultRole,
OcrQueueModel.OcrResultRole,
OcrQueueModel.ChartRole,
],
[
OcrQueueModel.DeviceOcrResultRole,
OcrQueueModel.OcrResultRole,
OcrQueueModel.ScoreInsertRole,
OcrQueueModel.ChartRole,
OcrQueueModel.ScoreValidateOkRole,
@ -333,9 +363,9 @@ class OcrQueueTableProxyModel(QAbstractTableModel):
def setData(self, index, value, role):
if index.column() == 2 and role == OcrQueueModel.ChartRole:
return self.sourceModel().setItemChart(index.row(), value)
return self.sourceModel().setData(index, value, role)
if index.column() == 3 and role == OcrQueueModel.ScoreInsertRole:
return self.sourceModel().setItemScore(index.row(), value)
return self.sourceModel().setData(index, value, role)
return False
def flags(self, index: QModelIndex) -> Qt.ItemFlag:
@ -365,9 +395,7 @@ class OcrChartDelegate(ChartDelegate):
return index.data(OcrQueueModel.ChartRole)
def paintWarningBackground(self, index: QModelIndex) -> bool:
return isinstance(
index.data(OcrQueueModel.DeviceOcrResultRole), DeviceOcrResult
)
return isinstance(index.data(OcrQueueModel.OcrResultRole), DeviceOcrResult)
def setModelData(self, editor, model: OcrQueueTableProxyModel, index):
if editor.validate():
@ -385,9 +413,13 @@ class OcrScoreDelegate(ScoreDelegate):
return index.data(OcrQueueModel.ScoreValidateOkRole)
def paintWarningBackground(self, index: QModelIndex) -> bool:
return isinstance(
index.data(OcrQueueModel.DeviceOcrResultRole), DeviceOcrResult
)
return True
# return isinstance(self.getChart(index), Chart) and isinstance(
# self.getScore(index), ScoreInsert
# )
# return isinstance(
# index.data(OcrQueueModel.OcrResultRole), (DeviceOcrResult, B30OcrResultItem)
# )
def setModelData(self, editor, model: OcrQueueTableProxyModel, index):
if super().confirmSetModelData(editor):

View File

@ -0,0 +1,28 @@
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,
)

View File

@ -51,7 +51,10 @@ class ImageDelegate(QStyledItemDelegate):
label.setWindowFlag(Qt.WindowType.WindowMinimizeButtonHint, False)
label.setWindowFlag(Qt.WindowType.WindowMaximizeButtonHint, False)
label.setWindowFlag(Qt.WindowType.WindowCloseButtonHint, True)
label.setWindowTitle(QFileInfo(self.getImagePath(index)).fileName())
imagePath = self.getImagePath(index)
label.setWindowTitle(
QFileInfo(imagePath).fileName() if imagePath else "Preview"
)
pixmap = pixmap.scaled(
800,
800,

View File

@ -0,0 +1,51 @@
import logging
from arcaea_offline.database import Database
from arcaea_offline.models import Chart, ScoreInsert
from arcaea_offline_ocr.b30.chieri.v4.ocr import ChieriBotV4Ocr
from arcaea_offline_ocr.b30.shared import B30OcrResultItem
from PySide6.QtGui import QImage
logger = logging.getLogger(__name__)
from ui.extends.components.ocrQueue import OcrRunnable
class ChieriV4OcrRunnable(OcrRunnable):
def __init__(self, ocr: ChieriBotV4Ocr, component):
super().__init__()
self.ocr = ocr
self.component = component.copy()
def run(self):
try:
result = self.ocr.ocr_component(self.component)
self.signals.resultReady.emit(result)
except Exception:
logger.exception("ChieriV4 ocr component error")
finally:
self.signals.finished.emit()
def b30ResultToScoreInsert(_, qImage: QImage, result: B30OcrResultItem):
if not result.song_id and not result.title:
raise ValueError("no title or song_id")
db = Database()
if not result.song_id:
song_id = db.fuzzy_search_song_id(result.title)[0][0]
else:
song_id = result.song_id
chart = Chart.from_db_row(db.get_chart(song_id, result.rating_class))
score = ScoreInsert(
song_id=song_id,
rating_class=result.rating_class,
score=result.score,
time=1485014400,
pure=result.pure,
far=result.far,
lost=result.lost,
)
return (chart, score)

View File

@ -3,7 +3,7 @@ import logging
from typing import Tuple
from arcaea_offline.database import Database
from arcaea_offline.models import ScoreInsert, Chart
from arcaea_offline.models import Chart, ScoreInsert
from arcaea_offline_ocr.device.shared import DeviceOcrResult
from arcaea_offline_ocr.device.v2.ocr import DeviceV2Ocr
from arcaea_offline_ocr.device.v2.rois import DeviceV2Rois
@ -52,7 +52,9 @@ def getImageDate(imagePath: str) -> QDateTime:
class ScoreInsertConverter:
@staticmethod
def deviceV2(imagePath: str, result: DeviceOcrResult) -> Tuple[Chart, ScoreInsert]:
def deviceV2(
imagePath: str, _, result: DeviceOcrResult
) -> Tuple[Chart, ScoreInsert]:
db = Database()
scoreInsert = ScoreInsert(
song_id=result.song_id,

View File

@ -3,7 +3,7 @@ from traceback import format_exception
from PySide6.QtWidgets import QMainWindow
from ui.designer.mainwindow_ui import Ui_MainWindow
from ui.implements.tabs.tabOcr import TabOcr
from ui.implements.tabs.tabOcrEntry import TabOcrEntry
# try:
# import arcaea_offline_ocr
@ -32,7 +32,7 @@ class MainWindow(Ui_MainWindow, QMainWindow):
# else:
# self.tab_ocr = TabOcrDisabled(self.tabWidget)
# self.tab_ocr.contentLabel.setText(OCR_ERROR_TEXT)
self.tab_ocr = TabOcr(self.tabWidget)
self.tab_ocr = TabOcrEntry(self.tabWidget)
self.tabWidget.insertTab(ocrTabIndex, self.tab_ocr, "")
self.tabWidget.setCurrentIndex(currentIndex)
self.retranslateUi(self)

View File

@ -0,0 +1,161 @@
import logging
from pathlib import Path
import cv2
from arcaea_offline_ocr.b30.chieri.v4.ocr import ChieriBotV4Ocr
from arcaea_offline_ocr.sift_db import SIFTDatabase
from arcaea_offline_ocr.utils import imread_unicode
# from paddleocr import PaddleOCR
from PySide6.QtCore import Signal, Slot
from PySide6.QtWidgets import QWidget
from ui.designer.tabs.tabOcr.tabOcr_B30_ui import Ui_TabOcr_B30
from ui.extends.components.ocrQueue import OcrQueueModel
from ui.extends.shared.cv2_utils import cv2BgrMatToQImage, qImageToCvMatBgr
from ui.extends.tabs.tabOcr.tabOcr_B30 import (
ChieriV4OcrRunnable,
b30ResultToScoreInsert,
)
logger = logging.getLogger(__name__)
class TabOcr_B30(Ui_TabOcr_B30, QWidget):
tryPrepareOcr = Signal()
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)
self.b30TypeComboBox.addItem("ChieriV4", "chieri_v4")
self.b30TypeComboBox.setCurrentIndex(0)
self.b30TypeComboBox.setEnabled(False)
# self.paddleFolderSelector.setMode(
# self.paddleFolderSelector.getExistingDirectory
# )
self.imageSelector.filesSelected.connect(self.imageSelected)
self.knnModelSelector.filesSelected.connect(self.knnModelSelected)
self.b30KnnModelSelector.filesSelected.connect(self.b30KnnModelSelected)
# self.paddleFolderSelector.filesSelected.connect(self.paddleFolderSelected)
self.siftDatabaseSelector.filesSelected.connect(self.siftDatabaseSelected)
self.imagePath = None # for checking only
self.img = None
self.paddleFolder = None
self.paddle = None
self.knnModel = None
self.b30KnnModel = None
self.siftDatabase = None
self.ocr = None
self.tryPrepareOcr.connect(self.prepareOcr)
self.ocrQueueModel = OcrQueueModel(self)
self.ocrQueue.setModel(self.ocrQueueModel)
def imageSelected(self):
selectedFiles = self.imageSelector.selectedFiles()
if selectedFiles:
imagePath = selectedFiles[0]
self.imagePath = imagePath
self.img = imread_unicode(imagePath)
self.tryPrepareOcr.emit()
def knnModelSelected(self):
selectedFiles = self.knnModelSelector.selectedFiles()
if selectedFiles:
knnModelPath = selectedFiles[0]
self.knnModel = cv2.ml.KNearest.load(knnModelPath)
self.tryPrepareOcr.emit()
def b30KnnModelSelected(self):
selectedFiles = self.b30KnnModelSelector.selectedFiles()
if selectedFiles:
b30KnnModelPath = selectedFiles[0]
self.b30KnnModel = cv2.ml.KNearest.load(b30KnnModelPath)
self.tryPrepareOcr.emit()
def siftDatabaseSelected(self):
selectedFiles = self.siftDatabaseSelector.selectedFiles()
if selectedFiles:
siftDatabasePath = selectedFiles[0]
self.siftDatabase = SIFTDatabase(siftDatabasePath)
self.tryPrepareOcr.emit()
def paddleFolderSelected(self):
selectedFiles = self.paddleFolderSelector.selectedFiles()
if selectedFiles:
self.paddleFolder = selectedFiles[0]
self.initPaddle()
self.tryPrepareOcr.emit()
def initPaddle(self):
paddleFolder = Path(self.paddleFolder)
paddleDetFolder = paddleFolder / "det"
paddleClsFolder = paddleFolder / "cls"
paddleRecFolder = paddleFolder / "rec"
if not (paddleDetFolder.exists() and paddleRecFolder.exists()):
logger.warning("paddleocr folder incomplete, aborting.")
return
self.paddle = PaddleOCR(
show_log=False,
use_angle_cls=False,
det_model_dir=str(paddleDetFolder),
cls_model_dir=str(paddleClsFolder),
rec_model_dir=str(paddleRecFolder),
)
def prepareOcr(self):
b30Type = self.b30TypeComboBox.currentData()
if not b30Type:
return
if b30Type == "chieri_v4":
if (
not self.imagePath
or not self.knnModel
or not self.b30KnnModel
or not self.siftDatabase
):
return
self.ocrQueueModel.clear()
ocr = ChieriBotV4Ocr(self.knnModel, self.b30KnnModel, self.siftDatabase)
ocr.set_factor(self.img)
self.ocr = ocr
roi = ocr.rois
for component in roi.components(self.img):
qImage = cv2BgrMatToQImage(component.copy())
self.ocrQueueModel.addItem(qImage)
self.ocrQueue.resizeTableView()
@Slot()
def on_ocr_startButton_clicked(self):
if (
not self.imagePath
or not self.knnModel
or not self.b30KnnModel
or not self.siftDatabase
):
return
for row in range(self.ocrQueueModel.rowCount()):
index = self.ocrQueueModel.index(row, 0)
qImage = index.data(OcrQueueModel.ImageQImageRole)
cv2Mat = qImageToCvMatBgr(qImage)
runnable = ChieriV4OcrRunnable(self.ocr, cv2Mat)
self.ocrQueueModel.setData(index, runnable, OcrQueueModel.OcrRunnableRole)
self.ocrQueueModel.setData(
index,
b30ResultToScoreInsert,
OcrQueueModel.ProcessOcrResultFuncRole,
)
self.ocrQueueModel.startQueue()

View File

@ -8,13 +8,16 @@ from arcaea_offline_ocr.sift_db import SIFTDatabase
from PySide6.QtCore import Slot
from PySide6.QtWidgets import QFileDialog, QWidget
from ui.designer.tabs.tabOcr_ui import Ui_TabOcr
from ui.designer.tabs.tabOcr.tabOcr_Device_ui import Ui_TabOcr_Device
from ui.extends.components.ocrQueue import OcrQueueModel
from ui.extends.settings import Settings
from ui.extends.tabs.tabOcr import ScoreInsertConverter, TabDeviceV2OcrRunnable
from ui.extends.tabs.tabOcr.tabOcr_Device import (
ScoreInsertConverter,
TabDeviceV2OcrRunnable,
)
class TabOcr(Ui_TabOcr, QWidget):
class TabOcr_Device(Ui_TabOcr_Device, QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)

View File

@ -0,0 +1,9 @@
from PySide6.QtWidgets import QWidget
from ui.designer.tabs.tabOcrEntry_ui import Ui_TabOcrEntry
class TabOcrEntry(Ui_TabOcrEntry, QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.setupUi(self)