프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / OcrResultDialog.py @ 17cbda7d

이력 | 보기 | 이력해설 | 다운로드 (12 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 not self.isModify:
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
            app_doc_data = AppDocData.instance()
127

    
128
            ocr_data = self.ui.comboBoxOCRData.currentText()
129

    
130
            whiteCharList = app_doc_data.getConfigs('Text Recognition', 'White Character List')
131
            if len(whiteCharList) is 0:
132
                self.textInfoList = TOCR.getTextInfo(img, (round(self.boundingBox.x()), round(self.boundingBox.y())), 0,
133
                                                     language=ocr_data)
134
            else:
135
                self.textInfoList = TOCR.getTextInfo(img, (round(self.boundingBox.x()), round(self.boundingBox.y())), 0,
136
                                                     language=ocr_data, conf=whiteCharList[0].value)
137

    
138
            if self.textInfoList is not None and len(self.textInfoList) > 0:
139
                self.ui.detectResultTextEdit.setText(self.getPlainText(self.textInfoList))
140
                for textInfo in self.textInfoList:
141
                    self.graphicsView.scene.addRect(textInfo.getX() - int(self.boundingBox.x()),
142
                                                    textInfo.getY() - int(self.boundingBox.y()), textInfo.getW(),
143
                                                    textInfo.getH(), QPen(Qt.red, 1, Qt.SolidLine))
144
            else:
145
                self.ui.detectResultTextEdit.setText("Not Found")
146
        except Exception as ex:
147
            from App import App
148
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
149
                                                           sys.exc_info()[-1].tb_lineno)
150
            App.mainWnd().addMessage.emit(MessageType.Error, message)
151

    
152
    def getPlainText(self, textInfoList):
153
        text = ''
154
        for index in range(len(textInfoList)):
155
            textInfo = textInfoList[index]
156
            if index != 0:
157
                text = text + '\n'
158
            text = text + textInfo.getText()
159
        return text
160

    
161
    '''
162
        @brief      OK Button Clicked. Remake TextInfo object
163
        @author     Jeongwoo
164
        @date       18.04.19
165
        @history    18.04.20    Jeongwoo    Calculate Start Point Coordinates by rotated angle
166
                    18.04.26    Jeongwoo    Scene.itemAt(textX - boundBox.x(), textY - boundBox.y())
167
    '''
168

    
169
    def accept(self):
170
        from TextInfo import TextInfo
171
        self.isAccepted = True
172

    
173
        try:
174
            text = self.ui.detectResultTextEdit.toPlainText()
175
            if text == '' or text == 'Not Found':
176
                QMessageBox.about(self.ui.ocrDialogButtonBox, 'Notice', 'Please try again after recognition or type.')
177
                return
178

    
179
            isSplit = self.ui.checkBoxSeperate.isChecked()
180
            if isSplit:
181
                splitText = text.split('\n')
182
            else:
183
                splitText = [text]
184

    
185
            if not len(self.textInfoList) > 0:
186
                import cv2
187

    
188
                buffer = QBuffer()
189
                buffer.open(QBuffer.ReadWrite)
190
                self.image.save(buffer, "PNG")
191
                pyImage = Image.open(io.BytesIO(buffer.data()))
192
                img = np.array(pyImage)
193

    
194
                img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
195
                imgNot = np.ones(img.shape, np.uint8)
196
                cv2.bitwise_not(img, imgNot)
197
                imgNot = cv2.dilate(imgNot, np.ones((8, 8), np.uint8))
