프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / TrainingEditorDialog.py @ 99e0f49b

이력 | 보기 | 이력해설 | 다운로드 (15.3 KB)

1
import sys
2
import os, time
3
from PyQt5.QtCore import *
4
from PyQt5.QtGui import *
5
from PyQt5.QtWidgets import *
6
from AppDocData import AppDocData, Source
7
import TrainingEditor_UI
8
import QtImageViewer
9
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem
10
from TrainingBoxItem import QTrainingBoxItem
11
import cv2
12
from PIL import Image
13
import AreaZoomCommand
14
import PlaceLineCommand
15

    
16
class QTrainingEditorDialog(QDialog):
17
    def __init__(self, parent, trainingImgPath, trainingBoxPath, boundaryOcrData, cellItem):
18
        self.spinBoxFlag = False
19
        QDialog.__init__(self, parent)
20
        self.setWindowFlag(Qt.WindowMinMaxButtonsHint)
21

    
22
        self.trainingImgPath = trainingImgPath
23
        self.trainingBoxPath = trainingBoxPath
24
        self.boundaryOcrData = boundaryOcrData
25
        self.cellItem = cellItem
26
        self.isChanged = False
27

    
28
        appDocData = AppDocData.instance()
29
        project = appDocData.getCurrentProject()
30

    
31
        self.ui = TrainingEditor_UI.Ui_TrainingEditorDialog()
32
        self.ui.setupUi(self)
33

    
34
        self.graphicsViewTrainingDrawing = QtImageViewer.QtImageViewer(self)
35
        self.graphicsViewTrainingDrawing.setParent(self.ui.centralWidget)
36
        self.graphicsViewTrainingDrawing.useDefaultCommand()
37
        self.ui.verticalLayoutTrainingDrawing.addWidget(self.graphicsViewTrainingDrawing)
38

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

    
55
            self.graphicsViewTrainingDrawing.setImage(image)
56

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

    
76
        except Exception as ex:
77
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
78

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

    
90
            for box in boxList:
91
                if box == '': continue
92
                boxComponent = box.split(' ')
93
                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]))
94
                singleBox.transfer.onRemoved.connect(self.itemRemoved)
95
                singleBox.addTextItemToScene(self.ui, self.graphicsViewTrainingDrawing, self.graphicsViewZoomDrawing, self.spinBoxFlag)
96
        except Exception as ex:
97
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
98

    
99
        #'''test'''
100
        #item = QGraphicsBoundingBoxItem(0, 0, 30, 30)
101
        #item.isSymbol = True
102
        #item.angle = 0
103
        #item.setPen(QPen(Qt.red, 1, Qt.SolidLine))
104
        #self.graphicsViewTrainingDrawing.scene.addItem(item)
105

    
106
        self.removedItems = []
107

    
108
        self.ui.pushButtonZoom.clicked.connect(self.onAreaZoom)
109
        self.ui.pushButtonSave.clicked.connect(self.pushButtonSaveClicked)
110
        self.ui.pushButtonCancel.clicked.connect(self.pushButtonCancelClicked)
111
        self.ui.pushButtonChange.clicked.connect(self.pushButtonChangeClicked)
112
        self.ui.pushButtonDelete.clicked.connect(self.pushButtonDeleteClicked)
113
        self.ui.pushButtonAdd.clicked.connect(self.pushButtonAddClicked)
114
        self.ui.pushButtonSplit.clicked.connect(self.pushButtonSplitClicked)
115
        self.ui.spinBoxLeft.valueChanged.connect(self.spinBoxChangedEvent)
116
        self.ui.spinBoxTop.valueChanged.connect(self.spinBoxChangedEvent)
117
        self.ui.spinBoxWidth.valueChanged.connect(self.spinBoxChangedEvent)
118
        self.ui.spinBoxHeight.valueChanged.connect(self.spinBoxChangedEvent)
119

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

    
136
    '''
137
        @brief      add boxitem by button click
138
        @author     euisung
139
        @date       2018.10.17
140
    '''
141
    def pushButtonAddClicked(self):
142
        self.isChanged = True
143
        items = self.graphicsViewTrainingDrawing.scene.selectedItems()
144
        allItems = self.graphicsViewTrainingDrawing.scene.items()
