프로젝트

일반

사용자정보

개정판 35eb686f

ID35eb686ff620c7958ebd9092ceb165dd7dbbc5d8
상위 6d59f069
하위 207a4cce, 9ff9a98d

함의성이(가) 5년 이상 전에 추가함

issue #663: add symbol data merge function

Change-Id: I1fce5d3aecb7ccf354933533e8c5cece81c08625

차이점 보기:

DTI_PID/DTI_PID/AppDocData.py
247 247
        try:
248 248
            project = AppDocData.instance().getCurrentProject()
249 249
            path = project.getTrainingFilePath()
250
            drawingFileList = os.listdir(path)
251
            drawingFileList.sort()
250
            trainingFileList = os.listdir(path)
251
            trainingFileList.sort()
252 252
        except Exception as ex:
253 253
            from App import App
254 254
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
255 255
                                                          sys.exc_info()[-1].tb_lineno)
256 256
            App.mainWnd().addMessage.emit(MessageType.Error, message)
257 257

  
258
        return drawingFileList
258
        return trainingFileList
259

  
260
    def getTrainingSymbolFileList(self):
261
        """  Get Symbol Training file list """
262
        try:
263
            project = AppDocData.instance().getCurrentProject()
264
            path = project.getTrainingSymbolFilePath()
265
            symbolTrainingFileList = os.listdir(path)
266
            symbolTrainingFileList.sort()
267
        except Exception as ex:
268
            from App import App
269
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
270
                                                          sys.exc_info()[-1].tb_lineno)
271
            App.mainWnd().addMessage.emit(MessageType.Error, message)
272

  
273
        return symbolTrainingFileList
259 274

  
260 275
    '''
261 276
        @brief      Get DB file path in ProgramData
DTI_PID/DTI_PID/MainWindow.py
59 59
from UserInputAttribute import UserInputAttribute
60 60
from TextItemFactory import TextItemFactory
61 61
from TrainingImageListDialog import QTrainingImageListDialog
62
from TrainingSymbolImageListDialog import QTrainingSymbolImageListDialog
62 63
from TextDataListDialog import QTextDataListDialog
63 64
from ImportTextFromCADDialog import QImportTextFromCADDialog
64 65
from SymbolThicknessDialog import QSymbolThicknessDialog
......
252 253
        configs = docData.getAppConfigs('app', 'mode')
253 254
        if configs and 1 == len(configs) and 'advanced' == configs[0].value:
254 255
            self.actionOCR_Training.triggered.connect(self.oCRTrainingClicked)
255
            self.pushButtonBatchRecognition
256
            self.actionSymbol_Training.triggered.connect(self.symbolTrainingClicked)
256 257
        else:
257 258
            self.actionOCR_Training.setVisible(False)
259
            self.actionSymbol_Training.setVisible(False)
258 260
            self.pushButtonBatchRecognition.setVisible(False)
259 261
            self.pushButtonCreateSymbol.setVisible(False)
260 262
            self.pushButtonDetectSymbol.setVisible(False)
......
544 546
                                                          sys.exc_info()[-1].tb_lineno)
545 547
            self.addMessage.emit(MessageType.Error, message)
546 548

  
549

  
550
    def symbolTrainingClicked(self):
551
        try:
552
            dialog = QTrainingSymbolImageListDialog(self)
553
            dialog.exec_()
554
        except Exception as ex:
555
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename,
556
                                                          sys.exc_info()[-1].tb_lineno)
557
            self.addMessage.emit(MessageType.Error, message)
558

  
547 559
    '''
548 560
        @brief      show unknownitem's count
549 561
        @author     kyouho
DTI_PID/DTI_PID/MainWindow_UI.py
1 1
# -*- coding: utf-8 -*-
2 2

  
3
# Form implementation generated from reading ui file '.\UI\MainWindow.ui'
3
# Form implementation generated from reading ui file './UI/MainWindow.ui'
4 4
#
5
# Created by: PyQt5 UI code generator 5.13.0
5
# Created by: PyQt5 UI code generator 5.11.3
6 6
#
7 7
# WARNING! All changes made in this file will be lost!
8 8

  
9

  
10 9
from PyQt5 import QtCore, QtGui, QtWidgets
11 10

  
12

  
13 11
class Ui_MainWindow(object):
14 12
    def setupUi(self, MainWindow):
15 13
        MainWindow.setObjectName("MainWindow")
......
497 495
        self.actionSymbol_Thickness_Reinforcement.setObjectName("actionSymbol_Thickness_Reinforcement")
498 496
        self.actionExportEqpDatasheet = QtWidgets.QAction(MainWindow)
499 497
        self.actionExportEqpDatasheet.setObjectName("actionExportEqpDatasheet")
498
        self.actionSymbol_Training = QtWidgets.QAction(MainWindow)
499
        self.actionSymbol_Training.setObjectName("actionSymbol_Training")
500 500
        self.menu.addAction(self.actionOpen)
501 501
        self.menu.addAction(self.actionArea)
502 502
        self.menu.addAction(self.actionConfiguration)
......
513 513
        self.menu_2.addAction(self.actionOPCRelation)
514 514
        self.menu_2.addSeparator()
515 515
        self.menu_2.addAction(self.actionCodeTable)
516
        self.menu_2.addSeparator()
516 517
        self.menu_2.addAction(self.actionOCR_Training)
518
        self.menu_2.addAction(self.actionSymbol_Training)
517 519
        self.menu_3.addAction(self.actionImage_Drawing)
518 520
        self.menu_3.addAction(self.actionViewText)
519 521
        self.menu_3.addAction(self.actionViewSymbol)
......
663 665
        self.actionSymbol_Thickness_Reinforcement.setText(_translate("MainWindow", "Symbol Thickness Reinforcement"))
664 666
        self.actionExportEqpDatasheet.setText(_translate("MainWindow", "Export Eqp Datasheet"))
665 667
        self.actionExportEqpDatasheet.setToolTip(_translate("MainWindow", "Export Equipment Datasheet"))
668
        self.actionSymbol_Training.setText(_translate("MainWindow", "Symbol Training"))
669

  
666 670
import MainWindow_rc
671

  
672
if __name__ == "__main__":
673
    import sys
674
    app = QtWidgets.QApplication(sys.argv)
675
    MainWindow = QtWidgets.QMainWindow()
676
    ui = Ui_MainWindow()
677
    ui.setupUi(MainWindow)
678
    MainWindow.show()
679
    sys.exit(app.exec_())
680

  
DTI_PID/DTI_PID/Project.py
116 116
    def getTrainingFilePath(self):
117 117
        return os.path.join(self.getPath(), 'Training')
118 118

  
119
    def getTrainingSymbolFilePath(self):
120
        """ return symbol training path """
121
        return os.path.join(self.getPath(), 'Training_Symbol')
122

  
119 123
    def get_data_sheet_path(self):
120 124
        """ return data sheet path """
121 125

  
......
172 176
        trainingPath = self.getTrainingFilePath()
173 177
        if not os.path.exists(trainingPath):
174 178
            os.makedirs(trainingPath)
179
        trainingSymbolPath = self.getTrainingSymbolFilePath()
180
        if not os.path.exists(trainingSymbolPath):
181
            os.makedirs(trainingSymbolPath)
175 182

  
176 183
        path = os.path.join(tempDir, 'Tile')
177 184
        if not os.path.exists(path):