198

    
199
                contours, hierarchy = cv2.findContours(imgNot, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
200
                minX, minY, maxX, maxY = sys.maxsize, sys.maxsize, 0, 0
201
                if len(contours) is 0:
202
                    minX, minY, maxX, maxY = self.boundingBox.x(), self.boundingBox.y(), self.boundingBox.x() + self.image.width(), self.boundingBox.y() + self.image.height()
203
                else:
204
                    minX, minY, maxX, maxY = sys.maxsize, sys.maxsize, 0, 0
205
                    for cnt in contours:
206
                        x, y, w, h = cv2.boundingRect(cnt)
207
                        minX = min(x, minX)
208
                        minY = min(y, minY)
209
                        maxX = max(x + w, maxX)
210
                        maxY = max(y + h, maxY)
211
                    minX, minY, maxX, maxY = minX + self.boundingBox.x(), minY + self.boundingBox.y(), maxX + self.boundingBox.x(), maxY + self.boundingBox.y()
212

    
213
                self.textInfoList.append(TextInfo(text, minX, minY, maxX - minX, maxY - minY, 0))
214

    
215
            if not isSplit:
216
                minX, minY, maxX, maxY = sys.maxsize, sys.maxsize, 0, 0
217
                for textInfo in self.textInfoList:
218
                    x, y, w, h = textInfo.getX(), textInfo.getY(), textInfo.getW(), textInfo.getH()
219
                    minX = min(x, minX)
220
                    minY = min(y, minY)
221
                    maxX = max(x + w, maxX)
222
                    maxY = max(y + h, maxY)
223

    
224
                self.textInfoList = [TextInfo(text, minX, minY, maxX - minX, maxY - minY, 0)]
225

    
226
            if len(self.textInfoList) > 0:
227
                for index in range(len(splitText)):
228
                    textInfo = self.textInfoList[index]
229
                    item = self.graphicsView.scene.itemAt(QPointF(float(textInfo.getX() - int(self.boundingBox.x())),
230
                                                                  float(textInfo.getY() - int(self.boundingBox.y()))),
231
                                                          QTransform())
232
                    if item is not None:
233
                        # Transform rectangle for calculate start point
234
                        imgTransform = QTransform()
235
                        if self.angle == 90 or self.angle == 270:
236
                            imgTransform.translate(self.image.height() * 0.5, self.image.width() * 0.5)
237
                        elif self.angle == 0 or self.angle == 360:
238
                            imgTransform.translate(self.image.width() * 0.5, self.image.height() * 0.5)
239
                        imgTransform.rotate(-abs(self.angle))
240
                        imgTransform.translate(-self.image.width() * 0.5, -self.image.height() * 0.5)
241
                        rect = QRect(textInfo.getX() - int(self.boundingBox.x()),
242
                                     textInfo.getY() - int(self.boundingBox.y()), textInfo.getW(), textInfo.getH())
243
                        rect = imgTransform.mapRect(rect)
244
                        # up to here
245
                        textInfo.setX(rect.x() + int(self.boundingBox.x()))
246
                        textInfo.setY(rect.y() + int(self.boundingBox.y()))
247
                        textInfo.setText(splitText[index])
248
                        radian = round(math.radians(abs(self.angle)), 2)
249
                        textInfo.setAngle(radian)  # 360 degree == 6.28319 radian
250
                        if radian == 1.57 or radian == 4.71:
251
                            width = textInfo.getW()
252
                            height = textInfo.getH()
253
                            textInfo.setW(height)  # SWAP
254
                            textInfo.setH(width)  # SWAP
255
                self.textInfoList = self.textInfoList[:len(splitText)]
256

    
257
                QDialog.accept(self)
258

    
259
        except Exception as ex:
260
            from App import App
261
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
262
                                                           sys.exc_info()[-1].tb_lineno)
263
            App.mainWnd().addMessage.emit(MessageType.Error, message)
264

    
265
    def reject(self):
266
        self.isAccepted = False
267
        self.textInfoList = None
268
        QDialog.reject(self)
269

    
270
    '''
271
        @brief  Display this QDialog
272
    '''
273

    
274
    def showDialog(self):
275
        # self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
276
        self.exec_()
277
        return (self.isAccepted, self.textInfoList)
클립보드 이미지 추가 (최대 크기: 500 MB)