개정판 02519509
issue 366: 텍스트 영역 인식 및 텍스트 인식 속도 개선
issue 479: 심볼 인식 후 hit ratio를 툴팁에 표기
기타 - tesseract version 표기
Change-Id: I7c41eb524de4919bce6aed18c361dcacc09f8aeb
DTI_PID/DTI_PID/AppDocData.py | ||
---|---|---|
1358 | 1358 |
''' |
1359 | 1359 |
|
1360 | 1360 |
def saveConfigs(self, configs): |
1361 |
conn = self.project.database.connect() |
|
1362 |
with conn: |
|
1361 |
with self.project.database.connect() as conn: |
|
1363 | 1362 |
try: |
1364 | 1363 |
# Get a cursor object |
1365 | 1364 |
cursor = conn.cursor() |
1365 |
if self.project.database.db_type == 'SQLite': |
|
1366 |
cursor.execute('begin') |
|
1366 | 1367 |
|
1367 | 1368 |
for config in configs: |
1368 | 1369 |
if type(config) is Config: |
... | ... | |
1388 | 1389 |
if sql is not None and 2 == len(sql): |
1389 | 1390 |
cursor.execute(self.project.database.to_sql(sql[0]), sql[1]) |
1390 | 1391 |
self._configs = None # reset config table |
1391 |
conn.commit() |
|
1392 |
|
|
1393 |
if self.project.database.db_type == 'SQLite': |
|
1394 |
cursor.execute('commit') |
|
1395 |
else: |
|
1396 |
conn.commit() |
|
1392 | 1397 |
# Catch the exception |
1393 | 1398 |
except Exception as ex: |
1394 | 1399 |
# Roll back any change if something goes wrong |
... | ... | |
1648 | 1653 |
def getSymbolListByType(self, field_name=None, param=None): |
1649 | 1654 |
ret = [] |
1650 | 1655 |
|
1651 |
conn = self.project.database.connect() |
|
1652 |
with conn: |
|
1656 |
with self.project.database.connect() as conn: |
|
1653 | 1657 |
cursor = conn.cursor() |
1654 | 1658 |
if field_name is not None and param is not None: |
1655 | 1659 |
sql = """SELECT a.UID,a.Name,b.Type,a.Threshold,a.MinMatchPoint,a.IsDetectOrigin,a.RotationCount,a.OCROption,a.IsContainChild,a.OriginalPoint,a.ConnectionPoint, |
... | ... | |
3639 | 3643 |
def getSymbolTypeList(self): |
3640 | 3644 |
symbolTypeList = [] |
3641 | 3645 |
|
3642 |
conn = self.project.database.connect() |
|
3643 |
with conn: |
|
3646 |
with self.project.database.connect() as conn: |
|
3644 | 3647 |
cursor = conn.cursor() |
3645 | 3648 |
sql = 'SELECT * FROM SymbolType ORDER BY Type ASC' |
3646 | 3649 |
try: |
... | ... | |
3691 | 3694 |
|
3692 | 3695 |
def isEquipmentType(self, type): |
3693 | 3696 |
category = self.getSymbolCategoryByType(type) |
3694 |
return (category is not None and category == 'Equipment')
|
|
3697 |
return category is not None and category == 'Equipment'
|
|
3695 | 3698 |
|
3696 | 3699 |
''' |
3697 | 3700 |
@brief Return Symbol Type Items with "None" |
... | ... | |
3701 | 3704 |
''' |
3702 | 3705 |
|
3703 | 3706 |
def getSymbolTypeComboBoxItems(self): |
3704 |
symbolTypeList = self.getSymbolTypeList()
|
|
3707 |
symbolTypeList = [symbol_type for symbol_type in self.getSymbolTypeList() if symbol_type[1]]
|
|
3705 | 3708 |
symbolTypeList.insert(0, ('None', 'None', 'None')) |
3706 | 3709 |
|
3707 | 3710 |
return symbolTypeList |
DTI_PID/DTI_PID/Commands/RemoveTextCommand.py | ||
---|---|---|
1 | 1 |
import os.path |
2 | 2 |
import AbstractCommand |
3 |
|
|
3 | 4 |
try: |
4 | 5 |
from PyQt5.QtCore import Qt, QPoint, QPointF, QRectF, pyqtSignal, QT_VERSION_STR, QBuffer, QRect, QRegExp |
5 |
from PyQt5.QtGui import QImage, QPixmap, QPainterPath, QPainter, QColor, QPen, QBrush, QCursor, QTransform, QFont, QRegExpValidator, QValidator |
|
6 |
from PyQt5.QtGui import QImage, QPixmap, QPainterPath, QPainter, QColor, QPen, QBrush, QCursor, QTransform, QFont, \ |
|
7 |
QRegExpValidator, QValidator |
|
6 | 8 |
from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog, QMessageBox |
7 | 9 |
except ImportError: |
8 | 10 |
try: |
9 | 11 |
from PyQt4.QtCore import Qt, QPoint, QPointF, QRectF, pyqtSignal, QT_VERSION_STR, QBuffer, QRect, QRegExp |
10 |
from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog, QPainter, QColor, QPen, QBrush, QCursor, QTransform, QFont, QRegExpValidator, QValidator |
|
12 |
from PyQt4.QtGui import QGraphicsView, QGraphicsScene, QImage, QPixmap, QPainterPath, QFileDialog, QPainter, \ |
|
13 |
QColor, QPen, QBrush, QCursor, QTransform, QFont, QRegExpValidator, QValidator |
|
11 | 14 |
except ImportError: |
12 | 15 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
13 | 16 |
import sys |
... | ... | |
18 | 21 |
import io |
19 | 22 |
import cv2 |
20 | 23 |
|
24 |
|
|
21 | 25 |
class RemoveTextCommand(AbstractCommand.AbstractCommand): |
22 | 26 |
''' |
23 | 27 |
@history 2018.05.09 Jeongwoo Draw Rect on ±1 area |
24 | 28 |
2018.06.11 Jeongwoo Change method to set image (setImage → setPixmap/updateViewer) |
25 | 29 |
''' |
30 |
|
|
26 | 31 |
def __init__(self, imageViewer): |
27 | 32 |
super(RemoveTextCommand, self).__init__(imageViewer) |
28 |
self.name = 'RemoveText'
|
|
29 |
#self.imageViewer.setCursor(QCursor(Qt.ArrowCursor)) |
|
33 |
self.name = 'RemoveText' |
|
34 |
# self.imageViewer.setCursor(QCursor(Qt.ArrowCursor))
|
|
30 | 35 |
image = self.imageViewer.image() |
31 | 36 |
buffer = QBuffer() |
32 | 37 |
buffer.open(QBuffer.ReadWrite) |
... | ... | |
34 | 39 |
pyImage = Image.open(io.BytesIO(buffer.data())) |
35 | 40 |
dst = cv2.cvtColor(np.array(pyImage), cv2.COLOR_BGR2GRAY) |
36 | 41 |
textDetector = TextDetector() |
37 |
self.textInfoList = textDetector.detectTextAreas(dst, (0, 0)) |
|
42 |
self.textInfoList, _ = textDetector.detectTextAreas(dst, (0, 0))
|
|
38 | 43 |
pixmap = self.imageViewer.pixmap() |
39 | 44 |
ADJUST = 1 |
40 | 45 |
for textInfo in self.textInfoList: |
... | ... | |
42 | 47 |
painter.begin(pixmap) |
43 | 48 |
painter.setPen(QColor(255, 255, 255)) |
44 | 49 |
painter.setBrush(QColor(255, 255, 255)) |
45 |
painter.drawRect(QRect(textInfo.getX()-ADJUST, textInfo.getY()-ADJUST, textInfo.getW()+ADJUST, textInfo.getH()+ADJUST)) |
|
50 |
painter.drawRect(QRect(textInfo.getX() - ADJUST, textInfo.getY() - ADJUST, textInfo.getW() + ADJUST, |
|
51 |
textInfo.getH() + ADJUST)) |
|
46 | 52 |
painter.end() |
47 | 53 |
pixmapHandle = self.imageViewer.getPixmapHandle() |
48 | 54 |
if pixmapHandle is not None: |
49 | 55 |
pixmapHandle.setPixmap(pixmap) |
50 | 56 |
self.imageViewer.setSceneRect(QRectF(pixmap.rect())) |
51 | 57 |
self.imageViewer.updateViewer() |
52 |
|
|
58 |
|
|
53 | 59 |
def execute(self, param): |
54 | 60 |
event = param[1] |
55 | 61 |
scenePos = param[2] |
... | ... | |
59 | 65 |
pass |
60 | 66 |
|
61 | 67 |
def redo(self): |
62 |
pass |
|
68 |
pass |
DTI_PID/DTI_PID/ConfigurationDialog.py | ||
---|---|---|
12 | 12 |
from AppDocData import Color |
13 | 13 |
from EngineeringAbstractItem import QEngineeringAbstractItem |
14 | 14 |
import Configuration_UI |
15 |
import pytesseract |
|
15 | 16 |
import tesseract_ocr_module as TOCR |
16 | 17 |
|
17 | 18 |
|
... | ... | |
60 | 61 |
self.ui.comboBoxOCRData.setCurrentIndex(at) |
61 | 62 |
else: |
62 | 63 |
self.ui.comboBoxOCRData.selectedIndex = 0 |
64 |
self.ui.labelTesseractVersion.setText(f"tesseract={str(pytesseract.get_tesseract_version())}") |
|
63 | 65 |
|
64 | 66 |
configs = docData.getConfigs('Text Recognition', 'Expand Size') |
65 |
self.ui.spinBoxExpandSize.setValue(int(configs[0].value)) if 1 == len( |
|
66 |
configs) else self.ui.spinBoxExpandSize.setValue(10)
|
|
67 |
self.ui.spinBoxExpandSize.setValue(int(configs[0].value)) if 1 == len(configs) else \
|
|
68 |
self.ui.spinBoxExpandSize.setValue(10) |
|
67 | 69 |
configs = docData.getConfigs('Text Recognition', 'Shrink Size') |
68 |
self.ui.spinBoxShrinkSize.setValue(int(configs[0].value)) if 1 == len( |
|
69 |
configs) else self.ui.spinBoxShrinkSize.setValue(0)
|
|
70 |
self.ui.spinBoxShrinkSize.setValue(int(configs[0].value)) if 1 == len(configs) else \
|
|
71 |
self.ui.spinBoxShrinkSize.setValue(0) |
|
70 | 72 |
configs = docData.getConfigs('Text Recognition', 'Merge Size') |
71 |
self.ui.spinBoxMergeSize.setValue(int(configs[0].value)) if 1 == len( |
|
72 |
configs) else self.ui.spinBoxMergeSize.setValue(10)
|
|
73 |
self.ui.spinBoxMergeSize.setValue(int(configs[0].value)) if 1 == len(configs) else \
|
|
74 |
self.ui.spinBoxMergeSize.setValue(10) |
|
73 | 75 |
configs = docData.getConfigs('Text Recognition', 'White Character List') |
74 |
self.ui.lineEditWhiteCharList.setText(configs[0].value) if 1 == len(configs) else self.ui.lineEditWhiteCharList.setText(TOCR.DEFAULT_CONF[40:]) |
|
76 |
self.ui.lineEditWhiteCharList.setText(configs[0].value) if 1 == len(configs) else \ |
|
77 |
self.ui.lineEditWhiteCharList.setText(TOCR.DEFAULT_CONF[40:]) |
|
78 |
self.set_page_segmentation_modes() |
|
75 | 79 |
configs = docData.getConfigs('Text Recognition', 'White Single Text') |
76 |
self.ui.lineEditSingleText.setText(configs[0].value) if 1 == len(configs) else self.ui.lineEditSingleText.setText('H,L') |
|
80 |
self.ui.lineEditSingleText.setText(configs[0].value) if 1 == len(configs) else \ |
|
81 |
self.ui.lineEditSingleText.setText('H,L') |
|
77 | 82 |
|
78 | 83 |
configs = docData.getConfigs('Text Size', 'Min Text Size') |
79 | 84 |
self.ui.minTextSizeSpinBox.setValue(int(configs[0].value)) if 1 == len( |
... | ... | |
405 | 410 |
self.ui.listWidgetTagNo.itemDoubleClicked.connect(self.tagNoItemDoubleCliced) |
406 | 411 |
self.ui.pushButtonClearAccessInfo.clicked.connect(self.clear_drawing_access_info_clicked) |
407 | 412 |
|
413 |
def set_page_segmentation_modes(self): |
|
414 |
"""show page segmentation modes""" |
|
415 |
try: |
|
416 |
model = QStandardItemModel() |
|
417 |
|
|
418 |
items = [('0', 'Orientation and script detection(OSD) only.'), |
|
419 |
('1', 'Automatic page segmentation with OSD.'), |
|
420 |
('2', 'Automatic page segmentation, but no OSD, or OCR.'), |
|
421 |
('3', 'Fully automatic page segmentation, but no OSD.(Default)'), |
|
422 |
('4', 'Assume a single column of text of variable sizes.'), |
|
423 |
('5', 'Assume a single uniform block of vertically aligned text.'), |
|
424 |
('6', 'Assume a single uniform block of text.'), |
|
425 |
('7', 'Treat the image as a single text line.'), |
|
426 |
('8', 'Treat the image as a single word.'), |
|
427 |
('9', 'Treat the image as a single word in a circle.'), |
|
428 |
('10', 'Treat the image as a single character.'), |
|
429 |
('11', 'Sparse text.Find as much text as possible in no particular order.'), |
|
430 |
('12', 'Sparse text with OSD.'), |
|
431 |
('13', 'Raw line.Treat the image as a single text line, bypassing hacks that are Tesseract - ' |
|
432 |
'specific.')] |
|
433 |
|
|
434 |
for value, label in items: |
|
435 |
value_item = QStandardItem(value) |
|
436 |
label_item = QStandardItem(label) |
|
437 |
model.appendRow([value_item, label_item]) |
|
438 |
|
|
439 |
model.setHorizontalHeaderLabels(['Value', 'Desc.']) |
|
440 |
|
|
441 |
view = QTableView(self) |
|
442 |
view.verticalHeader().hide() |
|
443 |
|
|
444 |
self.ui.comboBoxPageSegmentationModes.setModel(model) |
|
445 |
self.ui.comboBoxPageSegmentationModes.setView(view) |
|
446 |
view.resizeColumnsToContents() |
|
447 |
|
|
448 |
app_doc_data = AppDocData.instance() |
|
449 |
configs = app_doc_data.getConfigs('Text Recognition', 'Page Segmentation Modes') |
|
450 |
if configs: |
|
451 |
self.ui.comboBoxPageSegmentationModes.setCurrentIndex(int(configs[0].value)) |
|
452 |
else: |
|
453 |
self.ui.comboBoxPageSegmentationModes.setCurrentIndex(3) |
|
454 |
except Exception as ex: |
|
455 |
from App import App |
|
456 |
from AppDocData import MessageType |
|
457 |
|
|
458 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
459 |
sys.exc_info()[-1].tb_lineno) |
|
460 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
461 |
|
|
408 | 462 |
def clear_drawing_access_info_clicked(self): |
409 | 463 |
reply = QMessageBox.question(self, self.tr('Continue?'), |
410 | 464 |
self.tr('Are you sure you want to clear drawing access information?'), |
... | ... | |
812 | 866 |
configs.append(Config('Drain Size Rule', 'Size', docData.drain_size)) |
813 | 867 |
configs.append(Config('Text Recognition', 'White Character List', self.ui.lineEditWhiteCharList.text())) |
814 | 868 |
configs.append(Config('Text Recognition', 'White Single Text', self.ui.lineEditSingleText.text())) |
869 |
configs.append(Config('Text Recognition', 'Page Segmentation Modes', |
|
870 |
str(self.ui.comboBoxPageSegmentationModes.currentIndex()))) |
|
815 | 871 |
# Add Line Color Option - 2018.07.06 by kyouho |
816 | 872 |
rbRandomValue = self.ui.radioButtonRandom.isChecked() |
817 | 873 |
|
DTI_PID/DTI_PID/Configuration_UI.py | ||
---|---|---|
13 | 13 |
class Ui_ConfigurationDialog(object): |
14 | 14 |
def setupUi(self, ConfigurationDialog): |
15 | 15 |
ConfigurationDialog.setObjectName("ConfigurationDialog") |
16 |
ConfigurationDialog.resize(632, 616)
|
|
16 |
ConfigurationDialog.resize(648, 631)
|
|
17 | 17 |
font = QtGui.QFont() |
18 | 18 |
font.setFamily("맑은 고딕") |
19 | 19 |
ConfigurationDialog.setFont(font) |
... | ... | |
90 | 90 |
self.gridLayout_14.setObjectName("gridLayout_14") |
91 | 91 |
self.gridLayout_25 = QtWidgets.QGridLayout() |
92 | 92 |
self.gridLayout_25.setObjectName("gridLayout_25") |
93 |
self.maxTextSizeSpinBox = QtWidgets.QSpinBox(self.groupBoxText) |
|
94 |
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) |
|
95 |
sizePolicy.setHorizontalStretch(0) |
|
96 |
sizePolicy.setVerticalStretch(0) |
|
97 |
sizePolicy.setHeightForWidth(self.maxTextSizeSpinBox.sizePolicy().hasHeightForWidth()) |
|
98 |
self.maxTextSizeSpinBox.setSizePolicy(sizePolicy) |
|
99 |
self.maxTextSizeSpinBox.setProperty("value", 60) |
|
100 |
self.maxTextSizeSpinBox.setObjectName("maxTextSizeSpinBox") |
|
101 |
self.gridLayout_25.addWidget(self.maxTextSizeSpinBox, 4, 3, 1, 1) |
|
102 | 93 |
self.minTextSizeSpinBox = QtWidgets.QSpinBox(self.groupBoxText) |
103 | 94 |
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) |
104 | 95 |
sizePolicy.setHorizontalStretch(0) |
... | ... | |
108 | 99 |
self.minTextSizeSpinBox.setMaximumSize(QtCore.QSize(16777215, 16777215)) |
109 | 100 |
self.minTextSizeSpinBox.setProperty("value", 30) |
110 | 101 |
self.minTextSizeSpinBox.setObjectName("minTextSizeSpinBox") |
111 |
self.gridLayout_25.addWidget(self.minTextSizeSpinBox, 4, 1, 1, 1) |
|
112 |
self.label_18 = QtWidgets.QLabel(self.groupBoxText) |
|
113 |
self.label_18.setObjectName("label_18") |
|
114 |
self.gridLayout_25.addWidget(self.label_18, 4, 2, 1, 1) |
|
115 |
self.label_17 = QtWidgets.QLabel(self.groupBoxText) |
|
116 |
self.label_17.setObjectName("label_17") |
|
117 |
self.gridLayout_25.addWidget(self.label_17, 4, 0, 1, 1) |
|
102 |
self.gridLayout_25.addWidget(self.minTextSizeSpinBox, 5, 1, 1, 1) |
|
103 |
self.maxTextSizeSpinBox = QtWidgets.QSpinBox(self.groupBoxText) |
|
104 |
sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed) |
|
105 |
sizePolicy.setHorizontalStretch(0) |
|
106 |
sizePolicy.setVerticalStretch(0) |
|
107 |
sizePolicy.setHeightForWidth(self.maxTextSizeSpinBox.sizePolicy().hasHeightForWidth()) |
|
108 |
self.maxTextSizeSpinBox.setSizePolicy(sizePolicy) |
|
109 |
self.maxTextSizeSpinBox.setProperty("value", 60) |
|
110 |
self.maxTextSizeSpinBox.setObjectName("maxTextSizeSpinBox") |
|
111 |
self.gridLayout_25.addWidget(self.maxTextSizeSpinBox, 5, 3, 1, 1) |
|
118 | 112 |
self.label_21 = QtWidgets.QLabel(self.groupBoxText) |
119 | 113 |
self.label_21.setObjectName("label_21") |
120 |
self.gridLayout_25.addWidget(self.label_21, 3, 2, 1, 1) |
|
121 |
self.spinBoxShrinkSize = QtWidgets.QSpinBox(self.groupBoxText) |
|
122 |
self.spinBoxShrinkSize.setMinimumSize(QtCore.QSize(100, 0)) |
|
123 |
self.spinBoxShrinkSize.setObjectName("spinBoxShrinkSize") |
|
124 |
self.gridLayout_25.addWidget(self.spinBoxShrinkSize, 3, 3, 1, 1) |
|
114 |
self.gridLayout_25.addWidget(self.label_21, 4, 2, 1, 1) |
|
115 |
self.label_17 = QtWidgets.QLabel(self.groupBoxText) |
|
116 |
self.label_17.setObjectName("label_17") |
|
117 |
self.gridLayout_25.addWidget(self.label_17, 5, 0, 1, 1) |
|
118 |
self.label_18 = QtWidgets.QLabel(self.groupBoxText) |
|
119 |
self.label_18.setObjectName("label_18") |
|
120 |
self.gridLayout_25.addWidget(self.label_18, 5, 2, 1, 1) |
|
125 | 121 |
self.spinBoxExpandSize = QtWidgets.QSpinBox(self.groupBoxText) |
126 | 122 |
self.spinBoxExpandSize.setMinimumSize(QtCore.QSize(100, 0)) |
127 | 123 |
self.spinBoxExpandSize.setObjectName("spinBoxExpandSize") |
128 |
self.gridLayout_25.addWidget(self.spinBoxExpandSize, 3, 1, 1, 1) |
|
124 |
self.gridLayout_25.addWidget(self.spinBoxExpandSize, 4, 1, 1, 1) |
|
125 |
self.spinBoxShrinkSize = QtWidgets.QSpinBox(self.groupBoxText) |
|
126 |
self.spinBoxShrinkSize.setMinimumSize(QtCore.QSize(100, 0)) |
|
127 |
self.spinBoxShrinkSize.setObjectName("spinBoxShrinkSize") |
|
128 |
self.gridLayout_25.addWidget(self.spinBoxShrinkSize, 4, 3, 1, 1) |
|
129 | 129 |
self.label_19 = QtWidgets.QLabel(self.groupBoxText) |
130 | 130 |
self.label_19.setObjectName("label_19") |
131 | 131 |
self.gridLayout_25.addWidget(self.label_19, 0, 0, 1, 1) |
132 |
self.label_20 = QtWidgets.QLabel(self.groupBoxText) |
|
133 |
self.label_20.setObjectName("label_20") |
|
134 |
self.gridLayout_25.addWidget(self.label_20, 4, 0, 1, 1) |
|
132 | 135 |
self.label_7 = QtWidgets.QLabel(self.groupBoxText) |
133 | 136 |
self.label_7.setObjectName("label_7") |
134 | 137 |
self.gridLayout_25.addWidget(self.label_7, 1, 0, 1, 1) |
135 |
self.label_20 = QtWidgets.QLabel(self.groupBoxText) |
|
136 |
self.label_20.setObjectName("label_20") |
|
137 |
self.gridLayout_25.addWidget(self.label_20, 3, 0, 1, 1) |
|
138 | 138 |
self.label_37 = QtWidgets.QLabel(self.groupBoxText) |
139 | 139 |
self.label_37.setObjectName("label_37") |
140 |
self.gridLayout_25.addWidget(self.label_37, 2, 0, 1, 1)
|
|
140 |
self.gridLayout_25.addWidget(self.label_37, 3, 0, 1, 1)
|
|
141 | 141 |
self.label_22 = QtWidgets.QLabel(self.groupBoxText) |
142 | 142 |
self.label_22.setObjectName("label_22") |
143 |
self.gridLayout_25.addWidget(self.label_22, 5, 0, 1, 1) |
|
143 |
self.gridLayout_25.addWidget(self.label_22, 6, 0, 1, 1) |
|
144 |
self.lineEditWhiteCharList = QtWidgets.QLineEdit(self.groupBoxText) |
|
145 |
self.lineEditWhiteCharList.setObjectName("lineEditWhiteCharList") |
|
146 |
self.gridLayout_25.addWidget(self.lineEditWhiteCharList, 1, 1, 1, 3) |
|
147 |
self.lineEditSingleText = QtWidgets.QLineEdit(self.groupBoxText) |
|
148 |
self.lineEditSingleText.setObjectName("lineEditSingleText") |
|
149 |
self.gridLayout_25.addWidget(self.lineEditSingleText, 3, 1, 1, 1) |
|
144 | 150 |
self.spinBoxMergeSize = QtWidgets.QSpinBox(self.groupBoxText) |
145 | 151 |
self.spinBoxMergeSize.setMinimumSize(QtCore.QSize(100, 0)) |
146 | 152 |
self.spinBoxMergeSize.setObjectName("spinBoxMergeSize") |
147 |
self.gridLayout_25.addWidget(self.spinBoxMergeSize, 5, 1, 1, 1)
|
|
153 |
self.gridLayout_25.addWidget(self.spinBoxMergeSize, 6, 1, 1, 1)
|
|
148 | 154 |
self.comboBoxOCRData = QtWidgets.QComboBox(self.groupBoxText) |
149 | 155 |
self.comboBoxOCRData.setMinimumSize(QtCore.QSize(200, 0)) |
150 | 156 |
self.comboBoxOCRData.setMaximumSize(QtCore.QSize(200, 16777215)) |
151 | 157 |
self.comboBoxOCRData.setObjectName("comboBoxOCRData") |
152 | 158 |
self.gridLayout_25.addWidget(self.comboBoxOCRData, 0, 1, 1, 1) |
153 |
self.lineEditSingleText = QtWidgets.QLineEdit(self.groupBoxText) |
|
154 |
self.lineEditSingleText.setObjectName("lineEditSingleText") |
|
155 |
self.gridLayout_25.addWidget(self.lineEditSingleText, 2, 1, 1, 1) |
|
156 |
self.lineEditWhiteCharList = QtWidgets.QLineEdit(self.groupBoxText) |
|
157 |
self.lineEditWhiteCharList.setObjectName("lineEditWhiteCharList") |
|
158 |
self.gridLayout_25.addWidget(self.lineEditWhiteCharList, 1, 1, 1, 3) |
|
159 |
self.label_39 = QtWidgets.QLabel(self.groupBoxText) |
|
160 |
self.label_39.setObjectName("label_39") |
|
161 |
self.gridLayout_25.addWidget(self.label_39, 2, 0, 1, 1) |
|
162 |
self.comboBoxPageSegmentationModes = QtWidgets.QComboBox(self.groupBoxText) |
|
163 |
self.comboBoxPageSegmentationModes.setObjectName("comboBoxPageSegmentationModes") |
|
164 |
self.gridLayout_25.addWidget(self.comboBoxPageSegmentationModes, 2, 1, 1, 3) |
|
165 |
self.labelTesseractVersion = QtWidgets.QLabel(self.groupBoxText) |
|
166 |
self.labelTesseractVersion.setAlignment(QtCore.Qt.AlignRight|QtCore.Qt.AlignTrailing|QtCore.Qt.AlignVCenter) |
|
167 |
self.labelTesseractVersion.setObjectName("labelTesseractVersion") |
|
168 |
self.gridLayout_25.addWidget(self.labelTesseractVersion, 0, 2, 1, 2) |
|
159 | 169 |
self.gridLayout_14.addLayout(self.gridLayout_25, 0, 0, 1, 1) |
160 | 170 |
self.gridLayout_2.addWidget(self.groupBoxText, 0, 1, 1, 1) |
161 | 171 |
self.groupBoxAttribute = QtWidgets.QGroupBox(self.Recognition) |
... | ... | |
647 | 657 |
self.buttonBox.accepted.connect(ConfigurationDialog.accept) |
648 | 658 |
self.buttonBox.rejected.connect(ConfigurationDialog.reject) |
649 | 659 |
QtCore.QMetaObject.connectSlotsByName(ConfigurationDialog) |
660 |
ConfigurationDialog.setTabOrder(self.comboBoxOCRData, self.lineEditWhiteCharList) |
|
661 |
ConfigurationDialog.setTabOrder(self.lineEditWhiteCharList, self.comboBoxPageSegmentationModes) |
|
662 |
ConfigurationDialog.setTabOrder(self.comboBoxPageSegmentationModes, self.lineEditSingleText) |
|
663 |
ConfigurationDialog.setTabOrder(self.lineEditSingleText, self.spinBoxExpandSize) |
|
664 |
ConfigurationDialog.setTabOrder(self.spinBoxExpandSize, self.spinBoxShrinkSize) |
|
665 |
ConfigurationDialog.setTabOrder(self.spinBoxShrinkSize, self.minTextSizeSpinBox) |
|
666 |
ConfigurationDialog.setTabOrder(self.minTextSizeSpinBox, self.maxTextSizeSpinBox) |
|
667 |
ConfigurationDialog.setTabOrder(self.maxTextSizeSpinBox, self.spinBoxMergeSize) |
|
668 |
ConfigurationDialog.setTabOrder(self.spinBoxMergeSize, self.lineEditSizeDelimiter) |
|
669 |
ConfigurationDialog.setTabOrder(self.lineEditSizeDelimiter, self.doubleSpinBoxDetectionRange) |
|
670 |
ConfigurationDialog.setTabOrder(self.doubleSpinBoxDetectionRange, self.spinBoxFlowMarkPosition) |
|
671 |
ConfigurationDialog.setTabOrder(self.spinBoxFlowMarkPosition, self.spinBoxFlowMarkLength) |
|
672 |
ConfigurationDialog.setTabOrder(self.spinBoxFlowMarkLength, self.spinBoxMinimumSize) |
|
673 |
ConfigurationDialog.setTabOrder(self.spinBoxMinimumSize, self.spinBoxUnrecognitionIgnoreStep) |
|
674 |
ConfigurationDialog.setTabOrder(self.spinBoxUnrecognitionIgnoreStep, self.spinBoxDilateSize) |
|
675 |
ConfigurationDialog.setTabOrder(self.spinBoxDilateSize, self.spinBoxFlatSize) |
|
676 |
ConfigurationDialog.setTabOrder(self.spinBoxFlatSize, self.radioButtonMode1) |
|
677 |
ConfigurationDialog.setTabOrder(self.radioButtonMode1, self.radioButtonMode2) |
|
678 |
ConfigurationDialog.setTabOrder(self.radioButtonMode2, self.spinBoxMinArea) |
|
679 |
ConfigurationDialog.setTabOrder(self.spinBoxMinArea, self.spinBoxMaxArea) |
|
680 |
ConfigurationDialog.setTabOrder(self.spinBoxMaxArea, self.spinBoxWidth) |
|
681 |
ConfigurationDialog.setTabOrder(self.spinBoxWidth, self.spinBoxHeight) |
|
682 |
ConfigurationDialog.setTabOrder(self.spinBoxHeight, self.smallLineMinLengthSpinBox) |
|
683 |
ConfigurationDialog.setTabOrder(self.smallLineMinLengthSpinBox, self.spinBoxLengthToConnectLine) |
|
684 |
ConfigurationDialog.setTabOrder(self.spinBoxLengthToConnectLine, self.comboBoxLineType) |
|
685 |
ConfigurationDialog.setTabOrder(self.comboBoxLineType, self.radioButtonDiagonalYes) |
|
686 |
ConfigurationDialog.setTabOrder(self.radioButtonDiagonalYes, self.radioButtonDiagonalNo) |
|
687 |
ConfigurationDialog.setTabOrder(self.radioButtonDiagonalNo, self.pushButtonLineNoAttribute) |
|
688 |
ConfigurationDialog.setTabOrder(self.pushButtonLineNoAttribute, self.pushButtonAddProperty) |
|
689 |
ConfigurationDialog.setTabOrder(self.pushButtonAddProperty, self.pushButtonDeleteProperty) |
|
690 |
ConfigurationDialog.setTabOrder(self.pushButtonDeleteProperty, self.listWidgetLineNo) |
|
691 |
ConfigurationDialog.setTabOrder(self.listWidgetLineNo, self.pushButtonTagNoAttribute) |
|
692 |
ConfigurationDialog.setTabOrder(self.pushButtonTagNoAttribute, self.pushButtonAddTagProperty) |
|
693 |
ConfigurationDialog.setTabOrder(self.pushButtonAddTagProperty, self.pushButtonDeleteTagProperty) |
|
694 |
ConfigurationDialog.setTabOrder(self.pushButtonDeleteTagProperty, self.listWidgetTagNo) |
|
695 |
ConfigurationDialog.setTabOrder(self.listWidgetTagNo, self.checkBoxNoteNoSymbolName) |
|
696 |
ConfigurationDialog.setTabOrder(self.checkBoxNoteNoSymbolName, self.lineEditNoteNoSymbolName) |
|
697 |
ConfigurationDialog.setTabOrder(self.lineEditNoteNoSymbolName, self.lineEditNoteNoExpression) |
|
698 |
ConfigurationDialog.setTabOrder(self.lineEditNoteNoExpression, self.lineEditOPCFromPrefix) |
|
699 |
ConfigurationDialog.setTabOrder(self.lineEditOPCFromPrefix, self.lineEditOPCToPrefix) |
|
700 |
ConfigurationDialog.setTabOrder(self.lineEditOPCToPrefix, self.lineEditByVendor) |
|
701 |
ConfigurationDialog.setTabOrder(self.lineEditByVendor, self.lineEditDrainSize) |
|
702 |
ConfigurationDialog.setTabOrder(self.lineEditDrainSize, self.lineEdit_2) |
|
650 | 703 |
ConfigurationDialog.setTabOrder(self.lineEdit_2, self.tableWidgetLineTypes) |
651 |
ConfigurationDialog.setTabOrder(self.tableWidgetLineTypes, self.tabWidget) |
|
704 |
ConfigurationDialog.setTabOrder(self.tableWidgetLineTypes, self.pushButtonInstrumentColor) |
|
705 |
ConfigurationDialog.setTabOrder(self.pushButtonInstrumentColor, self.pushButtonEquipColor) |
|
706 |
ConfigurationDialog.setTabOrder(self.pushButtonEquipColor, self.spinBoxSymbolOpacity) |
|
707 |
ConfigurationDialog.setTabOrder(self.spinBoxSymbolOpacity, self.fontComboBox) |
|
708 |
ConfigurationDialog.setTabOrder(self.fontComboBox, self.radioButtonAutoSize) |
|
709 |
ConfigurationDialog.setTabOrder(self.radioButtonAutoSize, self.radioButtonFixedSize) |
|
710 |
ConfigurationDialog.setTabOrder(self.radioButtonFixedSize, self.spinBoxFontSize) |
|
711 |
ConfigurationDialog.setTabOrder(self.spinBoxFontSize, self.radioButtonRandom) |
|
712 |
ConfigurationDialog.setTabOrder(self.radioButtonRandom, self.radioButtonProperty) |
|
713 |
ConfigurationDialog.setTabOrder(self.radioButtonProperty, self.comboBoxColorOption) |
|
714 |
ConfigurationDialog.setTabOrder(self.comboBoxColorOption, self.tableWidgetColorProperty) |
|
715 |
ConfigurationDialog.setTabOrder(self.tableWidgetColorProperty, self.radioButtonLoadXmlYes) |
|
716 |
ConfigurationDialog.setTabOrder(self.radioButtonLoadXmlYes, self.radioButtonLoadXmlNo) |
|
717 |
ConfigurationDialog.setTabOrder(self.radioButtonLoadXmlNo, self.radioButtonSaveUnknownYes) |
|
718 |
ConfigurationDialog.setTabOrder(self.radioButtonSaveUnknownYes, self.radioButtonSaveUnknownNo) |
|
719 |
ConfigurationDialog.setTabOrder(self.radioButtonSaveUnknownNo, self.pushButtonClearAccessInfo) |
|
720 |
ConfigurationDialog.setTabOrder(self.pushButtonClearAccessInfo, self.radioButtonBackTextYes) |
|
721 |
ConfigurationDialog.setTabOrder(self.radioButtonBackTextYes, self.radioButtonBackTextNo) |
|
722 |
ConfigurationDialog.setTabOrder(self.radioButtonBackTextNo, self.tabWidget) |
|
652 | 723 |
|
653 | 724 |
def retranslateUi(self, ConfigurationDialog): |
654 | 725 |
_translate = QtCore.QCoreApplication.translate |
... | ... | |
662 | 733 |
self.radioButtonMode1.setText(_translate("ConfigurationDialog", "Default")) |
663 | 734 |
self.radioButtonMode2.setText(_translate("ConfigurationDialog", "Advanced")) |
664 | 735 |
self.groupBoxText.setTitle(_translate("ConfigurationDialog", "Text Detection")) |
665 |
self.label_18.setText(_translate("ConfigurationDialog", "Maximum Text Size : ")) |
|
666 |
self.label_17.setText(_translate("ConfigurationDialog", "Minimum Text Size : ")) |
|
667 | 736 |
self.label_21.setText(_translate("ConfigurationDialog", "Erosion Size : ")) |
737 |
self.label_17.setText(_translate("ConfigurationDialog", "Minimum Text Size : ")) |
|
738 |
self.label_18.setText(_translate("ConfigurationDialog", "Maximum Text Size : ")) |
|
668 | 739 |
self.label_19.setText(_translate("ConfigurationDialog", "OCR Source : ")) |
669 |
self.label_7.setText(_translate("ConfigurationDialog", "Detected string : ")) |
|
670 | 740 |
self.label_20.setText(_translate("ConfigurationDialog", "Expansion Size : ")) |
741 |
self.label_7.setText(_translate("ConfigurationDialog", "Detected string : ")) |
|
671 | 742 |
self.label_37.setText(_translate("ConfigurationDialog", "Allowed Single Text : ")) |
672 | 743 |
self.label_22.setText(_translate("ConfigurationDialog", "Merge Size : ")) |
744 |
self.label_39.setText(_translate("ConfigurationDialog", "Page segmentations modes")) |
|
745 |
self.labelTesseractVersion.setText(_translate("ConfigurationDialog", "TextLabel")) |
|
673 | 746 |
self.groupBoxAttribute.setTitle(_translate("ConfigurationDialog", "Attribute")) |
674 | 747 |
self.label_6.setText(_translate("ConfigurationDialog", "Size Delimiter : ")) |
675 | 748 |
self.label_24.setText(_translate("ConfigurationDialog", "Line Flow Mark Position(Percent) : ")) |
DTI_PID/DTI_PID/LineDetector.py | ||
---|---|---|
582 | 582 |
|
583 | 583 |
return None |
584 | 584 |
|
585 |
def detectLineWithoutSymbol(self, area): # path, offsetX, offsetY):
|
|
585 |
def detectLineWithoutSymbol(self): # path, offsetX, offsetY): |
|
586 | 586 |
''' |
587 | 587 |
@brief detect remain line after detection using symbol info |
588 | 588 |
@author euisung |
... | ... | |
593 | 593 |
from HoughBundler import HoughBundler |
594 | 594 |
|
595 | 595 |
docData = AppDocData.instance() |
596 |
img = area.img |
|
597 | 596 |
|
598 | 597 |
if True: |
599 | 598 |
imgNot = np.ones(self._image.shape, np.uint8) * 255 |
DTI_PID/DTI_PID/MainWindow.py | ||
---|---|---|
2350 | 2350 |
svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg') |
2351 | 2351 |
if os.path.isfile(svgFilePath): |
2352 | 2352 |
svg = SymbolSvgItem.createItem(_type, None, svgFilePath, owner=None, flip=flip) |
2353 |
svg.hit_ratio = symbol.hitRate |
|
2353 | 2354 |
svg.buildItem(name, _type, angle, pt, size, origin, connPts, parentSymbol, childSymbol, |
2354 | 2355 |
hasInstrumentLabel) |
2355 | 2356 |
svg.reCalculationRotatedItem() |
DTI_PID/DTI_PID/OPCRelationDialog.py | ||
---|---|---|
11 | 11 |
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\UI') |
12 | 12 |
import OPCRelation_UI |
13 | 13 |
|
14 |
|
|
14 | 15 |
class QOPCRelationDialog(QDialog): |
15 | 16 |
""" This OPC Relation dialog class """ |
16 | 17 |
|
... | ... | |
31 | 32 |
from AppDocData import AppDocData |
32 | 33 |
|
33 | 34 |
self.ui.tableWidgetSource.setColumnCount(6) |
34 |
self.ui.tableWidgetSource.setHorizontalHeaderLabels([self.tr('Drawing'), self.tr('Line No'), self.tr('OPC'), self.tr('Drawing'), self.tr('Line No'), self.tr('OPC')]) |
|
35 |
self.ui.tableWidgetSource.setHorizontalHeaderLabels( |
|
36 |
[self.tr('Drawing'), self.tr('Line No'), self.tr('OPC'), self.tr('Drawing'), self.tr('Line No'), |
|
37 |
self.tr('OPC')]) |
|
35 | 38 |
self.ui.tableWidgetSource.horizontalHeaderItem(0).setSizeHint(QSize(25, 25)) |
36 | 39 |
self.ui.tableWidgetSource.verticalHeader().hide() |
37 | 40 |
self.ui.tableWidgetSource.horizontalHeader().setStretchLastSection(True) |
... | ... | |
79 | 82 |
target_opc = item.text() if item else None |
80 | 83 |
self.ui.tableWidgetTarget.setRowCount(0) |
81 | 84 |
if self._opcs: |
82 |
opcs = [opc for opc in self._opcs if opc['Drawing'] != drawing and opc['Line No'] == line_no and opc['OPC'] != target_opc] |
|
85 |
opcs = [opc for opc in self._opcs if |
|
86 |
opc['Drawing'] != drawing and opc['Line No'] == line_no and opc['OPC'] != target_opc] |
|
83 | 87 |
self.ui.tableWidgetTarget.setRowCount(len(opcs)) |
84 | 88 |
row = 0 |
85 | 89 |
for opc in opcs: |
... | ... | |
122 | 126 |
""" assign target opc with double clicked item """ |
123 | 127 |
current = self.ui.tableWidgetSource.currentItem() |
124 | 128 |
if current: |
125 |
self.ui.tableWidgetSource.item(current.row(), 3).setText(self.ui.tableWidgetTarget.item(item.row(), 0).text()) |
|
126 |
self.ui.tableWidgetSource.item(current.row(), 4).setText(self.ui.tableWidgetTarget.item(item.row(), 1).text()) |
|
127 |
self.ui.tableWidgetSource.item(current.row(), 5).setText(self.ui.tableWidgetTarget.item(item.row(), 2).text()) |
|
129 |
self.ui.tableWidgetSource.item(current.row(), 3).setText( |
|
130 |
self.ui.tableWidgetTarget.item(item.row(), 0).text()) |
|
131 |
self.ui.tableWidgetSource.item(current.row(), 4).setText( |
|
132 |
self.ui.tableWidgetTarget.item(item.row(), 1).text()) |
|
133 |
self.ui.tableWidgetSource.item(current.row(), 5).setText( |
|
134 |
self.ui.tableWidgetTarget.item(item.row(), 2).text()) |
|
128 | 135 |
|
129 | 136 |
def eventFilter(self, source, event): |
130 | 137 |
""" display mouse position of graphics view """ |
... | ... | |
144 | 151 |
|
145 | 152 |
except Exception as ex: |
146 | 153 |
from App import App |
147 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
154 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
155 |
sys.exc_info()[-1].tb_lineno) |
|
148 | 156 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
149 | 157 |
|
150 | 158 |
def accept(self): |
... | ... | |
165 | 173 |
to_line_no = self.ui.tableWidgetSource.item(row, 4).text() |
166 | 174 |
to_opc = self.ui.tableWidgetSource.item(row, 5).text() |
167 | 175 |
opcs.append([from_drawing, from_line_no, from_opc, to_drawing, to_line_no, to_opc]) |
168 |
|
|
176 |
|
|
169 | 177 |
app_doc_data.save_opc_relations(opcs) |
170 | 178 |
|
171 | 179 |
QDialog.accept(self) |
172 | 180 |
except Exception as ex: |
173 | 181 |
from App import App |
174 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
182 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
183 |
sys.exc_info()[-1].tb_lineno) |
|
175 | 184 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
176 | 185 |
finally: |
177 |
QApplication.restoreOverrideCursor() |
|
186 |
QApplication.restoreOverrideCursor() |
DTI_PID/DTI_PID/OcrResultDialog.py | ||
---|---|---|
63 | 63 |
self.ui.setupUi(self) |
64 | 64 |
self.ui.detectResultTextEdit = SpellTextEdit() |
65 | 65 |
self.ui.detectResultTextEdit.setFont(QFont('Consolas', 15, QFont.Bold)) |
66 |
self.ui.horizontalLayoutTextEdit.addWidget(self.ui.detectResultTextEdit) |
|
66 |
self.ui.horizontalLayoutTextEdit.addWidget(self.ui.detectResultTextEdit, 0)
|
|
67 | 67 |
|
68 | 68 |
appDocData = AppDocData.instance() |
69 | 69 |
configs = appDocData.getAppConfigs('app', 'mode') |
... | ... | |
80 | 80 |
self.graphicsView.setImage(self.image) |
81 | 81 |
self.graphicsView.zoomImage(False, event=None) |
82 | 82 |
self.ui.horizontalLayoutGraphicsView.addWidget(self.graphicsView) |
83 |
self.setLayout(self.ui.horizontalLayoutGraphicsView) |
|
83 | 84 |
|
84 | 85 |
self.ui.counterClockPushButton_2.clicked.connect(lambda: self.rotateImage(True)) |
85 | 86 |
self.ui.clockPushButton_2.clicked.connect(lambda: self.rotateImage(False)) |
DTI_PID/DTI_PID/RecognitionDialog.py | ||
---|---|---|
338 | 338 |
pool.shutdown(wait=True) |
339 | 339 |
# up to here |
340 | 340 |
|
341 |
pool = futures.ThreadPoolExecutor(max_workers=THREAD_MAX_WORKER) |
|
342 |
for symbol in targetSymbolList[2]: |
|
343 |
if type(symbol) is list: |
|
344 |
pool.submit(Worker.detectSymbolsOnPid, mainRes, symbol, listWidget, worker) |
|
345 |
else: |
|
346 |
pool.submit(Worker.detectSymbolOnPid, mainRes, symbol, listWidget, worker) |
|
347 |
pool.shutdown(wait=True) |
|
341 |
with futures.ThreadPoolExecutor(max_workers=THREAD_MAX_WORKER) as pool: |
|
342 |
future_symbol = {pool.submit(Worker.detectSymbolsOnPid, mainRes, symbol, listWidget, worker): |
|
343 |
symbol for symbol in targetSymbolList[2]} |
|
344 |
futures.wait(future_symbol) |
|
348 | 345 |
|
349 | 346 |
if worker.isTrainingChecked: |
350 | 347 |
import uuid |
... | ... | |
362 | 359 |
continue |
363 | 360 |
|
364 | 361 |
pool = futures.ThreadPoolExecutor(max_workers=THREAD_MAX_WORKER) |
365 |
|
|
366 | 362 |
searchedTextSymList = [] |
367 | 363 |
for sym in searchedSymbolList: |
368 |
""" |
|
369 |
if sym.getHasInstrumentLabel() >= 1: |
|
370 |
searchedTextSymList.append(sym) |
|
371 |
continue |
|
372 |
""" |
|
373 | 364 |
pool.submit(Worker.remove_detected_symbol_image, sym, app_doc_data.imgSrc) |
374 | 365 |
pool.shutdown(wait=True) |
375 | 366 |
else: |
... | ... | |
449 | 440 |
titleBlockTextInfoList = None |
450 | 441 |
textInfoList = [] |
451 | 442 |
if worker.isTextChecked: |
452 |
textAreas = textDetector.detectTextAreas(area.img if area is not None else app_doc_data.imgSrc, |
|
443 |
textAreas, ocr_image = textDetector.detectTextAreas(area.img if area is not None else app_doc_data.imgSrc,
|
|
453 | 444 |
offset) |
454 | 445 |
if maxProgressValue < 2 * len(textAreas): |
455 | 446 |
for _ in range(len(textAreas) - int(maxProgressValue * 0.5)): |
... | ... | |
459 | 450 |
maxProgressValue = int(maxProgressValue * 0.5) + len(textAreas) |
460 | 451 |
|
461 | 452 |
worker.displayTitle.emit(worker.tr('Detecting texts...')) |
462 |
textDetector.recognizeText(app_doc_data.imgSrc, (0, 0), textAreas, searchedSymbolList, worker,
|
|
453 |
textDetector.recognizeText(ocr_image, offset, textAreas, searchedSymbolList, worker,
|
|
463 | 454 |
listWidget, maxProgressValue) |
464 | 455 |
textInfoList = textDetector.textInfoList.copy() if textDetector.textInfoList is not None else None |
465 | 456 |
otherTextInfoList = textDetector.otherTextInfoList.copy() if textDetector.otherTextInfoList is not None else None |
... | ... | |
699 | 690 |
# line detection without symbol connection point info |
700 | 691 |
configs = app_doc_data.getConfigs('Line', 'Diagonal') |
701 | 692 |
if configs and int(configs[0].value) is 1: |
702 |
remainLines = detector.detectLineWithoutSymbol(area)
|
|
693 |
remainLines = detector.detectLineWithoutSymbol() |
|
703 | 694 |
windowSize = app_doc_data.getSlidingWindowSize() |
704 | 695 |
thickness = int(windowSize[1]) |
705 | 696 |
for line in remainLines: |
... | ... | |
1581 | 1572 |
|
1582 | 1573 |
@staticmethod |
1583 | 1574 |
def detectSymbolsOnPid(mainRes, targetSymbols, listWidget, updateProgressSignal): |
1584 |
for detailTarget in targetSymbols: |
|
1585 |
Worker.detectSymbolOnPid(mainRes, detailTarget, listWidget, updateProgressSignal) |
|
1575 |
if type(targetSymbols) is list: |
|
1576 |
for detailTarget in targetSymbols: |
|
1577 |
Worker.detectSymbolOnPid(mainRes, detailTarget, listWidget, updateProgressSignal) |
|
1578 |
else: |
|
1579 |
Worker.detectSymbolOnPid(mainRes, targetSymbols, listWidget, updateProgressSignal) |
|
1586 | 1580 |
|
1587 | 1581 |
@staticmethod |
1588 | 1582 |
def convertDirectionCodeToValue(directionCode): |
... | ... | |
1683 | 1677 |
@staticmethod |
1684 | 1678 |
def remove_detected_symbol_image(sym, imgSrc): |
1685 | 1679 |
"""remove detected symbol image from drawing image""" |
1686 |
global ocrCompletedSrc |
|
1687 | 1680 |
global threadLock |
1688 | 1681 |
|
1689 | 1682 |
path = sym.getPath() |
DTI_PID/DTI_PID/Shapes/SymbolSvgItem.py | ||
---|---|---|
57 | 57 |
self.childSymbol = '' |
58 | 58 |
self.hasInstrumentLabel = 0 |
59 | 59 |
self.flip = flip |
60 |
self.hit_ratio = None |
|
60 | 61 |
# attributeType uid |
61 | 62 |
self.attribute = '' |
62 | 63 |
self._properties = {SymbolProp(None, 'Supplied By', 'String'): None} |
... | ... | |
648 | 649 |
self.currentPointModeIndex = 0 |
649 | 650 |
self.special_item_type = SpecialItemTypes.instance().find_match_exactly(self) |
650 | 651 |
|
651 |
tooltip = '<b>{}</b><br>{}={}'.format(str(self.uid), self.type, self.name) |
|
652 |
tooltip = f"<b>{str(self.uid)}</b><br>{self.type}={self.name}" |
|
653 |
if self.hit_ratio: |
|
654 |
tooltip += f"<br><li>recognition ratio={self.hit_ratio}" |
|
652 | 655 |
self.setToolTip(tooltip) |
653 | 656 |
|
654 | 657 |
return True |
DTI_PID/DTI_PID/SymbolTreeWidget.py | ||
---|---|---|
72 | 72 |
editSymbolAction = QAction(self.tr("Edit Symbol")) |
73 | 73 |
editSymbolAction.triggered.connect(lambda: self.editSymbolActionClickEvent(item, 0)) |
74 | 74 |
menu.addAction(editSymbolAction) |
75 |
editDisplaySymbolAction = QAction(self.tr("Edit Symbol for Dispay")) |
|
75 |
editDisplaySymbolAction = QAction(self.tr("Edit Symbol for Display"))
|
|
76 | 76 |
editDisplaySymbolAction.triggered.connect(lambda: self.editDisplaySymbolActionClickEvent(item, 0)) |
77 | 77 |
menu.addAction(editDisplaySymbolAction) |
78 | 78 |
displaySymbolAction = QAction(self.tr("Display Symbol")) |
... | ... | |
200 | 200 |
try: |
201 | 201 |
app_doc_data = AppDocData.instance() |
202 | 202 |
|
203 |
symbolTypeList = AppDocData.instance().getSymbolTypeList()
|
|
203 |
symbolTypeList = app_doc_data.getSymbolTypeList()
|
|
204 | 204 |
for symbolType in symbolTypeList: |
205 | 205 |
if not symbolType[1]: continue # skip if category is empty |
206 | 206 |
parent = QTreeWidgetItem(self, [symbolType[2]]) |
207 | 207 |
parent.setData(0, self.TREE_DATA_ROLE, symbolType) |
208 |
symbolList = AppDocData.instance().getSymbolListByType('UID', symbolType[0])
|
|
208 |
symbolList = app_doc_data.getSymbolListByType('UID', symbolType[0])
|
|
209 | 209 |
for symbol in symbolList: |
210 | 210 |
symbolItem = QTreeWidgetItem(parent, [symbol.getName()]) |
211 | 211 |
symbolItem.setData(0, self.TREE_DATA_ROLE, symbol) |
DTI_PID/DTI_PID/TextDetector.py | ||
---|---|---|
38 | 38 |
''' |
39 | 39 |
|
40 | 40 |
def detectTextAreas(self, img, offset): |
41 |
tInfoList = [] |
|
42 | 41 |
try: |
43 |
tInfoList = self.getTextAreaInfo(img, offset[0], offset[1])
|
|
42 |
return self.getTextAreaInfo(img, offset[0], offset[1])
|
|
44 | 43 |
except Exception as ex: |
45 | 44 |
print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
46 | 45 |
sys.exc_info()[-1].tb_lineno)) |
47 | 46 |
|
48 |
return tInfoList
|
|
47 |
return None, None
|
|
49 | 48 |
|
50 | 49 |
''' |
51 | 50 |
@brief Get Text Area info by contour |
... | ... | |
58 | 57 |
def getTextAreaInfo(self, imgGray, offsetX, offsetY): |
59 | 58 |
from AppDocData import AppDocData |
60 | 59 |
|
61 |
appDocData = AppDocData.instance()
|
|
62 |
project = appDocData.getCurrentProject()
|
|
60 |
app_doc_data = AppDocData.instance()
|
|
61 |
project = app_doc_data.getCurrentProject()
|
|
63 | 62 |
|
64 |
configs = appDocData.getConfigs('Text Size', 'Max Text Size')
|
|
63 |
configs = app_doc_data.getConfigs('Text Size', 'Max Text Size')
|
|
65 | 64 |
maxTextSize = int(configs[0].value) if 1 == len(configs) else 100 |
66 | 65 |
minSize = 5 |
67 | 66 |
|
68 |
contourImg = np.ones(imgGray.shape, np.uint8) * 255
|
|
67 |
ocr_image = np.ones(imgGray.shape, np.uint8) * 255
|
|
69 | 68 |
binaryImg, mask = cv2.threshold(imgGray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU) |
70 | 69 |
|
71 | 70 |
contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) |
... | ... | |
76 | 75 |
|
77 | 76 |
# skip one which size is greater than max size or less then minimum size |
78 | 77 |
if area >= 0: |
79 |
if (w > maxTextSize or h > maxTextSize) or (w <= minSize and h <= minSize): continue |
|
78 |
if (w > maxTextSize or h > maxTextSize) or (w <= minSize and h <= minSize): |
|
79 |
continue |
|
80 | 80 |
|
81 | 81 |
if area >= 0: |
82 |
cv2.drawContours(contourImg, [contour], -1, (0, 0, 0), -1)
|
|
83 |
cv2.drawContours(contourImg, [contour], -1, (255, 255, 255), 1)
|
|
82 |
cv2.drawContours(ocr_image, [contour], -1, (0, 0, 0), -1)
|
|
83 |
cv2.drawContours(ocr_image, [contour], -1, (255, 255, 255), 1)
|
|
84 | 84 |
else: |
85 |
cv2.drawContours(contourImg, [contour], -1, (255, 255, 255), -1)
|
|
85 |
cv2.drawContours(ocr_image, [contour], -1, (255, 255, 255), -1)
|
|
86 | 86 |
|
87 |
path = os.path.join(project.getTempPath(), 'OCR_{}.png'.format(appDocData.imgName))
|
|
88 |
cv2.imwrite(path, contourImg)
|
|
87 |
path = os.path.join(project.getTempPath(), 'OCR_{}.png'.format(app_doc_data.imgName))
|
|
88 |
cv2.imwrite(path, ocr_image)
|
|
89 | 89 |
|
90 | 90 |
rects = [] |
91 |
configs = appDocData.getConfigs('Text Recognition', 'Expand Size')
|
|
91 |
configs = app_doc_data.getConfigs('Text Recognition', 'Expand Size')
|
|
92 | 92 |
expandSize = int(configs[0].value) if 1 == len(configs) else 10 |
93 |
configs = appDocData.getConfigs('Text Recognition', 'Shrink Size')
|
|
93 |
configs = app_doc_data.getConfigs('Text Recognition', 'Shrink Size')
|
|
94 | 94 |
shrinkSize = int(configs[0].value) if 1 == len(configs) else 0 |
95 | 95 |
|
96 |
eroded = cv2.erode(contourImg, np.ones((expandSize, expandSize), np.uint8)) |
|
97 |
# path = os.path.join(project.getTempPath(), 'ERODED_OCR_{}.png'.format(appDocData.imgName)) |
|
98 |
# cv2.imwrite(path, eroded) |
|
99 |
|
|
96 |
eroded = cv2.erode(ocr_image, np.ones((expandSize, expandSize), np.uint8)) |
|
100 | 97 |
eroded = cv2.bitwise_not(eroded) |
101 |
# path = os.path.join(project.getTempPath(), 'bitwise_not_{}.png'.format(appDocData.imgName)) |
|
102 |
# cv2.imwrite(path, eroded) |
|
103 | 98 |
|
99 |
bboxes = [] |
|
104 | 100 |
contours, hierarchy = cv2.findContours(eroded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
105 | 101 |
for contour in contours: |
106 | 102 |
area = cv2.contourArea(contour, True) |
107 | 103 |
if area < 0: |
108 | 104 |
[x, y, w, h] = cv2.boundingRect(contour) |
109 |
|
|
110 |
img = contourImg[y:y + h, x:x + w] |
|
111 |
img = cv2.bitwise_not(img)
|
|
112 |
|
|
113 |
horizontal, max_width = 0, 0
|
|
114 |
vertical, max_height = 0, 0
|
|
115 |
_contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
|
|
116 |
for xx in _contours:
|
|
117 |
[_x, _y, _w, _h] = cv2.boundingRect(xx)
|
|
118 |
cv2.rectangle(img, (_x, _y), (_x + _w, _y + _h), 255, 1) |
|
119 |
|
|
120 |
max_width = _x if _x > max_width else max_width
|
|
121 |
max_height = _y if _y > max_height else max_height
|
|
122 |
|
|
123 |
if (_w < _h) or (_w > maxTextSize and _h < maxTextSize): # width is greater than height
|
|
124 |
horizontal += 1 + (_w * _h) / (w * h) |
|
125 |
else:
|
|
126 |
vertical += 1 + (_w * _h) / (w * h)
|
|
127 |
|
|
128 |
if (w < 10 and h < 10) or (
|
|
129 |
max_width > maxTextSize and max_height > maxTextSize): continue; # skip too small or big one
|
|
130 |
|
|
131 |
"""
|
|
132 |
if w > maxTextSize:
|
|
133 |
horizontal = 1 |
|
134 |
elif h > maxTextSize:
|
|
135 |
vertical = 1
|
|
105 |
bboxes.append(QRect(x, y, w, h)) |
|
106 |
|
|
107 |
# exclude bounding boxes contains child bounding box
|
|
108 |
not_containing_bbox = [] |
|
109 |
for bbox in bboxes:
|
|
110 |
matches = [_bbox for _bbox in bboxes if bbox != _bbox and bbox.contains(_bbox)]
|
|
111 |
if not matches:
|
|
112 |
not_containing_bbox.append(bbox)
|
|
113 |
# up to here
|
|
114 |
|
|
115 |
for bbox in not_containing_bbox: |
|
116 |
x, y = bbox.left(), bbox.top()
|
|
117 |
w, h = bbox.width(), bbox.height()
|
|
118 |
img = ocr_image[bbox.top():bbox.bottom(), bbox.left():bbox.right()] |
|
119 |
img = cv2.bitwise_not(img)
|
|
120 |
|
|
121 |
horizontal, max_width = 0, 0
|
|
122 |
vertical, max_height = 0, 0
|
|
123 |
_contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
|
124 |
for xx in _contours:
|
|
125 |
[_x, _y, _w, _h] = cv2.boundingRect(xx)
|
|
126 |
|
|
127 |
max_width = _x if _x > max_width else max_width
|
|
128 |
max_height = _y if _y > max_height else max_height
|
|
129 |
|
|
130 |
if (_w < _h) or (_w > maxTextSize > _h): # width is greater than height
|
|
131 |
horizontal += 1 + (_w * _h) / (w * h)
|
|
136 | 132 |
else: |
137 |
if shrinkSize > 0: |
|
138 |
img = cv2.erode(img, np.ones((shrinkSize,shrinkSize), np.uint8)) |
|
133 |
vertical += 1 + (_w * _h) / (w * h) |
|
139 | 134 |
|
140 |
_contours, _ = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) |
|
141 |
for xx in _contours: |
|
142 |
[_x, _y, _w, _h] = cv2.boundingRect(xx) |
|
143 |
cv2.rectangle(img, (_x, _y), (_x+_w, _y+_h), 255, 1) |
|
135 |
if (w < minSize and h < minSize) or (max_width > maxTextSize and max_height > maxTextSize): |
|
136 |
continue # skip too small or big one |
|
144 | 137 |
|
145 |
if (_w < _h) or (_w > maxTextSize and _h < maxTextSize): # width is greater than height |
|
146 |
horizontal += 1 + (_w*_h)/(w*h) |
|
147 |
else: |
|
148 |
vertical += 1 + (_w*_h)/(w*h) |
|
149 |
""" |
|
150 |
|
|
151 |
""" |
|
152 |
if horizontal > vertical: |
|
153 |
filePath = os.path.join(project.getTempPath(), "Tile", "H-{}-{}-{}-{}.png".format(x,y,w,h)) |
|
154 |
else: |
|
155 |
filePath = os.path.join(project.getTempPath(), "Tile", "V-{}-{}-{}-{}.png".format(x,y,w,h)) |
|
156 |
cv2.imwrite(filePath, img) |
|
157 |
""" |
|
138 |
rects.append([0 if horizontal > vertical else 90, QRect(x, y, w, h)]) |
|
158 | 139 |
|
159 |
rects.append([0 if horizontal > vertical else 90, QRect(x, y, w, h)]) |
|
160 |
|
|
161 |
configs = appDocData.getConfigs('Text Recognition', 'Merge Size') |
|
140 |
configs = app_doc_data.getConfigs('Text Recognition', 'Merge Size') |
|
162 | 141 |
mergeSize = int(configs[0].value) if 1 == len(configs) else 10 |
163 | 142 |
# merge rectangles |
164 |
intersected = True |
|
165 |
while intersected: |
|
166 |
intersected = False |
|
167 |
for rect in rects[:]: # clone rects |
|
168 |
if 0 == rect[0]: |
|
169 |
rectExpand = rect[1].adjusted(-mergeSize, 0, mergeSize, 0) |
|
170 |
else: |
|
171 |
rectExpand = rect[1].adjusted(0, -mergeSize, 0, mergeSize) |
|
172 |
|
|
173 |
matches = [x for x in rects if (x[0] == rect[0]) and rectExpand.intersects(x[1])] |
|
174 |
if len(matches) > 1: |
|
175 |
united = matches[0] |
|
176 |
for _rect in matches: |
|
177 |
united[1] = united[1].united(_rect[1]) |
|
178 |
if _rect in rects: rects.remove(_rect) |
|
179 |
rects.append(united) |
|
180 |
intersected = True |
|
181 |
break |
|
143 |
interestings = [] |
|
144 |
while rects: |
|
145 |
rect = rects.pop() |
|
146 |
|
|
147 |
if 0 == rect[0]: # x-direction text |
|
148 |
rectExpand = rect[1].adjusted(-mergeSize, 0, mergeSize, 0) |
|
149 |
matches = [x for x in rects if (x[0] == rect[0]) and |
|
150 |
abs(x[1].height() - rect[1].height()) < (x[1].height() + rect[1].height())*0.5 and |
|
151 |
abs(x[1].center().y() - rect[1].center().y()) < rect[1].height()*0.5 and |
|
152 |
rectExpand.intersects(x[1])] |
|
153 |
else: # y -direction text |
|
154 |
rectExpand = rect[1].adjusted(0, -mergeSize, 0, mergeSize) |
|
155 |
matches = [x for x in rects if (x[0] == rect[0]) and |
|
156 |
abs(x[1].width() - rect[1].width()) < (x[1].width() + rect[1].width())*0.5 and |
|
157 |
abs(x[1].center().x() - rect[1].center().x()) < rect[1].width()*0.5 and |
|
158 |
rectExpand.intersects(x[1])] |
|
159 |
|
|
160 |
if matches: |
|
161 |
for _rect in matches: |
|
162 |
rect[1] = rect[1].united(_rect[1]) |
|
163 |
if _rect in rects: |
|
164 |
rects.remove(_rect) |
|
165 |
rects.append(rect) |
|
166 |
else: |
|
167 |
interestings.append(rect) |
|
182 | 168 |
|
183 | 169 |
list = [] |
184 |
for rect in rects:
|
|
170 |
for rect in interestings:
|
|
185 | 171 |
angle = rect[0] |
186 | 172 |
list.append(ti.TextInfo('', round(offsetX) + rect[1].x(), round(offsetY) + rect[1].y(), rect[1].width(), |
187 | 173 |
rect[1].height(), angle)) |
188 | 174 |
|
189 |
x = rect[1].x() |
|
190 |
y = rect[1].y() |
|
191 |
w = rect[1].width() |
|
192 |
h = rect[1].height() |
|
193 |
img = contourImg[y:y + h, x:x + w] |
|
194 |
## DEBUG |
|
195 |
# if angle == 0: |
|
196 |
# filePath = os.path.join(project.getTempPath(), "Tile", "H-{}-{}-{}-{}.png".format(x,y,w,h)) |
|
197 |
# else: |
|
198 |
# filePath = os.path.join(project.getTempPath(), "Tile", "V-{}-{}-{}-{}.png".format(x,y,w,h)) |
|
199 |
# cv2.imwrite(filePath, img) |
|
200 |
## up to here |
|
201 |
|
|
202 |
return list |
|
175 |
return list, ocr_image |
|
203 | 176 |
|
204 | 177 |
''' |
205 | 178 |
@brief recognize text of given text info |
... | ... | |
300 | 273 |
project = app_doc_data.getCurrentProject() |
301 | 274 |
|
302 | 275 |
text_info_array = np.array_split(tInfoList, THREAD_MAX_WORKER) |
303 |
pool = futures.ThreadPoolExecutor(max_workers=THREAD_MAX_WORKER) |
|
304 |
for tInfo in text_info_array: |
|
276 |
with futures.ThreadPoolExecutor(max_workers=THREAD_MAX_WORKER) as pool: |
|
277 |
future_text = {pool.submit(TextDetector.recognizeTextFromImage, tInfo, imgSrc, offset, |
|
278 |
searchedSymbolList, worker, listWidget, maxProgressValue): |
|
279 |
tInfo for tInfo in text_info_array} |
|
280 |
""" |
|
305 | 281 |
future = pool.submit(TextDetector.recognizeTextFromImage, tInfo, imgSrc, offset, |
306 | 282 |
searchedSymbolList, worker, listWidget, maxProgressValue) |
307 |
data = future.result() |
|
308 |
if data: |
|
309 |
self.textInfoList.extend(data) |
|
310 |
pool.shutdown(wait=True) |
|
283 |
""" |
|
284 |
for future in futures.as_completed(future_text): |
|
285 |
try: |
|
286 |
data = future.result() |
|
287 |
if data: |
|
288 |
self.textInfoList.extend(data) |
|
289 |
except Exception as ex: |
|
290 |
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
291 |
sys.exc_info()[-1].tb_lineno) |
|
292 |
worker.displayLog.emit(MessageType.Error, message) |
|
311 | 293 |
|
312 | 294 |
if onlyTextArea: |
313 | 295 |
return |
... | ... | |
325 | 307 |
conf=whiteCharList[0].value) |
326 | 308 |
self.otherTextInfoList.append([area.name, texts]) |
327 | 309 |
else: |
328 |
img = imgSrc[round(area.y):round(area.y + area.height), |
|
310 |
img = app_doc_data.imgSrc[round(area.y):round(area.y + area.height),
|
|
329 | 311 |
round(area.x):round(area.x + area.width)] |
330 | 312 |
if len(whiteCharList) is 0: |
331 | 313 |
texts = TOCR.getTextInfo(img, (area.x, area.y), 0, language='eng') |
... | ... | |
343 | 325 |
area = Area(titleBlockProp[0]) |
344 | 326 |
area.parse(titleBlockProp[2]) |
345 | 327 |
if not (titleBlockProp[3] and titleBlockProp[3] != ''): |
346 |
img = imgSrc[round(area.y):round(area.y + area.height), |
|
328 |
img = app_doc_data.imgSrc[round(area.y):round(area.y + area.height),
|
|
347 | 329 |
round(area.x):round(area.x + area.width)] |
348 | 330 |
if len(whiteCharList) is 0: |
349 | 331 |
texts = TOCR.getTextInfo(img, (area.x, area.y), 0, language=app_doc_data.OCRData) |
... | ... | |
357 | 339 |
self.titleBlockTextInfoList.append([area.name, texts]) |
358 | 340 |
|
359 | 341 |
if worker is not None: worker.updateProgress.emit(maxProgressValue, None) |
342 |
|
|
343 |
""" |
|
344 |
for text_box in tInfoList: |
|
345 |
x = text_box.getX() |
|
346 |
y = text_box.getY() |
|
347 |
cv2.rectangle(imgSrc, (x - offset[0], y - offset[1]), |
|
348 |
(x - offset[0] + text_box.getW(), y - offset[1] + text_box.getH()), 1, 1) |
|
349 |
cv2.imwrite('c:\\Temp\\text_box.png', imgSrc) |
|
350 |
""" |
|
360 | 351 |
except Exception as ex: |
361 | 352 |
message = 'error occurred({}) in {}:{}'.format(repr(ex), sys.exc_info()[-1].tb_frame.f_code.co_filename, |
362 | 353 |
sys.exc_info()[-1].tb_lineno) |
DTI_PID/DTI_PID/UI/Configuration.ui | ||
---|---|---|
6 | 6 |
<rect> |
7 | 7 |
<x>0</x> |
8 | 8 |
<y>0</y> |
9 |
<width>632</width>
|
|
10 |
<height>616</height>
|
|
9 |
<width>648</width>
|
|
10 |
<height>631</height>
|
|
11 | 11 |
</rect> |
12 | 12 |
</property> |
13 | 13 |
<property name="font"> |
... | ... | |
166 | 166 |
<layout class="QGridLayout" name="gridLayout_14"> |
167 | 167 |
<item row="0" column="0"> |
168 | 168 |
<layout class="QGridLayout" name="gridLayout_25"> |
169 |
<item row="4" column="3">
|
|
170 |
<widget class="QSpinBox" name="maxTextSizeSpinBox">
|
|
169 |
<item row="5" column="1">
|
|
170 |
<widget class="QSpinBox" name="minTextSizeSpinBox">
|
|
171 | 171 |
<property name="sizePolicy"> |
172 | 172 |
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> |
173 | 173 |
<horstretch>0</horstretch> |
174 | 174 |
<verstretch>0</verstretch> |
175 | 175 |
</sizepolicy> |
176 | 176 |
</property> |
177 |
<property name="maximumSize"> |
|
178 |
<size> |
|
179 |
<width>16777215</width> |
|
180 |
<height>16777215</height> |
|
181 |
</size> |
|
182 |
</property> |
|
177 | 183 |
<property name="value"> |
178 |
<number>60</number>
|
|
184 |
<number>30</number>
|
|
179 | 185 |
</property> |
180 | 186 |
</widget> |
181 | 187 |
</item> |
182 |
<item row="4" column="1">
|
|
183 |
<widget class="QSpinBox" name="minTextSizeSpinBox">
|
|
188 |
<item row="5" column="3">
|
|
189 |
<widget class="QSpinBox" name="maxTextSizeSpinBox">
|
|
184 | 190 |
<property name="sizePolicy"> |
185 | 191 |
<sizepolicy hsizetype="Expanding" vsizetype="Fixed"> |
186 | 192 |
<horstretch>0</horstretch> |
187 | 193 |
<verstretch>0</verstretch> |
188 | 194 |
</sizepolicy> |
189 | 195 |
</property> |
190 |
<property name="maximumSize"> |
|
191 |
<size> |
|
192 |
<width>16777215</width> |
|
193 |
<height>16777215</height> |
|
194 |
</size> |
|
195 |
</property> |
|
196 | 196 |
<property name="value"> |
197 |
<number>30</number>
|
|
197 |
<number>60</number>
|
|
198 | 198 |
</property> |
199 | 199 |
</widget> |
200 | 200 |
</item> |
201 | 201 |
<item row="4" column="2"> |
202 |
<widget class="QLabel" name="label_18">
|
|
202 |
<widget class="QLabel" name="label_21">
|
|
203 | 203 |
<property name="text"> |
204 |
<string>Maximum Text Size : </string>
|
|
204 |
<string>Erosion Size : </string>
|
|
205 | 205 |
</property> |
206 | 206 |
</widget> |
207 | 207 |
</item> |
208 |
<item row="4" column="0">
|
|
208 |
<item row="5" column="0">
|
|
209 | 209 |
<widget class="QLabel" name="label_17"> |
210 | 210 |
<property name="text"> |
211 | 211 |
<string>Minimum Text Size : </string> |
212 | 212 |
</property> |
213 | 213 |
</widget> |
214 | 214 |
</item> |
215 |
<item row="3" column="2">
|
|
216 |
<widget class="QLabel" name="label_21">
|
|
215 |
<item row="5" column="2">
|
|
216 |
<widget class="QLabel" name="label_18">
|
|
217 | 217 |
<property name="text"> |
218 |
<string>Erosion Size : </string>
|
|
218 |
<string>Maximum Text Size : </string>
|
|
219 | 219 |
</property> |
220 | 220 |
</widget> |
221 | 221 |
</item> |
222 |
<item row="3" column="3">
|
|
223 |
<widget class="QSpinBox" name="spinBoxShrinkSize">
|
|
222 |
<item row="4" column="1">
|
|
223 |
<widget class="QSpinBox" name="spinBoxExpandSize">
|
|
224 | 224 |
<property name="minimumSize"> |
225 | 225 |
<size> |
226 | 226 |
<width>100</width> |
... | ... | |
229 | 229 |
</property> |
230 | 230 |
</widget> |
231 | 231 |
</item> |
232 |
<item row="3" column="1">
|
|
233 |
<widget class="QSpinBox" name="spinBoxExpandSize">
|
|
232 |
<item row="4" column="3">
|
|
233 |
<widget class="QSpinBox" name="spinBoxShrinkSize">
|
|
234 | 234 |
<property name="minimumSize"> |
235 | 235 |
<size> |
236 | 236 |
<width>100</width> |
... | ... | |
246 | 246 |
</property> |
247 | 247 |
</widget> |
248 | 248 |
</item> |
249 |
<item row="1" column="0">
|
|
250 |
<widget class="QLabel" name="label_7">
|
|
249 |
<item row="4" column="0">
|
|
250 |
<widget class="QLabel" name="label_20">
|
|
251 | 251 |
<property name="text"> |
252 |
<string>Detected string : </string>
|
|
252 |
<string>Expansion Size : </string>
|
|
253 | 253 |
</property> |
254 | 254 |
</widget> |
255 | 255 |
</item> |
256 |
<item row="3" column="0">
|
|
257 |
<widget class="QLabel" name="label_20">
|
|
256 |
<item row="1" column="0">
|
|
257 |
<widget class="QLabel" name="label_7">
|
|
258 | 258 |
<property name="text"> |
259 |
<string>Expansion Size : </string>
|
|
259 |
<string>Detected string : </string>
|
|
260 | 260 |
</property> |
261 | 261 |
</widget> |
262 | 262 |
</item> |
263 |
<item row="2" column="0">
|
|
263 |
<item row="3" column="0">
|
|
264 | 264 |
<widget class="QLabel" name="label_37"> |
265 | 265 |
<property name="text"> |
266 | 266 |
<string>Allowed Single Text : </string> |
267 | 267 |
</property> |
268 | 268 |
</widget> |
269 | 269 |
</item> |
270 |
<item row="5" column="0">
|
|
270 |
<item row="6" column="0">
|
|
271 | 271 |
<widget class="QLabel" name="label_22"> |
272 | 272 |
<property name="text"> |
273 | 273 |
<string>Merge Size : </string> |
274 | 274 |
</property> |
275 | 275 |
</widget> |
276 | 276 |
</item> |
277 |
<item row="5" column="1"> |
|
277 |
<item row="1" column="1" colspan="3"> |
|
278 |
<widget class="QLineEdit" name="lineEditWhiteCharList"/> |
|
279 |
</item> |
|
280 |
<item row="3" column="1"> |
|
281 |
<widget class="QLineEdit" name="lineEditSingleText"/> |
|
282 |
</item> |
|
283 |
<item row="6" column="1"> |
|
278 | 284 |
<widget class="QSpinBox" name="spinBoxMergeSize"> |
279 | 285 |
<property name="minimumSize"> |
280 | 286 |
<size> |
... | ... | |
300 | 306 |
</property> |
301 | 307 |
</widget> |
302 | 308 |
</item> |
303 |
<item row="2" column="1"> |
|
304 |
<widget class="QLineEdit" name="lineEditSingleText"/> |
|
309 |
<item row="2" column="0"> |
|
310 |
<widget class="QLabel" name="label_39"> |
|
311 |
<property name="text"> |
|
312 |
<string>Page segmentations modes</string> |
|
313 |
</property> |
|
314 |
</widget> |
|
305 | 315 |
</item> |
306 |
<item row="1" column="1" colspan="3"> |
|
307 |
<widget class="QLineEdit" name="lineEditWhiteCharList"/> |
|
316 |
<item row="2" column="1" colspan="3"> |
|
317 |
<widget class="QComboBox" name="comboBoxPageSegmentationModes"/> |
|
318 |
</item> |
|
319 |
<item row="0" column="2" colspan="2"> |
|
320 |
<widget class="QLabel" name="labelTesseractVersion"> |
|
321 |
<property name="text"> |
|
322 |
<string>TextLabel</string> |
|
323 |
</property> |
|
324 |
<property name="alignment"> |
|
325 |
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set> |
|
326 |
</property> |
|
327 |
</widget> |
|
308 | 328 |
</item> |
309 | 329 |
</layout> |
310 | 330 |
</item> |
... | ... | |
1373 | 1393 |
</layout> |
1374 | 1394 |
</widget> |
1375 | 1395 |
<tabstops> |
1396 |
<tabstop>comboBoxOCRData</tabstop> |
|
1397 |
<tabstop>lineEditWhiteCharList</tabstop> |
|
1398 |
<tabstop>comboBoxPageSegmentationModes</tabstop> |
|
1399 |
<tabstop>lineEditSingleText</tabstop> |
|
1400 |
<tabstop>spinBoxExpandSize</tabstop> |
|
1401 |
<tabstop>spinBoxShrinkSize</tabstop> |
|
1402 |
<tabstop>minTextSizeSpinBox</tabstop> |
|
1403 |
<tabstop>maxTextSizeSpinBox</tabstop> |
|
1404 |
<tabstop>spinBoxMergeSize</tabstop> |
|
1405 |
<tabstop>lineEditSizeDelimiter</tabstop> |
|
1406 |
<tabstop>doubleSpinBoxDetectionRange</tabstop> |
|
1407 |
<tabstop>spinBoxFlowMarkPosition</tabstop> |
|
1408 |
<tabstop>spinBoxFlowMarkLength</tabstop> |
|
1409 |
<tabstop>spinBoxMinimumSize</tabstop> |
|
1410 |
<tabstop>spinBoxUnrecognitionIgnoreStep</tabstop> |
|
1411 |
<tabstop>spinBoxDilateSize</tabstop> |
|
1412 |
<tabstop>spinBoxFlatSize</tabstop> |
|
1413 |
<tabstop>radioButtonMode1</tabstop> |
|
1414 |
<tabstop>radioButtonMode2</tabstop> |
|
1415 |
<tabstop>spinBoxMinArea</tabstop> |
|
1416 |
<tabstop>spinBoxMaxArea</tabstop> |
|
1417 |
<tabstop>spinBoxWidth</tabstop> |
|
1418 |
<tabstop>spinBoxHeight</tabstop> |
|
1419 |
<tabstop>smallLineMinLengthSpinBox</tabstop> |
|
1420 |
<tabstop>spinBoxLengthToConnectLine</tabstop> |
|
1421 |
<tabstop>comboBoxLineType</tabstop> |
|
1422 |
<tabstop>radioButtonDiagonalYes</tabstop> |
|
1423 |
<tabstop>radioButtonDiagonalNo</tabstop> |
|
1424 |
<tabstop>pushButtonLineNoAttribute</tabstop> |
|
1425 |
<tabstop>pushButtonAddProperty</tabstop> |
|
1426 |
<tabstop>pushButtonDeleteProperty</tabstop> |
|
1427 |
<tabstop>listWidgetLineNo</tabstop> |
|
1428 |
<tabstop>pushButtonTagNoAttribute</tabstop> |
|
1429 |
<tabstop>pushButtonAddTagProperty</tabstop> |
|
1430 |
<tabstop>pushButtonDeleteTagProperty</tabstop> |
|
1431 |
<tabstop>listWidgetTagNo</tabstop> |
|
1432 |
<tabstop>checkBoxNoteNoSymbolName</tabstop> |
|
1433 |
<tabstop>lineEditNoteNoSymbolName</tabstop> |
|
1434 |
<tabstop>lineEditNoteNoExpression</tabstop> |
|
1435 |
<tabstop>lineEditOPCFromPrefix</tabstop> |
|
1436 |
<tabstop>lineEditOPCToPrefix</tabstop> |
|
1437 |
<tabstop>lineEditByVendor</tabstop> |
|
1438 |
<tabstop>lineEditDrainSize</tabstop> |
|
1376 | 1439 |
<tabstop>lineEdit_2</tabstop> |
1377 | 1440 |
<tabstop>tableWidgetLineTypes</tabstop> |
1441 |
<tabstop>pushButtonInstrumentColor</tabstop> |
|
1442 |
<tabstop>pushButtonEquipColor</tabstop> |
|
1443 |
<tabstop>spinBoxSymbolOpacity</tabstop> |
|
1444 |
<tabstop>fontComboBox</tabstop> |
|
1445 |
<tabstop>radioButtonAutoSize</tabstop> |
|
1446 |
<tabstop>radioButtonFixedSize</tabstop> |
|
1447 |
<tabstop>spinBoxFontSize</tabstop> |
|
1448 |
<tabstop>radioButtonRandom</tabstop> |
|
1449 |
<tabstop>radioButtonProperty</tabstop> |
|
1450 |
<tabstop>comboBoxColorOption</tabstop> |
|
1451 |
<tabstop>tableWidgetColorProperty</tabstop> |
|
1452 |
<tabstop>radioButtonLoadXmlYes</tabstop> |
|
1453 |
<tabstop>radioButtonLoadXmlNo</tabstop> |
|
1454 |
<tabstop>radioButtonSaveUnknownYes</tabstop> |
|
1455 |
<tabstop>radioButtonSaveUnknownNo</tabstop> |
|
1456 |
<tabstop>pushButtonClearAccessInfo</tabstop> |
|
1457 |
<tabstop>radioButtonBackTextYes</tabstop> |
|
1458 |
<tabstop>radioButtonBackTextNo</tabstop> |
|
1378 | 1459 |
<tabstop>tabWidget</tabstop> |
1379 | 1460 |
</tabstops> |
1380 | 1461 |
<resources> |
... | ... | |
1416 | 1497 |
</connections> |
1417 | 1498 |
<buttongroups> |
1418 | 1499 |
<buttongroup name="buttonGroup_3"/> |
1500 |
<buttongroup name="buttonGroup_2"/> |
|
1501 |
<buttongroup name="buttonGroup_5"/> |
|
1419 | 1502 |
<buttongroup name="buttonGroup_4"/> |
1420 | 1503 |
<buttongroup name="buttonGroup"/> |
1421 |
<buttongroup name="buttonGroup_5"/> |
|
1422 |
<buttongroup name="buttonGroup_2"/> |
|
1423 | 1504 |
</buttongroups> |
1424 | 1505 |
</ui> |
DTI_PID/DTI_PID/tesseract_ocr_module.py | ||
---|---|---|
38 | 38 |
|
39 | 39 |
tesseract_path = os.path.join(os.getenv('ALLUSERSPROFILE'), 'Digital PID', 'Tesseract-OCR') |
40 | 40 |
DEFAULT_CONF = """ |
41 |
--psm 6 -c tessedit_char_whitelist=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-~.,/!@#$%&*(){}[]<>:;+=?\\"
|
|
41 |
--psm {} -c tessedit_char_whitelist=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-~.,/!@#$%&*(){}[]<>:;+=?\\"
|
|
42 | 42 |
""" |
43 |
DEFAULT_CONF_COMM = "--psm 6 -c preserve_interword_spaces=1"
|
|
43 |
DEFAULT_CONF_COMM = "--psm {} -c preserve_interword_spaces=1"
|
|
44 | 44 |
|
45 | 45 |
|
46 | 46 |
def exist_trained_data(): |
... | ... | |
80 | 80 |
os.environ['TESSDATA_PREFIX'] = os.path.join(tesseract_path, 'tessdata') |
81 | 81 |
textInfoList = [] |
82 | 82 |
|
83 |
app_doc_data = AppDocData.instance() |
|
84 |
configs = app_doc_data.getConfigs('Text Recognition', 'Page Segmentation Modes') |
|
85 |
_conf = DEFAULT_CONF_COMM.format(configs[0].value if configs else '3') |
|
83 | 86 |
if conf: |
84 |
_conf = DEFAULT_CONF_COMM + f" tessedit_char_whitelist=\"{conf}\"" |
|
85 |
else: |
|
86 |
_conf = DEFAULT_CONF_COMM |
|
87 |
_conf += f" tessedit_char_whitelist=\"{conf}\"" |
|
87 | 88 |
|
88 |
app_doc_data = AppDocData.instance() |
|
89 | 89 |
oCRLang = language |
90 | 90 |
|
91 | 91 |
configs = app_doc_data.getConfigs('Text Size', 'Min Text Size') |
... | ... | |
102 | 102 |
|
103 | 103 |
thickness = 3 |
104 | 104 |
im = Image.fromarray(img) |
105 |
# add padding to increase text recognition |
|
105 | 106 |
im = ImageOps.expand(im, border=thickness, fill='white') |
106 | 107 |
im = im.rotate(-angle, expand=True) |
107 | 108 |
imgWidth = im.width |
... | ... | |
202 | 203 |
|
203 | 204 |
for rect in merged_boxes: |
204 | 205 |
if not rect.isValid() or \ |
205 |
rect.left() < 0 or rect.top() < 0 or rect.right() > imgWidth or rect.bottom() > imgHeight: continue |
|
206 |
rect.left() < 0 or rect.top() < 0 or rect.right() > imgWidth or rect.bottom() > imgHeight: |
|
207 |
continue |
|
206 | 208 |
if len(merged_boxes) == 1: |
207 | 209 |
cropped = im |
208 | 210 |
else: |
209 |
# recognition rate is increased when image has border
|
|
210 |
cropped = im.crop((rect.left() - 1, imgHeight - rect.bottom() - 1, rect.right() + 1,
|
|
211 |
imgHeight - rect.top() + 1))
|
|
211 |
cropped = im.crop((rect.left(), imgHeight - rect.bottom(), rect.right(), imgHeight - rect.top()))
|
|
212 |
# add padding to increase text recognition
|
|
213 |
cropped = ImageOps.expand(cropped, border=thickness, fill='white')
|
|
212 | 214 |
|
213 | 215 |
if cropped.width == 0 or cropped.height == 0: |
214 | 216 |
continue |
... | ... | |
231 | 233 |
text_rect.width(), text_rect.height(), angle) |
232 | 234 |
textInfoList.append(text_info) |
233 | 235 |
|
236 |
del im |
|
237 |
|
|
234 | 238 |
return textInfoList |
235 | 239 |
except Exception as ex: |
236 | 240 |
from App import App |
내보내기 Unified diff