DTI_PID/DTI_PID/TrainingEditorDialog.py
4 4
from PyQt5.QtCore import *
5 5
from PyQt5.QtGui import *
6 6
from PyQt5.QtWidgets import *
7
from AppDocData import AppDocData
7
from AppDocData import *
8 8
import TrainingEditor_UI
9 9
import QtImageViewer
10 10
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
DTI_PID/DTI_PID/TrainingImageListDialog.py
10 10
from PyQt5.QtCore import *
11 11
from PyQt5.QtGui import *
12 12
from PyQt5.QtWidgets import *
13
from AppDocData import AppDocData
13
from AppDocData import *
14 14
import pytesseract
15 15
import TrainingImageList_UI
16 16
from TrainingEditorDialog import QTrainingEditorDialog
......
320 320
                    grid_size[1] = box[4]
321 321

  
322 322
            space = 5
323
            grid_size[0] = grid_size[0] + space*2
324
            grid_size[1] = grid_size[1] + space*2
323
            grid_size[0] = grid_size[0] + space * 2
324
            grid_size[1] = grid_size[1] + space * 2
325 325

  
326 326
            dimension = [None, None]
327 327
            dimension[0] = int(math.sqrt(len(boxes)) + 1)
DTI_PID/DTI_PID/TrainingSymbolEditorDialog.py
1
# coding: utf-8
2
import sys
3
import os, time, datetime
4
from PyQt5.QtCore import *
5
from PyQt5.QtGui import *
6
from PyQt5.QtWidgets import *
7
from AppDocData import *
8
import TrainingEditor_UI
9
import QtImageViewer
10
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
11
from TrainingBoxItem import QTrainingBoxItem
12
import cv2
13
import numpy as np
14
from PIL import Image
15
import AreaZoomCommand
16
import PlaceLineCommand
17

  
18
class QTrainingSymbolEditorDialog(QDialog):
19
    def __init__(self, parent, trainingImgPath, trainingBoxPath, boundaryOcrData, dateItem, boxItem):
20
        self.spinBoxFlag = False
21
        QDialog.__init__(self, parent)
22
        self.setWindowFlag(Qt.WindowMinMaxButtonsHint)
23

  
24
        self.trainingImgPath = trainingImgPath
25
        self.trainingBoxPath = trainingBoxPath
26
        self.boundaryOcrData = boundaryOcrData
27
        self.dateItem = dateItem
28
        self.boxItem = boxItem
29
        self.isChanged = False
30

  
31
        appDocData = AppDocData.instance()
32
        project = appDocData.getCurrentProject()
33

  
34
        self.ui = TrainingEditor_UI.Ui_TrainingEditorDialog()
35
        self.ui.setupUi(self)
36

  
37
        self.graphicsViewTrainingDrawing = QtImageViewer.QtImageViewer(self)
38
        self.graphicsViewTrainingDrawing.setParent(self.ui.centralWidget)
39
        self.graphicsViewTrainingDrawing.useDefaultCommand()
40
        self.ui.verticalLayoutTrainingDrawing.addWidget(self.graphicsViewTrainingDrawing)
41

  
42
        self.graphicsViewZoomDrawing = QGraphicsView(self)
43
        self.graphicsViewZoomDrawing.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
44
        self.graphicsViewZoomDrawing.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
45
        self.graphicsViewZoomDrawing.setParent(self.ui.leftSideWidget)
46
        self.ui.horizontalLayoutZoomDrawing.addWidget(self.graphicsViewZoomDrawing)
47
        
48
        
49
        # 학습 이미지 읽어서 메인 뷰에 그림, 사이드 뷰에 추가
50
        try:
51
            #trainingImgPath = os.path.join(project.getTrainingFilePath(), 'seed.seedF.exp0.tif')
52
            cvImg = cv2.cvtColor(cv2.imread(trainingImgPath), cv2.COLOR_BGR2GRAY)
53
            blur = cv2.GaussianBlur(cvImg, (5,5),0)
