From 34e56395ab2d793c5eb525af9fceab0c0e1191f8 Mon Sep 17 00:00:00 2001 From: 283375 Date: Wed, 27 Sep 2023 18:04:38 +0800 Subject: [PATCH] feat: `ImagePHashDatabase` --- ui/extends/shared/settings.py | 20 +++++++ ui/implements/settings/settingsOcr.py | 63 +++++++++++++++++++++- ui/implements/tabs/tabOcr/tabOcr_B30.py | 22 +++----- ui/implements/tabs/tabOcr/tabOcr_Device.py | 20 +++---- ui/resources/lang/en_US.ts | 53 ++++++++++-------- ui/resources/lang/zh_CN.ts | 53 ++++++++++-------- 6 files changed, 159 insertions(+), 72 deletions(-) diff --git a/ui/extends/shared/settings.py b/ui/extends/shared/settings.py index c48b598..f368c72 100644 --- a/ui/extends/shared/settings.py +++ b/ui/extends/shared/settings.py @@ -25,7 +25,9 @@ DEVICES_JSON_FILE = "Ocr/DevicesJsonFile" DEVICE_UUID = "Ocr/DeviceUuid" TESSERACT_FILE = "Ocr/TesseractFile" KNN_MODEL_FILE = "Ocr/KnnModelFile" +B30_KNN_MODEL_FILE = "Ocr/B30KnnModelFile" SIFT_DATABASE_FILE = "Ocr/SiftDatabaseFile" +PHASH_DATABASE_FILE = "Ocr/PHashDatabaseFile" ANDREAL_FOLDER = "Andreal/AndrealFolder" ANDREAL_EXECUTABLE = "Andreal/AndrealExecutable" @@ -104,6 +106,15 @@ class Settings(QSettings, metaclass=QObjectSingleton): def resetKnnModelFile(self): self._resetStrItem(KNN_MODEL_FILE) + def b30KnnModelFile(self): + return self._strItem(B30_KNN_MODEL_FILE) + + def setB30KnnModelFile(self, value: str): + self._setStrItem(B30_KNN_MODEL_FILE, value) + + def resetB30KnnModelFile(self): + self._resetStrItem(B30_KNN_MODEL_FILE) + def siftDatabaseFile(self): return self._strItem(SIFT_DATABASE_FILE) @@ -113,6 +124,15 @@ class Settings(QSettings, metaclass=QObjectSingleton): def resetSiftDatabaseFile(self): self._resetStrItem(SIFT_DATABASE_FILE) + def phashDatabaseFile(self): + return self._strItem(PHASH_DATABASE_FILE) + + def setPHashDatabaseFile(self, value: str): + self._setStrItem(PHASH_DATABASE_FILE, value) + + def resetPHashDatabaseFile(self): + self._resetStrItem(PHASH_DATABASE_FILE) + def andrealFolder(self): return self._strItem(ANDREAL_FOLDER) diff --git a/ui/implements/settings/settingsOcr.py b/ui/implements/settings/settingsOcr.py index c5f831f..0754bbb 100644 --- a/ui/implements/settings/settingsOcr.py +++ b/ui/implements/settings/settingsOcr.py @@ -45,6 +45,17 @@ class SettingsOcr(SettingsBaseWidget): self.knnModelFileResetButton, ) + if self.settings.b30KnnModelFile(): + self.b30KnnModelFileValueWidget.selectFile(self.settings.b30KnnModelFile()) + self.b30KnnModelFileValueWidget.filesSelected.connect(self.setB30KnnModelFile) + self.b30KnnModelFileResetButton.clicked.connect(self.resetB30KnnModelFile) + self.insertItem( + "b30KnnModelFile", + self.b30KnnModelFileLabel, + self.b30KnnModelFileValueWidget, + self.b30KnnModelFileResetButton, + ) + if self.settings.siftDatabaseFile(): self.siftDatabaseFileValueWidget.selectFile( self.settings.siftDatabaseFile() @@ -58,6 +69,21 @@ class SettingsOcr(SettingsBaseWidget): self.siftDatabaseFileResetButton, ) + if self.settings.phashDatabaseFile(): + self.phashDatabaseFileValueWidget.selectFile( + self.settings.phashDatabaseFile() + ) + self.phashDatabaseFileValueWidget.filesSelected.connect( + self.setPHashDatabaseFile + ) + self.phashDatabaseFileResetButton.clicked.connect(self.resetPHashDatabaseFile) + self.insertItem( + "phashDatabaseFile", + self.phashDatabaseFileLabel, + self.phashDatabaseFileValueWidget, + self.phashDatabaseFileResetButton, + ) + def setDevicesJson(self): selectedFile = self.devicesJsonValueWidget.selectedFiles() if selectedFile and selectedFile[0]: @@ -79,8 +105,7 @@ class SettingsOcr(SettingsBaseWidget): self.settings.resetDevicesJsonFile() def setDeviceUuid(self): - device = self.deviceUuidValueWidget.currentData() - if device: + if device := self.deviceUuidValueWidget.currentData(): self.settings.setDeviceUuid(device.uuid) def resetDeviceUuid(self): @@ -97,6 +122,16 @@ class SettingsOcr(SettingsBaseWidget): self.knnModelFileValueWidget.reset() self.settings.resetKnnModelFile() + def setB30KnnModelFile(self): + selectedFile = self.b30KnnModelFileValueWidget.selectedFiles() + if selectedFile and selectedFile[0]: + file = selectedFile[0] + self.settings.setB30KnnModelFile(file) + + def resetB30KnnModelFile(self): + self.b30KnnModelFileValueWidget.reset() + self.settings.resetB30KnnModelFile() + def setSiftDatabaseFile(self): selectedFile = self.siftDatabaseFileValueWidget.selectedFiles() if selectedFile and selectedFile[0]: @@ -107,6 +142,16 @@ class SettingsOcr(SettingsBaseWidget): self.siftDatabaseFileValueWidget.reset() self.settings.resetSiftDatabaseFile() + def setPHashDatabaseFile(self): + selectedFile = self.phashDatabaseFileValueWidget.selectedFiles() + if selectedFile and selectedFile[0]: + file = selectedFile[0] + self.settings.setPHashDatabaseFile(file) + + def resetPHashDatabaseFile(self): + self.phashDatabaseFileValueWidget.reset() + self.settings.resetPHashDatabaseFile() + def setupUi(self, *args): self.devicesJsonLabel = QLabel(self) self.devicesJsonValueWidget = FileSelector(self) @@ -120,10 +165,18 @@ class SettingsOcr(SettingsBaseWidget): self.knnModelFileValueWidget = FileSelector(self) self.knnModelFileResetButton = QPushButton(self) + self.b30KnnModelFileLabel = QLabel(self) + self.b30KnnModelFileValueWidget = FileSelector(self) + self.b30KnnModelFileResetButton = QPushButton(self) + self.siftDatabaseFileLabel = QLabel(self) self.siftDatabaseFileValueWidget = FileSelector(self) self.siftDatabaseFileResetButton = QPushButton(self) + self.phashDatabaseFileLabel = QLabel(self) + self.phashDatabaseFileValueWidget = FileSelector(self) + self.phashDatabaseFileResetButton = QPushButton(self) + super().setupUi(self) self.retranslateUi() @@ -142,6 +195,12 @@ class SettingsOcr(SettingsBaseWidget): self.knnModelFileLabel.setText(QCoreApplication.translate("Settings", "ocr.knnModelFile.label")) self.knnModelFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton")) + self.b30KnnModelFileLabel.setText(QCoreApplication.translate("Settings", "ocr.b30KnnModelFile.label")) + self.b30KnnModelFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton")) + self.siftDatabaseFileLabel.setText(QCoreApplication.translate("Settings", "ocr.siftDatabaseFile.label")) self.siftDatabaseFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton")) + + self.phashDatabaseFileLabel.setText(QCoreApplication.translate("Settings", "ocr.phashDatabaseFile.label")) + self.phashDatabaseFileResetButton.setText(QCoreApplication.translate("Settings", "resetButton")) # fmt: on diff --git a/ui/implements/tabs/tabOcr/tabOcr_B30.py b/ui/implements/tabs/tabOcr/tabOcr_B30.py index 7426d56..529671b 100644 --- a/ui/implements/tabs/tabOcr/tabOcr_B30.py +++ b/ui/implements/tabs/tabOcr/tabOcr_B30.py @@ -12,7 +12,11 @@ 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.shared.language import LanguageChangeEventFilter -from ui.extends.shared.settings import KNN_MODEL_FILE, SIFT_DATABASE_FILE, Settings +from ui.extends.shared.settings import ( + B30_KNN_MODEL_FILE, + KNN_MODEL_FILE, + PHASH_DATABASE_FILE, +) from ui.extends.tabs.tabOcr.tabOcr_B30 import ChieriV4OcrRunnable, b30ResultToScore logger = logging.getLogger(__name__) @@ -35,12 +39,8 @@ class TabOcr_B30(Ui_TabOcr_B30, QWidget): self.imageSelector.filesSelected.connect(self.imageSelected) self.knnModelSelector.filesSelected.connect(self.knnModelSelected) self.b30KnnModelSelector.filesSelected.connect(self.b30KnnModelSelected) - # self.siftDatabaseSelector.filesSelected.connect(self.siftDatabaseSelected) self.phashDatabaseSelector.filesSelected.connect(self.phashDatabaseSelected) - self.knnModelSelector.connectSettings(KNN_MODEL_FILE) - # self.siftDatabaseSelector.connectSettings(SIFT_DATABASE_FILE) - self.imagePath = None # for checking only self.img = None self.paddleFolder = None @@ -54,10 +54,10 @@ class TabOcr_B30(Ui_TabOcr_B30, QWidget): self.tryPrepareOcr.connect(self.prepareOcr) - settings = Settings() logger.info("Applying default settings...") - self.knnModelSelector.selectFile(settings.knnModelFile()) - # self.siftDatabaseSelector.selectFile(settings.siftDatabaseFile()) + self.knnModelSelector.connectSettings(KNN_MODEL_FILE) + self.b30KnnModelSelector.connectSettings(B30_KNN_MODEL_FILE) + self.phashDatabaseSelector.connectSettings(PHASH_DATABASE_FILE) self.ocrQueueModel = OcrQueueModel(self) self.ocrQueue.setModel(self.ocrQueueModel) @@ -81,12 +81,6 @@ class TabOcr_B30(Ui_TabOcr_B30, QWidget): self.b30KnnModel = cv2.ml.KNearest.load(b30KnnModelPath) self.tryPrepareOcr.emit() - def siftDatabaseSelected(self): - if selectedFiles := self.siftDatabaseSelector.selectedFiles(): - siftDatabasePath = selectedFiles[0] - self.siftDatabase = SIFTDatabase(siftDatabasePath) - self.tryPrepareOcr.emit() - def phashDatabaseSelected(self): if selectedFiles := self.phashDatabaseSelector.selectedFiles(): phashDatabasePath = selectedFiles[0] diff --git a/ui/implements/tabs/tabOcr/tabOcr_Device.py b/ui/implements/tabs/tabOcr/tabOcr_Device.py index 8e3bd44..42984c9 100644 --- a/ui/implements/tabs/tabOcr/tabOcr_Device.py +++ b/ui/implements/tabs/tabOcr/tabOcr_Device.py @@ -5,8 +5,8 @@ import cv2 # from arcaea_offline_ocr_device_creation_wizard.implements.wizard import Wizard from arcaea_offline_ocr.device.v1.definition import DeviceV1 from arcaea_offline_ocr.device.v2.definition import DeviceV2 -from arcaea_offline_ocr.sift_db import SIFTDatabase from arcaea_offline_ocr.phash_db import ImagePHashDatabase +from arcaea_offline_ocr.sift_db import SIFTDatabase from PySide6.QtCore import Qt, Slot from PySide6.QtWidgets import QApplication, QFileDialog, QWidget @@ -16,7 +16,8 @@ from ui.extends.shared.language import LanguageChangeEventFilter from ui.extends.shared.settings import ( DEVICES_JSON_FILE, KNN_MODEL_FILE, - SIFT_DATABASE_FILE, + PHASH_DATABASE_FILE, + TESSERACT_FILE, Settings, ) from ui.extends.tabs.tabOcr.tabOcr_Device import ( @@ -39,20 +40,15 @@ class TabOcr_Device(Ui_TabOcr_Device, QWidget): self.deviceFileSelector.filesSelected.connect(self.deviceFileSelected) self.knnModelSelector.filesSelected.connect(self.knnModelFileSelected) - # self.siftDatabaseSelector.filesSelected.connect(self.siftDatabaseFileSelected) self.phashDatabaseSelector.filesSelected.connect(self.phashDatabaseFileSelected) + logger.info("Applying settings...") self.deviceFileSelector.connectSettings(DEVICES_JSON_FILE) self.knnModelSelector.connectSettings(KNN_MODEL_FILE) - # self.siftDatabaseSelector.connectSettings(SIFT_DATABASE_FILE) - + self.tesseractFileSelector.connectSettings(TESSERACT_FILE) + self.phashDatabaseSelector.connectSettings(PHASH_DATABASE_FILE) settings = Settings() - logger.info("Applying default settings...") - self.deviceFileSelector.selectFile(settings.devicesJsonFile()) - self.tesseractFileSelector.selectFile(settings.tesseractPath()) self.deviceComboBox.selectDevice(settings.deviceUuid()) - self.knnModelSelector.selectFile(settings.knnModelFile()) - # vself.siftDatabaseSelector.selectFile(settings.siftDatabaseFile()) self.ocrQueueModel = OcrQueueModel(self) self.ocrQueue.setModel(self.ocrQueueModel) @@ -94,10 +90,6 @@ class TabOcr_Device(Ui_TabOcr_Device, QWidget): if selectedFiles := self.knnModelSelector.selectedFiles(): self.knnModel = cv2.ml.KNearest.load(selectedFiles[0]) - def siftDatabaseFileSelected(self): - if selectedFiles := self.siftDatabaseSelector.selectedFiles(): - self.siftDatabase = SIFTDatabase(selectedFiles[0]) - def phashDatabaseFileSelected(self): if selectedFiles := self.phashDatabaseSelector.selectedFiles(): self.phashDatabase = ImagePHashDatabase(selectedFiles[0]) diff --git a/ui/resources/lang/en_US.ts b/ui/resources/lang/en_US.ts index b6bc12b..972e3b6 100644 --- a/ui/resources/lang/en_US.ts +++ b/ui/resources/lang/en_US.ts @@ -477,10 +477,12 @@ validation - - - - + + + + + + resetButton Reset @@ -515,30 +517,40 @@ validation Database URL - + ocr.title OCR - + ocr.devicesJson.label Default devices.json - + ocr.deviceUuid.label Default device - + ocr.knnModelFile.label Default KNearest model - + + ocr.b30KnnModelFile.label + Default B30 KNearest model + + + ocr.siftDatabaseFile.label Default SIFT database file + + + ocr.phashDatabaseFile.label + Default image PHash database + SongIdSelector @@ -570,7 +582,7 @@ validation Version Info - + Version Info @@ -704,8 +716,8 @@ validation - siftDatabaseSelector.title - Select Image SIFT Database + phashDatabaseSelector.title + Select Image PHash Database @@ -726,32 +738,31 @@ validation Select Device - + deviceSelector.useAutoFactor Auto calculate factor - + knnModelSelector.title Select KNearest Model - + tesseractSelector.title Select tesseract Path - - siftDatabaseSelector.title - Select Image SIFT Database + + phashDatabaseSelector.title + Select Image PHash Database TabOverview - + databaseDescribeLabel {} {} {} {} {} {} - This database now have {} packs, {} songs, {} difficulties, {} chart info ({} complete) and {} scores. There are {} packs, {} songs, {} difficulties, {} chart info ({} complete) and {} scores in database. @@ -841,7 +852,7 @@ validation Generate - + imageWhatIsThisDialog.description Generate image of...<ul><li>/a - the most recent score</li><li>/a b30 - best30 image</li><li>/a info - best score of the selected chart</li></ul> diff --git a/ui/resources/lang/zh_CN.ts b/ui/resources/lang/zh_CN.ts index 0c1fc8e..c95af67 100644 --- a/ui/resources/lang/zh_CN.ts +++ b/ui/resources/lang/zh_CN.ts @@ -476,10 +476,12 @@ - - - - + + + + + + resetButton 重置 @@ -514,30 +516,40 @@ 数据库 URL - + ocr.title OCR - + ocr.devicesJson.label 默认设备定义文件 - + ocr.deviceUuid.label 默认设备 - + ocr.knnModelFile.label 默认 KNearest 模型 - + + ocr.b30KnnModelFile.label + 默认 B30 KNearest 模型 + + + ocr.siftDatabaseFile.label 默认 SIFT 特征值数据库 + + + ocr.phashDatabaseFile.label + 默认图像 PHash 数据库 + SongIdSelector @@ -569,7 +581,7 @@ Version Info - + 版本信息 @@ -703,8 +715,8 @@ - siftDatabaseSelector.title - 选择图像 SIFT 特征值数据库 + phashDatabaseSelector.title + 选择图像 PHash 数据库 @@ -725,32 +737,31 @@ 选择设备 - + deviceSelector.useAutoFactor 自动计算 factor - + knnModelSelector.title 选择 KNearest 模型 - + tesseractSelector.title 选择 tesseract 路径 - - siftDatabaseSelector.title - 选择图像 SIFT 特征值数据库 + + phashDatabaseSelector.title + 选择图像 PHash 数据库 TabOverview - + databaseDescribeLabel {} {} {} {} {} {} - This database now have {} packs, {} songs, {} difficulties, {} chart info ({} complete) and {} scores. 数据库中有 {} 个曲包,{} 首歌曲,{} 个难度,{} 个谱面信息({} 个完整),{} 个分数记录。 @@ -840,7 +851,7 @@ 生成 - + imageWhatIsThisDialog.description 生成……<ul><li>/a - 最近一次成绩</li><li>/a b30 - /a b30</li><li>/a info - 所选谱面的最好成绩</li></ul>