145
        totalWidth = 0
146
        totalHeight = 0
147
        count = 0
148
        if len(items) is 1:
149
            rect = items[0].rect()
150
        elif len(allItems) > 1:
151
            for item in allItems:
152
                if type(item) is QGraphicsPixmapItem:
153
                    x = int(item.boundingRect().width() / 2)
154
                    y = int(item.boundingRect().height()/ 2)
155
                else:
156
                    count += 1
157
                    totalWidth += item.rect().width()
158
                    totalHeight += item.rect().height()
159
            rect = QRectF(x, y, round(totalWidth / count), round(totalHeight / count))
160
        else:
161
            for item in allItems:
162
                if type(item) is QGraphicsPixmapItem:
163
                    x = int(item.boundingRect().width() / 2)
164
                    y = int(item.boundingRect().height()/ 2)
165
            rect = QRectF(x, y, 5, 10)
166
        singleBox = QTrainingBoxItem('', rect.x() + 3, rect.y(), rect.width(), rect.height())
167
        singleBox.transfer.onRemoved.connect(self.itemRemoved)
168
        singleBox.addTextItemToScene(self.ui, self.graphicsViewTrainingDrawing, self.graphicsViewZoomDrawing, self.spinBoxFlag)
169

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

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

    
194
    '''
195
        @brief      close dialog by button click
196
        @author     euisung
197
        @date       2018.10.17
198
    '''
199
    def pushButtonCancelClicked(self):
200
        if self.isChanged:
201
            reply = QMessageBox.question(self, 'Continue?', '변경사항이 저장되지 않았을 수 있습니다.', QMessageBox.Ignore, QMessageBox.Cancel)
202
            if reply == QMessageBox.Ignore:
203
                QDialog.reject(self)
204
        else:
205
            QDialog.reject(self)
206

    
207
    '''
208
        @brief      save box item by button click
209
        @author     euisung
210
        @date       2018.10.16
211
    '''
212
    def pushButtonSaveClicked(self):
213
        items = self.graphicsViewTrainingDrawing.scene.items()
214
        outBox = ""
215
        for item in items:
216
            if type(item) is QGraphicsPixmapItem:
217
                imgHeight = int(item.boundingRect().height())
218
                imgWidth = int(item.boundingRect().width())
219
        for item in items:
220
            if type(item) is QTrainingBoxItem:
221
                rect = item.rect()
222
                char, x, y, width, height = item.char, int(rect.x()), int(rect.y()), int(rect.width()), int(rect.height())
223
                bx, by, bx2, by2 = str(x), str(imgHeight - y - height), str(x + width), str(imgHeight - y)
224
                if char == '':
225
                    continue
226
                outBox += char + " " + bx + " " + by + " " + bx2 + " " + by2 + "\n"
227
        fw = open(self.trainingBoxPath, 'w')
228
        fw.write(outBox)
229
        fw.close()
230
        modifiedTime = time.ctime(os.path.getmtime(self.trainingBoxPath))
231
        self.cellItem.setText(modifiedTime)
232

    
233
        self.isChanged = False
234
        QMessageBox.about(self, "알림", '저장하였습니다.')
235

    
236
    '''
237
        @brief      chane box item's rect by button click
238
        @author     euisung
239
        @date       2018.10.16
240
    '''
241
    def spinBoxChangedEvent(self, event):
242
        self.isChanged = True
243
        items = self.graphicsViewTrainingDrawing.scene.selectedItems()
244
        if (len(items) is not 1) or self.spinBoxFlag:
245
            return
246
        spinBoxName = self.sender().objectName()
247
        rect = items[0].rect()
248
        bound = self.graphicsViewZoomDrawing.scene().items()[0]
249

    
250
        if spinBoxName == 'spinBoxLeft':
251
            spinBoxValue = self.ui.spinBoxLeft.value()
252
            items[0].setRect(QRectF(spinBoxValue, rect.y(), rect.width(), rect.height()))
253
            items[0].textShowBox.setPos(items[0].rect().x() + round(items[0].rect().width() / 3), items[0].rect().y() - round(items[0].rect().height() / 2))
254
        elif spinBoxName == 'spinBoxTop':
255
            spinBoxValue = self.ui.spinBoxTop.value()
