프로젝트

일반

사용자정보

통계
| 개정판:

hytos / DTI_PID / DTI_PID / RecognitionDialog.py @ e9f0c81d

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

1
# coding: utf-8
2
"""
3
    This is recognition dialog module
4
"""
5
import sys
6
import os
7
import threading
8
import cv2
9
from PyQt5.QtCore import *
10
from PyQt5.QtGui import *
11
from PyQt5.QtWidgets import *
12
import Recognition_UI
13

    
14
import concurrent.futures as futures
15

    
16
from AppDocData import *
17
from SymbolSvgItem import SymbolSvgItem
18
from EngineeringTextItem import QEngineeringTextItem
19
from EngineeringUnknownItem import QEngineeringUnknownItem
20

    
21
from MainWindow import MainWindow
22

    
23
#region Symbol Image path List for test
24
targetSymbolList = []
25
#endregion
26

    
27
#region Global variables
28
searchedSymbolList = []
29
textInfoList = []
30

    
31
src = []
32

    
33
ocrCompletedSrc = []
34
afterDenoising = []
35
canvas = []
36

    
37
WHITE_LIST_CHARS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890-"
38

    
39
MIN_TEXT_SIZE = 10
40

    
41
THREAD_MAX_WORKER = os.cpu_count()
42
threadLock = threading.Lock()
43

    
44
ACCEPT_OVERLAY_AREA = 10
45
#endregion
46

    
47
'''
48
    @history    2018.05.25  Jeongwoo    Add pyqtSignal(recognizeLine, loadRecognitionResult)
49
'''
50
class Worker(QObject):
51
    from PyQt5.QtCore import QThread
52
    from PyQt5.QtCore import QTranslator
53
    from PyQt5.QtWidgets import QApplication, QLabel, QWidget, QGridLayout, QListWidget
54
    from QtImageViewer import QtImageViewer
55
    import sys
56

    
57
    '''
58
        @history    2018.05.30  Jeongwoo    Remove parameter on recognizeLine signal / Change signal name (drawDetectedItems)
59
        @history    humkyung 2018.06.08 add signal for progressbar
60
        @history    euisung 2018.11.27 add signal for unknown items
61
    '''
62
    finished = pyqtSignal()
63
    intReady = pyqtSignal(int)
64
    displayTitle = pyqtSignal(str)
65
    displayMessage = pyqtSignal(QListWidgetItem)
66
    updateProgress = pyqtSignal(int, str)
67
    updateBatchProgress = pyqtSignal(int, int)
68
    displayLog = pyqtSignal(MessageType, str)
69

    
70
    def __init__(self):
71
        super(Worker, self).__init__()
72

    
73
    '''
74
        @history    2018.05.25  Jeongwoo    Add if-statements by isSymbolTextChecked and isLineChecked variable
75
                    2018.05.28  Jeongwoo    Add Parameter 'xmlPath[0]'
76
                    2018.05.30  Jeongwoo    Remove import recognizeLine and self.xmlPath and remove parameter on recognizeLine.emit() (xmlPath)
77
                                            Change signal name (drawDetectedItems)
78
    '''
79
    def procCounter(self): # A slot takes no params
80
        try:
81
            if self.isSymbolChecked or self.isTextChecked:
82
                Worker.executeRecognition(self.createDetectedItems, self.path, self.listWidget, self.isLineChecked, self, self.batch, self.createUnknownItems)
83

    
84
            #if self.isLineChecked:
85
            #    Worker.recognizeLine(self.drawDetectedLines, self.path, self.listWidget, self.graphicsView, self)
86
        except Exception as ex:
87
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
88
            print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno))
89
            self.displayLog.emit(MessageType.Error, message)
90
        finally:
91
            self.finished.emit()
92

    
93
    '''
94
        @brief  remove small objects from given image
95
        @author humkyung
96
        @date   2018.04.26
97
        @history    2018.05.25  Jeongwoo    Moved from MainWindow
98
    '''
99
    @staticmethod
100
    def removeSmallObjects(image):
101
        try:
102
            appDocData = AppDocData.instance()
103
            configs = appDocData.getConfigs('Small Object Size', 'Min Area')
104
            minArea = int(configs[0].value) if 1 == len(configs) else 20
105
            configs = appDocData.getConfigs('Small Object Size', 'Max Area')
106
            maxArea = int(configs[0].value) if 1 == len(configs) else 50
107
    
108
            _,contours,_ = cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
109
            selectedContours=[]
110
            for contour in contours:
111
                area = cv2.contourArea(contour)
112
                if area > minArea and area < maxArea: selectedContours.append(contour)
113
            contourImage = cv2.drawContours(image, selectedContours, -1, (255,255,255), -1); # draw contour with white color
114
        except Exception as ex:
115
            from App import App
116
            
117
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
118
            App.mainWnd().addMessage.emit(MessageType.Error, message)
119
    
120
        return contourImage
121

    
122
    '''
123
        @brief  arrange line's position
124
        @author humkyung
125
        @date   2018.07.04
126
    '''
127
    @staticmethod
128
    def arrangeLinePosition(lines, symbols, listWidget):
129
        try:
130
            listWidget.addItem('Apply flow direction')
131
            pool = [line for line in lines if line.flowMark is not None]
132
            visited = []
133
            visited.extend(pool)
134
            while len(pool) > 0:
135
                line = pool.pop()
136
                print('{} - ({})'.format(line, len(pool)))
137
                rhs = [item for item in lines if item not in visited and item.isJointed(line)]
138
                if rhs:
139
                    pool.extend(rhs)
140
                    visited.extend(rhs)
141
                    for item in rhs:
142
                        item.arrangeVertexOrder(line)
143
                
144
                # skip jointed symbols
145
                symbolPool = [item for item in symbols if item not in visited and item.isJointed(line)]
146
                if symbolPool:
147
                    selected = []
148
                    visited.extend(symbolPool)
149
                    while len(symbolPool) > 0:
150
                        symbol = symbolPool.pop()
151
    
152
                        rhs = [item for item in symbols if item not in visited and item.isJointed(symbol)]
153
                        if rhs:
154
                            symbolPool.extend(rhs)
155
                            visited.extend(rhs)
156
                            selected.extend(rhs)
157
                        else:
158
                            selected.append(symbol)
159
    
160
                    # find lines which are connected last symbol
161
                    for symbol in selected:
162
                        rhs = [item for item in lines if item not in visited and item.isJointed(symbol)]
163
                        if rhs:
164
                            pool.extend(rhs)
165
                            visited.extend(rhs)
166
                            for item in rhs:
167
                                item.arrangeVertexOrder(line)
168
                # up to here
169
            # up to here
170
        except Exception as ex:
171
            from App import App
172
            
173
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
174
            App.mainWnd().addMessage.emit(MessageType.Error, message)
175

    
176
    @staticmethod
177
    def executeRecognition(createDetectedItems, path, listWidget, isLineChecked, worker, batch, createUnknownItems):
178
        """
179
        @brief      Main function
180
        @author     Jeongwoo
181
        @date
182
        @history    humkyung 2018.04.06 change error display from message box to print
183
                    Jeongwoo 2018.04.25 Remove 'Current Symbol : ' QListItem
184
                    Jeongwoo 2018.05.09 Make Comments OCR.removeTextFromNpArray block
185
                    Jeongwoo 2018.05.25 Remove imgLineList variable and parameter on writeXml()
186
                    humkyung 2018.05.26 add parameters(graphicsView, isSymbolTextChecked, isLineChecked)
187
                    Jeongwoo 2018.05.28 Add/Remove Parameters(Add : signal / Remove : graphicsView, isLineChecked)
188
                    Jeongwoo 2018.05.30 Remove return value
189
                    humkyung 2018.06.08 add signal for progressbar to parameter
190
                    humkyung 2018.06.11 get difference between original and recognized image
191
                    Jeongwoo 2018.06.21 If noteTextInfoList is None, change from None to empty list
192
                    humkyung 2018.08.20 remove alreay existing symbol and text item before recognizing
193
                                        block until drawing reconized objects
194
                    euisung  2018.11.12 add title block properties
195
        """
196
        import re
197
        from TextDetector import TextDetector
198
        from Drawing import Drawing
199
    
200
        global ocrCompletedSrc
201
        global threadLock
202
        global searchedSymbolList
203
        global textInfoList
204
        global maxProgressValue
205
        
206
        try:
207
            appDocData = AppDocData.instance()
208
            project = appDocData.getCurrentProject()
209
            textDetector = TextDetector()
210
    
211
            #remove already existing symbol and text
212
            if not batch:
213
                items = [item for item in worker.graphicsView.scene.items() if issubclass(type(item), SymbolSvgItem) or \
214
                    issubclass(type(item), QEngineeringTextItem) or \
215
                    type(item) is QEngineeringUnknownItem]
216
                for item in items:
217
                    worker.graphicsView.scene.removeItem(item)
218

    
219
            #up to here
220

    
221
            srcList = path
222
    
223
            Worker.initTargetSymbolDataList()
224
    
225
            for mainRes in srcList:
226
                ocrCompletedSrc = []
227
                searchedSymbolList = []
228
                textInfoList = []
229
    
230
                if not os.path.isfile(mainRes):
231
                    item = QListWidgetItem('{} file is not found'.format(os.path.basename(mainRes)))
232
                    item.setBackground(Qt.red)
233
                    listWidget.addItem(item)
234
                    continue
235

    
236
                appDocData.clearItemList(True)
237

    
238
                appDocData.setImgFilePath(mainRes)
239
                appDocData.imgSrc = None
240
                appDocData.activeDrawing = Drawing(appDocData.imgName)
241
                appDocData.setCurrentPidSource(Image.open(mainRes))