54
            cvImg = cv2.threshold(cvImg, 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
55
            bytesPerLine = cvImg.shape[1]
56
            image = QImage(cvImg.data, cvImg.shape[1], cvImg.shape[0], bytesPerLine, QImage.Format_Indexed8)
57

  
58
            self.graphicsViewTrainingDrawing.setImage(image)
59

  
60
            # 사이드 뷰
61
            if type(image) is QPixmap:
62
                pixmap = image
63
            elif type(image) is QImage:
64
                pixmap = QPixmap.fromImage(image)
65
            scene = QGraphicsScene()
66
            self.graphicsViewZoomDrawing.setScene(scene)
67
            self._pixmapHandle = self.graphicsViewZoomDrawing.scene().addPixmap(pixmap)
68
            self.graphicsViewZoomDrawing.scene().setSceneRect(0, 0, pixmap.width(), pixmap.height())
69
            self.graphicsViewZoomDrawing.fitInView(self.graphicsViewZoomDrawing.scene().sceneRect(), Qt.KeepAspectRatioByExpanding)
70
            rect = QGraphicsRectItem(0, 0, 0, 0)
71
            pen = QPen(Qt.SolidLine)
72
            pen.setColor(Qt.green)
73
            pen.setWidthF(1)
74
            pen.setJoinStyle(Qt.MiterJoin)
75
            rect.setPen(pen)
76
            rect.setOpacity(0.7)
77
            self.graphicsViewZoomDrawing.scene().addItem(rect)
78

  
79
        except Exception as ex:
80
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
81

  
82
        # 박스 읽어서 메인 뷰에 그림
83
        try:
84
            boxList = []
85
            if self.boundaryOcrData is None:
86
                fBox = open(trainingBoxPath, 'r', encoding='utf8')
87
                SBox = fBox.read()
88
                fBox.close()
89
                boxList = SBox.split('\n')
90
            else:
91
                boxList = boundaryOcrData.split('\n')
92

  
93
            for box in boxList:
94
                if box == '': continue
95
                boxComponent = box.split(' ')
96
                singleBox = QTrainingBoxItem(str(boxComponent[0]), int(boxComponent[1]), cvImg.shape[0] - int(boxComponent[4]), int(boxComponent[3]) - int(boxComponent[1]), int(boxComponent[4]) - int(boxComponent[2]))
97
                singleBox.transfer.onRemoved.connect(self.itemRemoved)
98
                singleBox.addTextItemToScene(self.ui, self.graphicsViewTrainingDrawing, self.graphicsViewZoomDrawing, self.spinBoxFlag)
99
        except Exception as ex:
100
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
101

  
102
        self.removedItems = []
103

  
104
        self.ui.pushButtonZoom.clicked.connect(self.onAreaZoom)
105
        self.ui.pushButtonSave.clicked.connect(self.pushButtonSaveClicked)
106
        self.ui.pushButtonCancel.clicked.connect(self.pushButtonCancelClicked)
107
        self.ui.pushButtonDelete.clicked.connect(self.pushButtonDeleteClicked)
108
        self.ui.pushButtonAdd.clicked.connect(self.pushButtonAddClicked)
109
        self.ui.pushButtonSplit.clicked.connect(self.pushButtonSplitClicked)
110
        self.ui.spinBoxLeft.valueChanged.connect(self.spinBoxChangedEvent)
111
        self.ui.spinBoxTop.valueChanged.connect(self.spinBoxChangedEvent)
112
        self.ui.spinBoxWidth.valueChanged.connect(self.spinBoxChangedEvent)
113
        self.ui.spinBoxHeight.valueChanged.connect(self.spinBoxChangedEvent)
114
        self.ui.lineEditChar.returnPressed.connect(self.pushButtonChangeClicked)
115

  
116
    '''
117
        @brief      split boxitem by button click
118
        @author     euisung
119
        @date       2018.10.31
120
    '''
121
    def pushButtonSplitClicked(self):
122
        self.isChanged = True
123
        items = self.graphicsViewTrainingDrawing.scene.selectedItems()
124
        if len(items) is not 1:
125
            return
126
        rect = items[0].rect()
127
        secondBox = QTrainingBoxItem('', rect.x() + round(rect.width() / 2), rect.y(), round(rect.width() / 2), rect.height())
128
        secondBox.transfer.onRemoved.connect(self.itemRemoved)
129
        secondBox.addTextItemToScene(self.ui, self.graphicsViewTrainingDrawing, self.graphicsViewZoomDrawing, self.spinBoxFlag)
130
        items[0].setRect(rect.x(), rect.y(), round(rect.width() / 2), rect.height())
131

  
132
    '''
133
        @brief      add boxitem by button click
134
        @author     euisung
135
        @date       2018.10.17
136
    '''
137
    def pushButtonAddClicked(self):
138
        self.isChanged = True
139
        items = self.graphicsViewTrainingDrawing.scene.selectedItems()
140
        allItems = self.graphicsViewTrainingDrawing.scene.items()
141
        totalWidth = 0
142
        totalHeight = 0
143
        count = 0
144
        if len(items) is 1:
145
            rect = items[0].rect()
146
        elif len(allItems) > 1:
147
            for item in allItems:
148
                if type(item) is QGraphicsPixmapItem:
149
                    x = int(item.boundingRect().width() / 2)
150
                    y = int(item.boundingRect().height()/ 2)
151
                elif hasattr(item, 'rect'):
152
                    count += 1
153
                    totalWidth += item.rect().width()
154
                    totalHeight += item.rect().height()
155

  
156
            rect = QRectF(x, y, round(totalWidth / count), round(totalHeight / count))
157
        else:
158
            for item in allItems:
159
                if type(item) is QGraphicsPixmapItem:
160
                    x = int(item.boundingRect().width() / 2)
161
                    y = int(item.boundingRect().height()/ 2)
162
            rect = QRectF(x, y, 5, 10)
163
        singleBox = QTrainingBoxItem('', rect.x() + 3, rect.y(), rect.width(), rect.height())
164
        singleBox.transfer.onRemoved.connect(self.itemRemoved)
165
        singleBox.addTextItemToScene(self.ui, self.graphicsViewTrainingDrawing, self.graphicsViewZoomDrawing, self.spinBoxFlag)
166

  
167
    '''
168
        @brief      delete boxitem by button click
169
        @author     euisung
170
        @date       2018.10.17
171
    '''
172
    def pushButtonDeleteClicked(self):
173
        self.isChanged = True
174
        items = self.graphicsViewTrainingDrawing.scene.selectedItems()
175
        for item in items:
176
            item.transfer.onRemoved.emit(item)
177

  
178
    def onCharChanged(self, text):
179
        """
180
        change lineedit's text with given text
181
        """
182
        if text:
183
            self.ui.lineEditChar.setText(text)
184
            self.pushButtonChangeClicked()
185

  
186
    '''
187
        @brief      change boxitem char by button click
188
        @author     euisung
189
        @date       2018.10.17
190
    '''
191
    def pushButtonChangeClicked(self):
192
        self.isChanged = True
193
        items = self.graphicsViewTrainingDrawing.scene.selectedItems()
194
        if len(items) is not 1:
195
            return
196
        items[0].char = self.ui.lineEditChar.text()
197
        items[0].textShowBox.setHtml(self.ui.lineEditChar.text())
198

  
199
    '''
200
        @brief      close dialog by button click
201
        @author     euisung
202
        @date       2018.10.17
203
    '''
204
    def pushButtonCancelClicked(self):
205
        if self.isChanged:
206
            reply = QMessageBox.question(self, self.tr('Continue?'), self.tr('Changes may not have been saved.'), QMessageBox.Ignore, QMessageBox.Cancel)
207
            if reply == QMessageBox.Ignore:
208
                QDialog.reject(self)
209
        else:
210
            QDialog.reject(self)
211

  
212
    '''
213
        @brief      save box item by button click
214
        @author     euisung
215
        @date       2018.10.16
216
    '''
217
    def pushButtonSaveClicked(self):
218
        items = self.graphicsViewTrainingDrawing.scene.items()
219
        outBox = ""
220
        for item in items:
221
            if type(item) is QGraphicsPixmapItem:
222
                imgHeight = int(item.boundingRect().height())
223
                imgWidth = int(item.boundingRect().width())
224
        for item in items:
225
            if type(item) is QTrainingBoxItem:
226
                rect = item.rect()
227
                char, x, y, width, height = item.char, int(rect.x()), int(rect.y()), int(rect.width()), int(rect.height())
228
                bx, by, bx2, by2 = str(x), str(imgHeight - y - height), str(x + width), str(imgHeight - y)
229
                if char == '':
230
                    continue
231
                outBox += char + " " + bx + " " + by + " " + bx2 + " " + by2 + "\n"
232
        fw = open(self.trainingBoxPath, 'w')
233
        fw.write(outBox)
234
        fw.close()
235
        modifiedTime = str(datetime.datetime.strptime(time.ctime(os.path.getmtime(self.trainingBoxPath)), "%a %b %d %H:%M:%S %Y"))
236
        self.dateItem.setText(modifiedTime)
237

  
238
        boxContent = outBox.split('\n')
239
        boxContent = boxContent[:-1]
240
        boxchars = ''
241
        for char in boxContent:
242
            boxchars += char[0]
243
        self.boxItem.setText(boxchars)
244

  
245
        self.isChanged = False
246
        reply = QMessageBox.information(self, self.tr('Information'), self.tr('Save Success!'), QMessageBox.Ok, QMessageBox.Cancel)
247
        if reply == QMessageBox.Ok:
248
            QDialog.reject(self)
249

  
250
    '''
251
        @brief      chane box item's rect by button click
252
        @author     euisung
253
        @date       2018.10.16
254
    '''
255
    def spinBoxChangedEvent(self, event):
256
        self.isChanged = True
257
        items = self.graphicsViewTrainingDrawing.scene.selectedItems()
258
        if (len(items) is not 1) or self.spinBoxFlag:
259
            return
260
        spinBoxName = self.sender().objectName()
261
        rect = items[0].rect()
262
        bound = self.graphicsViewZoomDrawing.scene().items()[0]
263

  
264
        if spinBoxName == 'spinBoxLeft':
265
            spinBoxValue = self.ui.spinBoxLeft.value()
266
            items[0].setRect(QRectF(spinBoxValue, rect.y(), rect.width(), rect.height()))
267
            items[0].textShowBox.setPos(items[0].rect().x() + round(items[0].rect().width() / 3), items[0].rect().y() - round(items[0].rect().height() / 2))
268
        elif spinBoxName == 'spinBoxTop':
269
            spinBoxValue = self.ui.spinBoxTop.value()
270
            items[0].setRect(QRectF(rect.x(), spinBoxValue, rect.width(), rect.height()))
271
            items[0].textShowBox.setPos(items[0].rect().x() + round(items[0].rect().width() / 3), items[0].rect().y() - round(items[0].rect().height() / 2))
272
        elif spinBoxName == 'spinBoxWidth':
273
            spinBoxValue = self.ui.spinBoxWidth.value()
274
            items[0].setRect(QRectF(rect.x(),  rect.y(), spinBoxValue, rect.height()))
275
            items[0].textShowBox.setPos(items[0].rect().x() + round(items[0].rect().width() / 3), items[0].rect().y() - round(items[0].rect().height() / 2))
276
        elif spinBoxName == 'spinBoxHeight':
277
            spinBoxValue = self.ui.spinBoxHeight.value()
278
            items[0].setRect(QRectF(rect.x(), rect.y(), rect.width(), spinBoxValue))
279
            items[0].textShowBox.setPos(items[0].rect().x() + round(items[0].rect().width() / 3), items[0].rect().y() - round(items[0].rect().height() / 2))
280

  
281
        rect = items[0].rect()        
282
        bound.setRect(rect)
283
        rectSide = QRectF(rect.x() - 3, rect.y() - 3, rect.width() + 6,  rect.height() + 6)
284
        self.graphicsViewZoomDrawing.fitInView(rectSide)
285
        self.graphicsViewTrainingDrawing.scene.update()
286
    
287
    def onAreaZoom(self, action):
288
        if self.ui.pushButtonZoom.isChecked():
289
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsViewTrainingDrawing)
290
            cmd.onRejected.connect(self.onCommandRejected)
