프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / TrainingEditorDialog.py @ 8a2f59cb

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

1
import sys
2
import os, time, datetime
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
        self.removedItems = []
100

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

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

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

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

    
174
    def onCharChanged(self, text):
175
        """
176
        change lineedit's text with given text
177
        """
178
        if text:
179
            self.ui.lineEditChar.setText(text)
180
            self.pushButtonChangeClicked()
181

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

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

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

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

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

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

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

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

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

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

    
296
    '''
297
        @brief      key pressed event
298
        @author     euisung
299
        @date       2018.11.05
300
    '''
301
    def keyPressEvent(self, event):
302
        try:
303
            items = self.graphicsViewTrainingDrawing.scene.selectedItems()
304
            if len(items) is not 1 or type(items[0]) is not QTrainingBoxItem:
305
                return
306
            selectedItem = items[0]
307
            closestItem = None
308
            x = selectedItem.rect().x()
309

    
310
            if event.key() == Qt.Key_Left:
311
                dx =  sys.maxsize
312
                for item in self.graphicsViewTrainingDrawing.scene.items():
313
                    if type(item) is QTrainingBoxItem:
314
                        if x - item.rect().x() > 0 and x - item.rect().x() < dx:
315
                            closestItem = item
316
                            dx = x - item.rect().x()
317
                if closestItem is not None:
318
                    closestItem.setSelected(True)
319
                    selectedItem.setSelected(False)
320
                    closestItem.mousePressEvent('arrow key')
321
                        
322
            elif event.key() == Qt.Key_Right:
323
                dx = -sys.maxsize
324
                for item in self.graphicsViewTrainingDrawing.scene.items():
325
                    if type(item) is QTrainingBoxItem:
326
                        if x - item.rect().x() < 0 and x - item.rect().x() > dx:
327
                            closestItem = item
328
                            dx = x - item.rect().x()
329
                if closestItem is not None:
330
                    closestItem.setSelected(True)
331
                    selectedItem.setSelected(False)
332
                    closestItem.mousePressEvent('arrow key')
333
            elif event.key() == Qt.Key_Return:
334
                pass
335
            elif selectedItem:
336
                text = event.text()
337
                if text: self.onCharChanged(text)
338
        except Exception as ex:
339
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
340
            from App import App
341
            from AppDocData import MessageType
342

    
343
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
344
            App.mainWnd().addMessage.emit(MessageType.Error, message)
345
            return None
클립보드 이미지 추가 (최대 크기: 500 MB)