hytos / DTI_PID / DTI_PID / OcrResultDialog.py @ 02e3cc34
이력 | 보기 | 이력해설 | 다운로드 (12.5 KB)
1 |
# coding: utf-8
|
---|---|
2 |
"""
|
3 |
This is ocr result dialog module
|
4 |
"""
|
5 |
from PIL import Image |
6 |
import io, sys |
7 |
import numpy as np |
8 |
import math |
9 |
from PyQt5.QtCore import * |
10 |
from PyQt5.QtGui import * |
11 |
from PyQt5.QtWidgets import * |
12 |
import OcrResultDialog_UI |
13 |
import QtImageViewer |
14 |
import tesseract_ocr_module as TOCR |
15 |
from App import App |
16 |
from AppDocData import * |
17 |
|
18 |
|
19 |
class QOcrResultDialog(QDialog): |
20 |
def __init__(self, parent, qimage, boundingBox, isModify=False, text=None): |
21 |
QDialog.__init__(self, parent)
|
22 |
self.textInfoList = []
|
23 |
|
24 |
self.isModify = isModify
|
25 |
self.image = qimage
|
26 |
self.originImageWidth = qimage.width()
|
27 |
self.originImageHeight = qimage.height()
|
28 |
self.boundingBox = boundingBox
|
29 |
|
30 |
self.angle = 0 # angle is degree |
31 |
|
32 |
self.ui = OcrResultDialog_UI.Ui_Dialog()
|
33 |
self.ui.setupUi(self) |
34 |
|
35 |
appDocData = AppDocData.instance() |
36 |
configs = appDocData.getAppConfigs('app', 'mode') |
37 |
if configs and 1 == len(configs) and 'advanced' == configs[0].value: |
38 |
pass
|
39 |
else:
|
40 |
self.ui.pushButtonMakeTrainingImage.setVisible(False) |
41 |
|
42 |
self.imgW = qimage.width()
|
43 |
self.imgH = qimage.height()
|
44 |
self.image = self.image.scaled(self.imgW, self.imgH) |
45 |
self.graphicsView = QtImageViewer.QtImageViewer(App.mainWnd())
|
46 |
self.graphicsView.useDefaultCommand() ##### USE DEFAULT COMMAND |
47 |
self.graphicsView.setImage(self.image) |
48 |
self.ui.horizontalLayoutGraphicsView.addWidget(self.graphicsView) |
49 |
|
50 |
self.ui.counterClockPushButton_2.clicked.connect(lambda: self.rotateImage(True)) |
51 |
self.ui.clockPushButton_2.clicked.connect(lambda: self.rotateImage(False)) |
52 |
self.ui.redetectPushButton_2.clicked.connect(self.detectText) |
53 |
self.ui.pushButtonMakeTrainingImage.clicked.connect(self.pushButtonMakeTrainingImageClicked) |
54 |
|
55 |
self.ui.comboBoxOCRData.addItem('eng') |
56 |
tessdata_path = os.path.join(os.getenv('ALLUSERSPROFILE'), 'Digital PID', 'Tesseract-OCR', 'tessdata') |
57 |
if os.path.isfile(os.path.join(tessdata_path, appDocData.getCurrentProject().getName() + '.traineddata')): |
58 |
self.ui.comboBoxOCRData.addItem(appDocData.getCurrentProject().getName())
|
59 |
|
60 |
configs = appDocData.getConfigs('Text Recognition', 'OCR Data') |
61 |
value = configs[0].value if 1 == len(configs) else '' |
62 |
if value:
|
63 |
at = self.ui.comboBoxOCRData.findText(value)
|
64 |
self.ui.comboBoxOCRData.setCurrentIndex(at)
|
65 |
else:
|
66 |
self.ui.comboBoxOCRData.selectedIndex = 0 |
67 |
|
68 |
if self.isModify == False: |
69 |
self.detectText()
|
70 |
else:
|
71 |
self.ui.detectResultTextEdit.setPlainText(text)
|
72 |
|
73 |
self.isAccepted = False |
74 |
|
75 |
'''
|
76 |
@brief Make OCR Training Image
|
77 |
@author euisung
|
78 |
@date 2018.10.16
|
79 |
@history euisung 2018.11.02 add notice push
|
80 |
'''
|
81 |
|
82 |
def pushButtonMakeTrainingImageClicked(self): |
83 |
import uuid |
84 |
uid = str(uuid.uuid4()) + '.png' |
85 |
appDocData = AppDocData.instance() |
86 |
project = appDocData.getCurrentProject() |
87 |
trainingImgPath = os.path.join(project.getTrainingFilePath(), uid) |
88 |
|
89 |
self.image.save(trainingImgPath)
|
90 |
QMessageBox.about(self, self.tr("INFO"), self.tr('Successfully saved.')) |
91 |
QDialog.reject(self)
|
92 |
|
93 |
def rotateImage(self, isCounterClock): |
94 |
for item in self.graphicsView.scene.items(): |
95 |
self.graphicsView.scene.removeItem(item)
|
96 |
self.graphicsView.clearImage()
|
97 |
transform = QTransform() |
98 |
if isCounterClock:
|
99 |
'''CounterClock'''
|
100 |
self.angle = (self.angle - 90) % 360 |
101 |
transform.rotate(-90)
|
102 |
else:
|
103 |
'''Clock'''
|
104 |
self.angle = (self.angle - 270) % 360 |
105 |
transform.rotate(90)
|
106 |
# print(str(360 - self.angle))
|
107 |
self.image = self.image.transformed(transform) |
108 |
self.graphicsView.setImage(self.image) |
109 |
self.textInfoList = []
|
110 |
|
111 |
'''
|
112 |
@history 2018.04.26 Jeongwoo Add Rectangle with modified Coords
|
113 |
2018.06.20 Jeongwoo Remove test code
|
114 |
2018.11.08 euisung add white char list check process on db
|
115 |
2018.11.22 euisung OCR lang apply fixed
|
116 |
'''
|
117 |
|
118 |
def detectText(self): |
119 |
try:
|
120 |
buffer = QBuffer() |
121 |
buffer.open(QBuffer.ReadWrite)
|
122 |
self.image.save(buffer, "PNG") |
123 |
pyImage = Image.open(io.BytesIO(buffer.data()))
|
124 |
img = np.array(pyImage) |
125 |
|
126 |
# self.image.save('c:\\temp\\a.png')
|
127 |
|
128 |
docData = AppDocData.instance() |
129 |
|
130 |
'''
|
131 |
# get ocr data of area which has the text
|
132 |
pt = self.boundingBox.center()
|
133 |
areas = [area for area in docData.getAreaList() if area.contains((pt.x(), pt.y()))]
|
134 |
ocr_data = sorted(areas, key=lambda attr: attr.area)[0].OCRData if areas else 'eng'
|
135 |
# up to here
|
136 |
'''
|
137 |
ocr_data = self.ui.comboBoxOCRData.currentText()
|
138 |
|
139 |
whiteCharList = docData.getConfigs('Text Recognition', 'White Character List') |
140 |
if len(whiteCharList) is 0: |
141 |
self.textInfoList = TOCR.getTextInfo(img, (round(self.boundingBox.x()), round(self.boundingBox.y())), 0, |
142 |
language=ocr_data) |
143 |
else:
|
144 |
self.textInfoList = TOCR.getTextInfo(img, (round(self.boundingBox.x()), round(self.boundingBox.y())), 0, |
145 |
language=ocr_data, conf=whiteCharList[0].value)
|
146 |
|
147 |
if self.textInfoList is not None and len(self.textInfoList) > 0: |
148 |
self.ui.detectResultTextEdit.setText(self.getPlainText(self.textInfoList)) |
149 |
for textInfo in self.textInfoList: |
150 |
self.graphicsView.scene.addRect(textInfo.getX() - int(self.boundingBox.x()), |
151 |
textInfo.getY() - int(self.boundingBox.y()), textInfo.getW(), |
152 |
textInfo.getH(), QPen(Qt.red, 1, Qt.SolidLine))
|
153 |
else:
|
154 |
self.ui.detectResultTextEdit.setText("Not Found") |
155 |
except Exception as ex: |
156 |
from App import App |
157 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
158 |
sys.exc_info()[-1].tb_lineno)
|
159 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
160 |
|
161 |
def getPlainText(self, textInfoList): |
162 |
text = ''
|
163 |
for index in range(len(textInfoList)): |
164 |
textInfo = textInfoList[index] |
165 |
if index != 0: |
166 |
text = text + '\n'
|
167 |
text = text + textInfo.getText() |
168 |
return text
|
169 |
|
170 |
'''
|
171 |
@brief OK Button Clicked. Remake TextInfo object
|
172 |
@author Jeongwoo
|
173 |
@date 18.04.19
|
174 |
@history 18.04.20 Jeongwoo Calculate Start Point Coordinates by rotated angle
|
175 |
18.04.26 Jeongwoo Scene.itemAt(textX - boundBox.x(), textY - boundBox.y())
|
176 |
'''
|
177 |
|
178 |
def accept(self): |
179 |
from TextInfo import TextInfo |
180 |
self.isAccepted = True |
181 |
|
182 |
try:
|
183 |
text = self.ui.detectResultTextEdit.toPlainText()
|
184 |
if text == '' or text == 'Not Found': |
185 |
QMessageBox.about(self.ui.ocrDialogButtonBox, 'Notice', 'Please try again after recognition or type.') |
186 |
return
|
187 |
|
188 |
isSplit = self.ui.checkBoxSeperate.isChecked()
|
189 |
if isSplit:
|
190 |
splitText = text.split('\n')
|
191 |
else:
|
192 |
splitText = [text] |
193 |
|
194 |
if not len(self.textInfoList) > 0: |
195 |
import cv2 |
196 |
# QMessageBox.about(self.ui.ocrDialogButtonBox, "알림", "텍스트 검출을 하신 후 다시 시도해주세요.")
|
197 |
|
198 |
buffer = QBuffer() |
199 |
buffer.open(QBuffer.ReadWrite)
|
200 |
self.image.save(buffer, "PNG") |
201 |
pyImage = Image.open(io.BytesIO(buffer.data()))
|
202 |
img = np.array(pyImage) |
203 |
|
204 |
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) |
205 |
imgNot = np.ones(img.shape, np.uint8) |
206 |
cv2.bitwise_not(img, imgNot) |
207 |
imgNot = cv2.dilate(imgNot, np.ones((8, 8), np.uint8)) |
208 |
|
209 |
contours, hierarchy = cv2.findContours(imgNot, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
210 |
minX, minY, maxX, maxY = sys.maxsize, sys.maxsize, 0, 0 |
211 |
if len(contours) is 0: |
212 |
minX, minY, maxX, maxY = self.boundingBox.x(), self.boundingBox.y(), self.boundingBox.x() + self.image.width(), self.boundingBox.y() + self.image.height() |
213 |
else:
|
214 |
minX, minY, maxX, maxY = sys.maxsize, sys.maxsize, 0, 0 |
215 |
for cnt in contours: |
216 |
x, y, w, h = cv2.boundingRect(cnt) |
217 |
minX = min(x, minX)
|
218 |
minY = min(y, minY)
|
219 |
maxX = max(x + w, maxX)
|
220 |
maxY = max(y + h, maxY)
|
221 |
minX, minY, maxX, maxY = minX + self.boundingBox.x(), minY + self.boundingBox.y(), maxX + self.boundingBox.x(), maxY + self.boundingBox.y() |
222 |
|
223 |
self.textInfoList.append(TextInfo(text, minX, minY, maxX - minX, maxY - minY, 0)) |
224 |
|
225 |
if not isSplit: |
226 |
minX, minY, maxX, maxY = sys.maxsize, sys.maxsize, 0, 0 |
227 |
for textInfo in self.textInfoList: |
228 |
x, y, w, h = textInfo.getX(), textInfo.getY(), textInfo.getW(), textInfo.getH() |
229 |
minX = min(x, minX)
|
230 |
minY = min(y, minY)
|
231 |
maxX = max(x + w, maxX)
|
232 |
maxY = max(y + h, maxY)
|
233 |
|
234 |
self.textInfoList = [TextInfo(text, minX, minY, maxX - minX, maxY - minY, 0)] |
235 |
|
236 |
if len(self.textInfoList) > 0: |
237 |
for index in range(len(splitText)): |
238 |
textInfo = self.textInfoList[index]
|
239 |
item = self.graphicsView.scene.itemAt(QPointF(float(textInfo.getX() - int(self.boundingBox.x())), |
240 |
float(textInfo.getY() - int(self.boundingBox.y()))), |
241 |
QTransform()) |
242 |
if item is not None: |
243 |
## Transform rectangle for calculate start point
|
244 |
imgTransform = QTransform() |
245 |
if self.angle == 90 or self.angle == 270: |
246 |
imgTransform.translate(self.image.height() * 0.5, self.image.width() * 0.5) |
247 |
elif self.angle == 0 or self.angle == 360: |
248 |
imgTransform.translate(self.image.width() * 0.5, self.image.height() * 0.5) |
249 |
imgTransform.rotate(-abs(self.angle)) |
250 |
imgTransform.translate(-self.image.width() * 0.5, -self.image.height() * 0.5) |
251 |
rect = QRect(textInfo.getX() - int(self.boundingBox.x()), |
252 |
textInfo.getY() - int(self.boundingBox.y()), textInfo.getW(), textInfo.getH()) |
253 |
rect = imgTransform.mapRect(rect) |
254 |
## up to here
|
255 |
textInfo.setX(rect.x() + int(self.boundingBox.x())) |
256 |
textInfo.setY(rect.y() + int(self.boundingBox.y())) |
257 |
textInfo.setText(splitText[index]) |
258 |
radian = round(math.radians(abs(self.angle)), 2) |
259 |
textInfo.setAngle(radian) # 360 degree == 6.28319 radian
|
260 |
if radian == 1.57 or radian == 4.71: |
261 |
width = textInfo.getW() |
262 |
height = textInfo.getH() |
263 |
textInfo.setW(height) ## SWAP
|
264 |
textInfo.setH(width) ## SWAP
|
265 |
self.textInfoList = self.textInfoList[:len(splitText)] |
266 |
|
267 |
QDialog.accept(self)
|
268 |
|
269 |
except Exception as ex: |
270 |
from App import App |
271 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
272 |
sys.exc_info()[-1].tb_lineno)
|
273 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
274 |
|
275 |
def reject(self): |
276 |
self.isAccepted = False |
277 |
self.textInfoList = None |
278 |
QDialog.reject(self)
|
279 |
|
280 |
'''
|
281 |
@brief Display this QDialog
|
282 |
'''
|
283 |
|
284 |
def showDialog(self): |
285 |
# self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
|
286 |
self.exec_()
|
287 |
return (self.isAccepted, self.textInfoList) |