291
            self.graphicsViewTrainingDrawing.command = cmd
292

  
293
    def onCommandRejected(self, cmd):
294
        try:
295
            if type(cmd) is AreaZoomCommand.AreaZoomCommand:
296
                self.ui.pushButtonZoom.setChecked(False)
297
        finally:
298
            self.graphicsViewTrainingDrawing.useDefaultCommand()
299

  
300
    def itemRemoved(self, item):
301
        try:
302
            if type(item) is QTrainingBoxItem:
303
                self.removedItems.append(str(item.uid))
304

  
305
            if item.scene is not None: item.scene.removeItem(item)
306
        except Exception as ex:
307
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
308

  
309
    '''
310
        @brief      key pressed event
311
        @author     euisung
312
        @date       2018.11.05
313
    '''
314
    def keyPressEvent(self, event):
315
        try:
316
            items = self.graphicsViewTrainingDrawing.scene.selectedItems()
317
            if len(items) is not 1 or type(items[0]) is not QTrainingBoxItem:
318
                return
319
            selectedItem = items[0]
320
            closestItem = None
321
            x = selectedItem.rect().x()
322

  
323
            if event.key() == Qt.Key_Left:
324
                dx =  sys.maxsize
325
                for item in self.graphicsViewTrainingDrawing.scene.items():
326
                    if type(item) is QTrainingBoxItem:
327
                        if x - item.rect().x() > 0 and x - item.rect().x() < dx:
328
                            closestItem = item
329
                            dx = x - item.rect().x()
330
                if closestItem is not None:
331
                    closestItem.setSelected(True)
332
                    selectedItem.setSelected(False)
333
                    closestItem.mousePressEvent('arrow key')             
334
            elif event.key() == Qt.Key_Right:
335
                dx = -sys.maxsize
336
                for item in self.graphicsViewTrainingDrawing.scene.items():
337
                    if type(item) is QTrainingBoxItem:
338
                        if x - item.rect().x() < 0 and x - item.rect().x() > dx:
339
                            closestItem = item
340
                            dx = x - item.rect().x()
341
                if closestItem is not None:
342
                    closestItem.setSelected(True)
343
                    selectedItem.setSelected(False)
344
                    closestItem.mousePressEvent('arrow key')
345
            elif event.key() == Qt.Key_Up:
346
                self.ui.spinBoxWidth.setValue(self.ui.spinBoxWidth.value() + 1)
347
            elif event.key() == Qt.Key_Down:
348
                self.ui.spinBoxWidth.setValue(self.ui.spinBoxWidth.value() - 1)
349
            elif event.key() == Qt.Key_Return:
350
                pass
351
            elif selectedItem:
352
                text = event.text()
353
                if text: self.onCharChanged(text)
354
        except Exception as ex:
355
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
356
            from App import App
357
            from AppDocData import MessageType
358

  
359
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
360
            App.mainWnd().addMessage.emit(MessageType.Error, message)
361
            return None
DTI_PID/DTI_PID/TrainingSymbolImageListDialog.py
1
# coding: utf-8
2
""" This is symbol training image list dialog module """
3

  
4
import sys
5
import os, time, datetime, copy
6
from PyQt5.QtCore import *
7
from PyQt5.QtGui import *
8
from PyQt5.QtWidgets import *
9
from AppDocData import *
10
from xml.etree.ElementTree import Element, SubElement, dump, ElementTree, parse
11
import TrainingSymbolImageList_UI
12
from TrainingSymbolEditorDialog import QTrainingSymbolEditorDialog
13
import numpy as np
14
import pyqtgraph as pg
15
import cv2
16

  
17
#// for remove noise
18
#noisePassList = ['.', '\"', '\'', ',', '`', '-', '+']
19

  
20
class QTrainingSymbolImageListDialog(QDialog):
21
    """
22
    This is training image list dialog class
23
    """
24
    TRAINING_DATA_COUNT = 5
25

  
26
    def __init__(self, parent):
27
        QDialog.__init__(self, parent)
28
        self.setWindowFlag(Qt.WindowMinMaxButtonsHint)
29

  
30
        self.ui = TrainingSymbolImageList_UI.Ui_TraingingSymbolImageListDialog()
31
        self.ui.setupUi(self)
32
        self.ui.progressBar.setValue(0)
33
        self.labelList = []
34

  
35
        # for List 
36
        self.ui.tableWidgetList.setSelectionMode(QAbstractItemView.SingleSelection) 
37
        self.ui.tableWidgetList.setColumnCount(4)
38

  
39
        ## column header 명 설정
40
        self.ui.tableWidgetList.setHorizontalHeaderLabels([self.tr('No.'), self.tr('Image List'), self.tr('Modified Date'), self.tr('Label Contents')])
41
        self.ui.tableWidgetList.horizontalHeaderItem(1).setToolTip(self.tr('Image Name')) # header tooltip
42
        self.ui.tableWidgetList.horizontalHeaderItem(2).setToolTip(self.tr('Edit Status')) # header tooltip
43
        self.ui.tableWidgetList.horizontalHeaderItem(3).setToolTip(self.tr('Label Contents')) # header tooltip
44
        self.ui.tableWidgetList.horizontalHeaderItem(1).setSizeHint(QSize(30, 30))
45
        self.ui.tableWidgetList.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
46
        self.ui.tableWidgetList.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
47
        self.ui.tableWidgetList.horizontalHeader().setSectionResizeMode(2, QHeaderView.Stretch)
48
        self.ui.tableWidgetList.horizontalHeader().setSectionResizeMode(3, QHeaderView.Stretch)
49
        self.ui.tableWidgetList.resizeColumnsToContents()
50
        self.ui.tableWidgetList.setEditTriggers(QAbstractItemView.NoEditTriggers)
51
        
52
        self.listUpdate()
53

  
54
        # connect signals and slots
55
        self.ui.tableWidgetList.cellDoubleClicked.connect(self.listCellDoubleClicked)
56
        self.ui.pushButtonLabel.clicked.connect(self.pushButtonLabelClicked)
57
        self.ui.pushButtonMakeTrainingImage.clicked.connect(self.makeTrainingImageClicked)
58
        self.ui.pushButtonImageDelete.clicked.connect(self.pushButtonImageDeleteClicked)
59
        self.ui.pushButtonLabelDelete.clicked.connect(self.pushButtonLabelDeleteClicked)
60
        self.ui.pushButtonClose.clicked.connect(self.pushButtonCloseClicked)
61
        self.ui.pushButtonDeleteBatchLabel.clicked.connect(self.pushButtonDeleteBatchLabelClicked)
62

  
63
        # delete character in box
64
        #self.ui.pushButtonDeleteBatchLabel.setEnabled(False)
65
        #self.ui.pushButtonDeleteBatchLabel.setHidden(True)
66
        #self.ui.lineEditTargetLabel.setEnabled(False)
67
        #self.ui.lineEditTargetLabel.setHidden(True)
68
        self.ui.pushButtonDeleteBatchLabel.setEnabled(True)
69
        self.ui.pushButtonDeleteBatchLabel.setHidden(False)
70
        self.ui.lineEditTargetLabel.setEnabled(True)
71
        self.ui.lineEditTargetLabel.setHidden(False)
72

  
73
        appDocData = AppDocData.instance()
74
        project = appDocData.getCurrentProject()
75
        dataList = appDocData.getTrainingSymbolFileList()
