개정판 aece692b
delete unnecessary files for HYTOS
Change-Id: Ic44e270db940a61f23fa7a9ed77b0af2292d7213
DTI_PID/DTI_PID/Commands/AreaOcrCommand.py | ||
---|---|---|
1 |
import os.path |
|
2 |
import AbstractCommand |
|
3 |
try: |
|
4 |
from PyQt5.QtCore import * |
|
5 |
from PyQt5.QtGui import * |
|
6 |
from PyQt5.QtWidgets import * |
|
7 |
except ImportError: |
|
8 |
try: |
|
9 |
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 |
|
11 |
except ImportError: |
|
12 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
|
13 |
import OcrResultDialog |
|
14 |
import sys |
|
15 |
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.realpath(__file__))) + '\\Shapes') |
|
16 |
from EngineeringTextItem import QEngineeringTextItem |
|
17 |
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem |
|
18 |
from EngineeringNoteItem import QEngineeringNoteItem |
|
19 |
from TextItemFactory import TextItemFactory |
|
20 |
from AppDocData import AppDocData |
|
21 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
|
22 |
|
|
23 |
class AreaOcrCommand(AbstractCommand.AbstractCommand): |
|
24 |
onSuccess = pyqtSignal(float, float, float, float) |
|
25 |
onRejected = pyqtSignal(AbstractCommand.AbstractCommand) |
|
26 |
|
|
27 |
def __init__(self, imageViewer): |
|
28 |
super(AreaOcrCommand, self).__init__(imageViewer) |
|
29 |
self.name = 'AreaOcr' |
|
30 |
self.imageViewer.setCursor(QCursor(Qt.CrossCursor)) |
|
31 |
self._rubberBand = QRubberBand(QRubberBand.Rectangle, self.imageViewer) |
|
32 |
self._origin = QPoint() |
|
33 |
self.isLeftClicked = False |
|
34 |
|
|
35 |
''' |
|
36 |
@brief pan image by left click and drag |
|
37 |
@author Jeongwoo |
|
38 |
@date 18.04.19 |
|
39 |
@history 18.04.20 Jeongwoo Transform text box |
|
40 |
humkyung 2018.04.20 set item's location with selection box |
|
41 |
Jeongwoo 2018.04.25 Add if state with QEngineeringNoteItem |
|
42 |
Jeongwoo 2018.04.26 Change method to create TextItem with TextItemFactory |
|
43 |
Jeongwoo 2018.05.02 Add Checking imageViewer has image if-statement, when mouseReleaseEvent happen |
|
44 |
humkyung 2018.08.29 use rubberband for selection text area |
|
45 |
''' |
|
46 |
def execute(self, param): |
|
47 |
event = param[1] |
|
48 |
scenePos = param[2] |
|
49 |
if 'mousePressEvent' == param[0]: |
|
50 |
if event.button() == Qt.LeftButton: |
|
51 |
self.isLeftClicked = True |
|
52 |
self._origin = event.pos() |
|
53 |
self._rubberBand.setGeometry(QRect(self._origin, QSize())) |
|
54 |
self._rubberBand.show() |
|
55 |
|
|
56 |
self.imageViewer.leftMouseButtonPressed.emit(scenePos.x(), scenePos.y()) |
|
57 |
elif 'mouseMoveEvent' == param[0] and event.buttons() == Qt.LeftButton: |
|
58 |
if self._rubberBand.isVisible(): |
|
59 |
self._rubberBand.setGeometry(QRect(self._origin, event.pos()).normalized()) |
|
60 |
elif 'mouseReleaseEvent' == param[0]: |
|
61 |
QGraphicsView.mouseReleaseEvent(self.imageViewer, event) |
|
62 |
try: |
|
63 |
if event.button() == Qt.LeftButton: |
|
64 |
self.isLeftClicked = False |
|
65 |
if self.imageViewer.canZoom and event.button() == Qt.LeftButton: |
|
66 |
self._rubberBand.hide() |
|
67 |
topLeft = self.imageViewer.mapToScene(self._rubberBand.geometry().topLeft()) |
|
68 |
bottomRight = self.imageViewer.mapToScene(self._rubberBand.geometry().bottomRight()) |
|
69 |
rect = QRectF(topLeft, bottomRight) |
|
70 |
if rect.isValid(): |
|
71 |
if self.imageViewer.hasImage(): |
|
72 |
rect = rect.toAlignedRect() |
|
73 |
self.onSuccess.emit(rect.left(), rect.top(), rect.width(), rect.height()) |
|
74 |
else: |
|
75 |
QMessageBox.about(self.imageViewer, self.tr('Notice'), self.tr('Please check the image.')) |
|
76 |
elif event.button() == Qt.RightButton: |
|
77 |
if self.isLeftClicked == False: |
|
78 |
self.onRejected.emit(self) |
|
79 |
finally: |
|
80 |
pass |
|
81 |
|
|
82 |
self.isTreated = False |
|
83 |
|
|
84 |
def undo(self): |
|
85 |
pass |
|
86 |
|
|
87 |
def redo(self): |
|
88 |
pass |
DTI_PID/DTI_PID/Commands/RemoveTextCommand.py | ||
---|---|---|
1 |
import os.path |
|
2 |
import AbstractCommand |
|
3 |
try: |
|
4 |
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.QtWidgets import QGraphicsView, QGraphicsScene, QFileDialog, QMessageBox |
|
7 |
except ImportError: |
|
8 |
try: |
|
9 |
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 |
|
11 |
except ImportError: |
|
12 |
raise ImportError("ImageViewerQt: Requires PyQt5 or PyQt4.") |
|
13 |
import sys |
|
14 |
from AppDocData import AppDocData |
|
15 |
from TextDetector import TextDetector |
|
16 |
import numpy as np |
|
17 |
from PIL import Image |
|
18 |
import io |
|
19 |
import cv2 |
|
20 |
|
|
21 |
class RemoveTextCommand(AbstractCommand.AbstractCommand): |
|
22 |
''' |
|
23 |
@history 2018.05.09 Jeongwoo Draw Rect on ±1 area |
|
24 |
2018.06.11 Jeongwoo Change method to set image (setImage → setPixmap/updateViewer) |
|
25 |
''' |
|
26 |
def __init__(self, imageViewer): |
|
27 |
super(RemoveTextCommand, self).__init__(imageViewer) |
|
28 |
self.name = 'RemoveText' |
|
29 |
#self.imageViewer.setCursor(QCursor(Qt.ArrowCursor)) |
|
30 |
image = self.imageViewer.image() |
|
31 |
buffer = QBuffer() |
|
32 |
buffer.open(QBuffer.ReadWrite) |
|
33 |
image.save(buffer, "PNG") |
|
34 |
pyImage = Image.open(io.BytesIO(buffer.data())) |
|
35 |
dst = cv2.cvtColor(np.array(pyImage), cv2.COLOR_BGR2GRAY) |
|
36 |
textDetector = TextDetector() |
|
37 |
self.textInfoList = textDetector.detectTextAreas(dst, (0, 0)) |
|
38 |
pixmap = self.imageViewer.pixmap() |
|
39 |
ADJUST = 1 |
|
40 |
for textInfo in self.textInfoList: |
|
41 |
painter = QPainter() |
|
42 |
painter.begin(pixmap) |
|
43 |
painter.setPen(QColor(255, 255, 255)) |
|
44 |
painter.setBrush(QColor(255, 255, 255)) |
|
45 |
painter.drawRect(QRect(textInfo.getX()-ADJUST, textInfo.getY()-ADJUST, textInfo.getW()+ADJUST, textInfo.getH()+ADJUST)) |
|
46 |
painter.end() |
|
47 |
pixmapHandle = self.imageViewer.getPixmapHandle() |
|
48 |
if pixmapHandle is not None: |
|
49 |
pixmapHandle.setPixmap(pixmap) |
|
50 |
self.imageViewer.setSceneRect(QRectF(pixmap.rect())) |
|
51 |
self.imageViewer.updateViewer() |
|
52 |
|
|
53 |
def execute(self, param): |
|
54 |
event = param[1] |
|
55 |
scenePos = param[2] |
|
56 |
self.isTreated = False |
|
57 |
|
|
58 |
def undo(self): |
|
59 |
pass |
|
60 |
|
|
61 |
def redo(self): |
|
62 |
pass |
DTI_PID/DTI_PID/MainWindow.py | ||
---|---|---|
10 | 10 |
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Commands') |
11 | 11 |
import CreateCommand |
12 | 12 |
import CropCommand |
13 |
import AreaOcrCommand |
|
14 | 13 |
import CreateSymbolCommand |
15 | 14 |
import AreaZoomCommand |
16 | 15 |
import FenceCommand |
... | ... | |
55 | 54 |
import ItemPropertyTableWidget |
56 | 55 |
from UserInputAttribute import UserInputAttribute |
57 | 56 |
from TextItemFactory import TextItemFactory |
58 |
from TrainingImageListDialog import QTrainingImageListDialog |
|
59 | 57 |
from TextDataListDialog import QTextDataListDialog |
60 | 58 |
from DisplayColors import DisplayColors |
61 | 59 |
from DisplayColors import DisplayOptions |
DTI_PID/DTI_PID/Shapes/EngineeringLineItem.py | ||
---|---|---|
1 | 1 |
# coding: utf-8 |
2 | 2 |
""" This is engineering line item module """ |
3 | 3 |
import sys |
4 |
import cv2 |
|
5 | 4 |
import os |
6 | 5 |
|
7 | 6 |
try: |
DTI_PID/DTI_PID/Shapes/EngineeringLineNoTextItem.py | ||
---|---|---|
18 | 18 |
from EngineeringPolylineItem import QEngineeringPolylineItem |
19 | 19 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
20 | 20 |
from UserInputAttribute import UserInputAttribute |
21 |
from OcrResultDialog import QOcrResultDialog |
|
22 | 21 |
from AppDocData import AppDocData |
23 | 22 |
from EngineeringTextItem import QEngineeringTextItem |
24 | 23 |
from TextInfo import TextInfo |
DTI_PID/DTI_PID/Shapes/EngineeringNoteItem.py | ||
---|---|---|
15 | 15 |
|
16 | 16 |
from EngineeringPolylineItem import QEngineeringPolylineItem |
17 | 17 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
18 |
import OcrResultDialog |
|
19 | 18 |
from AppDocData import AppDocData |
20 | 19 |
from EngineeringTextItem import QEngineeringTextItem |
21 | 20 |
import re |
DTI_PID/DTI_PID/Shapes/EngineeringValveOperCodeTextItem.py | ||
---|---|---|
18 | 18 |
|
19 | 19 |
from EngineeringPolylineItem import QEngineeringPolylineItem |
20 | 20 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
21 |
import OcrResultDialog |
|
22 | 21 |
from AppDocData import AppDocData, MessageType |
23 | 22 |
from EngineeringTextItem import QEngineeringTextItem |
24 | 23 |
from SymbolSvgItem import SymbolSvgItem |
DTI_PID/DTI_PID/Shapes/QEngineeringSizeTextItem.py | ||
---|---|---|
15 | 15 |
|
16 | 16 |
from EngineeringPolylineItem import QEngineeringPolylineItem |
17 | 17 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
18 |
import OcrResultDialog |
|
19 | 18 |
from AppDocData import AppDocData, MessageType |
20 | 19 |
from EngineeringTextItem import QEngineeringTextItem |
21 | 20 |
from SymbolSvgItem import SymbolSvgItem |
DTI_PID/DTI_PID/Shapes/QEngineeringTagNoTextItem.py | ||
---|---|---|
17 | 17 |
|
18 | 18 |
from EngineeringPolylineItem import QEngineeringPolylineItem |
19 | 19 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
20 |
import OcrResultDialog |
|
21 | 20 |
from AppDocData import AppDocData,MessageType |
22 | 21 |
from EngineeringTextItem import QEngineeringTextItem |
23 | 22 |
from EngineeringEquipmentItem import QEngineeringEquipmentItem |
DTI_PID/DTI_PID/Shapes/QEngineeringTrimLineNoTextItem.py | ||
---|---|---|
19 | 19 |
|
20 | 20 |
from EngineeringPolylineItem import QEngineeringPolylineItem |
21 | 21 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
22 |
import OcrResultDialog |
|
23 | 22 |
from AppDocData import AppDocData |
24 | 23 |
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem |
25 | 24 |
|
DTI_PID/DTI_PID/SymbolEditorDialog.py | ||
---|---|---|
17 | 17 |
from AppDocData import * |
18 | 18 |
|
19 | 19 |
sys.path.insert(0, os.path.dirname(os.path.realpath(__file__)) + '\\Commands') |
20 |
import CropCommand, HandCommand, ZoomCommand, PenCommand, EraserCommand, AreaEraserCommand, OriginalPointCommand, ConnectionPointCommand, AreaZoomCommand, FitImageCommand, RemoveTextCommand, RotateImageCommand, FlipImageCommand
|
|
20 |
import CropCommand, HandCommand, ZoomCommand, PenCommand, EraserCommand, AreaEraserCommand, OriginalPointCommand, ConnectionPointCommand, AreaZoomCommand, FitImageCommand, RotateImageCommand, FlipImageCommand |
|
21 | 21 |
|
22 | 22 |
|
23 | 23 |
class QSymbolEditorDialog(QDialog): |
DTI_PID/DTI_PID/TextDetector.py | ||
---|---|---|
1 |
# coding: utf-8 |
|
2 |
""" |
|
3 |
This is text detector module |
|
4 |
""" |
|
5 |
import sys |
|
6 |
import os |
|
7 |
import cv2 |
|
8 |
import numpy as np |
|
9 |
from PyQt5.QtCore import * |
|
10 |
from PyQt5.QtGui import * |
|
11 |
from PyQt5.QtWidgets import * |
|
12 |
from PyQt5.QtSvg import * |
|
13 |
|
|
14 |
from AppDocData import * |
|
15 |
import TextInfo as ti |
|
16 |
import tesseract_ocr_module as TOCR |
|
17 |
|
|
18 |
MIN_TEXT_SIZE = 10 |
|
19 |
THREAD_MAX_WORKER = os.cpu_count() |
|
20 |
|
|
21 |
class TextDetector: |
|
22 |
''' |
|
23 |
@brief constructor |
|
24 |
@author humkyung |
|
25 |
@date 2018.07.11 |
|
26 |
''' |
|
27 |
def __init__(self): |
|
28 |
self.textInfoList = [] |
|
29 |
self.otherTextInfoList = [] |
|
30 |
self.titleBlockTextInfoList = [] |
|
31 |
|
|
32 |
''' |
|
33 |
@brief detect text areas |
|
34 |
@author humkyung |
|
35 |
@date 2018.06.16 |
|
36 |
''' |
|
37 |
def detectTextAreas(self, img, offset): |
|
38 |
tInfoList = [] |
|
39 |
try: |
|
40 |
tInfoList = self.getTextAreaInfo(img, offset[0], offset[1]) |
|
41 |
except Exception as ex: |
|
42 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
|
43 |
|
|
44 |
return tInfoList |
|
45 |
|
|
46 |
''' |
|
47 |
@brief Get Text Area info by contour |
|
48 |
@author Jeongwoo |
|
49 |
@date 2018.06.05 |
|
50 |
@history 2018.06.08 Jeongwoo Add angle |
|
51 |
humkyung 2018.06.18 fixed logic to detect text area |
|
52 |
''' |
|
53 |
def getTextAreaInfo(self, imgGray, offsetX, offsetY): |
|
54 |
from AppDocData import AppDocData |
|
55 |
|
|
56 |
appDocData = AppDocData.instance() |
|
57 |
project = appDocData.getCurrentProject() |
|
58 |
|
|
59 |
configs = appDocData.getConfigs('Text Size', 'Max Text Size') |
|
60 |
maxTextSize = int(configs[0].value) if 1 == len(configs) else 100 |
|
61 |
minSize = 5 |
|
62 |
|
|
63 |
contourImg = np.ones(imgGray.shape, np.uint8) * 255 |
|
64 |
binaryImg,mask = cv2.threshold(imgGray, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU) |
|
65 |
|
|
66 |
image, contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) |
|
67 |
for contour in contours: |
|
68 |
# remove too big one or horizontal/vertical line |
|
69 |
[x, y, w, h] = cv2.boundingRect(contour) |
|
70 |
area = cv2.contourArea(contour, True) |
|
71 |
|
|
72 |
# skip one which size is greater than max size or less then minimum size |
|
73 |
if area >= 0: |
|
74 |
if (w > maxTextSize or h > maxTextSize) or (w <= minSize and h <= minSize): continue |
|
75 |
|
|
76 |
if area >= 0: |
|
77 |
cv2.drawContours(contourImg, [contour], -1, (0,0,0), -1) |
|
78 |
cv2.drawContours(contourImg, [contour], -1, (255,255,255), 1) |
|
79 |
else: |
|
80 |
cv2.drawContours(contourImg, [contour], -1, (255,255,255), -1) |
|
81 |
|
|
82 |
path = os.path.join(project.getTempPath(), 'OCR_{}.png'.format(appDocData.imgName)) |
|
83 |
cv2.imwrite(path, contourImg) |
|
84 |
|
|
85 |
rects = [] |
|
86 |
configs = appDocData.getConfigs('Text Recognition', 'Expand Size') |
|
87 |
expandSize = int(configs[0].value) if 1 == len(configs) else 10 |
|
88 |
configs = appDocData.getConfigs('Text Recognition', 'Shrink Size') |
|
89 |
shrinkSize = int(configs[0].value) if 1 == len(configs) else 0 |
|
90 |
|
|
91 |
eroded = cv2.erode(contourImg, np.ones((expandSize,expandSize), np.uint8)) |
|
92 |
#path = os.path.join(project.getTempPath(), 'ERODED_OCR_{}.png'.format(appDocData.imgName)) |
|
93 |
#cv2.imwrite(path, eroded) |
|
94 |
|
|
95 |
eroded = cv2.bitwise_not(eroded) |
|
96 |
|
|
97 |
image, contours, hierarchy = cv2.findContours(eroded, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
|
98 |
for contour in contours: |
|
99 |
area = cv2.contourArea(contour, True) |
|
100 |
if area < 0: |
|
101 |
[x, y, w, h] = cv2.boundingRect(contour) |
|
102 |
|
|
103 |
img = contourImg[y:y+h, x:x+w] |
|
104 |
img = cv2.bitwise_not(img) |
|
105 |
|
|
106 |
horizontal,max_width = 0,0 |
|
107 |
vertical,max_height = 0,0 |
|
108 |
_, _contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
|
109 |
for xx in _contours: |
|
110 |
[_x, _y, _w, _h] = cv2.boundingRect(xx) |
|
111 |
cv2.rectangle(img, (_x, _y), (_x+_w, _y+_h), 255, 1) |
|
112 |
|
|
113 |
max_width = _x if _x > max_width else max_width |
|
114 |
max_height = _y if _y > max_height else max_height |
|
115 |
|
|
116 |
if (_w < _h) or (_w > maxTextSize and _h < maxTextSize): # width is greater than height |
|
117 |
horizontal += 1 + (_w*_h)/(w*h) |
|
118 |
else: |
|
119 |
vertical += 1 + (_w*_h)/(w*h) |
|
120 |
|
|
121 |
if (w < 10 and h < 10) or (max_width > maxTextSize and max_height > maxTextSize): continue; # skip too small or big one |
|
122 |
|
|
123 |
""" |
|
124 |
if w > maxTextSize: |
|
125 |
horizontal = 1 |
|
126 |
elif h > maxTextSize: |
|
127 |
vertical = 1 |
|
128 |
else: |
|
129 |
if shrinkSize > 0: |
|
130 |
img = cv2.erode(img, np.ones((shrinkSize,shrinkSize), np.uint8)) |
|
131 |
|
|
132 |
_, _contours, _ = cv2.findContours(img, cv2.RETR_CCOMP, cv2.CHAIN_APPROX_SIMPLE) |
|
133 |
for xx in _contours: |
|
134 |
[_x, _y, _w, _h] = cv2.boundingRect(xx) |
|
135 |
cv2.rectangle(img, (_x, _y), (_x+_w, _y+_h), 255, 1) |
|
136 |
|
|
137 |
if (_w < _h) or (_w > maxTextSize and _h < maxTextSize): # width is greater than height |
|
138 |
horizontal += 1 + (_w*_h)/(w*h) |
|
139 |
else: |
|
140 |
vertical += 1 + (_w*_h)/(w*h) |
|
141 |
""" |
|
142 |
|
|
143 |
""" |
|
144 |
if horizontal > vertical: |
|
145 |
filePath = os.path.join(project.getTempPath(), "Tile", "H-{}-{}-{}-{}.png".format(x,y,w,h)) |
|
146 |
else: |
|
147 |
filePath = os.path.join(project.getTempPath(), "Tile", "V-{}-{}-{}-{}.png".format(x,y,w,h)) |
|
148 |
cv2.imwrite(filePath, img) |
|
149 |
""" |
|
150 |
|
|
151 |
rects.append([0 if horizontal > vertical else 90, QRect(x, y, w, h)]) |
|
152 |
|
|
153 |
configs = appDocData.getConfigs('Text Recognition', 'Merge Size') |
|
154 |
mergeSize = int(configs[0].value) if 1 == len(configs) else 10 |
|
155 |
# merge rectangles |
|
156 |
intersected = True |
|
157 |
while intersected: |
|
158 |
intersected = False |
|
159 |
for rect in rects[:]: # clone rects |
|
160 |
if 0 == rect[0]: |
|
161 |
rectExpand = rect[1].adjusted(-mergeSize, 0, mergeSize, 0) |
|
162 |
else: |
|
163 |
rectExpand = rect[1].adjusted(0, -mergeSize, 0, mergeSize) |
|
164 |
|
|
165 |
matches = [x for x in rects if (x[0] == rect[0]) and rectExpand.intersects(x[1])] |
|
166 |
if len(matches) > 1: |
|
167 |
united = matches[0] |
|
168 |
for _rect in matches: |
|
169 |
united[1] = united[1].united(_rect[1]) |
|
170 |
if _rect in rects: rects.remove(_rect) |
|
171 |
rects.append(united) |
|
172 |
intersected = True |
|
173 |
break |
|
174 |
|
|
175 |
list = [] |
|
176 |
for rect in rects: |
|
177 |
angle = rect[0] |
|
178 |
list.append(ti.TextInfo('', round(offsetX) + rect[1].x(), round(offsetY) + rect[1].y(), rect[1].width(), rect[1].height(), angle)) |
|
179 |
|
|
180 |
x = rect[1].x() |
|
181 |
y = rect[1].y() |
|
182 |
w = rect[1].width() |
|
183 |
h = rect[1].height() |
|
184 |
img = contourImg[y:y+h, x:x+w] |
|
185 |
## DEBUG |
|
186 |
#if angle == 0: |
|
187 |
# filePath = os.path.join(project.getTempPath(), "Tile", "H-{}-{}-{}-{}.png".format(x,y,w,h)) |
|
188 |
#else: |
|
189 |
# filePath = os.path.join(project.getTempPath(), "Tile", "V-{}-{}-{}-{}.png".format(x,y,w,h)) |
|
190 |
#cv2.imwrite(filePath, img) |
|
191 |
## up to here |
|
192 |
|
|
193 |
return list |
|
194 |
|
|
195 |
''' |
|
196 |
@brief recognize text of given text info |
|
197 |
@author humkyung |
|
198 |
@date 2018.07.24 |
|
199 |
@history change parameter updateProgressSignal to worker |
|
200 |
2018.11.08 euisung add white char list check process on db |
|
201 |
''' |
|
202 |
@staticmethod |
|
203 |
def recognizeTextFromImage(tInfo, imgOCR, offset, searchedSymbolList, worker, listWidget, maxProgressValue): |
|
204 |
import re |
|
205 |
res = [] |
|
206 |
|
|
207 |
appDocData = AppDocData.instance() |
|
208 |
|
|
209 |
try: |
|
210 |
x = tInfo.getX() - round(offset[0]) |
|
211 |
y = tInfo.getY() - round(offset[1]) |
|
212 |
img = imgOCR[y:y+tInfo.getH(), x:x+tInfo.getW()] |
|
213 |
|
|
214 |
# set angle 0 if symbol contains the text area is instrumentation |
|
215 |
category = None |
|
216 |
contains = [symbol for symbol in searchedSymbolList if symbol.contains(tInfo)] |
|
217 |
if contains: |
|
218 |
_type = contains[0].getType() |
|
219 |
category = appDocData.getSymbolCategoryByType(_type) |
|
220 |
if 'Instrumentation' == category: tInfo.setAngle(0) |
|
221 |
# up to here |
|
222 |
|
|
223 |
whiteCharList = appDocData.getConfigs('Text Recognition', 'White Character List') |
|
224 |
if len(whiteCharList) is 0: |
|
225 |
resultTextInfo = TOCR.getTextInfo(img, (x, y), tInfo.getAngle(), language=appDocData.OCRData) |
|
226 |
else: |
|
227 |
resultTextInfo = TOCR.getTextInfo(img, (x, y), tInfo.getAngle(), language=appDocData.OCRData, conf = whiteCharList[0].value) |
|
228 |
|
|
229 |
if resultTextInfo is not None and len(resultTextInfo) > 0: |
|
230 |
for result in resultTextInfo: |
|
231 |
result.setX(result.getX() + round(offset[0])) |
|
232 |
result.setY(result.getY() + round(offset[1])) |
|
233 |
if 'Instrumentation' == category: |
|
234 |
text = re.sub('[^a-zA-Z0-9]+', '', result.getText()) |
|
235 |
result.setText(text) |
|
236 |
res.extend(resultTextInfo) |
|
237 |
|
|
238 |
if listWidget is not None: |
|
239 |
item = QListWidgetItem('{},{},{} is recognized'.format(resultTextInfo[0].getX(), resultTextInfo[0].getY(), resultTextInfo[0].getText())) |
|
240 |
listWidget.addItem(item) |
|
241 |
else: |
|
242 |
pass |
|
243 |
|
|
244 |
if worker is not None: worker.updateProgress.emit(maxProgressValue, resultTextInfo[0].getText() if resultTextInfo is not None and 1 == len(resultTextInfo) else None) |
|
245 |
except Exception as ex: |
|
246 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
247 |
worker.displayLog.emit(MessageType.Error, message) |
|
248 |
|
|
249 |
return res |
|
250 |
|
|
251 |
''' |
|
252 |
@brief read image drawing and then remove text |
|
253 |
@author jwkim |
|
254 |
@date |
|
255 |
@history humkyung 2018.04.06 check if file exists |
|
256 |
Jeongwoo 2018.05.09 Use Tesseract OCR after Azure OCR (Azure OCR : Getting text area) |
|
257 |
Jeongwoo 2018.05.25 Add condition on if-statement |
|
258 |
Jeongwoo 2018.06.05 Get text area data list by config.type |
|
259 |
Jeongwoo 2018.06.08 Add angle Parameter on TOCR.getTextInfo |
|
260 |
humkyung 2018.06.16 update proessbar while recognizing text |
|
261 |
humkyung 2018.07.03 remove white space and replace given oldStr with newStr |
|
262 |
humkyung 2018.07.07 change method name to recognizeText |
|
263 |
euisung 2018.11.08 add white char list check process on db |
|
264 |
euisung 2018.11.12 add title block properties |
|
265 |
''' |
|
266 |
def recognizeText(self, imgSrc, offset, tInfoList, searchedSymbolList, worker, listWidget, maxProgressValue, onlyTextArea = False): |
|
267 |
import concurrent.futures as futures |
|
268 |
from Area import Area |
|
269 |
|
|
270 |
try: |
|
271 |
self.otherTextInfoList = [] |
|
272 |
self.titleBlockTextInfoList = [] |
|
273 |
self.textInfoList = [] |
|
274 |
|
|
275 |
appDocData = AppDocData.instance() |
|
276 |
project = appDocData.getCurrentProject() |
|
277 |
|
|
278 |
path = os.path.join(project.getTempPath(), 'OCR_{}.png'.format(appDocData.imgName)) |
|
279 |
if os.path.isfile(path): |
|
280 |
imgOCR = cv2.imread(path, 1) |
|
281 |
imgOCR = cv2.threshold(cv2.cvtColor(imgOCR, cv2.COLOR_BGR2GRAY), 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1] |
|
282 |
|
|
283 |
pool = futures.ThreadPoolExecutor(max_workers = THREAD_MAX_WORKER) |
|
284 |
for tInfo in tInfoList: |
|
285 |
future = pool.submit(TextDetector.recognizeTextFromImage, tInfo, imgOCR, offset, searchedSymbolList, worker, listWidget, maxProgressValue) |
|
286 |
data = future.result() |
|
287 |
if data: self.textInfoList.extend(data) |
|
288 |
pool.shutdown(wait = True) |
|
289 |
|
|
290 |
if onlyTextArea: |
|
291 |
return |
|
292 |
# parse texts in area except Drawing area |
|
293 |
whiteCharList = appDocData.getConfigs('Text Recognition', 'White Character List') |
|
294 |
for area in appDocData.getAreaList(): |
|
295 |
if area.name == 'Drawing': continue |
|
296 |
|
|
297 |
if area.name == 'Unit': |
|
298 |
img = imgSrc[round(area.y):round(area.y+area.height), round(area.x):round(area.x+area.width)] |
|
299 |
if len(whiteCharList) is 0: |
|
300 |
texts = TOCR.getTextInfo(img, (area.x, area.y), 0, language='eng') |
|
301 |
else: |
|
302 |
texts = TOCR.getTextInfo(img, (area.x, area.y), 0, language='eng', conf = whiteCharList[0].value) |
|
303 |
if texts is not None and len(texts) > 0: |
|
304 |
appDocData.activeDrawing.setAttr('Unit', texts[0].getText()) |
|
305 |
self.otherTextInfoList.append([area.name, texts]) |
|
306 |
else: |
|
307 |
if area is not None and hasattr(area, 'img') and area.img is not None: |
|
308 |
if len(whiteCharList) is 0: |
|
309 |
texts = TOCR.getTextInfo(area.img, (area.x, area.y), 0, language='eng') |
|
310 |
else: |
|
311 |
texts = TOCR.getTextInfo(area.img, (area.x, area.y), 0, language='eng', conf=whiteCharList[0].value) |
|
312 |
self.otherTextInfoList.append([area.name, texts]) |
|
313 |
|
|
314 |
titleBlockProps = appDocData.getTitleBlockProperties() |
|
315 |
for titleBlockProp in titleBlockProps: |
|
316 |
area = Area(titleBlockProp[0]) |
|
317 |
area.parse(titleBlockProp[2]) |
|
318 |
img = imgSrc[round(area.y):round(area.y+area.height), round(area.x):round(area.x+area.width)] |
|
319 |
if len(whiteCharList) is 0: |
|
320 |
texts = TOCR.getTextInfo(img, (area.x, area.y), 0, language=appDocData.OCRData) |
|
321 |
else: |
|
322 |
texts = TOCR.getTextInfo(img, (area.x, area.y), 0, language='eng', conf=whiteCharList[0].value) |
|
323 |
self.titleBlockTextInfoList.append([area.name, texts]) |
|
324 |
|
|
325 |
if worker is not None: worker.updateProgress.emit(maxProgressValue, None) |
|
326 |
except Exception as ex: |
|
327 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
328 |
worker.displayLog.emit(MessageType.Error, message) |
|
329 |
|
|
330 |
''' |
|
331 |
@brief remove text from image |
|
332 |
@author humkyung |
|
333 |
@date 2018.07.24 |
|
334 |
''' |
|
335 |
def removeTextFromImage(self, imgSrc, offset): |
|
336 |
appDocData = AppDocData.instance() |
|
337 |
project = appDocData.getCurrentProject() |
|
338 |
|
|
339 |
path = os.path.join(project.getTempPath(), 'OCR_{}.png'.format(appDocData.imgName)) |
|
340 |
if os.path.isfile(path): |
|
341 |
imgOCR = cv2.imread(path) |
|
342 |
imgOCR = cv2.threshold(cv2.cvtColor(imgOCR, cv2.COLOR_BGR2GRAY), 127, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1] |
|
343 |
|
|
344 |
# remove recognized text from image |
|
345 |
for text in self.textInfoList: |
|
346 |
x = round(text.getX() - offset[0]) |
|
347 |
y = round(text.getY() - offset[1]) |
|
348 |
width = round(text.getW()) |
|
349 |
height = round(text.getH()) |
|
350 |
self.removeText(imgSrc, (round(text.getX()), round(text.getY())), imgOCR[y:y+height, x:x+width]) |
|
351 |
# up to here |
|
352 |
|
|
353 |
''' |
|
354 |
@brief remove text from image by using ocr image |
|
355 |
@author |
|
356 |
''' |
|
357 |
def removeText(self, img, pt, imgOCR): |
|
358 |
try: |
|
359 |
x = round(pt[0]) |
|
360 |
y = round(pt[1]) |
|
361 |
width, height = imgOCR.shape[::-1] |
|
362 |
|
|
363 |
temp = img[y:y+height, x:x+width] |
|
364 |
imgOCR = cv2.erode(imgOCR, np.ones((3,3), np.uint8)) |
|
365 |
mask = cv2.bitwise_or(temp, imgOCR) |
|
366 |
imgXOR = cv2.bitwise_xor(temp, mask) |
|
367 |
img[y:y+height, x:x+width] = cv2.bitwise_not(imgXOR) |
|
368 |
|
|
369 |
except Exception as ex: |
|
370 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
|
371 |
|
|
372 |
return img |
DTI_PID/DTI_PID/TrainingImageListDialog.py | ||
---|---|---|
1 |
import sys |
|
2 |
import os, time, subprocess, ctypes, datetime, copy |
|
3 |
from ctypes import wintypes |
|
4 |
_GetShortPathNameW = ctypes.windll.kernel32.GetShortPathNameW |
|
5 |
_GetShortPathNameW.argtypes = [wintypes.LPCWSTR, wintypes.LPWSTR, wintypes.DWORD] |
|
6 |
_GetShortPathNameW.restype = wintypes.DWORD |
|
7 |
from PyQt5.QtCore import * |
|
8 |
from PyQt5.QtGui import * |
|
9 |
from PyQt5.QtWidgets import * |
|
10 |
#from PyQt5.QtChart import * |
|
11 |
from AppDocData import AppDocData, Source |
|
12 |
import pytesseract |
|
13 |
import TrainingImageList_UI |
|
14 |
from TrainingEditorDialog import QTrainingEditorDialog |
|
15 |
import tesseract_ocr_module as TOCR |
|
16 |
import numpy as np |
|
17 |
import pyqtgraph as pg |
|
18 |
|
|
19 |
|
|
20 |
dataPath = os.path.join(os.getenv('ALLUSERSPROFILE'), 'Digital PID') |
|
21 |
tesseractPath = os.path.join(dataPath, 'Tesseract-OCR', 'tessdata') |
|
22 |
pytesseract.pytesseract.tesseract_cmd = os.path.join(dataPath, 'Tesseract-OCR', 'tesseract.exe') |
|
23 |
tesseract_cmd = os.path.join(dataPath, 'Tesseract-OCR', 'tesseract.exe') |
|
24 |
unicharset_extractor_cmd = os.path.join(dataPath, 'Tesseract-OCR', 'unicharset_extractor.exe') |
|
25 |
set_unicharset_properties_cmd = os.path.join(dataPath, 'Tesseract-OCR', 'set_unicharset_properties.exe') |
|
26 |
shapeclustering_cmd = os.path.join(dataPath, 'Tesseract-OCR', 'shapeclustering.exe') |
|
27 |
mftraining_cmd = os.path.join(dataPath, 'Tesseract-OCR', 'mftraining.exe') |
|
28 |
cntraining_cmd = os.path.join(dataPath, 'Tesseract-OCR', 'cntraining.exe') |
|
29 |
combine_tessdata_cmd = os.path.join(dataPath, 'Tesseract-OCR', 'combine_tessdata.exe') |
|
30 |
|
|
31 |
# for reset chart |
|
32 |
defaultCharList = [['0',0],['1',0],['2',0],['3',0],['4',0],['5',0],['6',0],['7',0],['8',0],['9',0],['a',0],['b',0],['c',0],['d',0],['e',0],['f',0],['g',0],['h',0],['i',0],['j',0],['k',0],['l',0],['m',0],['n',0],['o',0],['p',0],['q',0],['r',0],['s',0],['t',0],['u',0],['w',0],['x',0],['y',0],['z',0],['A',0],['B',0],['C',0],['D',0],['E',0],['F',0],['G',0],['H',0],['I',0],['J',0],['K',0],['L',0],['M',0],['N',0],['O',0],['P',0],['Q',0],['R',0],['S',0],['T',0],['U',0],['V',0],['W',0],['X',0],['Y',0],['Z',0]] |
|
33 |
#// for remove noise |
|
34 |
#noisePassList = ['.', '\"', '\'', ',', '`', '-', '+'] |
|
35 |
|
|
36 |
class EmittingStream(QObject): |
|
37 |
""" |
|
38 |
This is EmittingStream class |
|
39 |
""" |
|
40 |
textWritten = pyqtSignal(str) |
|
41 |
|
|
42 |
def write(self, text): |
|
43 |
self.textWritten.emit(str(text)) |
|
44 |
|
|
45 |
class QTrainingImageListDialog(QDialog): |
|
46 |
""" |
|
47 |
This is training image list dialog class |
|
48 |
""" |
|
49 |
TRAINING_DATA_COUNT = 5 |
|
50 |
|
|
51 |
def __init__(self, parent): |
|
52 |
QDialog.__init__(self, parent) |
|
53 |
self.setWindowFlag(Qt.WindowMinMaxButtonsHint) |
|
54 |
|
|
55 |
self.ui = TrainingImageList_UI.Ui_TraingingImageListDialog() |
|
56 |
self.ui.setupUi(self) |
|
57 |
self.ui.progressBar.setValue(0) |
|
58 |
self.charList = [] |
|
59 |
|
|
60 |
# for List |
|
61 |
self.ui.tableWidgetList.setSelectionMode(QAbstractItemView.SingleSelection) |
|
62 |
self.ui.tableWidgetList.setColumnCount(4) |
|
63 |
|
|
64 |
## column header 명 설정 |
|
65 |
self.ui.tableWidgetList.setHorizontalHeaderLabels([self.tr('No.'), self.tr('Image List'), self.tr('Modified Date'), self.tr('Box Contents')]) |
|
66 |
self.ui.tableWidgetList.horizontalHeaderItem(1).setToolTip(self.tr('Image Name')) # header tooltip |
|
67 |
self.ui.tableWidgetList.horizontalHeaderItem(2).setToolTip(self.tr('Edit Status')) # header tooltip |
|
68 |
self.ui.tableWidgetList.horizontalHeaderItem(3).setToolTip(self.tr('Box Contents')) # header tooltip |
|
69 |
self.ui.tableWidgetList.horizontalHeaderItem(1).setSizeHint(QSize(30, 30)) |
|
70 |
self.ui.tableWidgetList.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents) |
|
71 |
self.ui.tableWidgetList.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch) |
|
72 |
self.ui.tableWidgetList.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch) |
|
73 |
self.ui.tableWidgetList.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch) |
|
74 |
self.ui.tableWidgetList.resizeColumnsToContents() |
|
75 |
self.ui.tableWidgetList.setEditTriggers(QAbstractItemView.NoEditTriggers) |
|
76 |
|
|
77 |
self.listUpdate() |
|
78 |
|
|
79 |
# connect signals and slots |
|
80 |
self.ui.tableWidgetList.cellDoubleClicked.connect(self.listCellDoubleClicked) |
|
81 |
self.ui.pushButtonBox.clicked.connect(self.pushButtonBoxClicked) |
|
82 |
self.ui.pushButtonMakeTrainingData.clicked.connect(self.makeTrainingDataClicked) |
|
83 |
self.ui.pushButtonImageDelete.clicked.connect(self.pushButtonImageDeleteClicked) |
|
84 |
self.ui.pushButtonBoxDelete.clicked.connect(self.pushButtonBoxDeleteClicked) |
|
85 |
self.ui.pushButtonClose.clicked.connect(self.pushButtonCloseClicked) |
|
86 |
self.ui.pushButtonDeleteBatchChar.clicked.connect(self.pushButtonDeleteBatchCharClicked) |
|
87 |
|
|
88 |
# delete character in box |
|
89 |
self.ui.pushButtonDeleteBatchChar.setEnabled(False) |
|
90 |
self.ui.pushButtonDeleteBatchChar.setHidden(True) |
|
91 |
self.ui.lineEditTargetChar.setEnabled(False) |
|
92 |
self.ui.lineEditTargetChar.setHidden(True) |
|
93 |
|
|
94 |
# Install the custom output stream |
|
95 |
#sys.stdout = EmittingStream(textWritten=self.normalOutputWritten) |
|
96 |
|
|
97 |
os.environ['TESSDATA_PREFIX'] = os.path.join(os.getenv('ALLUSERSPROFILE'), 'Digital PID', 'Tesseract-OCR', 'tessdata') |
|
98 |
|
|
99 |
appDocData = AppDocData.instance() |
|
100 |
project = appDocData.getCurrentProject() |
|
101 |
dataList = appDocData.getTrainingFileList() |
|
102 |
self.charList = [] |
|
103 |
for charCounts in defaultCharList: |
|
104 |
charCount = [charCounts[0], charCounts[1]] |
|
105 |
self.charList.append(charCount) |
|
106 |
for data in dataList: |
|
107 |
if data.find('.boxS') is not -1: |
|
108 |
boxPath = os.path.join(project.getTrainingFilePath(), data) |
|
109 |
fw = open(boxPath, 'r', encoding='utf8') |
|
110 |
boxContent = fw.read() |
|
111 |
lines = boxContent.split('\n') |
|
112 |
for line in lines: |
|
113 |
if not line: continue |
|
114 |
char,min_x,min_y,max_x,max_y = line.split(' ') |
|
115 |
|
|
116 |
matches = [_char for _char in self.charList if _char[0] == char] |
|
117 |
if matches: |
|
118 |
matches[0][1] = matches[0][1] + 1 |
|
119 |
else: |
|
120 |
self.charList.append([char, 1]) |
|
121 |
fw.close() |
|
122 |
self.makeChart() |
|
123 |
|
|
124 |
def __del__(self): |
|
125 |
# Restore sys.stdout |
|
126 |
#sys.stdout = sys.__stdout__ |
|
127 |
pass |
|
128 |
|
|
129 |
def normalOutputWritten(self, text): |
|
130 |
"""Append text to the QTextEdit.""" |
|
131 |
# Maybe QTextEdit.append() works as well, but this is how I do it: |
|
132 |
cursor = self.ui.textEditConsole.textCursor() |
|
133 |
cursor.movePosition(QTextCursor.End) |
|
134 |
cursor.insertText(text) |
|
135 |
self.ui.textEditConsole.setTextCursor(cursor) |
|
136 |
self.ui.textEditConsole.ensureCursorVisible() |
|
137 |
|
|
138 |
''' |
|
139 |
@brief close dialog by button click |
|
140 |
@author euisung |
|
141 |
@date 2018.10.18 |
|
142 |
''' |
|
143 |
def pushButtonCloseClicked(self): |
|
144 |
QDialog.reject(self) |
|
145 |
|
|
146 |
''' |
|
147 |
@brief update image list |
|
148 |
@author euisung |
|
149 |
@date 2018.10.18 |
|
150 |
''' |
|
151 |
def listUpdate(self): |
|
152 |
appDocData = AppDocData.instance() |
|
153 |
project = appDocData.getCurrentProject() |
|
154 |
dataList = appDocData.getTrainingFileList() |
|
155 |
imgCount = 0 |
|
156 |
for data in dataList: |
|
157 |
if data.find('.png') is not -1: |
|
158 |
imgCount += 1 |
|
159 |
self.ui.tableWidgetList.setRowCount(imgCount) |
|
160 |
|
|
161 |
row = 0 |
|
162 |
for data in dataList: |
|
163 |
if data.find('.png') is not -1: |
|
164 |
self.ui.tableWidgetList.setItem(row, 0, QTableWidgetItem(str(row + 1))) |
|
165 |
self.ui.tableWidgetList.setItem(row, 1, QTableWidgetItem(data)) |
|
166 |
allDataList = appDocData.getTrainingFileList() |
|
167 |
for adata in allDataList: |
|
168 |
boxName = data.replace('.png', '.boxS') |
|
169 |
if adata.find(boxName) is not -1: |
|
170 |
boxPath = os.path.join(project.getTrainingFilePath(), boxName) |
|
171 |
modifiedTime = str(datetime.datetime.strptime(time.ctime(os.path.getmtime(boxPath)), "%a %b %d %H:%M:%S %Y")) |
|
172 |
self.ui.tableWidgetList.setItem(row, 2, QTableWidgetItem(modifiedTime)) |
|
173 |
|
|
174 |
fw = open(boxPath, 'r', encoding='utf8') |
|
175 |
boxContent = fw.read() |
|
176 |
fw.close() |
|
177 |
boxContent = boxContent.split('\n') |
|
178 |
boxContent = boxContent[:-1] |
|
179 |
boxchars = '' |
|
180 |
for char in boxContent: |
|
181 |
boxchars += char[0] |
|
182 |
boxContent = QTableWidgetItem(boxchars) |
|
183 |
boxContent.setFont(QFont('Consolas', 9, QFont.Bold)) |
|
184 |
self.ui.tableWidgetList.setItem(row, 3, QTableWidgetItem(boxContent)) |
|
185 |
break |
|
186 |
else: |
|
187 |
self.ui.tableWidgetList.setItem(row, 2, QTableWidgetItem('')) |
|
188 |
self.ui.tableWidgetList.setItem(row, 3, QTableWidgetItem('')) |
|
189 |
row += 1 |
|
190 |
|
|
191 |
''' |
|
192 |
@brief delete training box only by button click |
|
193 |
@author euisung |
|
194 |
@date 2018.10.18 |
|
195 |
''' |
|
196 |
def pushButtonBoxDeleteClicked(self): |
|
197 |
try: |
|
198 |
row = self.ui.tableWidgetList.selectedIndexes()[0].row() |
|
199 |
col = self.ui.tableWidgetList.selectedIndexes()[0].column() |
|
200 |
drawingName = self.ui.tableWidgetList.item(row, 1).text() |
|
201 |
boxDate = self.ui.tableWidgetList.item(row, 2).text() |
|
202 |
if boxDate == '': |
|
203 |
return |
|
204 |
except Exception as ex: |
|
205 |
pass |
|
206 |
try: |
|
207 |
reply = QMessageBox.question(self, self.tr('Continue?'), self.tr('Are you sure you want to delete the box job? '), QMessageBox.Yes, QMessageBox.Cancel) |
|
208 |
if reply == QMessageBox.Yes: |
|
209 |
appDocData = AppDocData.instance() |
|
210 |
project = appDocData.getCurrentProject() |
|
211 |
|
|
212 |
drawingPath = os.path.join(project.getTrainingFilePath(), drawingName) |
|
213 |
boxName = drawingPath.replace('.png', '.boxS') |
|
214 |
if os.path.isfile(boxName): |
|
215 |
os.remove(boxName) |
|
216 |
self.ui.tableWidgetList.item(row, 2).setText('') |
|
217 |
self.ui.tableWidgetList.item(row, 3).setText('') |
|
218 |
#self.listUpdate() |
|
219 |
except Exception as ex: |
|
220 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
|
221 |
|
|
222 |
''' |
|
223 |
@brief delete training image and box by button click |
|
224 |
@author euisung |
|
225 |
@date 2018.10.18 |
|
226 |
''' |
|
227 |
def pushButtonImageDeleteClicked(self): |
|
228 |
try: |
|
229 |
row = self.ui.tableWidgetList.selectedIndexes()[0].row() |
|
230 |
col = self.ui.tableWidgetList.selectedIndexes()[0].column() |
|
231 |
drawingName = self.ui.tableWidgetList.item(row, 1).text() |
|
232 |
except Exception as ex: |
|
233 |
pass |
|
234 |
try: |
|
235 |
reply = QMessageBox.question(self, self.tr('Continue?'), self.tr('Are you sure you want to delete selected image? '), QMessageBox.Yes, QMessageBox.Cancel) |
|
236 |
if reply == QMessageBox.Yes: |
|
237 |
appDocData = AppDocData.instance() |
|
238 |
project = appDocData.getCurrentProject() |
|
239 |
|
|
240 |
drawingPath = os.path.join(project.getTrainingFilePath(), drawingName) |
|
241 |
if os.path.isfile(drawingPath): |
|
242 |
os.remove(drawingPath) |
|
243 |
boxName = drawingPath.replace('.png', '.boxS') |
|
244 |
if os.path.isfile(boxName): |
|
245 |
os.remove(boxName) |
|
246 |
self.ui.tableWidgetList.removeRow(row) |
|
247 |
#self.listUpdate() |
|
248 |
except Exception as ex: |
|
249 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
|
250 |
|
|
251 |
def dataReady(self): |
|
252 |
cursor = self.ui.textEditConsole.textCursor() |
|
253 |
cursor.movePosition(cursor.End) |
|
254 |
cursor.insertText(str(self.process.readAll())) |
|
255 |
self.ui.textEditConsole.ensureCursorVisible() |
|
256 |
|
|
257 |
''' |
|
258 |
@brief make training data by button click |
|
259 |
@author euisung |
|
260 |
@date 2018.10.17 |
|
261 |
''' |
|
262 |
def makeTrainingDataClicked(self): |
|
263 |
from PIL import Image |
|
264 |
import math |
|
265 |
from random import shuffle |
|
266 |
|
|
267 |
try: |
|
268 |
appDocData = AppDocData.instance() |
|
269 |
project = appDocData.getCurrentProject() |
|
270 |
self.oCRLang = appDocData.getCurrentProject().getName() |
|
271 |
self.deleteMidProcessFile() |
|
272 |
dataList = appDocData.getTrainingFileList() |
|
273 |
listHasBox = [] |
|
274 |
|
|
275 |
self.ui.progressBar.setValue(0) |
|
276 |
self.ui.progressBar.setMaximum(7 + QTrainingImageListDialog.TRAINING_DATA_COUNT) |
|
277 |
|
|
278 |
images = {} |
|
279 |
boxes = [] |
|
280 |
self.charList = [] |
|
281 |
for charCounts in defaultCharList: |
|
282 |
charCount = [charCounts[0], charCounts[1]] |
|
283 |
self.charList.append(charCount) |
|
284 |
for data in dataList: |
|
285 |
if data.find('.boxS') is not -1: |
|
286 |
hasBox = data.replace('.boxS', '.png') |
|
287 |
listHasBox.append(hasBox) |
|
288 |
drawingPath = os.path.join(project.getTrainingFilePath(), hasBox) |
|
289 |
drawing = Image.open(drawingPath) |
|
290 |
images[os.path.splitext(os.path.basename(drawingPath))[0]] = drawing # save image and file name |
|
291 |
|
|
292 |
boxPath = os.path.join(project.getTrainingFilePath(), data) |
|
293 |
box_file_name = os.path.splitext(os.path.basename(boxPath))[0] |
|
294 |
fw = open(boxPath, 'r', encoding='utf8') |
|
295 |
boxContent = fw.read() |
|
296 |
lines = boxContent.split('\n') |
|
297 |
for line in lines: |
|
298 |
if not line: continue |
|
299 |
char,min_x,min_y,max_x,max_y = line.split(' ') |
|
300 |
boxes.append([char,int(min_x),int(min_y),int(max_x)-int(min_x),int(max_y)-int(min_y), box_file_name]) |
|
301 |
|
|
302 |
matches = [_char for _char in self.charList if _char[0] == char] |
|
303 |
if matches: |
|
304 |
matches[0][1] = matches[0][1] + 1 |
|
305 |
else: |
|
306 |
self.charList.append([char, 1]) |
|
307 |
fw.close() |
|
308 |
|
|
309 |
grid_size = [None, None] |
|
310 |
for box in boxes: |
|
311 |
if grid_size[0] is None or grid_size[0] < box[3]: |
|
312 |
grid_size[0] = box[3] |
|
313 |
if grid_size[1] is None or grid_size[1] < box[4]: |
|
314 |
grid_size[1] = box[4] |
|
315 |
|
|
316 |
space = 5 |
|
317 |
grid_size[0] = grid_size[0] + space*2 |
|
318 |
grid_size[1] = grid_size[1] + space*2 |
|
319 |
|
|
320 |
dimension = [None, None] |
|
321 |
dimension[0] = int(math.sqrt(len(boxes)) + 1) |
|
322 |
dimension[1] = (len(boxes) // dimension[0] + 1) if (len(boxes) % dimension[0]) > 0 else len(boxes) // dimension[0] |
|
323 |
|
|
324 |
for sample in range(QTrainingImageListDialog.TRAINING_DATA_COUNT): |
|
325 |
shuffle(boxes) |
|
326 |
|
|
327 |
out_boxes = [] |
|
328 |
train_image = Image.new("RGB", (dimension[0]*(grid_size[0]), dimension[1]*(grid_size[1])), (256,256,256)) |
|
329 |
for j in range(dimension[1]): |
|
330 |
for i in range(dimension[0]): |
|
331 |
index = j*dimension[0] + i |
|
332 |
if index >= len(boxes): break |
|
333 |
loc = [i*(grid_size[0]), j*(grid_size[1])] |
|
334 |
box_image = images[boxes[index][5]].crop((boxes[index][1],images[boxes[index][5]].height - (boxes[index][2] + boxes[index][4]), boxes[index][1] + boxes[index][3],images[boxes[index][5]].height - boxes[index][2])) |
|
335 |
if boxes[index][0] == '"' or boxes[index][0] == '\'': |
|
336 |
x = loc[0] + int((grid_size[0] - box_image.width)*0.5)#space |
|
337 |
y = loc[1] + space |
|
338 |
elif boxes[index][0] == ',': |
|
339 |
x = loc[0] + int((grid_size[0] - box_image.width)*0.5)#space |
|
340 |
y = loc[1] + grid_size[1] - box_image.height - space |
|
341 |
else: |
|
342 |
x = loc[0] + int((grid_size[0] - box_image.width)*0.5)#space |
|
343 |
y = loc[1] + int((grid_size[1] - box_image.height)*0.5)#grid_size[1] - (space + box_image.height) |
|
344 |
|
|
345 |
# //remove noise |
|
346 |
''' |
|
347 |
if self.isNoisable(boxes[index][0]): |
|
348 |
image, contours, hierarchy = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE) |
|
349 |
for contour in contours: |
|
350 |
# remove too big one |
|
351 |
[x, y, w, h] = cv2.boundingRect(contour) |
|
352 |
if (w > maxTextSize and h > maxTextSize): continue |
|
353 |
|
|
354 |
area = cv2.contourArea(contour, True) |
|
355 |
if area >= 0: |
|
356 |
cv2.drawContours(contourImg, [contour], -1, (0,0,0), -1) |
|
357 |
cv2.drawContours(contourImg, [contour], -1, (255,255,255), 1) |
|
358 |
else: |
|
359 |
cv2.drawContours(contourImg, [contour], -1, (255,255,255), -1) |
|
360 |
else: |
|
361 |
train_image.paste(box_image, (x, y, x + box_image.width, y + box_image.height)) |
|
362 |
''' |
|
363 |
train_image.paste(box_image, (x, y, x + box_image.width, y + box_image.height)) |
|
364 |
out_boxes.append([boxes[index][0], |
|
365 |
str(x - 1), str(train_image.height - y - box_image.height - 1), |
|
366 |
str(x + box_image.width + 1), str(train_image.height - y + 1)]) |
|
367 |
|
|
368 |
train_image_path = os.path.join(project.getTrainingFilePath(), 'eng.' + self.oCRLang + 'F.exp{}.tif'.format(sample)) |
|
369 |
train_image.save(train_image_path, compression='tiff_lzw', dpi=(70,70)) |
|
370 |
|
|
371 |
train_box_path = os.path.join(project.getTrainingFilePath(), 'eng.' + self.oCRLang + 'F.exp{}.box'.format(sample)) |
|
372 |
fw = open(train_box_path, 'w', encoding='utf8') |
|
373 |
for out_box in out_boxes: |
|
374 |
fw.write(' '.join(out_box) + ' 0\n') |
|
375 |
fw.close() |
|
376 |
except Exception as ex: |
|
377 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
|
378 |
from App import App |
|
379 |
from AppDocData import MessageType |
|
380 |
|
|
381 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
382 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
383 |
return None |
|
384 |
|
|
385 |
try: |
|
386 |
originPath = os.getcwd() |
|
387 |
os.chdir(dataPath) |
|
388 |
|
|
389 |
self.ui.progressBar.setValue(self.ui.progressBar.value() + 1) |
|
390 |
QApplication.processEvents() |
|
391 |
|
|
392 |
# 1 |
|
393 |
for sample in range(QTrainingImageListDialog.TRAINING_DATA_COUNT): |
|
394 |
train_image_path = os.path.join(project.getTrainingFilePath(), 'eng.' + self.oCRLang + 'F.exp{}.tif'.format(sample)) |
|
395 |
if ' ' in train_image_path: |
|
396 |
train_image_path = self.get_short_path_name(train_image_path) |
|
397 |
train_box_path = os.path.join(project.getTrainingFilePath(), 'eng.' + self.oCRLang + 'F.exp{}'.format(sample)) |
|
398 |
if ' ' in train_box_path: |
|
399 |
train_box_path = self.get_short_path_name(train_box_path) |
|
400 |
|
|
401 |
trainCmd = '\"' + tesseract_cmd + '\" ' + train_image_path + ' ' + train_box_path + ' box.train' |
|
402 |
""" |
|
403 |
self.process = QProcess(self) |
|
404 |
self.process.readyRead.connect(self.dataReady) |
|
405 |
self.process.start('\"' + tesseract_cmd + '\"', [train_image_path, train_box_path, 'box.train']) |
|
406 |
""" |
|
407 |
subprocess.call(trainCmd, shell = True) |
|
408 |
|
|
409 |
self.ui.progressBar.setValue(self.ui.progressBar.value() + 1) |
|
410 |
QApplication.processEvents() |
|
411 |
|
|
412 |
# 2 |
|
413 |
train_boxes = [] |
|
414 |
for sample in range(QTrainingImageListDialog.TRAINING_DATA_COUNT): |
|
415 |
train_box_path = os.path.join(project.getTrainingFilePath(), 'eng.' + self.oCRLang + 'F.exp{}.box'.format(sample)) |
|
416 |
if ' ' in train_box_path: |
|
417 |
train_box_path = self.get_short_path_name(train_box_path) |
|
418 |
train_boxes.append(train_box_path) |
|
419 |
|
|
420 |
#trainingBoxPathU = self.get_short_path_name(trainingBoxPath) |
|
421 |
unicharsetExtractorCmd = '\"' + unicharset_extractor_cmd + '\"' + ' ' + ' '.join(train_boxes)# + ' &timeout 15' |
|
422 |
subprocess.call(unicharsetExtractorCmd, shell = True) |
|
423 |
|
|
424 |
self.ui.progressBar.setValue(self.ui.progressBar.value() + 1) |
|
425 |
QApplication.processEvents() |
|
426 |
|
|
427 |
# 3 |
|
428 |
unicharset = os.path.join(dataPath, 'unicharset') |
|
429 |
if ' ' in unicharset: |
|
430 |
unicharset = self.get_short_path_name(unicharset) |
|
431 |
|
|
432 |
""" |
|
433 |
scriptPath = ' --script_dir=//langdata-master' |
|
434 |
setUnicharsetPropertiesCmd = '\"' + set_unicharset_properties_cmd + '\" -U ' + inputUnicharset + ' -O ' + inputUnicharset + scriptPath# + ' &timeout 15' |
|
435 |
subprocess.call(setUnicharsetPropertiesCmd, shell = True) |
|
436 |
self.ui.labelProgress.setText('unicharset 파일을 생성했습니다. (3/8)') |
|
437 |
QApplication.processEvents() |
|
438 |
""" |
|
439 |
|
|
440 |
# 4 |
|
441 |
font_properties = os.path.join(project.getTrainingFilePath(), 'font_properties') |
|
442 |
fw = open(font_properties, 'w', encoding='utf8') |
|
443 |
fw.write('{}F 0 1 1 0 0\n'.format(self.oCRLang)) |
|
444 |
fw.close() |
|
445 |
self.ui.progressBar.setValue(self.ui.progressBar.value() + 1) |
|
446 |
QApplication.processEvents() |
|
447 |
|
|
448 |
# 5 |
|
449 |
if ' ' in font_properties: |
|
450 |
font_properties = self.get_short_path_name(font_properties) |
|
451 |
train_data_files = [] |
|
452 |
for sample in range(QTrainingImageListDialog.TRAINING_DATA_COUNT): |
|
453 |
train_data_path = os.path.join(project.getTrainingFilePath(), 'eng.' + self.oCRLang + 'F.exp{}.tr'.format(sample)) |
|
454 |
if os.path.isfile(train_data_path): |
|
455 |
if ' ' in train_data_path: |
|
456 |
train_data_path = self.get_short_path_name(train_data_path) |
|
457 |
train_data_files.append(train_data_path) |
|
458 |
|
|
459 |
shapeclusteringCmd = '\"' + shapeclustering_cmd + '\" -F ' + font_properties + ' -U ' + unicharset + ' ' + ' '.join(train_data_files)# + ' &timeout 15' |
|
460 |
subprocess.call(shapeclusteringCmd, shell = True) |
|
461 |
self.ui.progressBar.setValue(self.ui.progressBar.value() + 1) |
|
462 |
QApplication.processEvents() |
|
463 |
|
|
464 |
# 6 |
|
465 |
mftrainingCmd = '\"' + mftraining_cmd + '\" -F ' + font_properties + ' -U ' + unicharset + ' ' + ' '.join(train_data_files)# + ' &timeout 15' |
|
466 |
subprocess.call(mftrainingCmd, shell = True) |
|
467 |
self.ui.progressBar.setValue(self.ui.progressBar.value() + 1) |
|
468 |
QApplication.processEvents() |
|
469 |
|
|
470 |
# 7 |
|
471 |
cntrainingCmd = '\"' + cntraining_cmd + '\" ' + ' '.join(train_data_files)# + ' &timeout 15' |
|
472 |
subprocess.call(cntrainingCmd, shell = True) |
|
473 |
self.ui.progressBar.setValue(self.ui.progressBar.value() + 1) |
|
474 |
QApplication.processEvents() |
|
475 |
|
|
476 |
self.deleteMidProcessFile() |
|
477 |
|
|
478 |
os.rename(os.path.join(dataPath, 'inttemp'), os.path.join(dataPath, self.oCRLang + '.inttemp')) |
|
479 |
os.rename(os.path.join(dataPath, 'normproto'), os.path.join(dataPath, self.oCRLang + '.normproto')) |
|
480 |
os.rename(os.path.join(dataPath, 'pffmtable'), os.path.join(dataPath, self.oCRLang + '.pffmtable')) |
|
481 |
os.rename(os.path.join(dataPath, 'shapetable'), os.path.join(dataPath, self.oCRLang + '.shapetable')) |
|
482 |
os.rename(os.path.join(dataPath, 'unicharset'), os.path.join(dataPath, self.oCRLang + '.unicharset')) |
|
483 |
# 8 |
|
484 |
combineTessdataCmd = '\"' + combine_tessdata_cmd + '\" ' + self.oCRLang + '.' |
|
485 |
subprocess.call(combineTessdataCmd, shell = True) |
|
486 |
self.ui.progressBar.setValue(self.ui.progressBar.value() + 1) |
|
487 |
QApplication.processEvents() |
|
488 |
|
|
489 |
if os.path.isfile(os.path.join(tesseractPath, self.oCRLang + '.traineddata')): |
|
490 |
os.remove(os.path.join(tesseractPath, self.oCRLang + '.traineddata')) |
|
491 |
os.rename(os.path.join(dataPath, self.oCRLang + '.traineddata'), os.path.join(tesseractPath, self.oCRLang + '.traineddata')) |
|
492 |
|
|
493 |
self.deleteMidProcessFile() |
|
494 |
print(self.charList) |
|
495 |
self.makeChart() |
|
496 |
QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. ')) |
|
497 |
except Exception as ex: |
|
498 |
from App import App |
|
499 |
from AppDocData import MessageType |
|
500 |
|
|
501 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
502 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
503 |
finally: |
|
504 |
self.deleteMidProcessFile() |
|
505 |
os.chdir(originPath) |
|
506 |
|
|
507 |
#def isNoisable(self, char): |
|
508 |
# ''' |
|
509 |
# @brief return True if char need noise reduce process |
|
510 |
# @author euisung |
|
511 |
# @date 2018.11.20 |
|
512 |
# ''' |
|
513 |
# for passChar in noisePassList: |
|
514 |
# if char == passChar: |
|
515 |
# return False |
|
516 |
# return True |
|
517 |
|
|
518 |
def makeChart(self): |
|
519 |
''' |
|
520 |
@brief make chart for trained charaters |
|
521 |
@author euisung |
|
522 |
@date 2018.11.19 |
|
523 |
''' |
|
524 |
try: |
|
525 |
barList = [] |
|
526 |
categories = [] |
|
527 |
for char in self.charList: |
|
528 |
categories.append(char[0]) |
|
529 |
barList.append(char[1]) |
|
530 |
|
|
531 |
categoriesDict = [list(zip(range(len(categories)), categories))] |
|
532 |
|
|
533 |
if not hasattr(self, '_winChart'): |
|
534 |
self._winChart = pg.PlotWidget(background = 'w', title = 'Trained Characters') |
|
535 |
self._winChart.setMouseEnabled(False, False) |
|
536 |
self._plot = pg.BarGraphItem(x = range(len(categories)), height = barList, width = 0.6, brush = 'b') |
|
537 |
self._winChart.addItem(self._plot) |
|
538 |
xax = self._winChart.getAxis('bottom') |
|
539 |
yax = self._winChart.getAxis('left') |
|
540 |
xax.setPen('k') |
|
541 |
yax.setPen('k') |
|
542 |
xax.setTicks(categoriesDict) |
|
543 |
self._winChart.showGrid(x = True, y = True) |
|
544 |
|
|
545 |
self.ui.horizontalLayoutChart.addWidget(self._winChart) |
|
546 |
else: |
|
547 |
self._winChart.removeItem(self._plot) |
|
548 |
|
|
549 |
self._plot = pg.BarGraphItem(x = range(len(categories)), height = barList, width = 0.6, brush = 'b') |
|
550 |
self._winChart.addItem(self._plot) |
|
551 |
xax = self._winChart.getAxis('bottom') |
|
552 |
yax = self._winChart.getAxis('left') |
|
553 |
xax.setPen('k') |
|
554 |
yax.setPen('k') |
|
555 |
xax.setTicks(categoriesDict) |
|
556 |
self._winChart.showGrid(x = True, y = True) |
|
557 |
except Exception as ex: |
|
558 |
from App import App |
|
559 |
from AppDocData import MessageType |
|
560 |
|
|
561 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
562 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
563 |
|
|
564 |
''' |
|
565 |
@brief delete Mid Process File |
|
566 |
@author euisung |
|
567 |
@date 2018.10.22 |
|
568 |
''' |
|
569 |
def deleteMidProcessFile(self): |
|
570 |
try: |
|
571 |
if os.path.isfile(os.path.join(dataPath, self.oCRLang + '.inttemp')): |
|
572 |
os.remove(os.path.join(dataPath, self.oCRLang + '.inttemp')) |
|
573 |
if os.path.isfile(os.path.join(dataPath, self.oCRLang + '.normproto')): |
|
574 |
os.remove(os.path.join(dataPath, self.oCRLang + '.normproto')) |
|
575 |
if os.path.isfile(os.path.join(dataPath, self.oCRLang + '.pffmtable')): |
|
576 |
os.remove(os.path.join(dataPath, self.oCRLang + '.pffmtable')) |
|
577 |
if os.path.isfile(os.path.join(dataPath, self.oCRLang + '.shapetable')): |
|
578 |
os.remove(os.path.join(dataPath, self.oCRLang + '.shapetable')) |
|
579 |
if os.path.isfile(os.path.join(dataPath, self.oCRLang + '.unicharset')): |
|
580 |
os.remove(os.path.join(dataPath, self.oCRLang + '.unicharset')) |
|
581 |
except Exception as ex: |
|
582 |
from App import App |
|
583 |
from AppDocData import MessageType |
|
584 |
|
|
585 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
586 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
587 |
|
|
588 |
''' |
|
589 |
@brief make Box data by button click |
|
590 |
@author euisung |
|
591 |
@date 2018.10.16 |
|
592 |
''' |
|
593 |
def pushButtonBoxClicked(self): |
|
594 |
from PIL import Image |
|
595 |
|
|
596 |
try: |
|
597 |
row = self.ui.tableWidgetList.selectedIndexes()[0].row() |
|
598 |
col = self.ui.tableWidgetList.selectedIndexes()[0].column() |
|
599 |
drawingName = self.ui.tableWidgetList.item(row, 1).text() |
|
600 |
except: |
|
601 |
return |
|
602 |
|
|
603 |
try: |
|
604 |
appDocData = AppDocData.instance() |
|
605 |
project = appDocData.getCurrentProject() |
|
606 |
|
|
607 |
drawingPath = os.path.join(project.getTrainingFilePath(), drawingName) |
|
608 |
drawing = Image.open(drawingPath) |
|
609 |
|
|
610 |
boxName = drawingName.replace('.png', '.boxS') |
|
611 |
|
|
612 |
dataList = appDocData.getTrainingFileList() |
|
613 |
isBoxFile = False |
|
614 |
for data in dataList: |
|
615 |
if data.find(boxName) is not -1: |
|
616 |
isBoxFile = True |
|
617 |
trainingBoxPath = os.path.join(project.getTrainingFilePath(), boxName) |
|
618 |
boundaryOcrData = None |
|
619 |
if not isBoxFile: |
|
620 |
docData = AppDocData.instance() |
|
621 |
oCRLang = docData.getCurrentProject().getName() if TOCR.existTrainedData() else 'eng' |
|
622 |
whiteCharList = docData.getConfigs('Text Recognition', 'White Character List') |
|
623 |
if len(whiteCharList) is 0: |
|
624 |
boundaryOcrData = pytesseract.image_to_boxes(drawing, config=TOCR.DEFAULT_CONF, lang=oCRLang) |
|
625 |
else: |
|
626 |
boundaryOcrData = pytesseract.image_to_boxes(drawing, config=TOCR.DEFAULT_CONF_COMM + whiteCharList[0].value, lang=oCRLang) |
|
627 |
|
|
628 |
except Exception as ex: |
|
629 |
from App import App |
|
630 |
from AppDocData import MessageType |
|
631 |
|
|
632 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
633 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
634 |
|
|
635 |
try: |
|
636 |
dialog = QTrainingEditorDialog(self, drawingPath, trainingBoxPath, boundaryOcrData, self.ui.tableWidgetList.item(row, 2), self.ui.tableWidgetList.item(row, 3)) |
|
637 |
dialog.exec_() |
|
638 |
except Exception as ex: |
|
639 |
from App import App |
|
640 |
from AppDocData import MessageType |
|
641 |
|
|
642 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
643 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
644 |
|
|
645 |
return |
|
646 |
|
|
647 |
''' |
|
648 |
@brief add drawing to Selected by button click |
|
649 |
@author euisung |
|
650 |
@date 2018.09.28 |
|
651 |
''' |
|
652 |
def addListClicked(self): |
|
653 |
try: |
|
654 |
row = self.ui.tableWidgetList.selectedIndexes()[0].row() |
|
655 |
col = self.ui.tableWidgetList.selectedIndexes()[0].column() |
|
656 |
self.listCellDoubleClicked(row, col) |
|
657 |
except Exception as ex: |
|
658 |
pass |
|
659 |
''' |
|
660 |
@brief delete character in box data as batch |
|
661 |
@author euisung |
|
662 |
@date 2019.02.22 |
|
663 |
''' |
|
664 |
def pushButtonDeleteBatchCharClicked(self): |
|
665 |
try: |
|
666 |
targetChar = self.ui.lineEditTargetChar.text() |
|
667 |
if targetChar == '': |
|
668 |
return |
|
669 |
reply = QMessageBox.question(self, self.tr('Continue?'), self.tr('Are you sure you want to delete character "{}" in all box data?\nData can not be restored! '.format(targetChar)), QMessageBox.Yes, QMessageBox.Cancel) |
|
670 |
if reply == QMessageBox.Yes: |
|
671 |
appDocData = AppDocData.instance() |
|
672 |
project = appDocData.getCurrentProject() |
|
673 |
|
|
674 |
drawingPath = project.getTrainingFilePath() |
|
675 |
boxList = os.listdir(drawingPath) |
|
676 |
nonBoxList = [] |
|
677 |
|
|
678 |
for index in range(len(boxList)): |
|
679 |
if boxList[index][-4:] != 'boxS': |
|
680 |
nonBoxList.append(index) |
|
681 |
|
|
682 |
nonBoxList.sort(reverse=True) |
|
683 |
for index in nonBoxList: |
|
684 |
boxList.pop(index) |
|
685 |
|
|
686 |
for box in boxList: |
|
687 |
boxPath = os.path.join(drawingPath, box) |
|
688 |
fw = open(boxPath, 'r', encoding='utf8') |
|
689 |
boxContent = fw.read() |
|
690 |
fw.close() |
|
691 |
boxContent = boxContent.split('\n')[:-1] |
|
692 |
newBoxContent = [] |
|
693 |
for boxString in boxContent: |
|
694 |
if boxString[0] != targetChar: |
|
695 |
newBoxContent.append(boxString) |
|
696 |
|
|
697 |
outBox = '' |
|
698 |
for boxString in newBoxContent: |
|
699 |
outBox += boxString + '\n' |
|
700 |
fw = open(boxPath, 'w', encoding='utf8') |
|
701 |
fw.write(outBox) |
|
702 |
fw.close() |
|
703 |
|
|
704 |
#self.listUpdate() |
|
705 |
self.ui.lineEditTargetChar.setText('') |
|
706 |
except Exception as ex: |
|
707 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
|
708 |
|
|
709 |
''' |
|
710 |
@brief make Box data by cell double click |
|
711 |
@author euisung |
|
712 |
@date 2018.09.28 |
|
713 |
''' |
|
714 |
def listCellDoubleClicked(self, row, col): |
|
715 |
self.pushButtonBoxClicked() |
|
716 |
|
|
717 |
def get_short_path_name(self, long_name): |
|
718 |
""" |
|
719 |
Gets the short path name of a given long path. |
|
720 |
http://stackoverflow.com/a/23598461/200291 |
|
721 |
""" |
|
722 |
output_buf_size = 0 |
|
723 |
while True: |
|
724 |
output_buf = ctypes.create_unicode_buffer(output_buf_size) |
|
725 |
needed = _GetShortPathNameW(long_name, output_buf, output_buf_size) |
|
726 |
if output_buf_size >= needed: |
|
727 |
return output_buf.value |
|
728 |
else: |
|
729 |
output_buf_size = needed |
|
730 |
|
|
731 |
''' |
|
732 |
@brief key pressed event |
|
733 |
@author euisung |
|
734 |
@date 2018.11.05 |
|
735 |
''' |
|
736 |
def keyPressEvent(self, event): |
|
737 |
try: |
|
738 |
if event.key() == Qt.Key_Delete: |
|
739 |
try: |
|
740 |
col = self.ui.tableWidgetList.selectedIndexes()[0].column() |
|
741 |
if col == 1: |
|
742 |
self.pushButtonImageDeleteClicked() |
|
743 |
elif col == 2: |
|
744 |
self.pushButtonBoxDeleteClicked() |
|
745 |
except Exception as ex: |
|
746 |
pass |
|
747 |
|
|
748 |
QDialog.keyPressEvent(self, event) |
|
749 |
except Exception as ex: |
|
750 |
from App import App |
|
751 |
from AppDocData import MessageType |
|
752 |
|
|
753 |
message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno) |
|
754 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
|
755 |
return None |
DTI_PID/DTI_PID/TrainingImageList_UI.py | ||
---|---|---|
1 |
# -*- coding: utf-8 -*- |
|
2 |
|
|
3 |
# Form implementation generated from reading ui file './UI/TrainingImageList.ui' |
|
4 |
# |
|
5 |
# Created by: PyQt5 UI code generator 5.11.3 |
|
6 |
# |
|
7 |
# WARNING! All changes made in this file will be lost! |
|
8 |
|
|
9 |
from PyQt5 import QtCore, QtGui, QtWidgets |
|
10 |
|
|
11 |
class Ui_TraingingImageListDialog(object): |
|
12 |
def setupUi(self, TraingingImageListDialog): |
|
13 |
TraingingImageListDialog.setObjectName("TraingingImageListDialog") |
|
14 |
TraingingImageListDialog.resize(1556, 707) |
|
15 |
font = QtGui.QFont() |
|
16 |
font.setFamily("맑은 고딕") |
|
17 |
font.setBold(True) |
|
18 |
font.setWeight(75) |
|
19 |
TraingingImageListDialog.setFont(font) |
|
20 |
self.gridLayout = QtWidgets.QGridLayout(TraingingImageListDialog) |
|
21 |
self.gridLayout.setObjectName("gridLayout") |
|
22 |
self.horizontalLayout_4 = QtWidgets.QHBoxLayout() |
|
23 |
self.horizontalLayout_4.setObjectName("horizontalLayout_4") |
|
24 |
self.pushButtonDeleteBatchChar = QtWidgets.QPushButton(TraingingImageListDialog) |
|
25 |
self.pushButtonDeleteBatchChar.setObjectName("pushButtonDeleteBatchChar") |
|
26 |
self.horizontalLayout_4.addWidget(self.pushButtonDeleteBatchChar) |
|
27 |
self.lineEditTargetChar = QtWidgets.QLineEdit(TraingingImageListDialog) |
|
28 |
self.lineEditTargetChar.setMaximumSize(QtCore.QSize(20, 16777215)) |
|
29 |
self.lineEditTargetChar.setMaxLength(1) |
|
30 |
self.lineEditTargetChar.setObjectName("lineEditTargetChar") |
|
31 |
self.horizontalLayout_4.addWidget(self.lineEditTargetChar) |
|
32 |
spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) |
|
33 |
self.horizontalLayout_4.addItem(spacerItem) |
|
34 |
self.pushButtonImageDelete = QtWidgets.QPushButton(TraingingImageListDialog) |
|
35 |
self.pushButtonImageDelete.setMinimumSize(QtCore.QSize(90, 0)) |
|
36 |
self.pushButtonImageDelete.setAutoDefault(False) |
|
37 |
self.pushButtonImageDelete.setObjectName("pushButtonImageDelete") |
|
38 |
self.horizontalLayout_4.addWidget(self.pushButtonImageDelete) |
|
39 |
self.pushButtonBoxDelete = QtWidgets.QPushButton(TraingingImageListDialog) |
|
40 |
self.pushButtonBoxDelete.setMinimumSize(QtCore.QSize(90, 0)) |
|
41 |
self.pushButtonBoxDelete.setAutoDefault(False) |
|
42 |
self.pushButtonBoxDelete.setObjectName("pushButtonBoxDelete") |
|
43 |
self.horizontalLayout_4.addWidget(self.pushButtonBoxDelete) |
|
44 |
self.gridLayout.addLayout(self.horizontalLayout_4, 0, 0, 1, 1) |
|
45 |
self.horizontalLayout_3 = QtWidgets.QHBoxLayout() |
|
46 |
self.horizontalLayout_3.setObjectName("horizontalLayout_3") |
|
47 |
self.label = QtWidgets.QLabel(TraingingImageListDialog) |
|
48 |
self.label.setMaximumSize(QtCore.QSize(100, 16777215)) |
|
49 |
font = QtGui.QFont() |
|
50 |
font.setBold(False) |
|
51 |
font.setWeight(50) |
|
52 |
self.label.setFont(font) |
|
53 |
self.label.setObjectName("label") |
|
54 |
self.horizontalLayout_3.addWidget(self.label) |
|
55 |
self.checkBoxItalic = QtWidgets.QCheckBox(TraingingImageListDialog) |
|
56 |
self.checkBoxItalic.setMaximumSize(QtCore.QSize(100, 16777215)) |
|
57 |
font = QtGui.QFont() |
|
58 |
font.setBold(False) |
|
59 |
font.setWeight(50) |
|
60 |
self.checkBoxItalic.setFont(font) |
|
61 |
self.checkBoxItalic.setObjectName("checkBoxItalic") |
|
62 |
self.horizontalLayout_3.addWidget(self.checkBoxItalic) |
내보내기 Unified diff