프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / TrainingEditorDialog.py @ 85f3f93b

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

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