76

  
77
        # for reset chart
78
        self.labelList = []
79
        for labelCounts in self.labelList:
80
            labelCount = [labelCounts[0], labelCounts[1]]
81
            self.labelList.append(labelCount)
82
        for data in dataList:
83
            if data.find('.xml') is not -1:
84
                labelPath = os.path.join(project.getTrainingSymbolFilePath(), data)
85
                xml = parse(labelPath)
86
                root = xml.getroot()
87
                objects = list(root.iter('object'))
88
                for object_node in objects:
89
                    name = object_node.find('name').text
90
                    matches = [_label for _label in self.labelList if _label[0] == name]
91
                    if matches:
92
                        matches[0][1] = matches[0][1] + 1
93
                    else:
94
                        self.labelList.append([name, 1])
95
        self.makeChart()
96

  
97
    '''
98
        @brief      close dialog by button click
99
        @author     euisung
100
        @date       2018.10.18
101
    '''
102
    def pushButtonCloseClicked(self):
103
        QDialog.reject(self)
104

  
105
    '''
106
        @brief      update image list
107
        @author     euisung
108
        @date       2018.10.18
109
    '''
110
    def listUpdate(self):
111
        appDocData = AppDocData.instance()
112
        project = appDocData.getCurrentProject()
113
        dataList = appDocData.getTrainingSymbolFileList()
114
        imgCount = 0
115
        for data in dataList:
116
            if data.find('.png') is not -1:
117
                imgCount += 1
118
        self.ui.tableWidgetList.setRowCount(imgCount)
119
        
120
        row = 0
121
        for data in dataList:
122
            if data.find('.png') is not -1:
123
                self.ui.tableWidgetList.setItem(row, 0, QTableWidgetItem(str(row + 1)))
124
                self.ui.tableWidgetList.setItem(row, 1, QTableWidgetItem(data))
125
                allDataList = appDocData.getTrainingSymbolFileList()
126
                for adata in allDataList:
127
                    labelName = data.replace('.png', '.xml')
128
                    if adata.find(labelName) is not -1:
129
                        labelPath = os.path.join(project.getTrainingSymbolFilePath(), labelName)
130
                        modifiedTime = str(datetime.datetime.strptime(time.ctime(os.path.getmtime(labelPath)), "%a %b %d %H:%M:%S %Y"))
131
                        self.ui.tableWidgetList.setItem(row, 2, QTableWidgetItem(modifiedTime))
132

  
133
                        labels = []
134
                        xml = parse(labelPath)
135
                        root = xml.getroot()
136
                        objects = list(root.iter('object'))
137
                        for object_node in objects:
138
                            name = object_node.find('name').text
139
                            if name not in labels:
140
                                labels.append(name)
141
                        labelContent = QTableWidgetItem(','.join(labels))
142
                        labelContent.setFont(QFont('Consolas', 9, QFont.Bold))
143
                        self.ui.tableWidgetList.setItem(row, 3, QTableWidgetItem(labelContent))
144
                        break
145
                    else:
146
                        self.ui.tableWidgetList.setItem(row, 2, QTableWidgetItem(''))
147
                        self.ui.tableWidgetList.setItem(row, 3, QTableWidgetItem(''))
148
                row += 1
149

  
150
    '''
151
        @brief      delete training box only by button click
152
        @author     euisung
153
        @date       2018.10.18
154
    '''
155
    def pushButtonLabelDeleteClicked(self):
156
        try:
157
            row = self.ui.tableWidgetList.selectedIndexes()[0].row()
158
            col = self.ui.tableWidgetList.selectedIndexes()[0].column()
159
            drawingName = self.ui.tableWidgetList.item(row, 1).text()
160
            labelDate = self.ui.tableWidgetList.item(row, 2).text()
161
            if labelDate == '':
162
                return
163
        except Exception as ex:
164
            pass
165
        try:
166
            reply = QMessageBox.question(self, self.tr('Continue?'), self.tr('Are you sure you want to delete the label job? '), QMessageBox.Yes, QMessageBox.Cancel)
167
            if reply == QMessageBox.Yes:
168
                appDocData = AppDocData.instance()
169
                project = appDocData.getCurrentProject()
170

  
171
                drawingPath = os.path.join(project.getTrainingSymbolFilePath(), drawingName)
172
                labelName = drawingPath.replace('.png', '.xml')
173
                if os.path.isfile(labelName):
174
                    os.remove(labelName)
175
                self.ui.tableWidgetList.item(row, 2).setText('')
176
                self.ui.tableWidgetList.item(row, 3).setText('')
177
                #self.listUpdate()
178
        except Exception as ex:
179
            from App import App 
180
            from AppDocData import MessageType
181

  
182
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
183
            App.mainWnd().addMessage.emit(MessageType.Error, message)
184

  
185
    '''
186
        @brief      delete training image and box by button click
187
        @author     euisung
188
        @date       2018.10.18
189
    '''
190
    def pushButtonImageDeleteClicked(self):
191
        try:
192
            row = self.ui.tableWidgetList.selectedIndexes()[0].row()
193
            col = self.ui.tableWidgetList.selectedIndexes()[0].column()
194
            drawingName = self.ui.tableWidgetList.item(row, 1).text()
195
        except Exception as ex:
196
            pass
197
        try:
198
            reply = QMessageBox.question(self, self.tr('Continue?'), self.tr('Are you sure you want to delete selected image? '), QMessageBox.Yes, QMessageBox.Cancel)
199
            if reply == QMessageBox.Yes:
200
                appDocData = AppDocData.instance()
201
                project = appDocData.getCurrentProject()
202

  
203
                drawingPath = os.path.join(project.getTrainingSymbolFilePath(), drawingName)
204
                if os.path.isfile(drawingPath):
205
                    os.remove(drawingPath)
206
                labelName = drawingPath.replace('.png', '.xml')
207
                if os.path.isfile(labelName):
208
                    os.remove(labelName)
209
                self.ui.tableWidgetList.removeRow(row)
210
                #self.listUpdate()
211
        except Exception as ex:
212
            from App import App 
213
            from AppDocData import MessageType
214

  
215
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
216
            App.mainWnd().addMessage.emit(MessageType.Error, message)
217

  
218
    '''
219
        @brief      make training data by button click
220
        @author     euisung
221
        @date       2018.10.17
222
    '''
223
    def makeTrainingImageClicked(self):
224
        from PIL import Image
225
        import math, uuid
226
        from random import shuffle
227

  
228
        try:
229
            appDocData = AppDocData.instance()
230
            project = appDocData.getCurrentProject()
231
            tilePath = os.path.join(project.getTempPath(), 'tile')
232
            rootList = os.listdir(tilePath)
233
            
234
            self.ui.progressBar.setValue(0)
235
            self.ui.progressBar.setMaximum(len(rootList))
236

  
237
            maxsize = self.ui.spinBox_2.value()
238

  
239
            for root in rootList:
240
                images = []
241

  
242
                rootPath = os.path.join(tilePath, root)
243
                imgList = os.listdir(rootPath)
244
                for img in imgList:
245
                    imgPath = os.path.join(rootPath, img)
246

  
247
                    img = Image.open(imgPath)
248
                    images.append([img, imgPath])
249

  
250
                grid_size = [None, None]
251
                for img in images:
252
                    if grid_size[0] is None or grid_size[0] < img[0].size[0]:
253
                        grid_size[0] = img[0].size[0]
254
                    if grid_size[1] is None or grid_size[1] < img[0].size[1]:
255
                        grid_size[1] = img[0].size[1]
256
                space = 5
257
                grid_size[0] = grid_size[0] + space * 2
258
                grid_size[1] = grid_size[1] + space * 2
259

  
260
                dimension = [None, None]
261
                dimension[0] = int(maxsize / grid_size[0])
