프로젝트

일반

사용자정보

통계
| 브랜치(Branch): | 개정판:

hytos / DTI_PID / DTI_PID / OcrResultDialog.py @ 09841ec5

이력 | 보기 | 이력해설 | 다운로드 (11.3 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
class QOcrResultDialog(QDialog):
19
    def __init__(self, parent, qimage, boundingBox, isModify = False, text = None):
20
        QDialog.__init__(self, parent)
21
        self.textInfoList = []
22

    
23
        self.isModify = isModify
24
        self.image = qimage
25
        self.originImageWidth = qimage.width()
26
        self.originImageHeight = qimage.height()
27
        self.boundingBox = boundingBox
28

    
29
        self.angle = 0 # angle is degree
30

    
31
        self.ui = OcrResultDialog_UI.Ui_Dialog()
32
        self.ui.setupUi(self)
33
        
34
        appDocData = AppDocData.instance()
35
        configs = appDocData.getAppConfigs('app', 'mode')
36
        if configs and 1 == len(configs) and 'advanced' == configs[0].value:
37
            pass
38
        else:
39
            self.ui.pushButtonMakeTrainingImage.setVisible(False)
40

    
41
        self.imgW = qimage.width()
42
        self.imgH = qimage.height()
43
        self.image = self.image.scaled(self.imgW, self.imgH)
44
        self.graphicsView = QtImageViewer.QtImageViewer(App.mainWnd())
45
        self.graphicsView.useDefaultCommand() ##### USE DEFAULT COMMAND
46
        self.graphicsView.setImage(self.image)
47
        self.ui.horizontalLayoutGraphicsView.addWidget(self.graphicsView)
48
        
49
        self.ui.counterClockPushButton_2.clicked.connect(lambda : self.rotateImage(True))
50
        self.ui.clockPushButton_2.clicked.connect(lambda : self.rotateImage(False))
51
        self.ui.redetectPushButton_2.clicked.connect(self.detectText)
52
        self.ui.pushButtonMakeTrainingImage.clicked.connect(self.pushButtonMakeTrainingImageClicked)
53

    
54
        if self.isModify == False:
55
            self.detectText()
56
        else:
57
            self.ui.detectResultTextEdit.setPlainText(text)
58

    
59
        self.isAccepted = False
60

    
61
    '''
62
        @brief      Make OCR Training Image
63
        @author     euisung
64
        @date       2018.10.16
65
        @history    euisung     2018.11.02       add notice push
66
    '''
67
    def pushButtonMakeTrainingImageClicked(self):
68
        import uuid
69
        uid = str(uuid.uuid4()) + '.png'
70
        appDocData = AppDocData.instance()
71
        project = appDocData.getCurrentProject()
72
        trainingImgPath = os.path.join(project.getTrainingFilePath(), uid)
73

    
74
        self.image.save(trainingImgPath)
75
        QMessageBox.about(self, self.tr("INFO"), self.tr('Successfully saved.'))
76
        QDialog.reject(self)
77
        
78
    def rotateImage(self, isCounterClock):
79
        for item in self.graphicsView.scene.items():
80
            self.graphicsView.scene.removeItem(item)
81
        self.graphicsView.clearImage()
82
        transform = QTransform()
83
        if isCounterClock:
84
            '''CounterClock'''
85
            self.angle = (self.angle - 90) % 360
86
            transform.rotate(-90)
87
        else:
88
            '''Clock'''
89
            self.angle = (self.angle - 270) % 360
90
            transform.rotate(90)
91
        #print(str(360 - self.angle))
92
        self.image = self.image.transformed(transform)
93
        self.graphicsView.setImage(self.image)
94
        self.textInfoList = []
95

    
96
    '''
97
        @history 2018.04.26 Jeongwoo    Add Rectangle with modified Coords
98
                 2018.06.20 Jeongwoo    Remove test code
99
                 2018.11.08 euisung     add white char list check process on db
100
                 2018.11.22 euisung     OCR lang apply fixed
101
    '''
102
    def detectText(self):
103
        try:
104
            buffer = QBuffer()
105
            buffer.open(QBuffer.ReadWrite)
106
            self.image.save(buffer, "PNG")
107
            pyImage = Image.open(io.BytesIO(buffer.data()))
108
            img = np.array(pyImage)
109
            
110
            #self.image.save('c:\\temp\\a.png')
111

    
112
            docData = AppDocData.instance()
113
            
114
            # get ocr data of area which has the text
115
            pt = self.boundingBox.center()
116
            areas = [area for area in docData.getAreaList() if area.contains((pt.x(), pt.y()))]
117
            ocr_data = sorted(areas, key=lambda attr: attr.area)[0].OCRData if areas else 'eng'
118
            # up to here
119

    
120
            whiteCharList = docData.getConfigs('Text Recognition', 'White Character List')
121
            if len(whiteCharList) is 0:
122
                self.textInfoList = TOCR.getTextInfo(img, (round(self.boundingBox.x()), round(self.boundingBox.y())), 0, language=ocr_data)
123
            else:
124
                self.textInfoList = TOCR.getTextInfo(img, (round(self.boundingBox.x()), round(self.boundingBox.y())), 0, language=ocr_data, conf = whiteCharList[0].value)
125

    
126
            if self.textInfoList is not None and len(self.textInfoList) > 0:
127
                self.ui.detectResultTextEdit.setText(self.getPlainText(self.textInfoList))
128
                for textInfo in self.textInfoList:
129
                    self.graphicsView.scene.addRect(textInfo.getX()-int(self.boundingBox.x()), textInfo.getY()-int(self.boundingBox.y()), textInfo.getW(), textInfo.getH(), QPen(Qt.red, 1, Qt.SolidLine))
130
            else:
131
                self.ui.detectResultTextEdit.setText("Not Found")
132
        except Exception as ex:
133
            from App import App 
134
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
135
            App.mainWnd().addMessage.emit(MessageType.Error, message)
136

    
137
    def getPlainText(self, textInfoList):
138
        text = ''
139
        for index in range(len(textInfoList)):
140
            textInfo = textInfoList[index]
141
            if index != 0:
142
                text = text + '\n'
143
            text = text + textInfo.getText()
144
        return text
145

    
146
    '''
147
        @brief      OK Button Clicked. Remake TextInfo object
148
        @author     Jeongwoo
149
        @date       18.04.19
150
        @history    18.04.20    Jeongwoo    Calculate Start Point Coordinates by rotated angle
151
                    18.04.26    Jeongwoo    Scene.itemAt(textX - boundBox.x(), textY - boundBox.y())
152
    '''
153
    def accept(self):
154
        from TextInfo import TextInfo
155
        self.isAccepted = True
156

    
157
        try:
158
            text = self.ui.detectResultTextEdit.toPlainText()
159
            if text == '' or text == 'Not Found':
160
                QMessageBox.about(self.ui.ocrDialogButtonBox, 'Notice', 'Please try again after recognition or type.')
161
                return
162

    
163
            isSplit = self.ui.checkBoxSeperate.isChecked()
164
            if isSplit:
165
                splitText = text.split('\n')
166
            else:
167
                splitText = [text]
168

    
169
            if not len(self.textInfoList) > 0:
170
                import cv2
171
                #QMessageBox.about(self.ui.ocrDialogButtonBox, "알림", "텍스트 검출을 하신 후 다시 시도해주세요.")
172
                
173
                buffer = QBuffer()
174
                buffer.open(QBuffer.ReadWrite)
175
                self.image.save(buffer, "PNG")
176
                pyImage = Image.open(io.BytesIO(buffer.data()))
177
                img = np.array(pyImage)
178

    
179
                img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
180
                imgNot = np.ones(img.shape, np.uint8)
181
                cv2.bitwise_not(img, imgNot)
182
                imgNot = cv2.dilate(imgNot, np.ones((8,8), np.uint8))
183

    
184
                image, contours, hierarchy = cv2.findContours(imgNot, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
185
                minX, minY, maxX, maxY = sys.maxsize, sys.maxsize, 0 ,0
186
                if len(contours) is 0:
187
                    minX, minY, maxX, maxY = self.boundingBox.x(), self.boundingBox.y(), self.boundingBox.x() + self.image.width(), self.boundingBox.y() + self.image.height()
188
                else:
189
                    minX, minY, maxX, maxY = sys.maxsize, sys.maxsize, 0, 0
190
                    for cnt in contours:
191
                        x, y, w, h = cv2.boundingRect(cnt)
192
                        minX = min(x ,minX)
193
                        minY = min(y, minY)
194
                        maxX = max(x + w, maxX)
195
                        maxY = max(y + h, maxY)
196
                    minX, minY, maxX, maxY = minX + self.boundingBox.x(), minY + self.boundingBox.y(), maxX + self.boundingBox.x(), maxY + self.boundingBox.y()
197
                
198
                self.textInfoList.append(TextInfo(text, minX, minY, maxX - minX, maxY - minY, 0))
199

    
200
            if not isSplit:
201
                minX, minY, maxX, maxY = sys.maxsize, sys.maxsize, 0, 0
202
                for textInfo in self.textInfoList:
203
                    x, y, w, h = textInfo.getX() ,textInfo.getY(), textInfo.getW(), textInfo.getH()
204
                    minX = min(x ,minX)
205
                    minY = min(y, minY)
206
                    maxX = max(x + w, maxX)
207
                    maxY = max(y + h, maxY)
208
                
209
                self.textInfoList = [TextInfo(text, minX, minY, maxX - minX, maxY - minY, 0)]
210

    
211
            if len(self.textInfoList) > 0:
212
                for index in range(len(splitText)):
213
                    textInfo = self.textInfoList[index]
214
                    item = self.graphicsView.scene.itemAt(QPointF(float(textInfo.getX() - int(self.boundingBox.x())), float(textInfo.getY()-int(self.boundingBox.y()))), QTransform())
215
                    if item is not None:
216
                        ## Transform rectangle for calculate start point
217
                        imgTransform = QTransform()
218
                        if self.angle == 90 or self.angle == 270:
219
                            imgTransform.translate(self.image.height()*0.5, self.image.width()*0.5)
220
                        elif self.angle == 0 or self.angle == 360:
221
                            imgTransform.translate(self.image.width()*0.5, self.image.height()*0.5)
222
                        imgTransform.rotate(-abs(self.angle))
223
                        imgTransform.translate(-self.image.width()*0.5, -self.image.height()*0.5)
224
                        rect = QRect(textInfo.getX() - int(self.boundingBox.x()), textInfo.getY() - int(self.boundingBox.y()), textInfo.getW(), textInfo.getH())
225
                        rect = imgTransform.mapRect(rect)
226
                        ## up to here
227
                        textInfo.setX(rect.x() + int(self.boundingBox.x()))
228
                        textInfo.setY(rect.y() + int(self.boundingBox.y()))
229
                        textInfo.setText(splitText[index])
230
                        radian = round(math.radians(abs(self.angle)), 2)
231
                        textInfo.setAngle(radian) # 360 degree == 6.28319 radian
232
                        if radian == 1.57 or radian == 4.71:
233
                            width = textInfo.getW()
234
                            height = textInfo.getH()
235
                            textInfo.setW(height) ## SWAP
236
                            textInfo.setH(width) ## SWAP
237
                self.textInfoList = self.textInfoList[:len(splitText)]
238

    
239
                QDialog.accept(self)
240

    
241
        except Exception as ex:
242
            from App import App 
243
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
244
            App.mainWnd().addMessage.emit(MessageType.Error, message)
245

    
246
    def reject(self):
247
        self.isAccepted = False
248
        self.textInfoList = None
249
        QDialog.reject(self)
250

    
251
    '''
252
        @brief  Display this QDialog
253
    '''
254
    def showDialog(self):
255
        #self.setWindowFlags(self.windowFlags() & ~Qt.WindowContextHelpButtonHint)
256
        self.exec_()
257
        return (self.isAccepted, self.textInfoList)
클립보드 이미지 추가 (최대 크기: 500 MB)