프로젝트

일반

사용자정보

개정판 7d94b6f1

ID7d94b6f1a386674e0206485ba512b40d760b2979
상위 33de77e3
하위 91a4b6c6

함의성이(가) 4년 이상 전에 추가함

issue #663: line type determine using visual test and setting ui ongoing

Change-Id: I73bcd15ae80f1941dda8b7e2558858e5c0f8b4b0

차이점 보기:

DTI_PID/DTI_PID/LineTypeRegistration_UI.py
1
# -*- coding: utf-8 -*-
2

  
3
# Form implementation generated from reading ui file './UI/LineTypeRegistration.ui'
4
#
5
# Created by: PyQt5 UI code generator 5.11.3
6
#
7
# WARNING! All changes made in this file will be lost!
8

  
9
from PyQt5 import QtCore, QtGui, QtWidgets
10

  
11
class Ui_Dialog(object):
12
    def setupUi(self, Dialog):
13
        Dialog.setObjectName("Dialog")
14
        Dialog.resize(513, 273)
15
        self.gridLayout = QtWidgets.QGridLayout(Dialog)
16
        self.gridLayout.setObjectName("gridLayout")
17
        self.verticalLayout = QtWidgets.QVBoxLayout()
18
        self.verticalLayout.setObjectName("verticalLayout")
19
        self.lineEdit = QtWidgets.QLineEdit(Dialog)
20
        self.lineEdit.setEnabled(False)
21
        self.lineEdit.setReadOnly(False)
22
        self.lineEdit.setObjectName("lineEdit")
23
        self.verticalLayout.addWidget(self.lineEdit)
24
        self.horizontalLayout = QtWidgets.QHBoxLayout()
25
        self.horizontalLayout.setObjectName("horizontalLayout")
26
        self.verticalLayout.addLayout(self.horizontalLayout)
27
        self.buttonBox = QtWidgets.QDialogButtonBox(Dialog)
28
        self.buttonBox.setOrientation(QtCore.Qt.Horizontal)
29
        self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.Cancel|QtWidgets.QDialogButtonBox.Save)
30
        self.buttonBox.setObjectName("buttonBox")
31
        self.verticalLayout.addWidget(self.buttonBox)
32
        self.gridLayout.addLayout(self.verticalLayout, 0, 0, 1, 1)
33

  
34
        self.retranslateUi(Dialog)
35
        self.buttonBox.accepted.connect(Dialog.accept)
36
        self.buttonBox.rejected.connect(Dialog.reject)
37
        QtCore.QMetaObject.connectSlotsByName(Dialog)
38

  
39
    def retranslateUi(self, Dialog):
40
        _translate = QtCore.QCoreApplication.translate
41
        Dialog.setWindowTitle(_translate("Dialog", "Line Type Registration"))
42

  
43

  
44
if __name__ == "__main__":
45
    import sys
46
    app = QtWidgets.QApplication(sys.argv)
47
    Dialog = QtWidgets.QDialog()
48
    ui = Ui_Dialog()
49
    ui.setupUi(Dialog)
50
    Dialog.show()
51
    sys.exit(app.exec_())
52

  
DTI_PID/DTI_PID/MainWindow.py
219 219
        self.actionGroup.addAction(self.actionSave)
220 220
        self.actionGroup.addAction(self.actionValidate)
221 221
        self.actionGroup.addAction(self.actionVendor)
222
        self.actionGroup.addAction(self.actionLineRegistration)
222 223
        self.actionGroup.triggered.connect(self.actionGroupTriggered)
223 224

  
224 225
        # connect signals and slots
......
228 229
        self.actionExportAsXML.triggered.connect(self.export_as_xml)
229 230
        self.actionExportAsImage.triggered.connect(self.export_as_image)
230 231
        self.actionLine.triggered.connect(self.onPlaceLine)
232
        self.actionLineRegistration.triggered.connect(self.onLineTypeRegistration)
231 233
        self.actionRecognition.triggered.connect(self.recognize)
232 234
        self.pushButtonRefreshDrawings.clicked.connect(self.load_drawing_list)
233 235
        self.actionLineRecognition.triggered.connect(self.connect_attributes)
......
1777 1779
        for item in selected:
1778 1780
            item.setVisible(isChecked)
1779 1781

  
1782
    def onLineTypeRegistration(self):
1783
        ''' register line type '''
1784
        if not self.graphicsView.hasImage():
1785
            self.showImageSelectionMessageBox()
1786
            return
1787

  
1788
        cmd = FenceCommand.FenceCommand(self.graphicsView)
1789
        cmd.onSuccess.connect(self.onLineType)
1790
        self.graphicsView.command = cmd