242
    
243
                # remove not drawing area
244
                configs = appDocData.getConfigs('{} Equipment Desc Area'.format(appDocData.imgName))
245
                for config in configs:
246
                    found = re.findall('\\d+', config.value)
247
                    if len(found) == 4:
248
                        cv2.rectangle(appDocData.imgSrc, (int(found[0]), int(found[1])), (int(found[0])+int(found[2]), int(found[1])+int(found[3])), 255, -1)
249
                        
250
                configs = appDocData.getConfigs('{} Typical Area'.format(appDocData.imgName))
251
                for config in configs:
252
                    found = re.findall('\\d+', config.value)
253
                    if len(found) == 4:
254
                        cv2.rectangle(appDocData.imgSrc, (int(found[0]), int(found[1])), (int(found[0])+int(found[2]), int(found[1])+int(found[3])), 255, -1)
255

    
256
                noteArea = appDocData.getArea('Note')
257
                if noteArea is not None:
258
                    noteArea.img = appDocData.imgSrc[round(noteArea.y):round(noteArea.y+noteArea.height), round(noteArea.x):round(noteArea.x+noteArea.width)].copy()
259
                    cv2.rectangle(appDocData.imgSrc, (round(noteArea.x), round(noteArea.y)), (round(noteArea.x + noteArea.width), round(noteArea.y + noteArea.height)), 255, -1)
260
                # up to here
261
    
262
                area = appDocData.getArea('Drawing')
263
                if area is not None:
264
                    area.img = appDocData.imgSrc[round(area.y):round(area.y+area.height), round(area.x):round(area.x+area.width)]
265

    
266
                maxProgressValue = 0
267
                listWidget.addItem("Start recognition : " + mainRes)
268
                threadLock.acquire()
269

    
270
                worker.updateBatchProgress.emit(len(srcList), 1)
271

    
272
                if worker.isSymbolChecked:
273
                    ### calculate total count of symbol
274
                    for targetItem in targetSymbolList:
275
                        if type(targetItem) is list:
276
                            maxProgressValue += len(targetItem)
277
                        else:
278
                            maxProgressValue += 1
279
                    ### up to here
280
                    maxProgressValue = maxProgressValue*2
281
                threadLock.release()
282

    
283
                if worker.isSymbolChecked:
284
                    worker.displayTitle.emit(worker.tr('Detecting symbols...')) 
285

    
286
                    # detect equipments
287
                    pool = futures.ThreadPoolExecutor(max_workers = THREAD_MAX_WORKER)
288
                    for symbol in targetSymbolList[0]:
289
                        pool.submit(Worker.detectEquipmentOnPid, mainRes, symbol, listWidget, worker)
290
                    pool.shutdown(wait = True)
291
                    # up to here
292
    
293
                    pool = futures.ThreadPoolExecutor(max_workers = THREAD_MAX_WORKER)
294
                    for symbol in targetSymbolList[2]:
295
                        if type(symbol) is list:
296
                            pool.submit(Worker.detectSymbolsOnPid, mainRes, symbol, listWidget, worker)
297
                        else:
298
                            pool.submit(Worker.detectSymbolOnPid, mainRes, symbol, listWidget, worker)
299
                    pool.shutdown(wait = True)
300
    
301
                    ## DEBUG
302
                    for item in searchedSymbolList:
303
                        _img = appDocData.imgSrc[round(item.getSp()[1]):round(item.getSp()[1]+item.getHeight()), round(item.getSp()[0]):round(item.getSp()[0]+item.getWidth())]
304
                        cv2.imwrite(os.path.join(project.getTempPath(), 'Tile', item.getName()+'.png'), _img)
305
                    ## up to here
306
                
307
                    pool = futures.ThreadPoolExecutor(max_workers = THREAD_MAX_WORKER)
308

    
309
                    for sym in searchedSymbolList:
310
                        pool.submit(Worker.removeDetectedSymbol, sym, appDocData.imgSrc)
311
                    pool.shutdown(wait = True)
312

    
313
                worker.updateBatchProgress.emit(len(srcList), 1)
314

    
315
                area = appDocData.getArea('Drawing')
316
                if area is not None:
317
                    area.img = appDocData.imgSrc[round(area.y):round(area.y+area.height), round(area.x):round(area.x+area.width)]
318
                
319
                offset = (area.x, area.y) if area is not None else (0,0)
320

    
321
                otherTextInfoList = None
322
                titleBlockTextInfoList = None
323
                if worker.isTextChecked:
324
                    textAreas = textDetector.detectTextAreas(area.img if area is not None else appDocData.imgSrc, offset)
325
                    if maxProgressValue < 2*len(textAreas):
326
                        for _ in range(len(textAreas)-int(maxProgressValue*0.5)):
327
                            worker.updateProgress.emit(2*len(textAreas), None)
328
                        maxProgressValue = 2*len(textAreas)
329
                    else:
330
                        maxProgressValue = int(maxProgressValue*0.5) + len(textAreas)
331

    
332
                    worker.displayTitle.emit(worker.tr('Detecting texts...'))
333
                    #textDetector.recognizeText(appDocData.imgSrc, (0,0), textAreas, searchedSymbolList, worker, listWidget, maxProgressValue)
334
                    textDetector.recognizeText(appDocData.imgSrc, offset, textAreas, searchedSymbolList, worker, listWidget, maxProgressValue)
335
                    textInfoList = textDetector.textInfoList.copy() if textDetector.textInfoList is not None else None
336
                    otherTextInfoList = textDetector.otherTextInfoList.copy() if textDetector.otherTextInfoList is not None else None
337
                    titleBlockTextInfoList = textDetector.titleBlockTextInfoList.copy() if textDetector.titleBlockTextInfoList is not None else None
338
    
339
                    appDocData.imgWidth, appDocData.imgHeight = appDocData.imgSrc.shape[::-1]
340
                    Worker.drawFoundSymbolsOnCanvas(mainRes, textInfoList, listWidget)
341
     
342
                    # remove text from image
343
                    textDetector.removeTextFromImage(appDocData.imgSrc, offset)
344
                    # up to here
345
                   
346
                    appDocData.imgName = os.path.splitext(os.path.basename(mainRes))[0]
347
    
348
                worker.updateBatchProgress.emit(len(srcList), 2)
349

    
350
                removedSymbolImgPath = os.path.join(project.getTempPath(), os.path.basename(mainRes))
351
                cv2.imwrite(removedSymbolImgPath, appDocData.imgSrc)
352
    
353
                area = AppDocData.instance().getArea('Drawing')
354
                if area is not None:
355
                    area.img = appDocData.imgSrc[round(area.y+1):round(area.y+area.height), round(area.x+1):round(area.x+area.width)]
356
                cv2.imwrite(os.path.join(project.getTempPath(), "RECT_" + os.path.basename(mainRes)), appDocData.imgSrc)
357

    
358
                listWidget.addItem("Recognized symbol count : " + str(len(searchedSymbolList)))
359
                    
360
                # get difference between original and recognized image
361
                foundFilePath = os.path.join(project.getTempPath(), "FOUND_" + os.path.basename(mainRes))
362
                Worker.getDifference(mainRes, foundFilePath)
363
                # up to here
364
                
365
                listWidget.addItem(worker.tr('Creating detected infos...'))
366
                worker.displayTitle.emit(worker.tr('Creating detected infos...'))
367
                #print(searchedSymbolList[0].getDetectFlip())
368
                #print(searchedSymbolList[1].getDetectFlip())
369
                createDetectedItems(searchedSymbolList, textInfoList, otherTextInfoList if otherTextInfoList is not None else [], titleBlockTextInfoList if titleBlockTextInfoList is not None else [])
370

    
371
                if isLineChecked:
372
                    Worker.recognizeLine(mainRes, listWidget, worker.graphicsView, worker, batch)
373

    
374
                createUnknownItems(mainRes)
375

    
376
                worker.updateBatchProgress.emit(len(srcList), 1)
377
        except Exception as ex:
378
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
379
            worker.displayLog.emit(MessageType.Error, message)
380
        finally:
381
            pass
382

    
383
    '''
384
        @history    2018.05.25  Jeongwoo    Moved from MainWindow
385
                    2018.05.28  Jeongwoo    Add xmlPath Parameter and append LineInfo into xml
386
                    2018.05.29  Jeongwoo    Change method to add item
387
                    2018.05.30  Jeongwoo    Remove parameter (xmlPath)
388
                    humkyung 2018.06.11 add drawing path to parameter and write recognized lines to image
389
                    humkyung 2018.07.04 call arrangeLinePosition after creating line
390
    '''
391
    @staticmethod
392
    def recognizeLine(path, listWidget, graphicsView, worker, batch):
393
        from shapely.geometry import Point, LineString
394
        from SymbolSvgItem import SymbolSvgItem
395
        from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem
396
        from EngineeringLineNoTextItem import QEngineeringLineNoTextItem
397
        from EngineeringTextItem import QEngineeringTextItem
398
        from EngineeringLineItem import QEngineeringLineItem
399
        from LineDetector import LineDetector
400
    
401
        try:
402
            listWidget.addItem('Starting line recognization')
403
            worker.displayTitle.emit(worker.tr('Detecting lines...'))
404
    
405
            appDocData = AppDocData.instance()
406
            #remove already existing line and flow arrow item
407
            if not batch:
408
                items = [item for item in worker.graphicsView.scene.items() if (type(item) is QEngineeringLineItem) or (type(item) is QEngineeringFlowArrowItem)]
409
                for item in items:
410
                    worker.graphicsView.scene.removeItem(item)
411

    
412
            #up to here
413
    
414
            # detect line
415
            connectedLines = []