262
                dimension[1] = int(maxsize / grid_size[1])
263
                pages = int(len(images) / (dimension[0] * dimension[1])) + 1
264

  
265
                for page in range(pages):
266
                    merged_img = Image.new("RGB", (maxsize, maxsize), (256,256,256))
267
                    done = False
268
                    for j in range(dimension[1]):
269
                        for i in range(dimension[0]):
270
                            index = (page * dimension[0] * dimension[1]) + j * dimension[0] + i
271
                            if index >= len(images):
272
                                done = True
273
                                break
274

  
275
                            loc = [i*(grid_size[0]), j*(grid_size[1])]
276
                            label_image = images[index][0]
277
                            
278
                            x = loc[0] + space
279
                            y = loc[1] + space
280

  
281
                            merged_img.paste(label_image, (x, y, x + label_image.width, y + label_image.height))
282
                        if done: break
283

  
284
                    train_image_path = os.path.join(project.getTrainingSymbolFilePath(), str(uuid.uuid4()) + '.png')
285
                    merged_img.save(train_image_path)
286
            
287
        except Exception as ex:
288
            from App import App
289
            from AppDocData import MessageType
290

  
291
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
292
            App.mainWnd().addMessage.emit(MessageType.Error, message)
293
            return None
294

  
295
        try:
296
            
297
            QMessageBox.about(self, self.tr("Notice"), self.tr('Successfully applied. '))
298
        except Exception as ex:
299
            from App import App
300
            from AppDocData import MessageType
301

  
302
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
303
            App.mainWnd().addMessage.emit(MessageType.Error, message)
304
    
305
    def makeChart(self):
306
        '''
307
            @brief      make chart for trained charaters
308
            @author     euisung
309
            @date       2018.11.19
310
        '''
311
        try:
312
            barList = []
313
            categories = []
314
            for char in self.labelList:
315
                categories.append(char[0])
316
                barList.append(char[1])
317

  
318
            categoriesDict = [list(zip(range(len(categories)), categories))]
319
            
320
            if not hasattr(self, '_winChart'):
321
                self._winChart = pg.PlotWidget(background = 'w', title = 'Trained Symbols')
322
                self._winChart.setMouseEnabled(False, False)
323
                self._plot = pg.BarGraphItem(x = range(len(categories)), height = barList, width = 0.6, brush = 'b')
324
                self._winChart.addItem(self._plot)
325
                xax = self._winChart.getAxis('bottom')
326
                yax = self._winChart.getAxis('left')
327
                xax.setPen('k')
328
                yax.setPen('k')
329
                xax.setTicks(categoriesDict)
330
                self._winChart.showGrid(x = True, y = True)
331

  
332
                self.ui.horizontalLayoutChart.addWidget(self._winChart)
333
            else:
334
                self._winChart.removeItem(self._plot)
335

  
336
                self._plot = pg.BarGraphItem(x = range(len(categories)), height = barList, width = 0.6, brush = 'b')
337
                self._winChart.addItem(self._plot)
338
                xax = self._winChart.getAxis('bottom')
339
                yax = self._winChart.getAxis('left')
340
                xax.setPen('k')
341
                yax.setPen('k')
342
                xax.setTicks(categoriesDict)
343
                self._winChart.showGrid(x = True, y = True)
344
        except Exception as ex:
345
            from App import App
346
            from AppDocData import MessageType
347

  
348
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
349
            App.mainWnd().addMessage.emit(MessageType.Error, message)
350

  
351
    '''
352
        @brief      make Box data by button click
353
        @author     euisung
354
        @date       2018.10.16
355
    '''
356
    def pushButtonLabelClicked(self):
357
        from PIL import Image
358

  
359
        try:
360
            row = self.ui.tableWidgetList.selectedIndexes()[0].row()
361
            col = self.ui.tableWidgetList.selectedIndexes()[0].column()
362
            drawingName = self.ui.tableWidgetList.item(row, 1).text()
363
        except:
364
            return
365

  
366
        try:
367
            appDocData = AppDocData.instance()
368
            project = appDocData.getCurrentProject()
369

  
370
            drawingPath = os.path.join(project.getTrainingSymbolFilePath(), drawingName)
371
            drawing = Image.open(drawingPath)
372
            
373
            labelName = drawingName.replace('.png', '.boxS')
374

  
375
            dataList = appDocData.getTrainingSymbolFileList()
376
            isBoxFile = False
377
            for data in dataList:
378
                if data.find(labelName) is not -1:
379
                    isBoxFile = True
380
            traininglabelPath = os.path.join(project.getTrainingSymbolFilePath(), labelName)
381
            boundaryOcrData = None
382
            if not isBoxFile:
383
                docData = AppDocData.instance()
384
                ### make contour
385

  
386
        except Exception as ex:
387
            from App import App
388
            from AppDocData import MessageType
389

  
390
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
391
            App.mainWnd().addMessage.emit(MessageType.Error, message)
392

  
393
        try:
394
            dialog = QTrainingSymbolEditorDialog(self, drawingPath, traininglabelPath, boundaryOcrData, self.ui.tableWidgetList.item(row, 2), self.ui.tableWidgetList.item(row, 3))
395
            dialog.exec_()
396
        except Exception as ex:
397
            from App import App
398
            from AppDocData import MessageType
399

  
400
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
401
            App.mainWnd().addMessage.emit(MessageType.Error, message)
402

  
403
        return
404

  
405
    '''
406
        @brief      add drawing to Selected by button click
407
        @author     euisung
408
        @date       2018.09.28
409
    '''        
410
    def addListClicked(self):
411
        try:
412
            row = self.ui.tableWidgetList.selectedIndexes()[0].row()
413
            col = self.ui.tableWidgetList.selectedIndexes()[0].column()
414
            self.listCellDoubleClicked(row, col)
415
        except Exception as ex:
416
            pass
417
    '''
418
        @brief      delete character in box data as batch
419
        @author     euisung
420
        @date       2019.02.22
421
    ''' 
422
    def pushButtonDeleteBatchLabelClicked(self):
423
        try:
424
            targetChar = self.ui.lineEditTargetLabel.text()
425
            if targetChar == '':
426
                return
427
            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)
428
            if reply == QMessageBox.Yes:
429
                appDocData = AppDocData.instance()
430
                project = appDocData.getCurrentProject()
431

  
432
                drawingPath = project.getTrainingSymbolFilePath()
433
                boxList = os.listdir(drawingPath)
434
                nonBoxList = []
435

  
436
                for index in range(len(boxList)):
437
                    if boxList[index][-4:] != 'boxS':
438
                        nonBoxList.append(index)
439

  
440
                nonBoxList.sort(reverse=True)
441
                for index in nonBoxList:
442
                    boxList.pop(index)
443

  
444
                for box in boxList:
445
                    labelPath = os.path.join(drawingPath, box)
446
                    fw = open(labelPath, 'r', encoding='utf8')
447
                    labelContent = fw.read()
448
                    fw.close()
449
                    labelContent = labelContent.split('\n')[:-1]
450
                    newlabelContent = []
451
                    for boxString in labelContent:
452
                        if boxString[0] != targetChar:
453
                            newlabelContent.append(boxString)
454

  
455
                    outBox = ''
456
                    for boxString in newlabelContent:
457
                        outBox += boxString + '\n'
458
                    fw = open(labelPath, 'w', encoding='utf8')
459
                    fw.write(outBox)
460
                    fw.close()
461

  
462
                #self.listUpdate()
463
            self.ui.lineEditTargetLabel.setText('')
464
        except Exception as ex:
465
            from App import App 
466
            from AppDocData import MessageType
467

  
468
            message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
469
            App.mainWnd().addMessage.emit(MessageType.Error, message)
