프로젝트

일반

사용자정보

통계
| 개정판:

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

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

1 c96518e7 esham21
import sys
2 405fdba5 esham21
import os, time, datetime
3 c96518e7 esham21
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 6913dbc8 esham21
from PIL import Image
13 c96518e7 esham21
import AreaZoomCommand
14
import PlaceLineCommand
15
16
class QTrainingEditorDialog(QDialog):
17 d89b1f19 esham21
    def __init__(self, parent, trainingImgPath, trainingBoxPath, boundaryOcrData, cellItem):
18 d45df999 esham21
        self.spinBoxFlag = False
19 c96518e7 esham21
        QDialog.__init__(self, parent)
20 63c55b90 esham21
        self.setWindowFlag(Qt.WindowMinMaxButtonsHint)
21 c96518e7 esham21
22 eeb349d8 esham21
        self.trainingImgPath = trainingImgPath
23
        self.trainingBoxPath = trainingBoxPath
24 726d4cf2 esham21
        self.boundaryOcrData = boundaryOcrData
25 d89b1f19 esham21
        self.cellItem = cellItem
26 53953154 esham21
        self.isChanged = False
27 eeb349d8 esham21
28 c96518e7 esham21
        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 6913dbc8 esham21
39
        self.graphicsViewZoomDrawing = QGraphicsView(self)
40 d45df999 esham21
        self.graphicsViewZoomDrawing.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
41
        self.graphicsViewZoomDrawing.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
42 6913dbc8 esham21
        self.graphicsViewZoomDrawing.setParent(self.ui.leftSideWidget)
43
        self.ui.horizontalLayoutZoomDrawing.addWidget(self.graphicsViewZoomDrawing)
44
        
45 c96518e7 esham21
        
46 d45df999 esham21
        # 학습 이미지 읽어서 메인 뷰에 그림, 사이드 뷰에 추가
47 c96518e7 esham21
        try:
48 eeb349d8 esham21
            #trainingImgPath = os.path.join(project.getTrainingFilePath(), 'seed.seedF.exp0.tif')
49 c96518e7 esham21
            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 d45df999 esham21
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 b7d5317e esham21
            self.graphicsViewZoomDrawing.scene().setSceneRect(0, 0, pixmap.width(), pixmap.height())
66
            self.graphicsViewZoomDrawing.fitInView(self.graphicsViewZoomDrawing.scene().sceneRect(), Qt.KeepAspectRatioByExpanding)
67 d45df999 esham21
            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 59e764f3 esham21
            rect.setOpacity(0.7)
74 d45df999 esham21
            self.graphicsViewZoomDrawing.scene().addItem(rect)
75
76 c96518e7 esham21
        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 d45df999 esham21
        # 박스 읽어서 메인 뷰에 그림
80 c96518e7 esham21
        try:
81
            boxList = []
82 726d4cf2 esham21
            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 c96518e7 esham21
90
            for box in boxList:
91 726d4cf2 esham21
                if box == '': continue
92 c96518e7 esham21
                boxComponent = box.split(' ')
93 1669b150 esham21
                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 c96518e7 esham21
                singleBox.transfer.onRemoved.connect(self.itemRemoved)
95 d45df999 esham21
                singleBox.addTextItemToScene(self.ui, self.graphicsViewTrainingDrawing, self.graphicsViewZoomDrawing, self.spinBoxFlag)
96 c96518e7 esham21
        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 eeb349d8 esham21
        self.ui.pushButtonSave.clicked.connect(self.pushButtonSaveClicked)
103 83575689 esham21
        self.ui.pushButtonCancel.clicked.connect(self.pushButtonCancelClicked)
104 726d4cf2 esham21
        self.ui.pushButtonDelete.clicked.connect(self.pushButtonDeleteClicked)
105
        self.ui.pushButtonAdd.clicked.connect(self.pushButtonAddClicked)
106 6fa02c93 esham21
        self.ui.pushButtonSplit.clicked.connect(self.pushButtonSplitClicked)
107 d45df999 esham21
        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 bb23850e humkyung
        self.ui.lineEditChar.returnPressed.connect(self.pushButtonChangeClicked)
112 6913dbc8 esham21
113 726d4cf2 esham21
    '''
114 6fa02c93 esham21
        @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 726d4cf2 esham21
        @brief      add boxitem by button click
131
        @author     euisung
132
        @date       2018.10.17
133
    '''
134
    def pushButtonAddClicked(self):
135 53953154 esham21
        self.isChanged = True
136 726d4cf2 esham21
        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 53953154 esham21
        self.isChanged = True
170 726d4cf2 esham21
        items = self.graphicsViewTrainingDrawing.scene.selectedItems()
171
        for item in items:
172
            item.transfer.onRemoved.emit(item)
173
174 b8d39c65 humkyung
    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 726d4cf2 esham21
    '''
183
        @brief      change boxitem char by button click
184
        @author     euisung
185
        @date       2018.10.17
186
    '''
187 83575689 esham21
    def pushButtonChangeClicked(self):
188 53953154 esham21
        self.isChanged = True
189 eeb349d8 esham21
        items = self.graphicsViewTrainingDrawing.scene.selectedItems()
190 726d4cf2 esham21
        if len(items) is not 1:
191 83575689 esham21
            return
192
        items[0].char = self.ui.lineEditChar.text()
193 b9091c43 esham21
        items[0].textShowBox.setHtml(self.ui.lineEditChar.text())