1791
        QApplication.setOverrideCursor(Qt.CrossCursor)
1792

  
1793
    def onLineType(self):
1794
        pass
1795

  
1780 1796
    '''
1781 1797
        @brief  create a symbol
1782 1798
        @history    2018.05.02  Jeongwoo    Change return value of QSymbolEditorDialog (Single variable → Tuple)
......
1785 1801
                                            Change method to make svg and image path
1786 1802
                    2018.06.08  Jeongwoo    Add Paramter on SymbolSvgItem.buildItem()
1787 1803
    '''
1788

  
1789 1804
    def onCreateSymbolClicked(self):
1790 1805
        selected = [item for item in self.graphicsView.scene().selectedItems() if issubclass(type(item), QEngineeringVendorItem)]
1791 1806
        if len(selected) == 1:
DTI_PID/DTI_PID/MainWindow_UI.py
582 582
        self.actionSymbol_Replace_Insert.setObjectName("actionSymbol_Replace_Insert")
583 583
        self.actionMake_Label_Data = QtWidgets.QAction(MainWindow)
584 584
        self.actionMake_Label_Data.setObjectName("actionMake_Label_Data")
585
        self.actionLineRegistration = QtWidgets.QAction(MainWindow)
586
        icon27 = QtGui.QIcon()