416
    
417
            area = appDocData.getArea('Drawing')
418
            #print(area.img.shape)
419
            area.img = worker.removeSmallObjects(area.img)
420
            detector = LineDetector(area.img)
421
    
422
            symbols = []
423
            for item in appDocData.symbols:
424
                if issubclass(type(item), SymbolSvgItem):
425
                    symbols.append(item)
426
                    res = detector.detectConnectedLine(item, round(area.x), round(area.y))
427
                    if res is not None:
428
                        connectedLines.extend(res)
429
            #print(connectedLines)
430
            listWidget.addItem('Connecting lines')
431
            if len(connectedLines) > 1:
432
                detector.mergeLines(connectedLines, toler=5)
433
                # connect line to symbol
434
                try:
435
                    for line in connectedLines:
436
                        matches = [symbol for symbol in symbols if symbol.isConnectable(line, (round(area.x), round(area.y)), toler=20)]
437
                        for symbol in matches:
438
                            detector.connectLineToSymbol(line, (round(area.x), round(area.y)), symbol)
439
                except Exception as ex:
440
                    message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
441
                    worker.displayLog.emit(MessageType.Error, message)
442
                # up to here
443
    
444
                # connect line to line
445
                toler = 10
446
                try:
447
                    for line in connectedLines:
448
                        matches = [it for it in connectedLines if (it is not line) and (not detector.isParallel(line, it))]
449
    
450
                        # get closest line
451
                        selected = []
452
                        #print(line)
453
                        shapelyLine = LineString(line[:-1])
454
                        for match in matches:
455
                            dist = [shapelyLine.distance(Point(match[0][0], match[0][1])),shapelyLine.distance(Point(match[1][0], match[1][1]))]
456
                            if dist[0] < toler or dist[1] < toler:
457
                                selected.append(match)
458
                        # up to here
459
    
460
                        for match in selected:
461
                            detector.connectLineToLine(match, line, toler)
462
                except Exception as ex:
463
                    message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
464
                    worker.displayLog.emit(MessageType.Error, message)
465
                # up to here
466
    
467
            listWidget.addItem(worker.tr('Creating lines...'))
468

    
469
            for pts in connectedLines:
470
                #print([area.x + pts[0][0], area.y + pts[0][1],area.x + pts[1][0], area.y + pts[1][1]])
471
                processLine = QEngineeringLineItem(vertices=[(area.x + param[0], area.y + param[1]) for param in pts[:-1]], thickness=pts[2])
472
                processLine.area = 'Drawing'
473

    
474
                appDocData.lines.append(processLine)
475
                appDocData.allItems.append(processLine)
476

    
477
                if processLine.length() > 100: # TODO: check critical length
478
                    processLine.addFlowArrow()
479

    
480
            # line detection without symbol connection point info
481
            remainLine = detector.detectLineWithoutSymbol(path, round(area.x), round(area.y))
482

    
483
            i = 0
484
            for pts in remainLine:
485
                #print(i)
486
                #print(pts)
487
                i = i + 1
488
                processLine = QEngineeringLineItem(vertices=[(param[0], param[1]) for param in pts[:]])
489
                processLine.area = 'Drawing'
490

    
491
                appDocData.lines.append(processLine)
492
                appDocData.allItems.append(processLine)
493

    
494
                if processLine.length() > 100: # TODO: check critical length
495
                    processLine.addFlowArrow()
496

    
497
        except Exception as ex:
498
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
499
            worker.displayLog.emit(MessageType.Error, message)
500
        finally:
501
            listWidget.addItem('Finishing line recognization')
502
            worker.finished.emit()
503

    
504
    '''
505
        @history    2018.04.24  Jeongwoo    Add isExceptDetect Field
506
                    2018.05.09  Jeongwoo    Add targetSymbolList clear
507
                    humkyung 2018.07.07 store symbols to list as like [equipments],[nozzles],[symbols]
508
    '''
509
    @staticmethod
510
    def initTargetSymbolDataList():
511
        global targetSymbolList
512
    
513
        targetSymbolList.clear()
514
        appDocData = AppDocData.instance()
515
        symbolList = appDocData.getTargetSymbolList()
516
        equipments = [item for item in symbolList if appDocData.getSymbolCategoryByType(item.getType()) == 'Equipment']
517
        nozzles = [item for item in symbolList if item.getType() == 'Nozzles']
518
        # [[equipments],[nozzles],[symbols]]
519
        targetSymbolList.append(equipments)
520
        targetSymbolList.append(nozzles)
521
        targetSymbolList.append([item for item in symbolList if item not in equipments and item not in nozzles])
522
    
523
        return targetSymbolList
524

    
525
    '''
526
        @brief  detect equipment
527
        @author humkyung
528
        @date   2018.07.07
529
    '''
530
    @staticmethod
531
    def detectEquipmentOnPid(mainRes, targetSymbol, listWidget, worker):
532
        try:
533
            equipments = Worker.detectSymbolOnPid(mainRes, targetSymbol, listWidget, worker)
534
            for equipment in equipments:
535
                # detect nozzles around equimpent
536
                for nozzle in targetSymbolList[1]:
537
                    Worker.detectNozzleOnPid(equipment, nozzle, listWidget, worker)
538
                # up to here
539
        except Exception as ex:
540
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
541
            worker.displayLog(MessageType.Error, message)
542

    
543
    '''
544
        @brief      detect symbol on PID
545
        @author     jwkim
546
        @date   
547
        @history    humkyung 2018.04.06 check if symbol file exists
548
                    Jeongwoo 2018.05.29 Change method to adjust detail symbol location with hit-rate. Not feature point count
549
                                        Change parameter on add symbol part (mpCount → hitRate)
550
                                        Remove unusing calculation (avg)
551
                    Jeongwoo 2018.06.27 Remove part to split P&ID image and for loop
552
                    humkyung 2018.07.07 return searched symbols
553
    '''
554
    @staticmethod
555
    def detectSymbolOnPid(mainRes, targetSymbol, listWidget, worker):
556
        import copy
557
        global ocrCompletedSrc
558
        global threadLock
559
        global maxProgressValue
560
        
561
        try:
562
            symbolName = targetSymbol.getName()
563
            symbolType = targetSymbol.getType()
564
            symbolPath = targetSymbol.getPath()
565
            symbolThreshold = targetSymbol.getThreshold()
566
            symbolMinMatchCount = targetSymbol.getMinMatchCount()
567
            isDetectOnOrigin = targetSymbol.getIsDetectOnOrigin()
568
            symbolRotateCount = targetSymbol.getRotationCount()
569
            symbolOcrOption = targetSymbol.getOcrOption()
570
            isContainChild = targetSymbol.getIsContainChild()
571
            symbolOriginalPoint = targetSymbol.getOriginalPoint()
572
            symbolConnectionPoint = targetSymbol.getConnectionPoint()
573
            baseSymbol = targetSymbol.getBaseSymbol()
574
            additionalSymbol = targetSymbol.getAdditionalSymbol()
575
            isExceptDetect = targetSymbol.getIsExceptDetect()
576
            detectFlip = targetSymbol.getDetectFlip()
577
    
578
            # check if symbol file is target or not
579
            if isExceptDetect == 1:
580
                item = QListWidgetItem('{} file is not target'.format(os.path.split(os.path.basename(symbolPath))[0]))
581
                item.setBackground(QColor('green'))
582
                listWidget.addItem(item)
583
                return
584
    
585
            foundSymbolCount = 0
586
    
587
            # check if symbol file exists
588
            if not os.path.isfile(symbolPath):
589
                item = QListWidgetItem('{} file not found'.format(os.path.split(os.path.basename(symbolPath))[0]))
590
                item.setBackground(QColor('red'))
591
                listWidget.addItem(item)
592
                return
593
            # up to here
594
    
595
            sym = cv2.imread(symbolPath, 1)
596
            symGray = Worker.cvtGrayImage(sym)
597
            symGrayOri = copy.copy(symGray)
598
            ## TODO: 이진화 시켰을때 심볼이 검출되지 않음
599
            ## symGray = cv2.threshold(cvtGrayImage(sym), 127, 255, cv2.THRESH_BINARY)[1]
600
            ## cv2.imshow('symbol', symGray)
601
            ## cv2.waitKey(0)
602
            sow, soh = symGray.shape[::-1] # symbol original w, h
603
    
604
            offsetDrawingArea=[]
605
            appDocData = AppDocData.instance()
606
            area = appDocData.getArea('Drawing')
607
            if area is not None:
608
                copiedBasePid = area.img.copy()
609
                offsetDrawingArea.append(area.x)
610
                offsetDrawingArea.append(area.y)
611
            else:
612
                offsetDrawingArea.append(0)
613
                offsetDrawingArea.append(0)
614
                if isDetectOnOrigin == 1:
615
                    copiedBasePid = appDocData.imgSrc.copy()
616
                else:
617
                    copiedBasePid = ocrCompletedSrc.copy()
618
            srcWidth, srcHeight = copiedBasePid.shape[::-1]
619
    
620
            roiItemSp = (0,0)
621
            roiItemEp = (srcWidth, srcHeight)
622
            roiItem = copiedBasePid
623
    
624
            for index in range(2):
625
                if index is 0:
626
                    #continue
627
                    pass
628
                elif detectFlip is not 1 and index is 1:
629
                    continue
630
                else:
631
                    pass
632
                    symGray = symGrayOri
633
                    symGray = cv2.flip(symGray, 1)
634
                    #cv2.imwrite('out.png', symGray)
635
                    opx = sow - float(symbolOriginalPoint.split(',')[0])
636
                    opy = float(symbolOriginalPoint.split(',')[1])
