프로젝트

일반

사용자정보

통계
| 개정판:

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)
클립보드 이미지 추가 (최대 크기: 500 MB)