refactor: TabOcr_B30

This commit is contained in:
283375 2023-10-13 20:15:16 +08:00
parent cd4ed51826
commit 858abe3415
Signed by: 283375
SSH Key Fingerprint: SHA256:UcX0qg6ZOSDOeieKPGokA5h7soykG61nz2uxuQgVLSk
7 changed files with 282 additions and 213 deletions

View File

@ -13,7 +13,7 @@
<property name="windowTitle">
<string notr="true">TabOcr_B30</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
@ -27,60 +27,87 @@
</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>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>
<widget class="QGroupBox" name="groupBox_6">
<property name="title">
<string>dependencies.title</string>
</property>
<layout class="QGridLayout" name="gridLayout" columnstretch="0,0,0,0,1">
<item row="0" column="0">
<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>
</layout>
</widget>
</item>
<item>
<widget class="OcrQueue" name="ocrQueue" native="true">

View File

@ -15,8 +15,9 @@ 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 PySide6.QtWidgets import (QApplication, QComboBox, QFrame, QGridLayout,
QGroupBox, QLabel, QSizePolicy, QVBoxLayout,
QWidget)
from ui.implements.components.fileSelector import FileSelector
from ui.implements.components.ocrQueue import OcrQueue
@ -27,8 +28,8 @@ class Ui_TabOcr_B30(object):
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.verticalLayout_2 = QVBoxLayout(TabOcr_B30)
self.verticalLayout_2.setObjectName(u"verticalLayout_2")
self.groupBox = QGroupBox(TabOcr_B30)
self.groupBox.setObjectName(u"groupBox")
self.verticalLayout = QVBoxLayout(self.groupBox)
@ -39,65 +40,80 @@ class Ui_TabOcr_B30(object):
self.verticalLayout.addWidget(self.b30TypeComboBox)
self.verticalLayout_3.addWidget(self.groupBox)
self.verticalLayout_2.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.groupBox_6 = QGroupBox(TabOcr_B30)
self.groupBox_6.setObjectName(u"groupBox_6")
self.gridLayout = QGridLayout(self.groupBox_6)
self.gridLayout.setObjectName(u"gridLayout")
self.label = QLabel(self.groupBox_6)
self.label.setObjectName(u"label")
self.label.setAlignment(Qt.AlignRight|Qt.AlignTrailing|Qt.AlignVCenter)
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.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.line_2 = QFrame(self.groupBox_6)
self.line_2.setObjectName(u"line_2")
self.line_2.setFrameShape(QFrame.VLine)
self.line_2.setFrameShadow(QFrame.Sunken)
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.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.phashDatabaseSelector = FileSelector(self.groupBox_4)
self.phashDatabaseSelector.setObjectName(u"phashDatabaseSelector")
self.line = QFrame(self.groupBox_6)
self.line.setObjectName(u"line")
self.line.setFrameShape(QFrame.VLine)
self.line.setFrameShadow(QFrame.Sunken)
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.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.dependencies_b30KnnModelStatusLabel = QLabel(self.groupBox_6)
self.dependencies_b30KnnModelStatusLabel.setObjectName(u"dependencies_b30KnnModelStatusLabel")
self.dependencies_b30KnnModelStatusLabel.setText(u"...")
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.setObjectName(u"ocrQueue")
@ -107,7 +123,7 @@ class Ui_TabOcr_B30(object):
sizePolicy.setHeightForWidth(self.ocrQueue.sizePolicy().hasHeightForWidth())
self.ocrQueue.setSizePolicy(sizePolicy)
self.verticalLayout_3.addWidget(self.ocrQueue)
self.verticalLayout_2.addWidget(self.ocrQueue)
self.retranslateUi(TabOcr_B30)
@ -117,10 +133,10 @@ class Ui_TabOcr_B30(object):
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"phashDatabaseSelector.title", None))
self.groupBox_2.setTitle(QCoreApplication.translate("TabOcr_B30", u"imageSelector.title", None))
self.groupBox_6.setTitle(QCoreApplication.translate("TabOcr_B30", u"dependencies.title", None))
self.label.setText(QCoreApplication.translate("TabOcr_B30", u"dependencies.knnModel", None))
self.label_2.setText(QCoreApplication.translate("TabOcr_B30", u"dependencies.b30KnnModel", None))
self.label_3.setText(QCoreApplication.translate("TabOcr_B30", u"dependencies.phashDatabase", None))
pass
# retranslateUi