637
                    symbolOriginalPoint = str(opx) + ',' + str(opy)
638

    
639
                    symbolConnectionPoint = symbolConnectionPoint.split("/")
640
                    symbolConnectionPointStr = ''
641
                    for strConnPt in symbolConnectionPoint:
642
                        if strConnPt == '': continue
643
                        tokens = strConnPt.split(',')
644

    
645
                        direction = 'AUTO'
646
                        symbol_idx = '0'
647
                        if len(tokens) == 2:
648
                            cpx = sow - float(tokens[0])
649
                            cpy = float(tokens[1])
650
                            cflip = direction + ',' + str(cpx) + ',' + str(cpy)
651
                        elif len(tokens) == 3:
652
                            direction = tokens[0]
653
                            cpx = sow - float(tokens[1])
654
                            cpy = float(tokens[2])
655
                            cflip = direction + ',' + str(cpx) + ',' + str(cpy)
656
                        elif len(tokens) == 4:
657
                            direction = tokens[0]
658
                            cpx = sow - float(tokens[1])
659
                            cpy = float(tokens[2])
660
                            symbol_idx = tokens[3]
661
                            cflip = direction + ',' + str(cpx) + ',' + str(cpy) + ',' + str(symbol_idx)
662

    
663
                        if symbolConnectionPointStr == '':
664
                            symbolConnectionPointStr = cflip
665
                        else:
666
                            symbolConnectionPointStr = symbolConnectionPointStr + '/' + cflip
667
                    symbolConnectionPoint = symbolConnectionPointStr
668
                
669
                #print(symbolOriginalPoint)
670
                #print(symbolConnectionPoint)
671
                symbolRotatedAngle = 0
672
                for rc in range(symbolRotateCount + 1): ## Rotation Count를 사용자 기준으로 받아서 1을 더한 후 사용
673
                    sw, sh = symGray.shape[::-1]
674
                    roiw = (roiItemEp[0] - roiItemSp[0])
675
                    roih = (roiItemEp[1] - roiItemSp[1])
676
    
677
                    ## Case : Bigger Symbol than Split ROI
678
                    if roiw < sw or roih < sh:
679
                        symGray = cv2.rotate(symGray, cv2.ROTATE_90_COUNTERCLOCKWISE)
680
                        symbolRotatedAngle = symbolRotatedAngle + 90
681
    
682
                        if baseSymbol is not None and additionalSymbol is not None:
683
                            additionalSymbol = Worker.getRotatedChildInfo(additionalSymbol)
684
                        continue
685
                        
686
                    ## get Rotated Original Point
687
                    originalPoint = Worker.getCalculatedOriginalPoint(additionalSymbol, symbolOriginalPoint, symbolRotatedAngle, sw, sh, sow, soh)
688
                    connectionPoint = Worker.getCalculatedConnectionPoint(symbolConnectionPoint, symbolRotatedAngle, sw, sh, sow, soh)
689
    
690
                    ## Template Matching
691
                    tmRes = cv2.matchTemplate(roiItem, symGray, cv2.TM_CCOEFF_NORMED)
692
                    loc = np.where(tmRes >= symbolThreshold)
693
    
694
                    for pt in zip(*loc[::-1]):
695
                        mpCount = 0 # Match Point Count
696
    
697
                        roi = roiItem[pt[1]:pt[1]+sh, pt[0]:pt[0]+sw]
698
    
699
                        if symbolMinMatchCount > 0:
700
                            mpCount = Worker.getMatchPointCount(roi, symGray)
701
                            if not (mpCount >= symbolMinMatchCount):
702
                                continue
703
    
704
                        searchedItemSp = (roiItemSp[0]+pt[0] + round(offsetDrawingArea[0]), roiItemSp[1]+pt[1] + round(offsetDrawingArea[1]))
705
                        #print(searchedItemSp)
706
                    
707
                        overlapArea = 0
708
                        symbolIndex = -1
709
                        for i in range(len(searchedSymbolList)):
710
                            area = Worker.contains(searchedSymbolList[i], searchedItemSp, sw, sh)
711
                            if area > ACCEPT_OVERLAY_AREA:
712
                                if area > overlapArea:
713
                                    overlapArea = area
714
                                    symbolIndex = i
715
                                """
716
                                categories = [appDocData.isEquipmentType(symbolType), appDocData.isEquipmentType(searchedSymbolList[i].getType())]
717
                                if categories[0] == categories[1]:
718
                                    symbolIndex = i
719
                                    break
720
                                """
721
                            
722
                        hitRate = tmRes[pt[1], pt[0]]
723
    
724
                        ## 겹치는 영역이 기준값보다 작을 경우
725
                        if overlapArea <= ACCEPT_OVERLAY_AREA:
726
                            threadLock.acquire()
727
                            foundSymbolCount = foundSymbolCount + 1
728
                            Worker.addSearchedSymbol(symbolName, symbolType , 
729
                                searchedItemSp, sw, sh, symbolThreshold, symbolMinMatchCount, hitRate, symbolRotatedAngle , 
730
                                isDetectOnOrigin, symbolRotateCount, symbolOcrOption, isContainChild , 
731
                                originalPoint, connectionPoint, baseSymbol, additionalSymbol,isExceptDetect, detectFlip=1 if index is 1 else 0)
732
                            threadLock.release()
733
                        else: ## 겹치는 영역이 기준값보다 클 경우
734
                            if symbolIndex != -1 and symbolIndex < len(searchedSymbolList):
735
                                searchedSymbol = searchedSymbolList[symbolIndex]
736
                                ## 현재 심볼과 검출된 심볼이 같을 경우 Match Point가 더 높은 정보로 교체
737
                                if symbolName == searchedSymbol.getName():
738
                                    symbolHitRate = searchedSymbol.getHitRate()
739
                                    if symbolHitRate < hitRate:
740
                                        threadLock.acquire()
741
                                        searchedSymbolList[symbolIndex] = symbol.Symbol(symbolName, symbolType , 
742
                                                                            searchedItemSp, sw, sh, symbolThreshold, symbolMinMatchCount, hitRate, symbolRotatedAngle , 
743
                                                                            isDetectOnOrigin, symbolRotateCount, symbolOcrOption, isContainChild , 
744
                                                                            ','.join(str(x) for x in originalPoint), 
745
                                                                            '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in connectionPoint), 
746
                                                                            baseSymbol, additionalSymbol,isExceptDetect, detectFlip=1 if index is 1 else 0)
747
                                        threadLock.release()
748
                                ## 현재 심볼과 검출된 심볼이 같지 않을 경우 (포함)
749
                                elif appDocData.isEquipmentType(searchedSymbol.getType()):
750
                                    if searchedSymbol.area > sw*sh*10:  # searched equipment area is greather than 10 times of symbol's area
751
                                        threadLock.acquire()
752
                                        foundSymbolCount = foundSymbolCount + 1
753
                                        Worker.addSearchedSymbol(symbolName, symbolType , 
754
                                            searchedItemSp, sw, sh, symbolThreshold, hitRate, hitRate, symbolRotatedAngle , 
755
                                            isDetectOnOrigin, symbolRotateCount, symbolOcrOption, isContainChild , 
756
                                            originalPoint, connectionPoint, baseSymbol, additionalSymbol, isExceptDetect, detectFlip=1 if index is 1 else 0)
757
                                        threadLock.release()
758
                                else:
759
                                    searchedSymbol = searchedSymbolList[symbolIndex]
760
                                    symbolHitRate = searchedSymbol.getHitRate()
761
                                    if symbolHitRate - searchedSymbol.getThreshold() < hitRate - symbolThreshold:
762
                                        threadLock.acquire()
763
                                        searchedSymbolList[symbolIndex] = symbol.Symbol(symbolName, symbolType , 
764
                                                                            searchedItemSp, sw, sh, symbolThreshold, symbolMinMatchCount, hitRate, symbolRotatedAngle , 
765
                                                                            isDetectOnOrigin, symbolRotateCount, symbolOcrOption, isContainChild , 
766
                                                                            ','.join(str(x) for x in originalPoint), 
767
                                                                            '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in connectionPoint), 
768
                                                                            baseSymbol, additionalSymbol,isExceptDetect, detectFlip=1 if index is 1 else 0)
769
                                        threadLock.release()
770

    
771
                    ## Rotate Symbol
772
                    symGray = cv2.rotate(symGray, cv2.ROTATE_90_COUNTERCLOCKWISE)
773
                    symbolRotatedAngle = symbolRotatedAngle + 90
774
    
775
                    if additionalSymbol is not None:
776
                        additionalSymbol = Worker.getRotatedChildInfo(additionalSymbol)
777
    
778
            threadLock.acquire()
779
            listWidget.addItem('Found Symbol   : ' + os.path.splitext(os.path.basename(symbolPath))[0] + ' - (' + str(foundSymbolCount) + ')')
780
            threadLock.release()
781
    
782
            worker.updateProgress.emit(maxProgressValue, symbolPath)
783
    
784
            return [symbol for symbol in searchedSymbolList if symbol.getName() == symbolName]
785
        except Exception as ex:
786
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
787
            worker.displayLog.emit(MessageType.Error, message)
788
        
789
        return []
790

    
791
    '''
792
        @brief      detect nozzle
793
        @author     humkyung
794
        @date       2018.07.07
795
        @history    humkyhung 2018.07.17 pass equpment as parameter instead of image
796
    '''
797
    @staticmethod
798
    def detectNozzleOnPid(equipment, nozzle, listWidget, worker):
799
        global src
800
        global threadLock
801
        global maxProgressValue
802
        
803
        try:
804
            symbolName = nozzle.getName()
805
            symbolType = nozzle.getType()
806
            symbolPath = nozzle.getPath()