470

  
471
    '''
472
        @brief      make Box data by cell double click
473
        @author     euisung
474
        @date       2018.09.28
475
    '''
476
    def listCellDoubleClicked(self, row, col):
477
        self.pushButtonLabelClicked()
478
    
479
    '''
480
        @brief      key pressed event
481
        @author     euisung
482
        @date       2018.11.05
483
    '''
484
    def keyPressEvent(self, event):
485
        try:
486
            if event.key() == Qt.Key_Delete:
487
                try:
488
                    col = self.ui.tableWidgetList.selectedIndexes()[0].column()
489
                    if col == 1:
490
                        self.pushButtonImageDeleteClicked()
491
                    elif col == 2:
492
                        self.pushButtonLabelDeleteClicked()
493
                except Exception as ex:
494
                    pass
495
                
496
            QDialog.keyPressEvent(self, event)
497
        except Exception as ex:
498
            from App import App
499
            from AppDocData import MessageType
500

  
501
            message = 'error occurred({}) 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
            return None
DTI_PID/DTI_PID/TrainingSymbolImageList_UI.py
27 27
        self.pushButtonDeleteBatchLabel = QtWidgets.QPushButton(TraingingSymbolImageListDialog)
28 28
        self.pushButtonDeleteBatchLabel.setObjectName("pushButtonDeleteBatchLabel")
29 29
        self.horizontalLayout_4.addWidget(self.pushButtonDeleteBatchLabel)
30
        self.lineEditTargetChar = QtWidgets.QLineEdit(TraingingSymbolImageListDialog)
31
        self.lineEditTargetChar.setMaximumSize(QtCore.QSize(20, 16777215))
32
        self.lineEditTargetChar.setMaxLength(1)
33
        self.lineEditTargetChar.setObjectName("lineEditTargetChar")
34
        self.horizontalLayout_4.addWidget(self.lineEditTargetChar)
30
        self.lineEditTargetLabel = QtWidgets.QLineEdit(TraingingSymbolImageListDialog)
31
        self.lineEditTargetLabel.setMaximumSize(QtCore.QSize(200, 16777215))
32
        self.lineEditTargetLabel.setMaxLength(50)
33
        self.lineEditTargetLabel.setObjectName("lineEditTargetLabel")
34
        self.horizontalLayout_4.addWidget(self.lineEditTargetLabel)
35 35
        spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
36 36
        self.horizontalLayout_4.addItem(spacerItem)
37 37
        self.pushButtonImageDelete = QtWidgets.QPushButton(TraingingSymbolImageListDialog)
DTI_PID/DTI_PID/TrainingSymbolListDialog.py
1
import sys
2
import os
3
from PyQt5.QtCore import *
4
from PyQt5.QtGui import *
5
from PyQt5.QtWidgets import *
6
from AppDocData import AppDocData, Source
7
import pytesseract
8
import TrainingList_UI
9

  
10

  
11
pytesseract.pytesseract.tesseract_cmd = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Tesseract-OCR', 'tesseract.exe')
12
tesseract_cmd = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'Tesseract-OCR', 'tesseract.exe')
13

  
14
DEFAULT_CONF = """
15
    --psm 6 -c tessedit_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-~.,/!@#$%&*(){}[]<>:;+=?\\"\\'
16
"""
17

  
18
class QTrainingListDialog(QDialog):
19

  
20
    trainingDataNumber = 0
21

  
22
    def __init__(self, parent):
23
        QDialog.__init__(self, parent)
24

  
25
        self.ui = TrainingList_UI.Ui_TraingingListDialog()
26
        self.ui.setupUi(self)
27

  
28
        # for List 
29
        self.ui.tableWidgetList.setSelectionMode(QAbstractItemView.SingleSelection) 
30
        self.ui.tableWidgetList.setColumnCount(2)
31
        self.ui.tableWidgetList.setSortingEnabled(True)
32

  
33
        docData = AppDocData.instance()
34
        dataList = docData.getDrawingFileList()
35
        self.ui.tableWidgetList.setRowCount(len(dataList))
36

  
37
        ## column header 명 설정
38
        headerLabel = docData.getCurrentProject().getName()
39
        self.ui.tableWidgetList.setHorizontalHeaderLabels(['No.', headerLabel])
40
        self.ui.tableWidgetList.horizontalHeaderItem(1).setToolTip('도면 이름') # header tooltip
41
        self.ui.tableWidgetList.horizontalHeaderItem(1).setSizeHint(QSize(30, 30))
42
        self.ui.tableWidgetList.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
43
        self.ui.tableWidgetList.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
44
        self.ui.tableWidgetList.setEditTriggers(QAbstractItemView.NoEditTriggers)
45
        
46
        row = 0
47
        for data in dataList:
48
            self.ui.tableWidgetList.setItem(row, 0, QTableWidgetItem(str(row + 1)))
49
            self.ui.tableWidgetList.setItem(row, 1, QTableWidgetItem(data))
50
            row += 1
51

  
52
        # for Selected
53
        self.ui.tableWidgetSelected.setSelectionMode(QAbstractItemView.SingleSelection) 
54
        self.ui.tableWidgetSelected.setColumnCount(3)
55

  
56
        ## column header 명 설정
57
        headerLabel = docData.getCurrentProject().getName()
58
        self.ui.tableWidgetSelected.setHorizontalHeaderLabels(['No.', headerLabel, '작업 상태'])
59
        self.ui.tableWidgetSelected.horizontalHeaderItem(1).setToolTip('도면 이름') # header tooltip
60
        self.ui.tableWidgetSelected.horizontalHeaderItem(2).setToolTip('작업 상태') # header tooltip
61
        self.ui.tableWidgetSelected.horizontalHeaderItem(1).setSizeHint(QSize(30, 30))
62
        self.ui.tableWidgetSelected.horizontalHeader().setSectionResizeMode(0, QHeaderView.ResizeToContents)
63
        self.ui.tableWidgetSelected.horizontalHeader().setSectionResizeMode(1, QHeaderView.Stretch)
64
        self.ui.tableWidgetSelected.setEditTriggers(QAbstractItemView.NoEditTriggers)
65

  
66
        # connect signals and slots
67
        self.ui.tableWidgetList.cellDoubleClicked.connect(self.listCellDoubleClicked)
68
        self.ui.pushButtonAddList.clicked.connect(self.addListClicked)
69
        self.ui.pushButtonMakeTrainingData.clicked.connect(self.makeTrainingDataClicked)
70

  
71

  
72
    '''
73
        @brief      make training data(text image + Box file) by button click
74
        @author     euisung
75
        @date       2018.09.28
76
    '''        
77
    def makeTrainingDataClicked(self):
78
        from TextDetector import TextDetector
79
        from PIL import Image
80
        import cv2, math
81
        import numpy as np
82

  
83
        try:
84
            row = self.ui.tableWidgetSelected.selectedIndexes()[0].row()
85
            col = self.ui.tableWidgetSelected.selectedIndexes()[0].column()
86
            drawingName = self.ui.tableWidgetSelected.item(row, 1).text()
87
        except:
88
            return
89

  
90
        try:
91
            appDocData = AppDocData.instance()
92
            project = appDocData.getCurrentProject()
93
            textDetector = TextDetector()
94

  
95
            drawingPath = os.path.join(project.getDrawingFilePath(), drawingName)
96
            drawing = Source(Image.open(drawingPath))
97

  
98
            _imgSrc = cv2.cvtColor(cv2.imread(drawingPath), cv2.COLOR_BGR2GRAY)
99
            blur = cv2.GaussianBlur(_imgSrc , (5,5),0)
100
            _imgSrc = cv2.threshold(_imgSrc , 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)[1]
101

  
102
            textAreas = textDetector.detectTextAreas(_imgSrc , (0,0))
103

  
104
            areasNumber = len(textAreas)