View 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}'

View File

@ -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,
)

View File

@ -1,16 +1,20 @@
import logging
import cv2
import numpy as np
from arcaea_offline_ocr.b30.chieri.v4.ocr import ChieriBotV4Ocr
from arcaea_offline_ocr.phash_db import ImagePHashDatabase
from arcaea_offline_ocr.sift_db import SIFTDatabase
from arcaea_offline_ocr.phash_db import ImagePhashDatabase
from arcaea_offline_ocr.utils import imread_unicode
from PIL import Image
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.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.settings import (
B30_KNN_MODEL_FILE,
@ -36,97 +40,119 @@ class TabOcr_B30(Ui_TabOcr_B30, QWidget):
self.b30TypeComboBox.setCurrentIndex(0)
self.b30TypeComboBox.setEnabled(False)
self.imageSelector.filesSelected.connect(self.imageSelected)
self.knnModelSelector.filesSelected.connect(self.knnModelSelected)
self.b30KnnModelSelector.filesSelected.connect(self.b30KnnModelSelected)
self.phashDatabaseSelector.filesSelected.connect(self.phashDatabaseSelected)
self.dependencies_knnModelSelector.filesSelected.connect(self.knnModelSelected)
self.dependencies_b30KnnModelSelector.filesSelected.connect(
self.b30KnnModelSelected
)
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.b30KnnModel = None
# self.siftDatabase = None
self.phashDatabase = None
self.ocr = None
self.tryPrepareOcr.connect(self.prepareOcr)
logger.info("Applying settings...")
self.knnModelSelector.connectSettings(KNN_MODEL_FILE)
self.b30KnnModelSelector.connectSettings(B30_KNN_MODEL_FILE)
self.phashDatabaseSelector.connectSettings(PHASH_DATABASE_FILE)
self.dependencies_knnModelSelector.connectSettings(KNN_MODEL_FILE)
self.dependencies_b30KnnModelSelector.connectSettings(B30_KNN_MODEL_FILE)
self.dependencies_phashDatabaseSelector.connectSettings(PHASH_DATABASE_FILE)
self.ocrQueueModel = OcrQueueModel(self)
self.ocrQueue.setModel(self.ocrQueueModel)
def imageSelected(self):
if selectedFiles := self.imageSelector.selectedFiles():
imagePath = selectedFiles[0]
self.imagePath = imagePath
self.img = imread_unicode(imagePath)
self.tryPrepareOcr.emit()
# def imageSelected(self):
# if selectedFiles := self.imageSelector.selectedFiles():
# imagePath = selectedFiles[0]
# self.imagePath = imagePath
# self.img = imread_unicode(imagePath)
# self.tryPrepareOcr.emit()
def knnModelSelected(self):
if selectedFiles := self.knnModelSelector.selectedFiles():
knnModelPath = selectedFiles[0]
self.knnModel = cv2.ml.KNearest.load(knnModelPath)
self.tryPrepareOcr.emit()
try:
filePath = self.dependencies_knnModelSelector.selectedFiles()[0]
self.knnModel = cv2.ml.KNearest.load(filePath)
except Exception:
self.knnModel = None
logger.exception("Error loading knn model:")
finally:
self.dependencies_knnModelStatusLabel.setText(
getCv2StatModelStatusText(self.knnModel)
)
def b30KnnModelSelected(self):
if selectedFiles := self.b30KnnModelSelector.selectedFiles():
b30KnnModelPath = selectedFiles[0]
self.b30KnnModel = cv2.ml.KNearest.load(b30KnnModelPath)
self.tryPrepareOcr.emit()
try:
filePath = self.dependencies_b30KnnModelSelector.selectedFiles()[0]
self.b30KnnModel = cv2.ml.KNearest.load(filePath)
except Exception:
self.b30KnnModel = None
logger.exception("Error loading b30 knn model:")
finally:
self.dependencies_b30KnnModelStatusLabel.setText(
getCv2StatModelStatusText(self.b30KnnModel)
)
def phashDatabaseSelected(self):
if selectedFiles := self.phashDatabaseSelector.selectedFiles():
phashDatabasePath = selectedFiles[0]
self.phashDatabase = ImagePHashDatabase(phashDatabasePath)
self.tryPrepareOcr.emit()
try:
filePath = self.dependencies_phashDatabaseSelector.selectedFiles()[0]
self.phashDatabase = ImagePhashDatabase(filePath)
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()
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
if b30Type == "chieri_v4":
if (
not self.imagePath
or not self.knnModel
or not self.b30KnnModel
or not self.phashDatabase
):
return
imagePath, _ = QFileDialog.getOpenFileName(
self, None, "", "Image Files (*.png *.jpg *.jpeg *.bmp *.webp);;*"
)
self.ocrQueueModel.clear()
if not imagePath:
return
ocr = ChieriBotV4Ocr(self.knnModel, self.b30KnnModel, self.phashDatabase)
ocr.set_factor(self.img)
self.ocr = ocr
self.ocrQueueModel.clear()
roi = ocr.rois
for component in roi.components(self.img):
qImage = cv2BgrMatToQImage(component.copy())
self.ocrQueueModel.addItem(qImage)
img = imread_unicode(imagePath, cv2.IMREAD_COLOR)
ocr = ChieriBotV4Ocr(self.knnModel, self.b30KnnModel, self.phashDatabase)
ocr.set_factor(img)
self.ocr = ocr
roi = ocr.rois
for component in roi.components(img):
qImage = Image.fromarray(component.copy()).toqimage()
self.ocrQueueModel.addItem(qImage)
self.ocrQueue.resizeTableView()
@Slot()
def on_ocr_startButton_clicked(self):
if (
not self.imagePath
or not self.knnModel
or not self.b30KnnModel
or not self.phashDatabase
):
if not self.ocr:
return
for row in range(self.ocrQueueModel.rowCount()):
index = self.ocrQueueModel.index(row, 0)
qImage = index.data(OcrQueueModel.ImageQImageRole)
cv2Mat = qImageToCvMatBgr(qImage)
cv2Mat = np.array(Image.fromqimage(qImage))
runnable = ChieriV4OcrRunnable(self.ocr, cv2Mat)
self.ocrQueueModel.setData(index, runnable, OcrQueueModel.OcrRunnableRole)
self.ocrQueueModel.setData(

View File

@ -692,24 +692,24 @@ validation</translation>
<translation>B30 Image Type</translation>
</message>
<message>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="34"/>
<source>knnModelSelector.title</source>
<translation>Select KNearest Model</translation>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="32"/>
<source>dependencies.title</source>
<translation>OCR Dependencies</translation>
</message>
<message>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="46"/>
<source>b30KnnModelSelector.title</source>
<translation>Select B30 Specialized KNearest Model</translation>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="38"/>
<source>dependencies.knnModel</source>
<translation>KNearest model</translation>
</message>
<message>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="62"/>
<source>phashDatabaseSelector.title</source>
<translation>Select Image PHash Database</translation>
<source>dependencies.b30KnnModel</source>
<translation>B30 KNearest model</translation>
</message>
<message>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="74"/>
<source>imageSelector.title</source>
<translation>Select Image</translation>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="86"/>
<source>dependencies.phashDatabase</source>
<translation>Image pHash database</translation>
</message>
</context>
<context>

View File

@ -691,24 +691,24 @@
<translation>B30 </translation>
</message>
<message>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="34"/>
<source>knnModelSelector.title</source>
<translation> KNearest </translation>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="32"/>
<source>dependencies.title</source>
<translation>OCR </translation>
</message>
<message>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="46"/>
<source>b30KnnModelSelector.title</source>
<translation> B30 KNearest </translation>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="38"/>
<source>dependencies.knnModel</source>
<translation>KNearest </translation>
</message>
<message>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="62"/>
<source>phashDatabaseSelector.title</source>
<translation> PHash </translation>
<source>dependencies.b30KnnModel</source>
<translation>B30 KNearest </translation>
</message>
<message>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="74"/>
<source>imageSelector.title</source>
<translation></translation>
<location filename="../../designer/tabs/tabOcr/tabOcr_B30.ui" line="86"/>
<source>dependencies.phashDatabase</source>
<translation> pHash </translation>
</message>
</context>
<context>