807
            symbolThreshold = nozzle.getThreshold()
808
            symbolMinMatchCount = nozzle.getMinMatchCount()
809
            isDetectOnOrigin = nozzle.getIsDetectOnOrigin()
810
            symbolRotateCount = nozzle.getRotationCount()
811
            symbolOcrOption = nozzle.getOcrOption()
812
            isContainChild = nozzle.getIsContainChild()
813
            symbolOriginalPoint = nozzle.getOriginalPoint()
814
            symbolConnectionPoint = nozzle.getConnectionPoint()
815
            baseSymbol = nozzle.getBaseSymbol()
816
            additionalSymbol = nozzle.getAdditionalSymbol()
817
            isExceptDetect = nozzle.getIsExceptDetect()
818
    
819
            foundSymbolCount = 0
820
    
821
            # check if symbol file exists
822
            if not os.path.isfile(symbolPath):
823
                item = QListWidgetItem('{} file not found'.format(os.path.split(os.path.basename(symbolPath))[0]))
824
                item.setBackground(QColor('red'))
825
                listWidget.addItem(item)
826
                return
827
            # up to here
828
    
829
            symGray = Worker.cvtGrayImage(cv2.imread(symbolPath, 1))
830
            sow, soh = symGray.shape[::-1] # symbol original w, h
831
    
832
            # get image of equipment with offset of nozzle size
833
            appDocData = AppDocData.instance()
834
            pt = equipment.getSp()
835
            nozzleSize = max(sow, soh)
836
            sx = round(pt[0]) - nozzleSize
837
            sy = round(pt[1]) - nozzleSize
838
            ex = round(pt[0] + equipment.getWidth()) + nozzleSize
839
            ey = round(pt[1] + equipment.getHeight()) + nozzleSize
840
            offset = (sx, sy)
841
            eqpSize = (pt[0], pt[1], equipment.getWidth(), equipment.getHeight())
842
            img = appDocData.imgSrc[sy:ey, sx:ex]
843
            srcWidth, srcHeight = img.shape[::-1]
844
            # up to here
845
    
846
            roiItemSp = (0,0)
847
            roiItemEp = (srcWidth, srcHeight)
848
            roiItem = img 
849
    
850
            symbolAngle = 0
851
            for rc in range(symbolRotateCount + 1): ## Rotation Count를 사용자 기준으로 받아서 1을 더한 후 사용
852
                sw, sh = symGray.shape[::-1]
853
                roiw = (roiItemEp[0] - roiItemSp[0])
854
                roih = (roiItemEp[1] - roiItemSp[1])
855
    
856
                ## get Rotated Original Point
857
                originalPoint = Worker.getCalculatedOriginalPoint(additionalSymbol, symbolOriginalPoint, symbolAngle, sw, sh, sow, soh)
858
                connectionPoint = Worker.getCalculatedConnectionPoint(symbolConnectionPoint, symbolAngle, sw, sh, sow, soh)
859
                dx = connectionPoint[0][0] - originalPoint[0]
860
                dy = connectionPoint[0][1] - originalPoint[1]
861
    
862
                ## Template Matching
863
                tmRes = cv2.matchTemplate(roiItem, symGray, cv2.TM_CCOEFF_NORMED)
864
                loc = np.where(tmRes >= symbolThreshold)
865
    
866
                for pt in zip(*loc[::-1]):
867
                    mpCount = 0 # Match Point Count
868
                    symbolIndex = -1
869
    
870
                    roi = roiItem[pt[1]:pt[1]+sh, pt[0]:pt[0]+sw]
871
    
872
                    if symbolMinMatchCount > 0:
873
                        mpCount = Worker.getMatchPointCount(roi, symGray)
874
                        if not (mpCount >= symbolMinMatchCount):
875
                            continue
876
                    
877
                    mid = (offset[0] + pt[0] + (originalPoint[0] + connectionPoint[0][0])*0.5, offset[1] + pt[1] + (originalPoint[1] + connectionPoint[0][1])*0.5) 
878
                    searchedItemSp = (roiItemSp[0]+pt[0]+offset[0], roiItemSp[1]+pt[1]+offset[1])
879
                    # check searched nozzle location
880
                    if abs(dx) > abs(dy):
881
                        if dx > 0:
882
                            if mid[0] < eqpSize[0] + eqpSize[2]*0.5: continue
883
                        else:
884
                            if mid[0] > eqpSize[0] + eqpSize[2]*0.5: continue
885
                    else:
886
                        if dy > 0:
887
                            if mid[1] < eqpSize[1] + eqpSize[3]*0.5: continue
888
                        else:
889
                            if mid[1] > eqpSize[1] + eqpSize[3]*0.5: continue
890
                    # up to here
891
    
892
                    overlapArea = 0
893
                    nozzles = [symbol for symbol in searchedSymbolList if symbol.getType() == 'Nozzles']
894
                    for i in range(len(nozzles)):
895
                        _pt = nozzles[i].getSp()
896
                        rect = QRectF(_pt[0], _pt[1], nozzles[i].getWidth(), nozzles[i].getHeight())
897
                        _rect = QRectF(searchedItemSp[0], searchedItemSp[1], sw, sh)
898
                        if rect.intersects(_rect):
899
                            intersect = rect.intersected(_rect)
900
                            overlapArea = intersect.width()*intersect.height()
901
                            if overlapArea > ACCEPT_OVERLAY_AREA:
902
                                symbolIndex = i
903
                                break
904
                            
905
                    hitRate = tmRes[pt[1], pt[0]]
906
    
907
                    ## 겹치는 영역이 기준값보다 작을 경우
908
                    if overlapArea <= ACCEPT_OVERLAY_AREA:
909
                        threadLock.acquire()
910
                        foundSymbolCount = foundSymbolCount + 1
911
                        searched = Worker.addSearchedSymbol(symbolName, symbolType
912
                            , searchedItemSp, sw, sh, symbolThreshold, symbolMinMatchCount, hitRate, symbolAngle
913
                            , isDetectOnOrigin, symbolRotateCount, symbolOcrOption, isContainChild
914
                            , originalPoint, connectionPoint, baseSymbol, additionalSymbol,isExceptDetect)
915
                        searched.owner = equipment
916
                        threadLock.release()
917
                    ## 겹치는 영역이 기준값보다 클 경우
918
                    else:
919
                        if symbolIndex != -1 and symbolIndex < len(nozzles):
920
                            searchedSymbol = nozzles[symbolIndex]
921
                            ## 현재 심볼과 검출된 심볼이 같을 경우 Match Point가 더 높은 정보로 교체
922
                            if symbolName == searchedSymbol.getName():
923
                                symbolHitRate = searchedSymbol.getHitRate()
924
                                if symbolHitRate < hitRate:
925
                                    threadLock.acquire()
926
                                    nozzles[symbolIndex] = symbol.Symbol(symbolName, symbolType , 
927
                                                                searchedItemSp, sw, sh, symbolThreshold, symbolMinMatchCount, hitRate, symbolAngle , 
928
                                                                isDetectOnOrigin, symbolRotateCount, symbolOcrOption, isContainChild , 
929
                                                                ','.join(str(x) for x in originalPoint), 
930
                                                                '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in connectionPoint), 
931
                                                                baseSymbol, additionalSymbol,isExceptDetect)
932
                                    threadLock.release()
933
                            ## 현재 심볼과 검출된 심볼이 같지 않을 경우 (포함)
934
                            elif appDocData.isEquipmentType(searchedSymbol.getType()):
935
                                threadLock.acquire()
936
                                foundSymbolCount = foundSymbolCount + 1
937
                                searched = Worker.addSearchedSymbol(symbolName, symbolType
938
                                    , searchedItemSp, sw, sh, symbolThreshold, hitRate, hitRate, symbolAngle
939
                                    , isDetectOnOrigin, symbolRotateCount, symbolOcrOption, isContainChild
940
                                    , originalPoint, connectionPoint, baseSymbol, additionalSymbol,isExceptDetect)
941
                                searched.owner = equipment
942
                                threadLock.release()
943
                                        
944
                ## Rotate Symbol
945
                symGray = cv2.rotate(symGray, cv2.ROTATE_90_COUNTERCLOCKWISE)
946
                symbolAngle = symbolAngle + 90
947
    
948
                if additionalSymbol is not None:
949
                    additionalSymbol = Worker.getRotatedChildInfo(additionalSymbol)
950
    
951
            threadLock.acquire()
952
            listWidget.addItem('Found Symbol   : ' + os.path.splitext(os.path.basename(symbolPath))[0] + ' - (' + str(foundSymbolCount) + ')')
953
            threadLock.release()
954
    
955
            worker.updateProgress.emit(maxProgressValue, symbolPath)
956
    
957
            return [symbol for symbol in searchedSymbolList if symbol.getName() == symbolName]
958
        except Exception as ex:
959
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
960
            worker.displayLog(MessageType.Error, message)
961
    
962
        return []
963

    
964
    #Convert into Grayscale image
965
    @staticmethod
966
    def cvtGrayImage(img):
967
        return cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
968

    
969
    '''
970
        @history    2018.06.12  Jeongwoo    Type changed (int → float)
971
                    humkyung 2018.07.07 change return type as like [x,y]
972
    '''
973
    @staticmethod
974
    def getCalculatedOriginalPoint(additionalSymbol, symbolOriginalPoint, symbolRotatedAngle, rotateSymbolWidth, rotateSymbolHeight, originalSymbolWidth, originalSymbolHeight):
975
        res = []
976
    
977
        if additionalSymbol is None and symbolOriginalPoint is None:
