개정판 7d94b6f1
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