587
        icon27.addPixmap(QtGui.QPixmap(":/newPrefix/crop.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
588
        self.actionLineRegistration.setIcon(icon27)
589
        self.actionLineRegistration.setObjectName("actionLineRegistration")
585 590
        self.menuExport.addAction(self.actionExportAsSVG)
586 591
        self.menuExport.addAction(self.actionExportAsXML)
587 592
        self.menuExport.addAction(self.actionExportAsImage)
......
645 650
        self.toolBar.addSeparator()
646 651
        self.toolBar.addAction(self.actionUndo)
647 652
        self.toolBar.addAction(self.actionRedo)
653
        self.toolBar.addSeparator()
648 654
        self.toolBar.addAction(self.actionLine)
655
        self.toolBar.addAction(self.actionLineRegistration)
649 656
        self.toolBar.addAction(self.actionOCR)
650 657
        self.toolBar.addAction(self.actionVendor)
651 658
        self.toolBar.addAction(self.actionValidate)
......
783 790
        self.actionRedo.setToolTip(_translate("MainWindow", "Redo"))
784 791
        self.actionSymbol_Replace_Insert.setText(_translate("MainWindow", "Symbol Replace/Insert"))
785 792
        self.actionMake_Label_Data.setText(_translate("MainWindow", "Make Label Data"))
793
        self.actionLineRegistration.setText(_translate("MainWindow", "Line Registration"))
794
        self.actionLineRegistration.setToolTip(_translate("MainWindow", "Line Registration"))
786 795

  
787 796
import MainWindow_rc
788 797

  
DTI_PID/DTI_PID/RecognitionDialog.py
1269 1269
                                    item = sym.connectors[index].connectedItem
1270 1270
                                    if item and type(item) is QEngineeringLineItem:
1271 1271
                                        Worker.changeConnectedLineType(item, sym.conn_type[index])
1272

  
1272 1273
                    except Exception as ex:
1273 1274
                        message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1274 1275
                                  f"{sys.exc_info()[-1].tb_lineno}"
......
1314 1315
                        worker.displayLog.emit(MessageType.Error, message)
1315 1316
                    # up to here
1316 1317

  
1318
                    # change line type using visual pattern
1319
                    try:
1320
                        Worker.changeVisualLineType(app_doc_data.lines)
1321

  
1322
                    except Exception as ex:
1323
                        message = f"error occurred({repr(ex)}) in {sys.exc_info()[-1].tb_frame.f_code.co_filename}:" \
1324
                                  f"{sys.exc_info()[-1].tb_lineno}"
1325
                        worker.displayLog.emit(MessageType.Error, message)
1326
                    # up to here
1327

  
1317 1328
                worker.create_unknown_items(mainRes)
1318 1329
                worker.add_detected_items_to_scene.emit(worker.scene, flange_list)
1319 1330
                worker.cond.wait(worker.mutex)
......
1340 1351
            pass
1341 1352

  
1342 1353
    @staticmethod
1354
    def changeVisualLineType(lines):
1355
        from LineDetector import LineDetector
1356

  
1357
        app_doc_data = AppDocData.instance()
1358
        image = app_doc_data.activeDrawing.image_origin
1359
        imgNot = np.ones(image.shape, np.uint8) * 255
1360
        image = cv2.bitwise_xor(image, imgNot)
1361

  
1362
        electric = [137, [1,1,1,1,1,1,1,1,1], sys.maxsize]
1363
        software = [187, [0.948,1.081,0.932,1.081,0.932,1.068,0.932,1.081,0.929], sys.maxsize]
1364
        line_patterns = {'Electric':electric, 'Software':software }
1365

  
1366
        lines_found = []
1367

  
1368
        for line in lines:
1369
            vertical = LineDetector.is_vertical([line.start_point()[0], line.start_point()[1], line.end_point()[0], line.end_point()[1]])
1370

  
1371
            rect = line.boundingRect()
1372
            image_line = image[round(rect.y()):round(rect.y() + rect.height()), round(rect.x()):round(rect.x() + rect.width())]
1373
            contours, _ = cv2.findContours(image_line, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
1374

  
1375
            # skip piping line
1376
            if len(contours) < 3:
1377
                continue
1378

  
1379
            i = 1 if vertical else 0
1380
            boundingBoxes = [cv2.boundingRect(contour) for contour in contours]
1381
            (contours, boundingBoxes) = zip(*sorted(zip(contours, boundingBoxes), key=lambda b:b[1][i], reverse=False))
1382

  
1383
            avg_area = sum([cv2.contourArea(contour) for contour in contours]) / len(contours)
1384
            ratio_area = [cv2.contourArea(contour) / avg_area for contour in contours]
1385

  
1386
            for line_type, line_pattern in line_patterns.items():
1387
                line_pattern[2] = sys.maxsize
1388
                ratio_area_cal = [ratio * avg_area / line_pattern[0] for ratio in ratio_area]
1389
                long_line = ratio_area_cal if len(ratio_area_cal) > len(line_pattern[1]) else line_pattern[1]
1390
                short_line = line_pattern[1] if len(ratio_area_cal) > len(line_pattern[1]) else ratio_area_cal
1391

  
1392
                min_error = sys.maxsize
1393
                for offset in range(len(long_line) - len(short_line) + 1):
1394
                    error = 0
1395
                    for index in range(len(short_line)):
1396
                        error += abs(short_line[index] - long_line[index + offset])
1397
                    error = error / len(short_line)
1398
                    if error < min_error:
1399
                        min_error = error
1400

  
1401
                line_pattern[2] = min_error
1402

  
1403
            line_type_found = sorted([(line_type, line_pattern[2]) for line_type, line_pattern in line_patterns.items()], key=lambda error:error[1])[0]
1404
            if line_type_found[1] < 0.4:
1405
                lines_found.append([line, line_type_found])
1406

  
1407
            '''
1408
            orb = cv2.ORB_create()
1409
            kp1, des1 = orb.detectAndCompute(image_line, None)
1410
            kp2, des2 = orb.detectAndCompute(image_line, None)
1411

  
1412
            bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
1413
            matches = bf.match(des1, des2)
1414
            matches = sorted(matches, key=lambda x: x.distance)
1415

  
1416
            good = []
1417
            for m, n in matches:
1418
                if m.distance < 0.75 * n.distance:
1419
                    good.append([m])
1420

  
1421
            sift = cv2.xfeatures2d.SIFT_create()
1422
            kp1, des1 = sift.detectAndCompute(image_line, None)
1423
            kp2, des2 = sift.detectAndCompute(image_line, None)
1424

  
1425
            bf = cv2.BFMatcher(cv2.NORM_L2, crossCheck=True)
1426
            matches = bf.match(des1, des2)
1427
            matches = sorted(matches, key=lambda x: x.distance)
1428

  
1429
            good = []
1430
            for m, n in matches:
1431
                if m.distance < 0.75 * n.distance:
1432
                    good.append([m])
1433
            '''
1434

  
1435
        line_runs = []
1436
        for line_found in lines_found:
1437
            inserted = False
1438
            for line_run in line_runs:
1439
                if line_found[0] in line_run:
1440
                    inserted = True
1441
                    break
1442

  
1443
            if inserted:
1444
                continue
1445
            else:
1446
                line_runs.append(Worker.find_connected_line(line_found[0]))
1447

  
1448
        for line_run in line_runs:
1449
            _lines_found = []
1450
            for _line in line_run:
1451
                _lines = [line_found[0] for line_found in lines_found]
1452
                if _line in _lines:
1453
                    index = _lines.index(_line)
1454
                    _lines_found.append(lines_found[index])
1455
            _line_found = sorted(_lines_found, key=lambda param:param[1][1])[0]
1456
            Worker.changeConnectedLineType(_line_found[0], _line_found[1][0])
1457

  
1458
    @staticmethod
1459
    def find_connected_line(line):
1460
        lines = [line]
1461

  
1462
        current_line = line
1463
        while True:
1464
            if type(current_line.connectors[0].connectedItem) is QEngineeringLineItem:
1465
                current_line = current_line.connectors[0].connectedItem
1466
                lines.append(current_line)
1467
            else:
1468
                break
1469

  
1470
        current_line = line
1471
        while True:
1472
            if type(current_line.connectors[1].connectedItem) is QEngineeringLineItem:
1473
                current_line = current_line.connectors[1].connectedItem
1474
                lines.append(current_line)
1475
            else:
1476
                break
1477

  
1478
        return lines
1479

  
1480
    @staticmethod
1343 1481
    def changeConnectedLineType(line, lineType):
1344 1482
        line.lineType = lineType
1345 1483
        if type(line.connectors[0].connectedItem) is QEngineeringLineItem and \
DTI_PID/DTI_PID/UI/LineTypeRegistration.ui
1
<?xml version="1.0" encoding="UTF-8"?>
2
<ui version="4.0">
3
 <class>Dialog</class>
4
 <widget class="QDialog" name="Dialog">
5
  <property name="geometry">
6
   <rect>
7
    <x>0</x>
8
    <y>0</y>
9
    <width>513</width>
10
    <height>273</height>
11
   </rect>
12
  </property>
13
  <property name="windowTitle">
14
   <string>Line Type Registration</string>
15
  </property>
16
  <layout class="QGridLayout" name="gridLayout">
17
   <item row="0" column="0">
18
    <layout class="QVBoxLayout" name="verticalLayout">
19
     <item>
20
      <widget class="QLineEdit" name="lineEdit">
21
       <property name="enabled">
22
        <bool>false</bool>
23
       </property>
24
       <property name="readOnly">
25
        <bool>false</bool>
26
       </property>
27
      </widget>
28
     </item>
29
     <item>
30
      <layout class="QHBoxLayout" name="horizontalLayout"/>
31
     </item>
32
     <item>
33
      <widget class="QDialogButtonBox" name="buttonBox">
34
       <property name="orientation">
35
        <enum>Qt::Horizontal</enum>
36
       </property>
37
       <property name="standardButtons">
38
        <set>QDialogButtonBox::Cancel|QDialogButtonBox::Save</set>
39
       </property>
40
      </widget>
41
     </item>
42
    </layout>
43
   </item>
44
  </layout>
45
 </widget>
46
 <resources/>
47
 <connections>
48
  <connection>
49
   <sender>buttonBox</sender>
50
   <signal>accepted()</signal>
51
   <receiver>Dialog</receiver>
52
   <slot>accept()</slot>
53
   <hints>
54
    <hint type="sourcelabel">
55
     <x>248</x>
56
     <y>254</y>
57
    </hint>
58
    <hint type="destinationlabel">
59
     <x>157</x>
60
     <y>274</y>
61
    </hint>
62
   </hints>
63
  </connection>
64
  <connection>
65
   <sender>buttonBox</sender>
66
   <signal>rejected()</signal>
67
   <receiver>Dialog</receiver>
68
   <slot>reject()</slot>
69
   <hints>
70
    <hint type="sourcelabel">
71
     <x>316</x>
72
     <y>260</y>
73
    </hint>
74
    <hint type="destinationlabel">
75
     <x>286</x>
76
     <y>274</y>
77
    </hint>
78
   </hints>
79
  </connection>
80
 </connections>
81
</ui>
DTI_PID/DTI_PID/UI/MainWindow.ui
193 193
   <addaction name="separator"/>
194 194
   <addaction name="actionUndo"/>
195 195
   <addaction name="actionRedo"/>
196
   <addaction name="separator"/>
196 197
   <addaction name="actionLine"/>
198
   <addaction name="actionLineRegistration"/>
197 199
   <addaction name="actionOCR"/>
198 200
   <addaction name="actionVendor"/>
199 201
   <addaction name="actionValidate"/>
......
1315 1317
    <string>Make Label Data</string>
1316 1318
   </property>
1317 1319
  </action>
1320
  <action name="actionLineRegistration">
1321
   <property name="icon">
1322
    <iconset resource="../res/MainWindow.qrc">
1323
     <normaloff>:/newPrefix/crop.png</normaloff>:/newPrefix/crop.png</iconset>
1324
   </property>
1325
   <property name="text">
1326
    <string>Line Registration</string>
1327
   </property>
1328
   <property name="toolTip">
1329
    <string>Line Registration</string>
1330
   </property>
1331
  </action>
1318 1332
 </widget>
1319 1333
 <resources>
1320 1334
  <include location="../res/MainWindow.qrc"/>

내보내기 Unified diff

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