978
            res.append(rotateSymbolWidth//2)
979
            res.append(rotateSymbolHeight//2)
980
        else:
981
            opx = float(symbolOriginalPoint.split(',')[0])
982
            opy = float(symbolOriginalPoint.split(',')[1])
983
            rPt = Worker.getCoordOnRotatedImage(symbolRotatedAngle, ('AUTO', opx, opy, '0'), originalSymbolWidth, originalSymbolHeight)
984

    
985
            res.append(rPt[1])
986
            res.append(rPt[2])
987
    
988
        return res 
989

    
990
    '''
991
        @history    2018.06.12  Jeongwoo    Type changed (int → float)
992
                    humkyung 2018.07.07 change return type as like [[x,y],...]
993
                    humkyung 2019.01.04 get symbol index
994
    '''
995
    @staticmethod
996
    def getCalculatedConnectionPoint(symbolConnectionPointStr, symbolRotatedAngle, rotateSymbolWidth, rotateSymbolHeight, originalSymbolWidth, originalSymbolHeight):
997
        res = []
998

    
999
        if symbolConnectionPointStr is not None and symbolConnectionPointStr != '':
1000
            splitConnectionPointStr = symbolConnectionPointStr.split("/")
1001
            for strConnPt in splitConnectionPointStr:
1002
                tokens = strConnPt.split(',')
1003

    
1004
                direction = 'AUTO'
1005
                symbol_idx = '0'
1006
                if len(tokens) == 2:
1007
                    cpx = float(tokens[0])
1008
                    cpy = float(tokens[1])
1009
                elif len(tokens) == 3:
1010
                    direction = tokens[0]
1011
                    cpx = float(tokens[1])
1012
                    cpy = float(tokens[2])
1013
                elif len(tokens) == 4:
1014
                    direction = tokens[0]
1015
                    cpx = float(tokens[1])
1016
                    cpy = float(tokens[2])
1017
                    symbol_idx = tokens[3]
1018

    
1019
                res.append(Worker.getCoordOnRotatedImage(symbolRotatedAngle, (direction, cpx, cpy, symbol_idx), originalSymbolWidth, originalSymbolHeight))
1020
    
1021
        return res
1022

    
1023
    '''
1024
        @brief      rotate (x,y) by given angle
1025
        @author     Jeongwoo
1026
        @date       2018.??.??
1027
        @history    humkyung 2018.04.13 fixed code when angle is 90 or 270    
1028
                    Jeongwoo 2018.04.27 Change calculation method with QTransform
1029
                    humkyung 2018.09.01 calculate rotated direction
1030
    '''
1031
    @staticmethod
1032
    def getCoordOnRotatedImage(rAngle, connPt, originImageWidth, originImageHeight):
1033
        rx = None
1034
        ry = None
1035
        
1036
        ## calculate rotated direction
1037
        direction = connPt[0]
1038
        if direction == 'LEFT':
1039
            direction = 'DOWN' if rAngle == 90 else 'RIGHT' if rAngle == 180 else 'UP' if rAngle == 270 else direction
1040
        elif direction == 'RIGHT':
1041
            direction = 'UP' if rAngle == 90 else 'LEFT' if rAngle == 180 else 'DOWN' if rAngle == 270 else direction
1042
        elif direction == 'UP':
1043
            direction = 'LEFT' if rAngle == 90 else 'DOWN' if rAngle == 180 else 'RIGHT' if rAngle == 270 else direction
1044
        elif direction == 'DOWN':
1045
            direction = 'RIGHT' if rAngle == 90 else 'UP' if rAngle == 180 else 'LEFT' if rAngle == 270 else direction
1046
        ## up to here
1047
        
1048
        transform = QTransform()
1049
        if rAngle == 90 or rAngle == 270:
1050
            transform.translate(originImageHeight*0.5, originImageWidth*0.5)
1051
        elif rAngle == 0 or rAngle == 180:
1052
            transform.translate(originImageWidth*0.5, originImageHeight*0.5)
1053
        transform.rotate(-abs(rAngle))
1054
        transform.translate(-originImageWidth*0.5, -originImageHeight*0.5)
1055
        point = QPoint(connPt[1], connPt[2])
1056
        point = transform.map(point)
1057
        rx = point.x()
1058
        ry = point.y()
1059

    
1060
        symbol_idx = connPt[3]
1061

    
1062
        return (direction, rx, ry, symbol_idx)
1063

    
1064
    '''
1065
        @brief      Add symbols
1066
        @author     jwkim
1067
        @date
1068
        @history    Change parameter (mpCount → hitRate)
1069
                    Yecheol 2018.07.04 Delete Symbol Id 
1070
    '''
1071
    @staticmethod
1072
    def addSearchedSymbol(sName, sType
1073
                          , sp, w, h, threshold, minMatchCount, hitRate, rotatedAngle
1074
                          , isDetectOnOrigin, rotateCount, ocrOption, isContainChild
1075
                          , originalPoint, connectionPoint, baseSymbol, additionalSymbol, isExceptDetect, detectFlip):
1076
        global searchedSymbolList
1077

    
1078
        newSym = None
1079
        try:
1080
            newSym = symbol.Symbol(sName, sType
1081
                                , sp, w, h, threshold, minMatchCount, hitRate, rotatedAngle , 
1082
                                isDetectOnOrigin, rotateCount, ocrOption, isContainChild , 
1083
                                ','.join(str(x) for x in originalPoint), 
1084
                                '/'.join('{},{},{},{}'.format(param[0], param[1], param[2], param[3]) for param in connectionPoint), 
1085
                                baseSymbol, additionalSymbol, isExceptDetect, detectFlip=detectFlip)
1086
        
1087
            searchedSymbolList.append(newSym)
1088
        except Exception as ex:
1089
            from App import App
1090

    
1091
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1092
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1093

    
1094
    
1095
        return newSym
1096

    
1097
    '''
1098
        @brief      Check object contains pt
1099
        @param      obj is item in searchedSymbolList
1100
    '''
1101
    @staticmethod
1102
    def contains(obj, pt, tw, th):
1103
        sp = obj.getSp()
1104
        width = obj.getWidth()
1105
        height = obj.getHeight()
1106
    
1107
        if sp[0] > pt[0]+tw:
1108
            return 0
1109
        if sp[0]+width < pt[0]: 
1110
            return 0
1111
        if sp[1] > pt[1]+th: 
1112
            return 0
1113
        if sp[1]+height < pt[1]: 
1114
            return 0
1115
        
1116
        #shared area
1117
        x = max(sp[0], pt[0])
1118
        y = max(sp[1], pt[1])
1119
        w = min(sp[0] + width, pt[0] + tw) - x
1120
        h = min(sp[1] + height, pt[1] + th) - y
1121
    
1122
        return float((w * h)) / float((tw * th)) * 100
1123
    
1124
    #Calculate count of keypoint match result
1125
    @staticmethod
1126
    def getMatchPointCount(src, cmp):
1127
        matchCount = 0
1128

    
1129
        try:
1130
            orb = cv2.ORB_create(1000, 2.0, 2, 1)
1131
        
1132
            kp1, des1 = orb.detectAndCompute(src, None)
1133
            kp2, des2 = orb.detectAndCompute(cmp, None)
1134
            
1135
            FLANN_INDEX_LSH = 6
1136
            # table_number      : The number of hash tables use
1137
            # key_size          : The length of the key in the hash tables
1138
            # multi_probe_level : Number of levels to use in multi-probe (0 for standard LSH)
1139
            #                     It controls how neighboring buckets are searched
1140
            #                     Recommended value is 2
1141
            # checks            : specifies the maximum leafs to visit when searching for neighbours.
1142
            # LSH : Locality-Sensitive Hashing
1143
            # ref : https://www.cs.ubc.ca/research/flann/uploads/FLANN/flann_manual-1.8.4.pdf
1144
            index_params = dict(algorithm = FLANN_INDEX_LSH, table_number = 20, key_size = 10, multi_probe_level = 4)
1145
            search_params = dict(checks = 100)
1146
            
1147
            flann = cv2.FlannBasedMatcher(index_params,search_params)
1148
            
1149
            matches = flann.knnMatch(des1, des2, k = 2)
1150
            matchesMask = [[0, 0] for i in range(len(matches))] #Python 3.x
1151
            
1152
            count = 0
1153
            # ratio test as per Lowe's paper
1154
            for i in range(len(matches)):
1155
                if len(matches[i]) == 2:
1156
                    m = matches[i][0]
1157
                    n = matches[i][1]
1158
                    if m.distance < 0.85 * n.distance:
1159
                        count = count + 1
1160
        
1161
            matchCount = count
1162
        except Exception as ex:
1163
            from App import App
1164

    
1165
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1166
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1167

    
1168
        return matchCount
1169

    
1170
    '''
1171
        @brief      Remake rotated child symbol info
1172
    '''
1173
    @staticmethod
1174
    def getRotatedChildInfo(additionalSymbol):
1175
        tempChildInfo = ""
1176
        if additionalSymbol:
1177
            childList = additionalSymbol.split("/")
1178
            for index in range(len(childList)):
1179
                child = childList[index]
1180
                direction = Worker.convertDirectionCodeToValue(child.split(",")[0])
1181
                childName = child.split(",")[1]
1182
                direction = (direction - 1) if direction > 0 else 3
1183
                if index != 0:
1184
                    tempChildInfo = tempChildInfo + "/"
1185
                tempChildInfo = tempChildInfo + Worker.convertValueToDirectionCode(direction) + "," + childName
1186
        return tempChildInfo
1187

    
1188
    '''
1189
        @brief   detect symbols on PID
1190
        @history humkyung 2018.06.08 add parameteres for signal
1191
    '''
1192
    @staticmethod
1193
    def detectSymbolsOnPid(mainRes, targetSymbols, listWidget, updateProgressSignal):
1194
        for detailTarget in targetSymbols:
1195
            Worker.detectSymbolOnPid(mainRes, detailTarget, listWidget, updateProgressSignal)
1196

    
1197
    @staticmethod
1198
    def convertDirectionCodeToValue(directionCode):
1199
        if directionCode == "UP":
1200
            return 0
1201
        elif directionCode == "RIGHT":
1202
            return 1
1203
        elif directionCode == "DOWN":
1204
            return 2
1205
        elif directionCode == "LEFT":
1206
            return 3
1207
        else:
1208
            return -1
1209

    
1210
    @staticmethod
1211
    def convertValueToDirectionCode(value):
1212
        if value == 0:
1213
            return "UP"
1214
        elif value == 1:
1215
            return "RIGHT"
1216
        elif value == 2:
1217
            return "DOWN"
1218
        elif value == 3:
1219
            return "LEFT"
1220
        else:
1221
            return "NONE"
1222

    
1223
    '''
1224
        @brief  draw found symbols and texts
1225
        @author Jeongwoo
1226
    '''
1227
    @staticmethod
1228
    def drawFoundSymbolsOnCanvas(drawingPath , textInfos , listWidget):
1229
        global src
1230
        global ocrCompletedSrc
1231
        global canvas
1232
    
1233
        appDocData = AppDocData.instance()
1234
        canvas = np.zeros(appDocData.imgSrc.shape, np.uint8)
1235
        canvas[::] = 255
1236
    
1237
        try:
1238
            appDocData = AppDocData.instance()
1239
            project = appDocData.getCurrentProject()
1240
    
1241
            for symbol in searchedSymbolList:
1242
                Worker.drawFoundSymbols(symbol, listWidget)
1243
    
1244
            for text in textInfos:
1245
                left = text.getX()
1246
                top = text.getY()
1247
                right = text.getX() + text.getW()
1248
                bottom = text.getY() + text.getH()
1249
    
1250
                canvas[top:bottom, left:right] = appDocData.imgSrc[top:bottom, left:right]
1251
    
1252
            cv2.imwrite(os.path.join(project.getTempPath(), "FOUND_" + os.path.basename(drawingPath)), canvas)
1253
        except Exception as ex:
1254
            from App import App
1255

    
1256
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1257
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1258

    
1259
    '''
1260
        @history    2018.04.27  Jeongwoo    Remove Tesseract Log on listWidget
1261
                    2018.05.04  Jeongwoo    Change method to OCR with tesseract_ocr_module.py
1262
                    2018.05.09  Jeongwoo    Add global variable textInfoList, Remove text in symbol and Add tesseract result text
1263
                    2018.05.10  Jeongwoo    Remove not used if-statement
1264
                    2018.06.19  Jeongwoo    When detect text in symbol, use getTextAreaInfo() and Tesseract
1265
                    2018.06.21  Jeongwoo    Add if-statement for way to detect text by Type A
1266
    '''
1267
    @staticmethod
1268
    def drawFoundSymbols(symbol, listWidget):
1269
        global src
1270
        global canvas
1271
        global WHITE_LIST_CHARS
1272
        global searchedSymbolList
1273
        global textInfoList
1274
    
1275
        #symbolId = symbol.getId()
1276
        symbolPath = symbol.getPath()
1277
        symbolSp = symbol.getSp()
1278
        symbolRotatedAngle = symbol.getRotatedAngle()
1279

    
1280
        symImg = cv2.cvtColor(cv2.imread(symbolPath, 1), cv2.COLOR_BGR2GRAY)
1281
        if symbol.getDetectFlip() is 1:
1282
            symImg = cv2.flip(symImg, 1)
1283
        for i in range(symbolRotatedAngle//90):
1284
            symImg = cv2.rotate(symImg, cv2.ROTATE_90_COUNTERCLOCKWISE)
1285
    
1286
        w, h = symImg.shape[::-1]
1287
        canvas[symbolSp[1]:symbolSp[1]+h, symbolSp[0]:symbolSp[0]+w] = cv2.bitwise_and(canvas[symbolSp[1]:symbolSp[1]+h, symbolSp[0]:symbolSp[0]+w], symImg)
1288

    
1289
    '''
1290
        @history    2018.05.17  Jeongwoo    Bitwise_not target changed (Original Image → Symbol Image)
1291
                    humkyung 2018.07.11 add parameter for image
1292
    '''
1293
    @staticmethod
1294
    def removeDetectedSymbol(sym, imgSrc):
1295
        global ocrCompletedSrc
1296
        global threadLock
1297
        
1298
        path = sym.getPath()
1299
        sp = sym.getSp()
1300
        sw = sym.getWidth()
1301
        sh = sym.getHeight()
1302
        angle = sym.getRotatedAngle()
1303
        symImg = cv2.imread(path)
1304
        symImg = cv2.threshold(Worker.cvtGrayImage(symImg), 127, 255, cv2.THRESH_BINARY)[1]
1305
        if sym.getDetectFlip() is 1:
1306
            symImg = cv2.flip(symImg, 1)
1307

    
1308
        for i in range(angle//90):
1309
            symImg = cv2.rotate(symImg, cv2.ROTATE_90_COUNTERCLOCKWISE)
1310
    
1311
        threadLock.acquire()
1312
        temp = imgSrc[sp[1]:sp[1]+sh, sp[0]:sp[0]+sw]
1313
        symImg = cv2.erode(symImg, np.ones((3,3), np.uint8))
1314
        mask = cv2.bitwise_or(temp, symImg)
1315
        imgXOR = cv2.bitwise_xor(temp, mask)
1316
        #imgXOR = cv2.dilate(imgXOR, np.ones((5, 5), np.uint8))
1317
        imgSrc[sp[1]:sp[1]+sh, sp[0]:sp[0]+sw] = cv2.bitwise_not(imgXOR)
1318
        threadLock.release()
1319

    
1320
    '''
1321
        @brief  get difference between given original and recognized image
1322
        @author humkyung
1323
        @date   2018.06.11
1324
    '''
1325
    @staticmethod
1326
    def getDifference(orgImagePath, recImagePath):
1327
        import re
1328
    
1329
        global ocrCompletedSrc
1330
        global textInfoList
1331
    
1332
        try:
1333
            appDocData = AppDocData.instance()
1334
            if os.path.isfile(orgImagePath) and os.path.isfile(recImagePath):
1335
                imgOriginal = cv2.threshold(Worker.cvtGrayImage(cv2.imread(orgImagePath, 1)), 127, 255, cv2.THRESH_BINARY)[1]
1336
                # remove not drawing area
1337
                configs = appDocData.getConfigs('{} Equipment Desc Area'.format(appDocData.imgName))
1338
                for config in configs:
1339
                    found = re.findall('\d+', config.value)
1340
                    if len(found) == 4:
1341
                        cv2.rectangle(imgOriginal, (int(found[0]), int(found[1])), (int(found[0])+int(found[2]), int(found[1])+int(found[3])), 255, -1)
1342

    
1343
                configs = appDocData.getConfigs('{} Typical Area'.format(appDocData.imgName))
1344
                for config in configs:
1345
                    found = re.findall('\\d+', config.value)
1346
                    if len(found) == 4:
1347
                        cv2.rectangle(imgOriginal, (int(found[0]), int(found[1])), (int(found[0])+int(found[2]), int(found[1])+int(found[3])), 255, -1)
1348
                
1349
                noteArea = appDocData.getArea('Note')
1350
                if noteArea is not None:
1351
                    noteArea.img = appDocData.imgSrc[round(noteArea.y):round(noteArea.y+noteArea.height), round(noteArea.x):round(noteArea.x+noteArea.width)].copy()
1352
                    cv2.rectangle(imgOriginal, (round(noteArea.x), round(noteArea.y)), (round(noteArea.x + noteArea.width), round(noteArea.y + noteArea.height)), 255, -1)
1353
                # up to here
1354
    
1355
                imgRecognized = cv2.threshold(Worker.cvtGrayImage(cv2.imread(recImagePath, 1)), 127, 255, cv2.THRESH_BINARY)[1]
1356
    
1357
                imgDiff = np.ones(imgOriginal.shape, np.uint8)*255
1358
    
1359
                area = AppDocData.instance().getArea('Drawing')
1360
                if area is not None:
1361
                    x = round(area.x)
1362
                    y = round(area.y)
1363
                    width = round(area.width)
1364
                    height = round(area.height)
1365
                    imgNotOper = cv2.bitwise_not(imgRecognized[y:y+height, x:x+width])
1366
                    imgDiff[y:y+height, x:x+width] = cv2.bitwise_xor(imgOriginal[y:y+height, x:x+width], imgNotOper)
1367
                    
1368
                # remove noise
1369
                imgDiff = cv2.dilate(imgDiff, np.ones((2, 2), np.uint8))
1370
    
1371
                appDocData = AppDocData.instance()
1372
                project = appDocData.getCurrentProject()
1373
                cv2.imwrite(os.path.join(project.getTempPath(), "DIFF_" + os.path.basename(orgImagePath)), imgDiff)
1374
        except Exception as ex:
1375
            from App import App
1376
            
1377
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1378
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1379

    
1380

    
1381
'''
1382
    @history    2018.05.25  Jeongwoo    Add pyqtSignal(svgItemClicked, itemRemoved)
1383
'''
1384
class QRecognitionDialog(QDialog):
1385
    svgItemClicked = pyqtSignal(SymbolSvgItem)
1386
    itemRemoved = pyqtSignal(QGraphicsItem)
1387
    unBlockEvent = pyqtSignal()
1388

    
1389
    '''
1390
        @history    2018.05.25  Jeongwoo    Add parameter and initialize / Connect recognizeButton signal and slot
1391
                    2018.05.29  Jeongwoo    Chnage parameter(graphicsView → parent) and Get graphicsView from parent
1392
    '''
1393
    def __init__(self, parent, path, batch): #Parent is MainWindow
1394
        from AppDocData import AppDocData
1395

    
1396
        QDialog.__init__(self, parent)
1397

    
1398
        self.parent = parent
1399
        self.graphicsView = parent.graphicsView
1400
        self.path = path
1401
        self.xmlPath = None
1402
        self.ui = Recognition_UI.Ui_Recognition()
1403
        self.ui.setupUi(self)
1404

    
1405
        appDocData = AppDocData.instance()
1406
        configs = appDocData.getAppConfigs('app', 'mode')
1407
        if configs and 1 == len(configs) and 'advanced' == configs[0].value:
1408
            pass
1409
        else:
1410
            self.ui.lineCheckBox.setVisible(False)
1411

    
1412
        self.ui.buttonBox.setEnabled(True)
1413
        self.ui.listWidget.model().rowsInserted.connect(self.rowInserted)
1414
        self.ui.recognizeButton.clicked.connect(self.recognizeButtonClicked)
1415
        self.isAccepted = False
1416
        self.batch = batch
1417

    
1418
    '''
1419
        @brief      QListWidget Row Inserted Listener
1420
                    Whenever row inserted, scroll to bottom
1421
        @author     Jeongwoo
1422
        @date       18.04.12
1423
    '''
1424
    def rowInserted(self, item):
1425
        self.ui.listWidget.scrollToBottom()
1426

    
1427
    def accept(self):
1428
        self.isAccepted = True
1429
        QDialog.accept(self)
1430

    
1431
    def recognizeButtonClicked(self, event):
1432
        """
1433
        @brief      start recognization
1434
        @author     humkyung
1435
        @history    humkyung 2018.10.05 clear imgSrc before recognizing
1436
        """ 
1437
        if self.ui.checkBoxSymbol.isChecked() or self.ui.checkBoxText.isChecked() or self.ui.lineCheckBox.isChecked():
1438
            appDocData = AppDocData.instance()
1439
            appDocData.imgSrc = None
1440
            area = appDocData.getArea('Drawing')
1441
            if area is None:
1442
                QMessageBox.about(self, self.tr("Notice"), self.tr('Please select drawing area.'))
1443
                return
1444

    
1445
            self.ui.recognizeButton.setEnabled(False)
1446
            self.ui.buttonBox.setEnabled(False)
1447
            self.ui.progressBar.setValue(0)
1448
            self.startThread()
1449

    
1450
    '''
1451
        @brief  add item to list widget
1452
        @author humkyung
1453
        @date   2018.06.19
1454
    '''
1455
    def addListItem(self, item):
1456
        self.ui.listWidget.addItem(item)
1457

    
1458
    '''
1459
        @brief  update progressbar with given value
1460
        @author humkyung
1461
        @date   2018.06.08
1462
    '''
1463
    def updateProgress(self, maxValue, image_path):
1464
        self.ui.progressBar.setMaximum(maxValue)
1465
        self.ui.progressBar.setValue(self.ui.progressBar.value() + 1)
1466
        
1467
        if image_path is not None and os.path.isfile(image_path):
1468
            self.ui.labelImage.setPixmap(QPixmap(image_path))
1469
        elif image_path is not None:
1470
            self.ui.labelImage.setText(image_path)
1471

    
1472
    def updateBatchProgress(self, maxValue, weight):
1473
        '''
1474
            @brief  update batch progressbar
1475
            @author euisung
1476
            @date   2018.11.28
1477
        '''
1478
        self.ui.progressBarBatch.setMaximum(maxValue * 5)
1479
        self.ui.progressBarBatch.setValue(self.ui.progressBarBatch.value() + weight)
1480
    '''
1481
        @brief      display title
1482
        @author     humkyung
1483
        @date       2018.08.20
1484
    '''
1485
    def displayTitle(self, title):
1486
        self.ui.labelTitle.setText(title)
1487

    
1488
    def startThread(self):
1489
        """
1490
        @brief  start thread
1491
        @author humkyung
1492
        @date   2018.04.??
1493
        @history    2018.05.25  Jeongwoo    Moved from MainWindow
1494
                    2018.05.28  Jeongwoo    Add connects (self.loadRecognitionResult, recognizeLine)
1495
                    2018.05.30  Jeongwoo    Change signal name (drawDetectedItems)
1496
                    humkyung 2018.06.08 connect signal to self.updateProgress
1497
        """
1498
        import timeit
1499
        from PyQt5 import QtWidgets
1500
        from App import App 
1501

    
1502
        self.ui.buttonBox.setDisabled(True)
1503

    
1504
        # 1 - create Worker and Thread inside the Form
1505
        self.obj = Worker()  # no parent!
1506
        self.obj.path = self.path
1507
        self.obj.listWidget = self.ui.listWidget
1508
        self.obj.graphicsView = self.graphicsView
1509
        self.obj.isSymbolChecked = self.ui.checkBoxSymbol.isChecked()
1510
        self.obj.isTextChecked = self.ui.checkBoxText.isChecked()
1511
        self.obj.isLineChecked = self.ui.lineCheckBox.isChecked()
1512
        self.obj.batch = self.batch
1513
        self.obj.createDetectedItems = self.parent.createDetectedItems
1514
        self.obj.createUnknownItems = self.parent.createUnknownItems
1515
        self.thread = QThread()  # no parent!
1516

    
1517
        # 2 - Move the Worker object to the Thread object
1518
        self.obj.moveToThread(self.thread)
1519

    
1520
        # 3 - Connect Worker Signals to the Thread slots
1521
        self.obj.finished.connect(self.thread.quit)
1522
        #self.obj.drawDetectedItems.connect(self.drawDetectedItems)
1523
        #self.obj.drawDetectedLines.connect(self.drawDetectedLines)
1524
        #self.obj.drawUnknownItems.connect(self.drawUnknownItems)
1525
        self.obj.displayMessage.connect(self.addListItem)
1526
        self.obj.updateProgress.connect(self.updateProgress)
1527
        self.obj.updateBatchProgress.connect(self.updateBatchProgress)
1528
        self.obj.displayLog.connect(App.mainWnd().addMessage)
1529
        self.obj.displayTitle.connect(self.displayTitle)
1530

    
1531
        # 4 - Connect Thread started signal to Worker operational slot method
1532
        self.thread.started.connect(self.obj.procCounter)
1533
        
1534
        # 5 - Thread finished signal will close the app if you want!
1535
        self.thread.finished.connect(self.dlgExit)
1536

    
1537
        # 6 - Start the thread
1538
        self.thread.start()
1539

    
1540
        self.tmStart = timeit.default_timer()
1541

    
1542
    '''
1543
        @brief set buttonbox's enabled flag
1544
        @history    2018.05.25  Jeongwoo    Moved from MainWindow
1545
                    2018.05.30  Jeongwoo    Remove self.xmlPath variable and Add writeXmlOnScene
1546
                    2018.06.14  Jeongwoo    Change sentence order
1547
                    2018.11.26  euisung     add drawing part
1548
                    2018.11.26  euising     move save and unknown part into executerecognition
1549
    '''
1550
    def dlgExit(self):
1551
        import timeit
1552
        import XmlGenerator as xg
1553

    
1554
        try:
1555
            self.ui.buttonBox.setEnabled(True)
1556
            
1557
            self.ui.progressBar.setValue(self.ui.progressBar.maximum())
1558
            #if not self.batch:
1559
            #    self.parent.drawDetectedItemsToScene()
1560
        except Exception as ex:
1561
            from App import App
1562
            
1563
            message = 'error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)
1564
            App.mainWnd().addMessage.emit(MessageType.Error, message)
1565
        finally:
1566
            self.tmStop = timeit.default_timer()
1567
            seconds = self.tmStop - self.tmStart
1568
            self.ui.listWidget.addItem("\nRunning Time : {} min".format(str(round(seconds/60, 1))) + "\n")
1569

    
1570
    '''
1571
        @history    2018.05.29  Jeongwoo    Call parent's method
1572
                    2018.05.30  Jeongwoo    Change method name
1573
                    2018.06.09  humkyung    set progressbar value to maximum
1574
                    2018.11.12  euisung     add title block properties
1575
                    2018.11.29  euisung     no more used
1576
    '''
1577
    def drawDetectedItems(self, symbolList, textInfoList, otherTextInfoList, titleBlockTextInfoList, loop):
1578
        try:
1579
            self.ui.progressBar.setValue(self.ui.progressBar.maximum())
1580
            self.parent.drawDetectedItems(symbolList, textInfoList, otherTextInfoList, titleBlockTextInfoList)
1581
        finally:
1582
            loop.quit()
1583

    
1584
    '''
1585
        @brief      draw detected lines
1586
        @author     humkyung
1587
        @date       2018.08.23
1588
        @history    2018.11.27  euisung     no more used
1589
    '''
1590
    def drawDetectedLines(self, lineList, loop):
1591
        try:
1592
            self.parent.drawDetectedLines(lineList, self.obj)
1593
        finally:
1594
            loop.quit()
1595

    
1596
    '''
1597
        @brief      draw detected lines
1598
        @author     euisung
1599
        @date       2018.11.27
1600
        @history    2018.11.27  euisung     no more used
1601
    '''
1602
    def drawUnknownItems(self, path, loop):
1603
        try:
1604
            self.parent.drawUnknownItems(path)
1605
        finally:
1606
            loop.quit()  
클립보드 이미지 추가 (최대 크기: 500 MB)