194 83575689 esham21
195 726d4cf2 esham21
    '''
196
        @brief      close dialog by button click
197
        @author     euisung
198
        @date       2018.10.17
199
    '''
200 83575689 esham21
    def pushButtonCancelClicked(self):
201 53953154 esham21
        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 83575689 esham21
208 726d4cf2 esham21
    '''
209
        @brief      save box item by button click
210
        @author     euisung
211
        @date       2018.10.16
212
    '''
213 83575689 esham21
    def pushButtonSaveClicked(self):
214
        items = self.graphicsViewTrainingDrawing.scene.items()
215 eeb349d8 esham21
        outBox = ""
216
        for item in items:
217 83575689 esham21
            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 726d4cf2 esham21
                bx, by, bx2, by2 = str(x), str(imgHeight - y - height), str(x + width), str(imgHeight - y)
225
                if char == '':
226
                    continue
227 83575689 esham21
                outBox += char + " " + bx + " " + by + " " + bx2 + " " + by2 + "\n"
228 eeb349d8 esham21
        fw = open(self.trainingBoxPath, 'w')
229
        fw.write(outBox)
230
        fw.close()
231 8a2f59cb esham21
        modifiedTime = str(datetime.datetime.strptime(time.ctime(os.path.getmtime(self.trainingBoxPath)), "%a %b %d %H:%M:%S %Y"))
232 d89b1f19 esham21
        self.cellItem.setText(modifiedTime)
233
234 53953154 esham21
        self.isChanged = False
235 452e4adb esham21
        QMessageBox.about(self, "알림", '저장하였습니다.')
236 eeb349d8 esham21
237 726d4cf2 esham21
    '''
238
        @brief      chane box item's rect by button click
239
        @author     euisung
240
        @date       2018.10.16
241
    '''
242 d45df999 esham21
    def spinBoxChangedEvent(self, event):
243 53953154 esham21
        self.isChanged = True
244 6913dbc8 esham21
        items = self.graphicsViewTrainingDrawing.scene.selectedItems()
245 726d4cf2 esham21
        if (len(items) is not 1) or self.spinBoxFlag:
246 6913dbc8 esham21
            return
247 d45df999 esham21
        spinBoxName = self.sender().objectName()
248 6913dbc8 esham21
        rect = items[0].rect()
249 d45df999 esham21
        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 99e0f49b esham21
            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 d45df999 esham21
        elif spinBoxName == 'spinBoxTop':
256
            spinBoxValue = self.ui.spinBoxTop.value()
257
            items[0].setRect(QRectF(rect.x(), spinBoxValue, rect.width(), rect.height()))
258 99e0f49b esham21
            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 d45df999 esham21
        elif spinBoxName == 'spinBoxWidth':
260
            spinBoxValue = self.ui.spinBoxWidth.value()
261
            items[0].setRect(QRectF(rect.x(),  rect.y(), spinBoxValue, rect.height()))
262 99e0f49b esham21
            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 d45df999 esham21
        elif spinBoxName == 'spinBoxHeight':
264
            spinBoxValue = self.ui.spinBoxHeight.value()
265
            items[0].setRect(QRectF(rect.x(), rect.y(), rect.width(), spinBoxValue))
266 99e0f49b esham21
            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 d45df999 esham21
        rect = items[0].rect()        
269
        bound.setRect(rect)
270 99e0f49b esham21
        rectSide = QRectF(rect.x() - 3, rect.y() - 3, rect.width() + 6,  rect.height() + 6)
271 d45df999 esham21
        self.graphicsViewZoomDrawing.fitInView(rectSide)
272 6913dbc8 esham21
        self.graphicsViewTrainingDrawing.scene.update()
273
    
274 c96518e7 esham21
    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 83575689 esham21
            if item.scene is not None: item.scene.removeItem(item)
293 c96518e7 esham21
        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 13502b99 esham21
    '''
297
        @brief      key pressed event
298
        @author     euisung
299
        @date       2018.11.05
300
    '''
301
    def keyPressEvent(self, event):
302
        try:
303 a247f3fd esham21
            items = self.graphicsViewTrainingDrawing.scene.selectedItems()
304
            if len(items) is not 1 or type(items[0]) is not QTrainingBoxItem:
305
                return
306 b8d39c65 humkyung
            selectedItem = items[0]
307 a247f3fd esham21
            closestItem = None
308 b8d39c65 humkyung
            x = selectedItem.rect().x()
309
310 13502b99 esham21
            if event.key() == Qt.Key_Left:
311 a247f3fd esham21
                dx =  sys.maxsize
312 13502b99 esham21
                for item in self.graphicsViewTrainingDrawing.scene.items():
313
                    if type(item) is QTrainingBoxItem:
314 a247f3fd esham21
                        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 b8d39c65 humkyung
                    selectedItem.setSelected(False)
320 a247f3fd esham21
                    closestItem.mousePressEvent('arrow key')
321
                        
322 13502b99 esham21
            elif event.key() == Qt.Key_Right:
323 a247f3fd esham21
                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 b8d39c65 humkyung
                    selectedItem.setSelected(False)
332 a247f3fd esham21
                    closestItem.mousePressEvent('arrow key')
333 b8d39c65 humkyung
            elif event.key() == Qt.Key_Return:
334
                pass
335
            elif selectedItem:
336
                text = event.text()
337
                if text: self.onCharChanged(text)
338 13502b99 esham21
        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 bb23850e humkyung
            return None
클립보드 이미지 추가 (최대 크기: 500 MB)