프로젝트

일반

사용자정보

개정판 aece692b

IDaece692bf575023780ba81248d96332d6467b3fd
상위 9f1fa28b
하위 080e2e98

백흠경이(가) 5년 이상 전에 추가함

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

클립보드 이미지 추가 (최대 크기: 500 MB)