105
            print('total text areas : ' + str(areasNumber))
106
            maxW, maxH, sumW, sumH, count = 0, 0, 0, 0, 0
107
            for textArea in textAreas:
108
                areaW = textArea.getW()
109
                areaH = textArea.getH()
110
                areaA = textArea.getAngle()
111
                if areaA is 90:
112
                    areaW, areaH = areaH, areaW
113
                if areaA is not 0 and areaA is not 90:
114
                    continue
115
                count += 1
116
                sumW += areaW
117
                sumH += areaH
118
                if maxW < areaW:
119
                    maxW = areaW
120
                if maxH < areaH:
121
                    maxH = areaH
122
            
123
            print('count : ' + str(count))
124
            print('max width : ' + str(maxW) + ', max height : ' + str(maxH))
125
            argW = sumW / count
126
            argH = sumH / count
127
            print('arg width : ' + str(argW) + ', arg height : ' + str(argH))
128
            totalArea = math.ceil(argW * argH * count)
129
            totalBaseWidth = math.ceil(math.sqrt(totalArea))
130
            print('total area theory : ' + str(totalArea) + ', total width : ' + str(totalBaseWidth))
131

  
132
            maxLineH, lineW, totalHeight = 0, 0, 0
133
            for index in range(0, areasNumber):
134
                areaW = textAreas[index].getW()
135
                areaH = textAreas[index].getH()
136
                areaA = textAreas[index].getAngle()
137
                if areaA is 90:
138
                    areaW, areaH = areaH, areaW
139
                if areaA is not 0 and areaA is not 90:
140
                    continue
141

  
142
                if maxLineH < areaH:
143
                    maxLineH = areaH
144
                if lineW + areaW < totalBaseWidth:
145
                    lineW += areaW
146
                else:
147
                    lineW = areaW
148
                    totalHeight += maxLineH
149
            totalHeight += maxLineH
150
            print('total area real : ' + str(totalBaseWidth * totalHeight) +', total width : ' + str(totalBaseWidth) + ', total height : ' + str(totalHeight) + ', ratio : ' + str(totalHeight / totalBaseWidth))
151

  
152
            trainingTextImg = Image.new("RGB", (totalBaseWidth, totalHeight), (256,256,256))
153
            maxLineH, lineW, totalHeight, currentX, currentY = 0, 0, 0, 0, 0
154
            for index in range(0, areasNumber):
155
                #print(index)
156
                areaW = textAreas[index].getW()
157
                areaH = textAreas[index].getH()
158
                areaA = textAreas[index].getAngle()
159

  
160
                textAreaImg = drawing.source.crop((textAreas[index].getX(), textAreas[index].getY(), textAreas[index].getX() + areaW, textAreas[index].getY() + areaH))
161

  
162
                if areaA is 90:
163
                    areaW, areaH = areaH, areaW
164
                    textAreaImg = textAreaImg.transpose(Image.ROTATE_270)
165
                if areaA is not 0 and areaA is not 90:
166
                    continue
167

  
168
                if maxLineH < areaH:
169
                    maxLineH = areaH
170
                if lineW + areaW < totalBaseWidth:
171
                    lineW += areaW
172
                    trainingTextImg.paste(textAreaImg, (currentX, currentY, currentX + areaW, currentY + areaH))
173
                    currentX = lineW
174
                else:
175
                    lineW = areaW
176
                    totalHeight += maxLineH
177
                    currentX = 0
178
                    currentY = totalHeight
179
                    trainingTextImg.paste(textAreaImg, (currentX, currentY, currentX + areaW, currentY + areaH))
180
                    currentX = areaW
181
               #trainingTextImg.show()
182
            #trainingTextImg.show()
183
            boundaryOcrData = pytesseract.image_to_boxes(trainingTextImg, config=DEFAULT_CONF, lang='seed+eng')
184

  
185
            trainingImgPath = os.path.join(project.getTrainingFilePath(), 'seed.seedF.exp0.tif')
186
            trainingBoxPath = os.path.join(project.getTrainingFilePath(), 'seed.seedF.exp0.box')
187

  
188
            trainingTextImg.save(trainingImgPath, compression='tiff_lzw')
189
            fw = open(trainingBoxPath, 'w') #파일 있으면 새로 만듬 예외 처리 안됨, 임시
190
            fw.write(boundaryOcrData)
191
            fw.close()
192
            
193
        except Exception as ex:
194
            print('error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
195
        return
196

  
197
    '''
198
        @brief      add drawing to Selected by button click
199
        @author     euisung
200
        @date       2018.09.28
201
    '''        
202
    def addListClicked(self):
203
        try:
204
            row = self.ui.tableWidgetList.selectedIndexes()[0].row()
205
            col = self.ui.tableWidgetList.selectedIndexes()[0].column()
206
            self.listCellDoubleClicked(row, col)
207
        except Exception as ex:
208
            pass
209
        return
210

  
211

  
212
    '''
213
        @brief      add drawing to Selected by cell double click
214
        @author     euisung
215
        @date       2018.09.28
216
    '''
217
    def listCellDoubleClicked(self, row, col):
218
        #print('row : ' + str(row) + ', col : ' + str(col))
219
        rowPosition = self.ui.tableWidgetSelected.rowCount()
220
        self.ui.tableWidgetSelected.setRowCount(rowPosition + 1)
221

  
222
        drawingName = self.ui.tableWidgetList.item(row, 1).text()
223
        #print(drawingName)
224
        self.trainingDataNumber = self.trainingDataNumber + 1
225
        self.ui.tableWidgetSelected.setItem(rowPosition, 0, QTableWidgetItem(str(self.trainingDataNumber)))
226
        self.ui.tableWidgetSelected.setItem(rowPosition, 1, QTableWidgetItem(drawingName))
227
        self.ui.tableWidgetSelected.setItem(rowPosition, 2, QTableWidgetItem('신규'))
228

  
229
        return
230

  
231

  
232
        
DTI_PID/DTI_PID/UI/MainWindow.ui
95 95
    <addaction name="actionOPCRelation"/>
96 96
    <addaction name="separator"/>
97 97
    <addaction name="actionCodeTable"/>
98
    <addaction name="separator"/>
98 99
    <addaction name="actionOCR_Training"/>
100
    <addaction name="actionSymbol_Training"/>
99 101
   </widget>
100 102
   <widget class="QMenu" name="menu_3">
101 103
    <property name="title">
......
1128 1130
    <string>Export Equipment Datasheet</string>
1129 1131
   </property>
1130 1132
  </action>
1133
  <action name="actionSymbol_Training">
1134
   <property name="text">
1135
    <string>Symbol Training</string>
1136
   </property>
1137
  </action>
1131 1138
 </widget>
1132 1139
 <resources>
1133 1140
  <include location="../res/MainWindow.qrc"/>
DTI_PID/DTI_PID/UI/TrainingSymbolImageList.ui
35 35
      </widget>
36 36
     </item>
37 37
     <item>
38
      <widget class="QLineEdit" name="lineEditTargetChar">
38
      <widget class="QLineEdit" name="lineEditTargetLabel">
39 39
       <property name="maximumSize">
40 40
        <size>
41
         <width>20</width>
41
         <width>200</width>
42 42
         <height>16777215</height>
43 43
        </size>
44 44
       </property>
45 45
       <property name="maxLength">
46
        <number>1</number>
46
        <number>50</number>
47 47
       </property>
48 48
      </widget>
49 49
     </item>
......
106 106
       </property>
107 107
       <property name="font">
108 108
        <font>
109
         <weight>50</weight>
110
         <bold>false</bold>
109
         <weight>75</weight>
110
         <bold>true</bold>
111 111
        </font>
112 112
       </property>
113 113
       <property name="text">

내보내기 Unified diff

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