256
            items[0].setRect(QRectF(rect.x(), spinBoxValue, rect.width(), rect.height()))
257
            items[0].textShowBox.setPos(items[0].rect().x() + round(items[0].rect().width() / 3), items[0].rect().y() - round(items[0].rect().height() / 2))
258
        elif spinBoxName == 'spinBoxWidth':
259
            spinBoxValue = self.ui.spinBoxWidth.value()
260
            items[0].setRect(QRectF(rect.x(),  rect.y(), spinBoxValue, rect.height()))
261
            items[0].textShowBox.setPos(items[0].rect().x() + round(items[0].rect().width() / 3), items[0].rect().y() - round(items[0].rect().height() / 2))
262
        elif spinBoxName == 'spinBoxHeight':
263
            spinBoxValue = self.ui.spinBoxHeight.value()
264
            items[0].setRect(QRectF(rect.x(), rect.y(), rect.width(), spinBoxValue))
265
            items[0].textShowBox.setPos(items[0].rect().x() + round(items[0].rect().width() / 3), items[0].rect().y() - round(items[0].rect().height() / 2))
266

    
267
        rect = items[0].rect()        
268
        bound.setRect(rect)
269
        rectSide = QRectF(rect.x() - 3, rect.y() - 3, rect.width() + 6,  rect.height() + 6)
270
        self.graphicsViewZoomDrawing.fitInView(rectSide)
271
        self.graphicsViewTrainingDrawing.scene.update()
272
    
273
    def onAreaZoom(self, action):
274
        if self.ui.pushButtonZoom.isChecked():
275
            cmd = AreaZoomCommand.AreaZoomCommand(self.graphicsViewTrainingDrawing)
276
            cmd.onRejected.connect(self.onCommandRejected)
277
            self.graphicsViewTrainingDrawing.command = cmd
278

    
279
    def onCommandRejected(self, cmd):
280
        try:
281
            if type(cmd) is AreaZoomCommand.AreaZoomCommand:
282
                self.ui.pushButtonZoom.setChecked(False)
283
        finally:
284
            self.graphicsViewTrainingDrawing.useDefaultCommand()
285

    
286
    def itemRemoved(self, item):
287
        try:
288
            if type(item) is QTrainingBoxItem:
289
                self.removedItems.append(str(item.uid))
290

    
291
            if item.scene is not None: item.scene.removeItem(item)
292
        except Exception as ex:
293
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
294

    
295
    '''
296
        @brief      key pressed event
297
        @author     euisung
298
        @date       2018.11.05
299
    '''
300
    def keyPressEvent(self, event):
301
        try:
302
            items = self.graphicsViewTrainingDrawing.scene.selectedItems()
303
            if len(items) is not 1 or type(items[0]) is not QTrainingBoxItem:
304
                return
305
            seletedItem = items[0]
306
            closestItem = None
307
            x = seletedItem.rect().x()
308
            if event.key() == Qt.Key_Left:
309
                dx =  sys.maxsize
310
                for item in self.graphicsViewTrainingDrawing.scene.items():
311
                    if type(item) is QTrainingBoxItem:
312
                        if x - item.rect().x() > 0 and x - item.rect().x() < dx:
313
                            closestItem = item
314
                            dx = x - item.rect().x()
315
                if closestItem is not None:
316
                    closestItem.setSelected(True)
317
                    seletedItem.setSelected(False)
318
                    closestItem.mousePressEvent('arrow key')
319
                        
320
            elif event.key() == Qt.Key_Right:
321
                dx = -sys.maxsize
322
                for item in self.graphicsViewTrainingDrawing.scene.items():
323
                    if type(item) is QTrainingBoxItem:
324
                        if x - item.rect().x() < 0 and x - item.rect().x() > dx:
325
                            closestItem = item
326
                            dx = x - item.rect().x()
327
                if closestItem is not None:
328
                    closestItem.setSelected(True)
329
                    seletedItem.setSelected(False)
330
                    closestItem.mousePressEvent('arrow key')
331
                
332
        except Exception as ex:
333
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
334
            from App import App
335
            from AppDocData import MessageType
336

    
337
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
338
            App.mainWnd().addMessage.emit(MessageType.Error, message)
339
            return None
340

    
341
        
342
        
343

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