개정판 26ec4aef
issue #663: 개별, 배치 인식 모드 통합
Change-Id: Id2f6f056199617c02ae465d27e8d3c9570c6fe17
DTI_PID/DTI_PID/AppDocData.py | ||
---|---|---|
915 | 915 |
if self._titleBlockProperties is None: |
916 | 916 |
self._titleBlockProperties = [] |
917 | 917 |
|
918 |
# Creates or opens a file called mydb with a SQLite3 DB |
|
919 |
conn = self.project.database.connect() |
|
920 |
with conn: |
|
918 |
with self.project.database.connect() as conn: |
|
921 | 919 |
try: |
922 | 920 |
# Get a cursor object |
923 | 921 |
cursor = conn.cursor() |
DTI_PID/DTI_PID/Commands/SaveWorkCommand.py | ||
---|---|---|
94 | 94 |
resultStr += "\r\n" + uid |
95 | 95 |
|
96 | 96 |
return resultStr |
97 |
|
|
98 |
@staticmethod |
|
99 |
def save_to_database(): |
|
100 |
"""db update when save or recognition""" |
|
101 |
from AppDocData import AppDocData |
|
102 |
from AppDocData import MessageType |
|
103 |
from EngineeringAbstractItem import QEngineeringAbstractItem |
|
104 |
from EngineeringErrorItem import QEngineeringErrorItem |
|
105 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
|
106 |
from EngineeringTextItem import QEngineeringTextItem |
|
107 |
from QEngineeringTrimLineNoTextItem import QEngineeringTrimLineNoTextItem |
|
108 |
from EngineeringLineNoTextItem import QEngineeringLineNoTextItem |
|
109 |
from EngineeringUnknownItem import QEngineeringUnknownItem |
|
110 |
|
|
111 |
try: |
|
112 |
app_doc_data = AppDocData.instance() |
|
113 |
items = app_doc_data.allItems |
|
114 |
|
|
115 |
# unknown item is not saved now for performance |
|
116 |
db_items = [item for item in items if issubclass(type(item), QEngineeringAbstractItem) and |
|
117 |
type(item) is not QGraphicsBoundingBoxItem and |
|
118 |
type(item) is not QEngineeringErrorItem and |
|
119 |
type(item) is not QEngineeringLineNoTextItem and |
|
120 |
type(item) is not QEngineeringUnknownItem] |
|
121 |
db_items.extend([item for item in items if type(item) is QEngineeringLineNoTextItem]) |
|
122 |
db_items.extend([line for line in app_doc_data.tracerLineNos if type(line) is QEngineeringTrimLineNoTextItem]) |
|
123 |
# db_items.extend(titleBlockItems) |
|
124 |
configs = app_doc_data.getConfigs('Data Save', 'Unknown Xml Only') |
|
125 |
if configs and int(configs[0].value) is -1: |
|
126 |
db_items.extend([item for item in items if type(item) is QEngineeringUnknownItem]) |
|
127 |
|
|
128 |
app_doc_data.saveToDatabase(db_items) |
|
129 |
except Exception as ex: |
|
130 |
from App import App |
|
131 |
from AppDocData import MessageType |
|
132 |
|
|
133 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
134 |
sys.exc_info()[-1].tb_lineno) |
|
135 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
DTI_PID/DTI_PID/LibraryItem.py | ||
---|---|---|
39 | 39 |
|
40 | 40 |
idx = 0 |
41 | 41 |
for _, symbol in enumerate(self._symbol_tree_widget.symbols): |
42 |
matches = [favorite for favorite in self.favorites if symbol.getUid() == favorite[1]]
|
|
42 |
matches = [favorite for favorite in self.favorites if symbol.getUid() == favorite['Symbol_UID']]
|
|
43 | 43 |
if matches: |
44 | 44 |
self.layout.addWidget(LibraryItem(symbol), idx // LibraryItemWidget.COLUMN, \ |
45 | 45 |
idx % LibraryItemWidget.COLUMN) |
... | ... | |
64 | 64 |
cursor.execute(sql, param) |
65 | 65 |
conn.commit() |
66 | 66 |
|
67 |
''' |
|
68 |
layout_item = self.layout.takeAt(matches[0]) |
|
69 |
self.layout.removeWidget(item) |
|
70 |
item.deleteLater() |
|
71 |
del item |
|
72 |
self.layout.removeItem(layout_item) |
|
73 |
del layout_item |
|
74 |
''' |
|
75 | 67 |
self.make_grid() |
76 | 68 |
|
77 | 69 |
self.layout.update() |
DTI_PID/DTI_PID/MainWindow.py | ||
---|---|---|
226 | 226 |
self.actionExportAsImage.triggered.connect(self.export_as_image) |
227 | 227 |
self.actionLine.triggered.connect(self.onPlaceLine) |
228 | 228 |
self.actionRecognition.triggered.connect(self.recognize) |
229 |
self.pushButtonBatchRecognition.clicked.connect(self.recognizeBatch) |
|
230 | 229 |
self.pushButtonRefreshDrawings.clicked.connect(self.load_drawing_list) |
231 | 230 |
self.actionLineRecognition.triggered.connect(self.connect_attributes) |
232 | 231 |
self.actionArea.triggered.connect(self.areaConfiguration) |
... | ... | |
282 | 281 |
self.menu_2.setEnabled(False) # Data |
283 | 282 |
self.menu_4.setEnabled(False) # Tool |
284 | 283 |
self.actionConfiguration.setVisible(False) |
285 |
self.pushButtonBatchRecognition.setVisible(False) |
|
286 | 284 |
self.pushButtonCreateSymbol.setVisible(False) |
287 | 285 |
self.pushButtonDetectSymbol.setVisible(False) |
288 | 286 |
|
... | ... | |
572 | 570 |
app_doc_data = AppDocData.instance() |
573 | 571 |
drawing = item.data(Qt.UserRole, 0) |
574 | 572 |
if drawing: |
573 |
# uncheck all drawing tree item |
|
574 |
drawing_top = self.treeWidgetDrawingList.topLevelItem(0) |
|
575 |
count = drawing_top.childCount() |
|
576 |
for idx in range(count): |
|
577 |
child = drawing_top.child(idx) |
|
578 |
child.setCheckState(column, Qt.Unchecked) |
|
579 |
# up to here |
|
580 |
|
|
575 | 581 |
drawing.image = None |
576 | 582 |
self.open_image_drawing(drawing) |
583 |
item.setCheckState(column, Qt.Checked) |
|
577 | 584 |
|
578 | 585 |
def show_detect_symbol_dialog(self): |
579 | 586 |
from DetectSymbolDialog import QDetectSymbolDialog |
... | ... | |
1419 | 1426 |
self.itemTreeWidget.setCurrentPID(app_doc_data.activeDrawing.name) |
1420 | 1427 |
|
1421 | 1428 |
drawingList = self.treeWidgetDrawingList.topLevelItem(0) |
1422 |
for childIdex in range(drawingList.childCount()): |
|
1423 |
drawingList.child(childIdex).setCheckState(0, Qt.Unchecked) |
|
1424 |
for childIdex in range(drawingList.childCount()): |
|
1425 |
child = drawingList.child(childIdex) |
|
1426 |
if child.text(0).replace('.png', '') == app_doc_data.activeDrawing.name: |
|
1429 |
for idx in range(drawingList.childCount()): |
|
1430 |
child = drawingList.child(idx) |
|
1431 |
if child.data(Qt.UserRole, 0) is drawing: |
|
1427 | 1432 |
child.setCheckState(0, Qt.Checked) |
1428 |
break |
|
1433 |
else: |
|
1434 |
child.setCheckState(0, Qt.Unchecked) |
|
1429 | 1435 |
|
1430 | 1436 |
try: |
1431 | 1437 |
self.show_Progress_bar() |
... | ... | |
2037 | 2043 |
sys.exc_info()[-1].tb_lineno) |
2038 | 2044 |
self.addMessage.emit(MessageType.Error, message) |
2039 | 2045 |
|
2040 |
def recognizeBatch(self, MainWindow): |
|
2041 |
''' |
|
2042 |
@brief batch recognize symbol, text and line |
|
2043 |
@author euisung |
|
2044 |
@date 2018.11.23 |
|
2045 |
|
|
2046 |
''' |
|
2046 |
def recognize(self): |
|
2047 |
"""recognize symbol, text and line for selected drawings""" |
|
2047 | 2048 |
from datetime import datetime |
2048 | 2049 |
from RecognitionDialog import QRecognitionDialog |
2049 | 2050 |
|
2050 | 2051 |
app_doc_data = AppDocData.instance() |
2051 |
project = app_doc_data.getCurrentProject() |
|
2052 |
app_doc_data.needReOpening = None |
|
2053 | 2052 |
current_drawing, currentPid = None, None |
2054 | 2053 |
|
2055 | 2054 |
if self.graphicsView.hasImage(): |
2056 | 2055 |
current_drawing = app_doc_data.activeDrawing |
2057 | 2056 |
currentPid = app_doc_data.activeDrawing.name |
2058 | 2057 |
|
2059 |
# TODO: 무슨 의미인지 주석 필요 |
|
2060 |
drawingTop = self.treeWidgetDrawingList.topLevelItem(0) |
|
2061 |
drawingCount = drawingTop.childCount() |
|
2062 |
checkedTreeItems = [] |
|
2063 |
checkedDrawingPath = [] |
|
2064 |
for drawing in range(drawingCount): |
|
2065 |
drawingChild = drawingTop.child(drawing) |
|
2066 |
if drawingChild.checkState(0) == 2: |
|
2067 |
checkedTreeItems.append(drawingChild) |
|
2068 |
checkedDrawingPath.append(os.path.join(project.getDrawingFilePath(), drawingChild.data(0, 0))) |
|
2069 |
if currentPid is not None and drawingChild.data(0, 0).find(currentPid) is 0: |
|
2070 |
app_doc_data.needReOpening = False # later check need reopening at drawUnknownItems() |
|
2071 |
currentPid = drawingChild.data(0, 0) |
|
2058 |
# get checked drawings |
|
2059 |
drawing_top = self.treeWidgetDrawingList.topLevelItem(0) |
|
2060 |
count = drawing_top.childCount() |
|
2061 |
checked_drawings = {} |
|
2062 |
for idx in range(count): |
|
2063 |
child = drawing_top.child(idx) |
|
2064 |
if child.checkState(0) == Qt.Checked and child.data(Qt.UserRole, 0): |
|
2065 |
checked_drawings[child.data(Qt.UserRole, 0)] = child |
|
2072 | 2066 |
# up to here |
2073 | 2067 |
|
2074 |
if len(checkedDrawingPath) == 0:
|
|
2068 |
if not checked_drawings:
|
|
2075 | 2069 |
self.showImageSelectionMessageBox() |
2076 | 2070 |
return |
2077 | 2071 |
|
2078 | 2072 |
try: |
2079 | 2073 |
self.onClearLog() |
2080 |
self.dlg = QRecognitionDialog(self, checkedDrawingPath, True) |
|
2081 |
self.dlg.exec_() |
|
2082 |
if self.dlg.isAccepted == True: |
|
2083 |
pass |
|
2074 |
dlg = QRecognitionDialog(self, [drawing.file_path for drawing in checked_drawings.keys()]) |
|
2075 |
dlg.exec_() |
|
2084 | 2076 |
|
2085 |
if app_doc_data.needReOpening == True:
|
|
2077 |
if current_drawing and current_drawing in checked_drawings.keys():
|
|
2086 | 2078 |
self.open_image_drawing(current_drawing) |
2087 | 2079 |
|
2088 | 2080 |
# save working date-time |
2089 |
drawings = app_doc_data.getDrawings() |
|
2090 |
checkedDrawings = [] |
|
2091 |
for checkedTreeItem in checkedTreeItems: |
|
2092 |
for drawing in drawings: |
|
2093 |
if checkedTreeItem.data(0, 0) == drawing.name: |
|
2094 |
if drawing: |
|
2095 |
drawing.datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S') |
|
2096 |
checkedDrawings.append(drawing) |
|
2097 |
checkedTreeItem.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S')) |
|
2098 |
app_doc_data.saveDrawings(checkedDrawings) |
|
2081 |
_now = datetime.now().strftime('%Y-%m-%d %H:%M:%S') |
|
2082 |
for drawing, tree_item in checked_drawings.items(): |
|
2083 |
drawing.datetime = _now |
|
2084 |
tree_item.setText(1, _now) |
|
2085 |
app_doc_data.saveDrawings(checked_drawings.keys()) |
|
2099 | 2086 |
self.changeViewCheckedState(True) |
2100 | 2087 |
# up to here |
2101 | 2088 |
except Exception as ex: |
... | ... | |
2104 | 2091 |
self.addMessage.emit(MessageType.Error, message) |
2105 | 2092 |
|
2106 | 2093 |
''' |
2107 |
@brief recognize symbol and text |
|
2108 |
@author humkyung |
|
2109 |
@date 2018.04.?? |
|
2110 |
@history 2018.04.16 humkyung execute line no tracing |
|
2111 |
2018.05.02 Jeongwoo Show MessageBox when imageviewer doesn't have image |
|
2112 |
2018.05.25 Jeongwoo Add parameter on QRecognitionDialog.__init__() and Move thread to QRecognitionDialog |
|
2113 |
Remove codes below if self.dlg.isAccepted == True |
|
2114 |
2018.05.29 Jeongwoo Remove connects and comments |
|
2115 |
humkyung 2018.11.05 save working date-time |
|
2116 |
''' |
|
2117 |
|
|
2118 |
def recognize(self, MainWindow): |
|
2119 |
from datetime import datetime |
|
2120 |
from RecognitionDialog import QRecognitionDialog |
|
2121 |
|
|
2122 |
if not self.graphicsView.hasImage(): |
|
2123 |
self.showImageSelectionMessageBox() |
|
2124 |
return |
|
2125 |
|
|
2126 |
# save alarm |
|
2127 |
self.save_alarm_enable(False) |
|
2128 |
|
|
2129 |
try: |
|
2130 |
appDocData = AppDocData.instance() |
|
2131 |
|
|
2132 |
self.onClearLog() |
|
2133 |
appDocData.needReOpening = False |
|
2134 |
drawingList = [] |
|
2135 |
drawingList.append(self.path) |
|
2136 |
self.dlg = QRecognitionDialog(self, drawingList, False) |
|
2137 |
self.dlg.exec_() |
|
2138 |
|
|
2139 |
if appDocData.needReOpening: |
|
2140 |
self.itemTreeWidget.setCurrentPID(appDocData.activeDrawing.name) |
|
2141 |
self.drawDetectedItemsToScene() |
|
2142 |
|
|
2143 |
# save working date-time |
|
2144 |
drawings = appDocData.getDrawings() |
|
2145 |
drawing = [drawing for drawing in drawings if appDocData.imgName == os.path.splitext(drawing.name)[0]] |
|
2146 |
if drawing[0]: |
|
2147 |
drawing[0].datetime = datetime.now().strftime('%Y-%m-%d %H:%M:%S') |
|
2148 |
appDocData.saveDrawings(drawing) |
|
2149 |
|
|
2150 |
currentPid = appDocData.activeDrawing.name |
|
2151 |
|
|
2152 |
drawingTop = self.treeWidgetDrawingList.topLevelItem(0) |
|
2153 |
drawingCount = drawingTop.childCount() |
|
2154 |
|
|
2155 |
for drawing in range(drawingCount): |
|
2156 |
drawingChild = drawingTop.child(drawing) |
|
2157 |
if drawingChild.data(0, 0).find(currentPid) is 0: |
|
2158 |
drawingChild.setText(1, datetime.now().strftime('%Y-%m-%d %H:%M:%S')) |
|
2159 |
self.changeViewCheckedState(True) |
|
2160 |
# up to here |
|
2161 |
except Exception as ex: |
|
2162 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
2163 |
sys.exc_info()[-1].tb_lineno) |
|
2164 |
self.addMessage.emit(MessageType.Error, message) |
|
2165 |
finally: |
|
2166 |
# save alarm |
|
2167 |
self.save_alarm_enable(True) |
|
2168 |
|
|
2169 |
''' |
|
2170 | 2094 |
@brief remove item from tree widget and then remove from scene |
2171 | 2095 |
@date 2018.05.25 |
2172 | 2096 |
@author Jeongwoo |
... | ... | |
2253 | 2177 |
sys.exc_info()[-1].tb_lineno) |
2254 | 2178 |
self.addMessage.emit(MessageType.Error, message) |
2255 | 2179 |
|
2256 |
''' |
|
2257 |
@brief recognize line |
|
2258 |
@author humkyung |
|
2259 |
@date 2018.04.19 |
|
2260 |
@history Jeongwoo 2018.04.26 Variable name changed (texts → lineNos) |
|
2261 |
TextItem type changed (QEngineeringTextItem → QEngineeringLineNoTextItem) |
|
2262 |
humkyung 2018.04.26 remove small objects before recognizing line |
|
2263 |
Jeongwoo 2018.05.02 Show MessageBox when imageviewer doesn't have image |
|
2264 |
Jeongwoo 2018.05.25 Move codes about LineDetector |
|
2265 |
humkyung 2018.06.17 show progress dialog |
|
2266 |
''' |
|
2267 |
|
|
2268 | 2180 |
def connect_attributes(self, MainWindow): |
2181 |
"""connect attributes to symbol""" |
|
2269 | 2182 |
from LineNoTracer import LineNoTracer |
2270 | 2183 |
from ConnectAttrDialog import QConnectAttrDialog |
2271 | 2184 |
|
... | ... | |
2305 | 2218 |
# save alarm |
2306 | 2219 |
self.save_alarm_enable(True) |
2307 | 2220 |
|
2308 |
''' |
|
2309 |
@history 2018.05.25 Jeongwoo Moved from MainWindow |
|
2310 |
SvgItem and TextItem Connect with method in this class |
|
2311 |
Change method to add GraphicsItem |
|
2312 |
2018.05.28 Jeongwoo Make QGraphicsItem by symbol, text object. Not xml |
|
2313 |
2018.05.29 Jeongwoo Change method name and Moved from QRecognitionDialog |
|
2314 |
2018.05.30 Jeongwoo Add parameters on SymbolSvgItem.__init__() (parentSymbol, childSymbol) |
|
2315 |
Change Method name and seperate each item |
|
2316 |
humkyung 2018.06.11 display difference between original and recognized image |
|
2317 |
Jeongwoo 2018.06.18 Update Scene after all item added |
|
2318 |
2018.11.05 euisung add save note item because of dependency |
|
2319 |
2018.11.05 euisung add db delete process before save |
|
2320 |
2018.11.12 euisung add title block properties |
|
2321 |
2018.11.12 euisung db part move new method to dbUpdate |
|
2322 |
2018.11.26 euisung isolate scene adding part -> drawDetectedItemsToScene() |
|
2323 |
2018.11.29 euisung change name drawDetectedItems() -> createDetectedItems |
|
2324 |
''' |
|
2325 |
|
|
2326 |
def createDetectedItems(self, symbolList, textInfoList, otherTextInfoList, titleBlockTextInfoList): |
|
2327 |
try: |
|
2328 |
QApplication.processEvents() |
|
2329 |
self.createDetectedSymbolItem(symbolList) |
|
2330 |
QApplication.processEvents() |
|
2331 |
self.createDetectedTextItem(textInfoList) |
|
2332 |
QApplication.processEvents() |
|
2333 |
self.createDetectedOtherTextItem(otherTextInfoList) |
|
2334 |
QApplication.processEvents() |
|
2335 |
self.createDetectedTitleBlockTextItem(titleBlockTextInfoList) |
|
2336 |
|
|
2337 |
# update scene |
|
2338 |
# self.graphicsView.scene().update(self.graphicsView.sceneRect()) |
|
2339 |
except Exception as ex: |
|
2340 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
2341 |
sys.exc_info()[-1].tb_lineno) |
|
2342 |
self.addMessage.emit(MessageType.Error, message) |
|
2343 |
|
|
2344 |
def drawDetectedItemsToScene(self): |
|
2345 |
"""add detected items to scene""" |
|
2346 |
from SaveWorkCommand import SaveWorkCommand |
|
2347 |
|
|
2348 |
app_doc_data = AppDocData.instance() |
|
2349 |
|
|
2350 |
try: |
|
2351 |
for symbol in app_doc_data.symbols: |
|
2352 |
if issubclass(type(symbol), SymbolSvgItem): |
|
2353 |
symbol.addSvgItemToScene(self.graphicsView.scene()) |
|
2354 |
else: |
|
2355 |
self.graphicsView.scene().addItem(symbol) |
|
2356 |
|
|
2357 |
for text in app_doc_data.texts: |
|
2358 |
self.addTextItemToScene(text) |
|
2359 |
|
|
2360 |
for lineNo in app_doc_data.tracerLineNos: |
|
2361 |
self.addTextItemToScene(lineNo) |
|
2362 |
|
|
2363 |
# remove lines which is located inside symbol |
|
2364 |
for symbol in app_doc_data.symbols: |
|
2365 |
rect = symbol.sceneBoundingRect() |
|
2366 |
rect.adjust(-10, -10, 10, 10) |
|
2367 |
matches = [line for line in app_doc_data.lines if rect.contains(line.line().p1()) and |
|
2368 |
rect.contains(line.line().p2()) and |
|
2369 |
not line.has_connection] |
|
2370 |
app_doc_data.lines = [line for line in app_doc_data.lines if line not in matches] |
|
2371 |
# up to here |
|
2372 |
|
|
2373 |
for line in app_doc_data.lines: |
|
2374 |
self.graphicsView.scene().addItem(line) |
|
2375 |
line.transfer.onRemoved.connect(self.itemRemoved) |
|
2376 |
for conn in line.connectors: |
|
2377 |
conn.transfer.onPosChanged.connect(line.onConnectorPosChaned) |
|
2378 |
|
|
2379 |
for unknown in app_doc_data.unknowns + app_doc_data.lineIndicators: |
|
2380 |
self.graphicsView.scene().addItem(unknown) |
|
2381 |
|
|
2382 |
# save scene |
|
2383 |
self.dbUpdate() |
|
2384 |
SaveWorkCommand.save_to_xml() |
|
2385 |
finally: |
|
2386 |
# update scene |
|
2387 |
self.graphicsView.scene().update(self.graphicsView.sceneRect()) |
|
2388 |
|
|
2389 | 2221 |
def postDetectLineProcess(self): |
2390 | 2222 |
''' |
2391 | 2223 |
@brief check allowables among undetected items |
... | ... | |
2428 | 2260 |
item.transfer.onRemoved.emit(item) |
2429 | 2261 |
appDocData.lineNos.append(lineItem) |
2430 | 2262 |
|
2431 |
def createDetectedTitleBlockTextItem(self, textInfoList): |
|
2432 |
''' |
|
2433 |
@brief draw title block |
|
2434 |
@author euisung |
|
2435 |
@date 2018.11.12 |
|
2436 |
@history 2018.11.26 euisung remove scene dependency |
|
2437 |
2018.11.29 euisung change name drawDetectedTitleBlockTextItem() -> createDetectedTitleBlockTextItem |
|
2438 |
''' |
|
2439 |
from TextItemFactory import TextItemFactory |
|
2440 |
import math |
|
2441 |
|
|
2442 |
try: |
|
2443 |
appDocData = AppDocData.instance() |
|
2444 |
|
|
2445 |
# parse texts |
|
2446 |
for textInfos in textInfoList: |
|
2447 |
if len(textInfos[1]) is 0: |
|
2448 |
continue |
|
2449 |
|
|
2450 |
for textInfo in textInfos[1]: |
|
2451 |
x = textInfo.getX() |
|
2452 |
y = textInfo.getY() |
|
2453 |
width = textInfo.getW() |
|
2454 |
height = textInfo.getH() |
|
2455 |
angle = round(math.radians(textInfo.getAngle()), 2) |
|
2456 |
text = textInfo.getText() |
|
2457 |
if not text: continue |
|
2458 |
item = TextItemFactory.instance().createTextItem(textInfo) |
|
2459 |
|
|
2460 |
if item is not None: |
|
2461 |
item.loc = [x, y] |
|
2462 |
item.size = (width, height) |
|
2463 |
item.angle = angle |
|
2464 |
item.area = textInfos[0] |
|
2465 |
# self.addTextItemToScene(item) |
|
2466 |
# appDocData.texts.append(item) |
|
2467 |
appDocData.allItems.append(item) |
|
2468 |
except Exception as ex: |
|
2469 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
2470 |
sys.exc_info()[-1].tb_lineno) |
|
2471 |
self.addMessage.emit(MessageType.Error, message) |
|
2472 |
|
|
2473 |
''' |
|
2474 |
@brief |
|
2475 |
@author humkyung |
|
2476 |
@date 2018.08.23 |
|
2477 |
@history 2018.11.26 euisung remove scene dependency |
|
2478 |
2018.11.26 euisung isolate scene adding part -> drawDetectedItemsToScene() |
|
2479 |
2018.11. euisung no more used |
|
2480 |
2018.11.29 euisung change name drawDetectedLines() -> createDetectedLines |
|
2481 |
''' |
|
2482 |
|
|
2483 |
def createDetectedLines(self, lineList, worker): |
|
2484 |
appDocData = AppDocData.instance() |
|
2485 |
area = appDocData.getArea('Drawing') |
|
2486 |
|
|
2487 |
for pts in lineList: |
|
2488 |
processLine = QEngineeringLineItem(vertices=[(area.x + param[0], area.y + param[1]) for param in pts]) |
|
2489 |
processLine.area = 'Drawing' |
|
2490 |
# self.graphicsView.scene().addItem(processLine) |
|
2491 |
appDocData.lines.append(processLine) |
|
2492 |
appDocData.allItems.append(processLine) |
|
2493 |
|
|
2494 |
# if processLine.length() > 100: # TODO: check critical length |
|
2495 |
# processLine.addFlowArrow() |
|
2496 |
|
|
2497 |
# re-order process line's start,end according to flow mark |
|
2498 |
# worker.arrangeLinePosition(lines, symbols, listWidget) |
|
2499 |
# up to here |
|
2500 |
|
|
2501 |
''' |
|
2502 |
history 2018.06.09 humkyung check length of original and connection point is 2 while parsing |
|
2503 |
2018.11.26 euisung remove scene dependency |
|
2504 |
2018.11.29 euisung change name drawDetectedSymbolItem() -> createDetectedSymbolItem |
|
2505 |
''' |
|
2506 |
|
|
2507 |
def createDetectedSymbolItem(self, symbolList): |
|
2508 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
|
2509 |
from SymbolSvgItem import SymbolSvgItem |
|
2510 |
import math |
|
2511 |
|
|
2512 |
try: |
|
2513 |
appDocData = AppDocData.instance() |
|
2514 |
project = appDocData.getCurrentProject() |
|
2515 |
|
|
2516 |
searchedMap = [] |
|
2517 |
for symbol in symbolList: |
|
2518 |
pt = [float(x) for x in symbol.getSp()] |
|
2519 |
size = [symbol.getWidth(), symbol.getHeight()] |
|
2520 |
name = symbol.getName() |
|
2521 |
angle = round(math.radians(symbol.getRotatedAngle()), 2) |
|
2522 |
_type = symbol.getType() |
|
2523 |
flip = symbol.getDetectFlip() |
|
2524 |
origin = [0, 0] |
|
2525 |
if 2 == len(symbol.getOriginalPoint().split(',')): |
|
2526 |
tokens = symbol.getOriginalPoint().split(',') |
|
2527 |
origin = [pt[0] + float(tokens[0]), pt[1] + float(tokens[1])] |
|
2528 |
connPts = [] |
|
2529 |
if symbol.getConnectionPoint() is not None and symbol.getConnectionPoint() != '': |
|
2530 |
for param in symbol.getConnectionPoint().split('/'): |
|
2531 |
tokens = param.split(',') |
|
2532 |
connPts.append( |
|
2533 |
('AUTO', pt[0] + float(tokens[0]), pt[1] + float(tokens[1]), '0') if len(tokens) == 2 else \ |
|
2534 |
(tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), '0') if len( |
|
2535 |
tokens) == 3 else \ |
|
2536 |
(tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), tokens[3]) if len( |
|
2537 |
tokens) == 4 else None) |
|
2538 |
|
|
2539 |
parentSymbol = symbol.getBaseSymbol() |
|
2540 |
childSymbol = symbol.getAdditionalSymbol() |
|
2541 |
hasInstrumentLabel = symbol.getHasInstrumentLabel() |
|
2542 |
|
|
2543 |
svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg') |
|
2544 |
if os.path.isfile(svgFilePath): |
|
2545 |
svg = SymbolSvgItem.createItem(_type, None, svgFilePath, owner=None, flip=flip) |
|
2546 |
svg.hit_ratio = symbol.hitRate |
|
2547 |
svg.buildItem(name, _type, angle, pt, size, origin, connPts, parentSymbol, childSymbol, |
|
2548 |
hasInstrumentLabel) |
|
2549 |
# svg.reCalculationRotatedItem() |
|
2550 |
svg.area = 'Drawing' |
|
2551 |
|
|
2552 |
# set owner - 2018.07.20 added by humkyung |
|
2553 |
matches = [searched for searched in searchedMap if searched[0] == symbol.owner] |
|
2554 |
if len(matches) == 1: |
|
2555 |
svg.owner = matches[0][1] |
|
2556 |
searchedMap.append((symbol, svg)) |
|
2557 |
# up to here |
|
2558 |
|
|
2559 |
svg.transfer.onRemoved.connect(self.itemRemoved) |
|
2560 |
# self.addSvgItemToScene(svg) |
|
2561 |
appDocData.symbols.append(svg) |
|
2562 |
appDocData.allItems.append(svg) |
|
2563 |
else: |
|
2564 |
item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1]) |
|
2565 |
item.isSymbol = True |
|
2566 |
item.angle = angle |
|
2567 |
item.setPen(QPen(Qt.red, 5, Qt.SolidLine)) |
|
2568 |
# self.graphicsView.scene().addItem(item) |
|
2569 |
# appDocData.symbols.append(item) |
|
2570 |
appDocData.allItems.append(item) |
|
2571 |
# up to here |
|
2572 |
except Exception as ex: |
|
2573 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
2574 |
sys.exc_info()[-1].tb_lineno) |
|
2575 |
self.addMessage.emit(MessageType.Error, message) |
|
2576 |
|
|
2577 |
''' |
|
2578 |
@history 2018.06.08 Jeongwoo Add parameter on round method |
|
2579 |
@history 2018.11.02 euisung Add save note text item |
|
2580 |
@history 2018.11.05 euisung delete save note text item and move to drawDetectedItems() |
|
2581 |
2018.11.26 euisung remove scene dependency |
|
2582 |
2018.11.29 euisung change name drawDetectedTextItem() -> createDetectedTextItem |
|
2583 |
''' |
|
2584 |
|
|
2585 |
def createDetectedTextItem(self, textInfoList): |
|
2586 |
from TextItemFactory import TextItemFactory |
|
2587 |
import math |
|
2588 |
|
|
2589 |
try: |
|
2590 |
appDocData = AppDocData.instance() |
|
2591 |
|
|
2592 |
# parse texts |
|
2593 |
for textInfo in textInfoList: |
|
2594 |
x = textInfo.getX() |
|
2595 |
y = textInfo.getY() |
|
2596 |
width = textInfo.getW() |
|
2597 |
height = textInfo.getH() |
|
2598 |
angle = round(math.radians(textInfo.getAngle()), 2) |
|
2599 |
text = textInfo.getText() |
|
2600 |
if not text: continue |
|
2601 |
|
|
2602 |
item = TextItemFactory.instance().createTextItem(textInfo) |
|
2603 |
if item is not None: |
|
2604 |
item.loc = [x, y] |
|
2605 |
item.size = (width, height) |
|
2606 |
item.angle = angle |
|
2607 |
item.area = 'Drawing' |
|
2608 |
item.transfer.onRemoved.connect(self.itemRemoved) |
|
2609 |
# self.addTextItemToScene(item) |
|
2610 |
# appDocData.texts.append(item) |
|
2611 |
appDocData.allItems.append(item) |
|
2612 |
except Exception as ex: |
|
2613 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
2614 |
sys.exc_info()[-1].tb_lineno) |
|
2615 |
self.addMessage.emit(MessageType.Error, message) |
|
2616 |
|
|
2617 |
''' |
|
2618 |
@brief draw detected texts except which in drawing area |
|
2619 |
@history 2018.11.29 euisung change name drawDetectedOtherTextItem() -> createDetectedOtherTextItem |
|
2620 |
''' |
|
2621 |
|
|
2622 |
def createDetectedOtherTextItem(self, otherTextInfoList): |
|
2623 |
from TextItemFactory import TextItemFactory |
|
2624 |
import math |
|
2625 |
|
|
2626 |
try: |
|
2627 |
appDocData = AppDocData.instance() |
|
2628 |
|
|
2629 |
# parse notes |
|
2630 |
for textInfoMap in otherTextInfoList: |
|
2631 |
if textInfoMap[0] == 'Note' or textInfoMap[1] is None: |
|
2632 |
pass |
|
2633 |
|
|
2634 |
for textInfo in textInfoMap[1]: |
|
2635 |
x = textInfo.getX() |
|
2636 |
y = textInfo.getY() |
|
2637 |
width = textInfo.getW() |
|
2638 |
height = textInfo.getH() |
|
2639 |
angle = round(math.radians(textInfo.getAngle())) |
|
2640 |
text = textInfo.getText() |
|
2641 |
|
|
2642 |
item = TextItemFactory.instance().createTextItem(textInfo) |
|
2643 |
|
|
2644 |
item.loc = [x, y] |
|
2645 |
item.size = (width, height) |
|
2646 |
item.angle = angle |
|
2647 |
item.area = textInfoMap[0] |
|
2648 |
item.transfer.onRemoved.connect(self.itemRemoved) |
|
2649 |
# appDocData.texts.append(item) |
|
2650 |
appDocData.allItems.append(item) |
|
2651 |
except Exception as ex: |
|
2652 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
2653 |
sys.exc_info()[-1].tb_lineno) |
|
2654 |
self.addMessage.emit(MessageType.Error, message) |
|
2655 |
|
|
2656 |
''' |
|
2657 |
@brief draw unknown items |
|
2658 |
@author humkyung |
|
2659 |
@date 2018.06.12 |
|
2660 |
@history 2018.06.14 Jeongwoo Change method to add unknown item |
|
2661 |
2018.06.18 Jeongwoo Add connect on unknown item |
|
2662 |
Add [transfer] for using pyqtSignal |
|
2663 |
2018.11.26 euisung remove scene dependency |
|
2664 |
2018.11.26 euisung isolate scene adding part -> drawDetectedItemsToScene() |
|
2665 |
2018.11.27 euisung add save to xml |
|
2666 |
2018.11.29 euisung change name drawUnknownItems() -> createUnknownItems |
|
2667 |
''' |
|
2668 |
|
|
2669 |
def createUnknownItems(self, path): |
|
2670 |
from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem |
|
2671 |
from EngineeringLineItem import QEngineeringLineItem |
|
2672 |
from EngineeringUnknownItem import QEngineeringUnknownItem |
|
2673 |
|
|
2674 |
try: |
|
2675 |
docData = AppDocData.instance() |
|
2676 |
project = docData.getCurrentProject() |
|
2677 |
windowSize = docData.getSlidingWindowSize() |
|
2678 |
|
|
2679 |
thickness = int(windowSize[1] / 2) |
|
2680 |
|
|
2681 |
if docData.needReOpening is not None: |
|
2682 |
docData.needReOpening = True |
|
2683 |
|
|
2684 |
diffFilePath = os.path.join(project.getTempPath(), "DIFF_" + os.path.basename(path)) |
|
2685 |
if os.path.isfile(diffFilePath): |
|
2686 |
imgDiff = cv2.threshold(cv2.cvtColor(cv2.imread(diffFilePath, 1), cv2.COLOR_BGR2GRAY), 0, 255, |
|
2687 |
cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] |
|
2688 |
|
|
2689 |
# remove line from image |
|
2690 |
lines = docData.lines |
|
2691 |
for line in lines: |
|
2692 |
line.drawToImage(imgDiff, 255, thickness) if line.thickness is None else \ |
|
2693 |
line.drawToImage(imgDiff, 255, line.thickness) |
|
2694 |
cv2.imwrite(diffFilePath, imgDiff) |
|
2695 |
# up to here |
|
2696 |
|
|
2697 |
imgNot = np.ones(imgDiff.shape, np.uint8) |
|
2698 |
cv2.bitwise_not(imgDiff, imgNot) |
|
2699 |
configs = docData.getConfigs('Filter', 'ErodeSize') |
|
2700 |
kernel = int(configs[0].value) if 1 == len(configs) else 3 |
|
2701 |
imgNot = cv2.erode(imgNot, np.ones((kernel, kernel), np.uint8)) |
|
2702 |
imgNot = cv2.dilate(imgNot, np.ones((8 + kernel, 8 + kernel), np.uint8)) |
|
2703 |
|
|
2704 |
contours, hierarchy = cv2.findContours(imgNot, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
|
2705 |
|
|
2706 |
## |
|
2707 |
idx = 0 |
|
2708 |
## |
|
2709 |
smallContours = [] |
|
2710 |
minimumSize = docData.getConfigs('Filter', 'MinimumSize') |
|
2711 |
for contour in contours: |
|
2712 |
[x, y, w, h] = cv2.boundingRect(contour) |
|
2713 |
|
|
2714 |
# remove too small one |
|
2715 |
if len(minimumSize) is 1: |
|
2716 |
if (w * h < int(minimumSize[0].value) * int(minimumSize[0].value)): |
|
2717 |
smallContours.append(contour) |
|
2718 |
idx += 1 |
|
2719 |
continue |
|
2720 |
|
|
2721 |
''' |
|
2722 |
rect = QRectF(x, y, w, h) |
|
2723 |
items = [item for item in diffItems if item.boundingRect().contains(rect)] |
|
2724 |
if len(items) > 0: continue |
|
2725 |
|
|
2726 |
items = [item for item in diffItems if rect.contains(item.boundingRect())] |
|
2727 |
for item in items: |
|
2728 |
diffItems.remove(item) |
|
2729 |
''' |
|
2730 |
|
|
2731 |
# create unknown item |
|
2732 |
epsilon = cv2.arcLength(contour, True) * 0.001 |
|
2733 |
approx = cv2.approxPolyDP(contour, epsilon, True) |
|
2734 |
approx = [pt[0] for pt in approx] |
|
2735 |
resultStr, resultList = self.determineRemainObject(idx, contours, imgNot) |
|
2736 |
if resultStr == 'LineIndicator': |
|
2737 |
item = QEngineeringUnknownItem(approx, 'True', resultList[0], resultList[1]) |
|
2738 |
docData.lineIndicators.append(item) |
|
2739 |
elif resultStr == 'MissingLine': |
|
2740 |
pass |
|
2741 |
elif resultStr == 'Unknown': |
|
2742 |
item = QEngineeringUnknownItem(approx, 'False') |
|
2743 |
docData.unknowns.append(item) |
|
2744 |
item.area = 'Drawing' |
|
2745 |
docData.allItems.append(item) |
|
2746 |
item.transfer.onRemoved.connect(self.itemRemoved) |
|
2747 |
idx += 1 |
|
2748 |
# up to here |
|
2749 |
|
|
2750 |
imgNotRemoveSmall = cv2.drawContours(imgNot, smallContours, -1, 0, -1) |
|
2751 |
notFilePath = os.path.join(project.getTempPath(), "NOT_" + os.path.basename(path)) |
|
2752 |
cv2.imwrite(notFilePath, imgNotRemoveSmall) |
|
2753 |
else: |
|
2754 |
message = 'can\'t found {}'.format(diffFilePath) |
|
2755 |
self.addMessage.emit(MessageType.Normal, message) |
|
2756 |
except Exception as ex: |
|
2757 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
2758 |
sys.exc_info()[-1].tb_lineno) |
|
2759 |
self.addMessage.emit(MessageType.Error, message) |
|
2760 |
|
|
2761 |
def determineRemainObject(self, idx, contours, imgNot): |
|
2762 |
''' |
|
2763 |
@brief determine remain objects -> line no indicator or unknown |
|
2764 |
@author euisung |
|
2765 |
@date 2018.12.26 |
|
2766 |
@history 2019.03.25 euisung Change name isLineNoIndicator -> determineRemainObject |
|
2767 |
''' |
|
2768 |
import math |
|
2769 |
[x, y, w, h] = cv2.boundingRect(contours[idx]) |
|
2770 |
|
|
2771 |
if (w < 250 and h < 250): |
|
2772 |
return ('Unknown', []) |
|
2773 |
|
|
2774 |
fLines = [] |
|
2775 |
maxDifAngle = 3 |
|
2776 |
mask = np.zeros_like(imgNot) |
|
2777 |
cv2.drawContours(mask, contours, idx, 123, -1) # Draw filled contour in mask |
|
2778 |
out = np.zeros_like(imgNot) # Extract out the object and place into output image |
|
2779 |
out[mask == 123] = imgNot[mask == 123] |
|
2780 |
|
|
2781 |
# Now crop |
|
2782 |
##print(out) |
|
2783 |
(x, y) = np.where(mask == 123) |
|
2784 |
(topx, topy) = (np.min(x), np.min(y)) |
|
2785 |
(bottomx, bottomy) = (np.max(x), np.max(y)) |
|
2786 |
out = out[topx:bottomx + 1, topy:bottomy + 1] |
|
2787 |
h, w = out.shape[0], out.shape[1] |
|
2788 |
maxDifH, maxDifW = math.ceil(math.tan(4 * math.pi / 180) / 2 * w), math.ceil( |
|
2789 |
math.tan(4 * math.pi / 180) / 2 * h) |
|
2790 |
|
|
2791 |
# detection lines |
|
2792 |
edged2 = cv2.Canny(out, 100, 200) |
|
2793 |
lines = cv2.HoughLinesP(image=edged2, rho=1, theta=np.pi / 180, threshold=25, minLineLength=30, maxLineGap=25) |
|
2794 |
# lines = cv2.HoughLines(edged2, 1, np.pi/180, 60) |
|
2795 |
if lines is None: |
|
2796 |
return ('Unknown', []) |
|
2797 |
for line in lines: |
|
2798 |
# r, theta = line[0] |
|
2799 |
# a, b = np.cos(theta), np.sin(theta) |
|
2800 |
# x0, y0 = a * r, b * r |
|
2801 |
# x1, y1 = int(x0 + 1000 * (-b)), int(y0 + 1000 * a) |
|
2802 |
# x2, y2 = int(x0 - 1000 * (-b)), int(y0 - 1000 * a) |
|
2803 |
# cv2.line(out, (x1, y1), (x2, y2), (0, 255, 0), 3) |
|
2804 |
x1, y1, x2, y2 = line[0] |
|
2805 |
degree = math.atan2(y2 - y1, x2 - x1) * 180 / math.pi |
|
2806 |
fLine = [x1, y1, x2, y2, degree] |
|
2807 |
# print(fLine) |
|
2808 |
fLines.append(fLine) |
|
2809 |
|
|
2810 |
horLines = [] |
|
2811 |
verLines = [] |
|
2812 |
otherLines = [] |
|
2813 |
isVH = None |
|
2814 |
for fLine in fLines: |
|
2815 |
degree = math.fabs(fLine[4]) |
|
2816 |
if degree >= 90 - maxDifAngle: |
|
2817 |
verLines.append(fLine) |
|
2818 |
elif degree <= maxDifAngle: |
|
2819 |
horLines.append(fLine) |
|
2820 |
else: |
|
2821 |
otherLines.append(fLine) |
|
2822 |
|
|
2823 |
baseLines = [] |
|
2824 |
baseDifV = 0 |
|
2825 |
if len(horLines): |
|
2826 |
x, y = w / 2, 0 |
|
2827 |
baseDifV = maxDifH |
|
2828 |
for horLine in horLines: |
|
2829 |
x1, y1, x2, y2 = horLine[0], horLine[1], horLine[2], horLine[3] |
|
2830 |
y = ((y2 - y1) / (x2 - x1)) * x + y1 - ((y2 - y1) / (x2 - x1)) * x1 |
|
2831 |
horLine.append(y) |
|
2832 |
baseLines = horLines |
|
2833 |
isVH = 'H' |
|
2834 |
if len(verLines): |
|
2835 |
x, y = 0, h / 2 |
|
2836 |
baseDifV = maxDifW |
|
2837 |
for verLine in verLines: |
|
2838 |
x1, y1, x2, y2 = verLine[0], verLine[1], verLine[2], verLine[3] |
|
2839 |
x = ((x2 - x1) / (y2 - y1)) * y + x1 - ((x2 - x1) / (y2 - y1)) * y1 |
|
2840 |
verLine.append(x) |
|
2841 |
baseLines = verLines |
|
2842 |
isVH = 'V' |
|
2843 |
|
|
2844 |
for otherLine in otherLines: |
|
2845 |
x, y = w / 2, 0 |
|
2846 |
x1, y1, x2, y2 = otherLine[0], otherLine[1], otherLine[2], otherLine[3] |
|
2847 |
y = ((y2 - y1) / (x2 - x1)) * x + y1 - ((y2 - y1) / (x2 - x1)) * x1 |
|
2848 |
otherLine.append(y) |
|
2849 |
|
|
2850 |
# determine line no indicator |
|
2851 |
if not ((len(horLines) > 0 and len(verLines) > 0) or len(otherLines) is 0 or ( |
|
2852 |
len(horLines) == 0 and len(verLines) == 0)): |
|
2853 |
result, mergedOtherLine = self.isLineNoIndicator(w, h, maxDifAngle, baseDifV, baseLines, otherLines) |
|
2854 |
if result: |
|
2855 |
# print(fLines) |
|
2856 |
return ('LineIndicator', [isVH, mergedOtherLine]) |
|
2857 |
|
|
2858 |
return ('Unknown', []) |
|
2859 |
|
|
2860 |
def isLineNoIndicator(self, w, h, maxDifAngle, baseDifV, baseLines, otherLines): |
|
2861 |
''' |
|
2862 |
@brief determine line no indicator |
|
2863 |
@author euisung |
|
2864 |
@date 2019.03.25 |
|
2865 |
''' |
|
2866 |
import math |
|
2867 |
|
|
2868 |
if (w < 250 and h < 250): |
|
2869 |
return (False, None) |
|
2870 |
|
|
2871 |
isSameLine = True |
|
2872 |
i = 0 |
|
2873 |
for baseLine in baseLines: |
|
2874 |
if not isSameLine: break |
|
2875 |
j = 0 |
|
2876 |
for baseLinee in baseLines: |
|
2877 |
if i == j: |
|
2878 |
j += 1 |
|
2879 |
continue |
|
2880 |
difV = math.fabs(baseLine[5] - baseLinee[5]) |
|
2881 |
if difV > baseDifV: |
|
2882 |
isSameLine = False |
|
2883 |
break |
|
2884 |
j += 1 |
|
2885 |
i += 1 |
|
2886 |
if not isSameLine: |
|
2887 |
return (False, None) |
|
2888 |
|
|
2889 |
isSameLine = True |
|
2890 |
i = 0 |
|
2891 |
maxY = 0 |
|
2892 |
for otherLine in otherLines: |
|
2893 |
y = otherLine[5] |
|
2894 |
if math.fabs(y) > maxY: |
|
2895 |
maxY = math.fabs(y) |
|
2896 |
if not isSameLine: break |
|
2897 |
j = 0 |
|
2898 |
for otherLinee in otherLines: |
|
2899 |
if i == j: |
|
2900 |
j += 1 |
|
2901 |
continue |
|
2902 |
difV = math.fabs(otherLine[4] - otherLinee[4]) |
|
2903 |
if difV > maxDifAngle: |
|
2904 |
isSameLine = False |
|
2905 |
break |
|
2906 |
j += 1 |
|
2907 |
i += 1 |
|
2908 |
if not isSameLine: |
|
2909 |
return (False, None) |
|
2910 |
|
|
2911 |
isSameLine = True |
|
2912 |
mergedOtherLine = [0, 0, 0, 0] |
|
2913 |
i = 0 |
|
2914 |
maxDif = math.ceil(math.tan(4 * math.pi / 180) * maxY) |
|
2915 |
for otherLine in otherLines: |
|
2916 |
if not isSameLine: break |
|
2917 |
j = 0 |
|
2918 |
for otherLinee in otherLines: |
|
2919 |
if i == j: |
|
2920 |
j += 1 |
|
2921 |
continue |
|
2922 |
angle = math.fabs(otherLine[4] + otherLinee[4]) / 2 |
|
2923 |
difV = math.fabs(otherLine[5] - otherLinee[5]) |
|
2924 |
dist = math.sin((90 - angle) * math.pi / 180) * difV |
|
2925 |
if dist > maxDif: |
|
2926 |
isSameLine = False |
|
2927 |
break |
|
2928 |
j += 1 |
|
2929 |
i += 1 |
|
2930 |
mergedOtherLine[0] += otherLine[0] |
|
2931 |
mergedOtherLine[1] += otherLine[1] |
|
2932 |
mergedOtherLine[2] += otherLine[2] |
|
2933 |
mergedOtherLine[3] += otherLine[3] |
|
2934 |
if not isSameLine: |
|
2935 |
(False, None) |
|
2936 |
|
|
2937 |
# Show the output image |
|
2938 |
# print('line no indicator') |
|
2939 |
mergedOtherLine[0] = round(mergedOtherLine[0] / len(otherLines)) |
|
2940 |
mergedOtherLine[1] = round(mergedOtherLine[1] / len(otherLines)) |
|
2941 |
mergedOtherLine[2] = round(mergedOtherLine[2] / len(otherLines)) |
|
2942 |
mergedOtherLine[3] = round(mergedOtherLine[3] / len(otherLines)) |
|
2943 |
# cv2.line(out, (mergedOtherLine[0], mergedOtherLine[1]), (mergedOtherLine[2], mergedOtherLine[3]), (255, 255, 255), 3) |
|
2944 |
# cv2.imshow('Output', out) |
|
2945 |
# cv2.waitKey(0) |
|
2946 |
# cv2.destroyAllWindows() |
|
2947 |
return (True, mergedOtherLine) |
|
2948 |
|
|
2949 | 2263 |
def init_add_tree_item(self, line_no_tree_item, run_item): |
2950 | 2264 |
""" insert symbol item and find line no as owner """ |
2951 | 2265 |
# insert |
... | ... | |
2999 | 2313 |
item.attribute = text['Value'] |
3000 | 2314 |
name = text['Name'] |
3001 | 2315 |
item.transfer.onRemoved.connect(self.itemRemoved) |
3002 |
self.addTextItemToScene(item)
|
|
2316 |
item.addTextItemToScene(self.graphicsView.scene())
|
|
3003 | 2317 |
|
3004 | 2318 |
self.progress.setValue(self.progress.value() + 1) |
3005 | 2319 |
|
... | ... | |
3014 | 2328 |
attributeValue = note['Value'] |
3015 | 2329 |
name = note['Name'] |
3016 | 2330 |
item.transfer.onRemoved.connect(self.itemRemoved) |
3017 |
self.addTextItemToScene(item)
|
|
2331 |
item.addTextItemToScene(self.graphicsView.scene())
|
|
3018 | 2332 |
|
3019 | 2333 |
self.progress.setValue(self.progress.value() + 1) |
3020 | 2334 |
|
... | ... | |
3284 | 2598 |
attributeValue = text.find('ATTRIBUTEVALUE') |
3285 | 2599 |
name = text.find('NAME').text |
3286 | 2600 |
item.transfer.onRemoved.connect(self.itemRemoved) |
3287 |
self.addTextItemToScene(item)
|
|
2601 |
item.addTextItemToScene(self.graphicsView.scene())
|
|
3288 | 2602 |
# docData.texts.append(item) |
3289 | 2603 |
|
3290 | 2604 |
if name == 'TEXT': |
... | ... | |
3304 | 2618 |
attributeValue = text.find('ATTRIBUTEVALUE') |
3305 | 2619 |
name = text.find('NAME').text |
3306 | 2620 |
item.transfer.onRemoved.connect(self.itemRemoved) |
3307 |
self.addTextItemToScene(item)
|
|
2621 |
item.addTextItemToScene(self.graphicsView.scene())
|
|
3308 | 2622 |
|
3309 | 2623 |
if name == 'NOTE': |
3310 | 2624 |
if uid is not None: |
... | ... | |
3353 | 2667 |
line_no = QEngineeringLineNoTextItem.fromXml(line_no_node) |
3354 | 2668 |
if line_no is None: continue |
3355 | 2669 |
line_no.transfer.onRemoved.connect(self.itemRemoved) |
3356 |
self.addTextItemToScene(line_no)
|
|
2670 |
line_no.addTextItemToScene(self.graphicsView.scene())
|
|
3357 | 2671 |
line_no_tree_item = self.itemTreeWidget.addTreeItem(self.itemTreeWidget.root, line_no) |
3358 | 2672 |
if type(line_no) is not QEngineeringLineNoTextItem: continue |
3359 | 2673 |
|
... | ... | |
3479 | 2793 |
''' |
3480 | 2794 |
@brief Remove added item on same place and Add GraphicsItem |
3481 | 2795 |
@author Jeongwoo |
3482 |
@date 2018.05.25 |
|
3483 |
@history 2018.05.29 Jeongwoo Moved from QRecognitionDialog |
|
3484 |
2018.06.05 Jeongwoo Remove Size condition |
|
3485 |
2018.06.18 Jeongwoo Set Z-index |
|
3486 |
''' |
|
3487 |
|
|
3488 |
def addTextItemToScene(self, textItem): |
|
3489 |
textItem.addTextItemToScene(self.graphicsView.scene()) |
|
3490 |
|
|
3491 |
''' |
|
3492 |
@brief Remove added item on same place and Add GraphicsItem |
|
3493 |
@author Jeongwoo |
|
3494 | 2796 |
@date 2018.05.29 |
3495 | 2797 |
@history 2018.06.18 Jeongwoo Set Z-index |
3496 | 2798 |
''' |
DTI_PID/DTI_PID/MainWindow_UI.py | ||
---|---|---|
1 | 1 |
# -*- coding: utf-8 -*- |
2 | 2 |
|
3 |
# Form implementation generated from reading ui file './UI/MainWindow.ui'
|
|
3 |
# Form implementation generated from reading ui file '.\UI\MainWindow.ui'
|
|
4 | 4 |
# |
5 |
# Created by: PyQt5 UI code generator 5.11.3
|
|
5 |
# Created by: PyQt5 UI code generator 5.14.2
|
|
6 | 6 |
# |
7 | 7 |
# WARNING! All changes made in this file will be lost! |
8 | 8 |
|
9 |
|
|
9 | 10 |
from PyQt5 import QtCore, QtGui, QtWidgets |
10 | 11 |
|
12 |
|
|
11 | 13 |
class Ui_MainWindow(object): |
12 | 14 |
def setupUi(self, MainWindow): |
13 | 15 |
MainWindow.setObjectName("MainWindow") |
... | ... | |
181 | 183 |
self.verticalLayoutDrawingList.setObjectName("verticalLayoutDrawingList") |
182 | 184 |
self.horizontalLayout_4 = QtWidgets.QHBoxLayout() |
183 | 185 |
self.horizontalLayout_4.setObjectName("horizontalLayout_4") |
184 |
self.pushButtonBatchRecognition = QtWidgets.QPushButton(self.tabDrawingList) |
|
185 |
self.pushButtonBatchRecognition.setMaximumSize(QtCore.QSize(80, 16777215)) |
|
186 |
self.pushButtonBatchRecognition.setObjectName("pushButtonBatchRecognition") |
|
187 |
self.horizontalLayout_4.addWidget(self.pushButtonBatchRecognition) |
|
188 | 186 |
spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) |
189 | 187 |
self.horizontalLayout_4.addItem(spacerItem1) |
190 | 188 |
self.pushButtonRefreshDrawings = QtWidgets.QPushButton(self.tabDrawingList) |
... | ... | |
655 | 653 |
self.retranslateUi(MainWindow) |
656 | 654 |
self.tabWidget.setCurrentIndex(0) |
657 | 655 |
self.tabWidgetSymbolProperty.setCurrentIndex(0) |
658 |
self.tabWidgetItemExplorer.setCurrentIndex(0)
|
|
656 |
self.tabWidgetItemExplorer.setCurrentIndex(1)
|
|
659 | 657 |
self.tabWidget_2.setCurrentIndex(0) |
660 | 658 |
QtCore.QMetaObject.connectSlotsByName(MainWindow) |
661 | 659 |
|
... | ... | |
680 | 678 |
self.tabWidgetSymbolProperty.setTabText(self.tabWidgetSymbolProperty.indexOf(self.tabSymbolProperty), _translate("MainWindow", "Property")) |
681 | 679 |
self.dockWidgetObjectExplorer.setWindowTitle(_translate("MainWindow", "Object Explorer")) |
682 | 680 |
self.tabWidgetItemExplorer.setTabText(self.tabWidgetItemExplorer.indexOf(self.tabItemProperty), _translate("MainWindow", "Object Explorer")) |
683 |
self.pushButtonBatchRecognition.setText(_translate("MainWindow", "Batch Job")) |
|
684 | 681 |
self.pushButtonRefreshDrawings.setText(_translate("MainWindow", "Refresh Drawing List")) |
685 | 682 |
self.treeWidgetDrawingList.setSortingEnabled(True) |
686 | 683 |
self.tabWidgetItemExplorer.setTabText(self.tabWidgetItemExplorer.indexOf(self.tabDrawingList), _translate("MainWindow", "Drawing List")) |
... | ... | |
777 | 774 |
self.actionUndo.setToolTip(_translate("MainWindow", "Undo")) |
778 | 775 |
self.actionRedo.setText(_translate("MainWindow", "Redo")) |
779 | 776 |
self.actionRedo.setToolTip(_translate("MainWindow", "Redo")) |
780 |
|
|
781 | 777 |
import MainWindow_rc |
782 |
|
|
783 |
if __name__ == "__main__": |
|
784 |
import sys |
|
785 |
app = QtWidgets.QApplication(sys.argv) |
|
786 |
MainWindow = QtWidgets.QMainWindow() |
|
787 |
ui = Ui_MainWindow() |
|
788 |
ui.setupUi(MainWindow) |
|
789 |
MainWindow.show() |
|
790 |
sys.exit(app.exec_()) |
|
791 |
|
DTI_PID/DTI_PID/QtImageViewerScene.py | ||
---|---|---|
114 | 114 |
|
115 | 115 |
super(QtImageViewerScene, self).keyReleaseEvent(event) |
116 | 116 |
|
117 |
def mousePressEvent(self, event: 'QGraphicsSceneMouseEvent') -> None: |
|
118 |
if self.selectedItems(): |
|
119 |
self._pressed_position = event.scenePos() |
|
120 |
elif not self.selectedItems() and self.items(event.scenePos()): |
|
121 |
self._pressed_position = event.scenePos() |
|
122 |
|
|
123 |
super(QtImageViewerScene, self).mousePressEvent(event) |
|
124 |
|
|
125 |
def mouseReleaseEvent(self, event: 'QGraphicsSceneMouseEvent') -> None: |
|
126 |
from MoveCommand import MoveCommand |
|
127 |
|
|
128 |
if self._pressed_position and self._pressed_position != event.scenePos() and self.selectedItems(): |
|
129 |
self._undo_stack.push(MoveCommand(self, event.scenePos() - self._pressed_position)) |
|
130 |
|
|
131 |
self._pressed_position = None |
|
132 |
super(QtImageViewerScene, self).mouseReleaseEvent(event) |
|
133 |
|
|
117 | 134 |
def clear(self): |
118 | 135 |
"""clear undo stack""" |
119 | 136 |
self._undo_stack.clear() |
DTI_PID/DTI_PID/RecognitionDialog.py | ||
---|---|---|
92 | 92 |
def procCounter(self): # A slot takes no params |
93 | 93 |
try: |
94 | 94 |
if self.isSymbolChecked or self.isTrainingChecked: |
95 |
Worker.executeRecognition(self.createDetectedItems, self.path, self.listWidget, self.isLineChecked, |
|
96 |
self, self.batch, self.createUnknownItems) |
|
95 |
Worker.executeRecognition(self.path, self.listWidget, self.isLineChecked, self) |
|
97 | 96 |
except Exception as ex: |
98 | 97 |
from App import App |
99 | 98 |
from AppDocData import MessageType |
... | ... | |
201 | 200 |
sys.exc_info()[-1].tb_lineno) |
202 | 201 |
App.mainWnd().addMessage.emit(MessageType.Error, message) |
203 | 202 |
|
203 |
def add_detected_items_to_scene(self, scene) -> None: |
|
204 |
"""add detected items to scene""" |
|
205 |
from SaveWorkCommand import SaveWorkCommand |
|
206 |
|
|
207 |
app_doc_data = AppDocData.instance() |
|
208 |
|
|
209 |
try: |
|
210 |
for symbol in app_doc_data.symbols: |
|
211 |
if issubclass(type(symbol), SymbolSvgItem): |
|
212 |
symbol.addSvgItemToScene(scene) |
|
213 |
else: |
|
214 |
scene.addItem(symbol) |
|
215 |
|
|
216 |
for text in app_doc_data.texts: |
|
217 |
text.addTextItemToScene(scene) |
|
218 |
|
|
219 |
for lineNo in app_doc_data.tracerLineNos: |
|
220 |
lineNo.addTextItemToScene(scene) |
|
221 |
|
|
222 |
# remove lines which is located inside symbol |
|
223 |
for symbol in app_doc_data.symbols: |
|
224 |
rect = symbol.sceneBoundingRect() |
|
225 |
rect.adjust(-10, -10, 10, 10) |
|
226 |
matches = [line for line in app_doc_data.lines if rect.contains(line.line().p1()) and |
|
227 |
rect.contains(line.line().p2()) and |
|
228 |
not line.has_connection] |
|
229 |
app_doc_data.lines = [line for line in app_doc_data.lines if line not in matches] |
|
230 |
# up to here |
|
231 |
|
|
232 |
for line in app_doc_data.lines: |
|
233 |
scene.addItem(line) |
|
234 |
# line.transfer.onRemoved.connect(self.itemRemoved) |
|
235 |
for conn in line.connectors: |
|
236 |
conn.transfer.onPosChanged.connect(line.onConnectorPosChaned) |
|
237 |
|
|
238 |
for unknown in app_doc_data.unknowns + app_doc_data.lineIndicators: |
|
239 |
scene.addItem(unknown) |
|
240 |
|
|
241 |
# save scene |
|
242 |
SaveWorkCommand.save_to_database() |
|
243 |
SaveWorkCommand.save_to_xml() |
|
244 |
except Exception as ex: |
|
245 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
246 |
sys.exc_info()[-1].tb_lineno) |
|
247 |
self.displayLog.emit(MessageType.Error, message) |
|
248 |
|
|
249 |
def create_detected_items(self, symbolList, textInfoList, otherTextInfoList, titleBlockTextInfoList): |
|
250 |
try: |
|
251 |
QApplication.processEvents() |
|
252 |
self.create_detected_symbol_item(symbolList) |
|
253 |
QApplication.processEvents() |
|
254 |
self.create_detected_text_item(textInfoList) |
|
255 |
QApplication.processEvents() |
|
256 |
self.create_detected_other_text_item(otherTextInfoList) |
|
257 |
QApplication.processEvents() |
|
258 |
self.create_detected_title_block_text_item(titleBlockTextInfoList) |
|
259 |
|
|
260 |
# update scene |
|
261 |
# self.graphicsView.scene().update(self.graphicsView.sceneRect()) |
|
262 |
except Exception as ex: |
|
263 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
264 |
sys.exc_info()[-1].tb_lineno) |
|
265 |
self.displayLog.emit(MessageType.Error, message) |
|
266 |
|
|
267 |
''' |
|
268 |
history 2018.06.09 humkyung check length of original and connection point is 2 while parsing |
|
269 |
2018.11.26 euisung remove scene dependency |
|
270 |
2018.11.29 euisung change name drawDetectedSymbolItem() -> createDetectedSymbolItem |
|
271 |
''' |
|
272 |
|
|
273 |
def create_detected_symbol_item(self, symbolList): |
|
274 |
from GraphicsBoundingBoxItem import QGraphicsBoundingBoxItem |
|
275 |
from SymbolSvgItem import SymbolSvgItem |
|
276 |
import math |
|
277 |
|
|
278 |
try: |
|
279 |
app_doc_data = AppDocData.instance() |
|
280 |
project = app_doc_data.getCurrentProject() |
|
281 |
|
|
282 |
searchedMap = [] |
|
283 |
for symbol in symbolList: |
|
284 |
pt = [float(x) for x in symbol.getSp()] |
|
285 |
size = [symbol.getWidth(), symbol.getHeight()] |
|
286 |
name = symbol.getName() |
|
287 |
angle = round(math.radians(symbol.getRotatedAngle()), 2) |
|
288 |
_type = symbol.getType() |
|
289 |
flip = symbol.getDetectFlip() |
|
290 |
origin = [0, 0] |
|
291 |
if 2 == len(symbol.getOriginalPoint().split(',')): |
|
292 |
tokens = symbol.getOriginalPoint().split(',') |
|
293 |
origin = [pt[0] + float(tokens[0]), pt[1] + float(tokens[1])] |
|
294 |
connPts = [] |
|
295 |
if symbol.getConnectionPoint() is not None and symbol.getConnectionPoint() != '': |
|
296 |
for param in symbol.getConnectionPoint().split('/'): |
|
297 |
tokens = param.split(',') |
|
298 |
connPts.append( |
|
299 |
('AUTO', pt[0] + float(tokens[0]), pt[1] + float(tokens[1]), '0') if len(tokens) == 2 else \ |
|
300 |
(tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), '0') if len( |
|
301 |
tokens) == 3 else \ |
|
302 |
(tokens[0], pt[0] + float(tokens[1]), pt[1] + float(tokens[2]), tokens[3]) if len( |
|
303 |
tokens) == 4 else None) |
|
304 |
|
|
305 |
parentSymbol = symbol.getBaseSymbol() |
|
306 |
childSymbol = symbol.getAdditionalSymbol() |
|
307 |
hasInstrumentLabel = symbol.getHasInstrumentLabel() |
|
308 |
|
|
309 |
svgFilePath = os.path.join(project.getSvgFilePath(), _type, name + '.svg') |
|
310 |
if os.path.isfile(svgFilePath): |
|
311 |
svg = SymbolSvgItem.createItem(_type, None, svgFilePath, owner=None, flip=flip) |
|
312 |
svg.hit_ratio = symbol.hitRate |
|
313 |
svg.buildItem(name, _type, angle, pt, size, origin, connPts, parentSymbol, childSymbol, |
|
314 |
hasInstrumentLabel) |
|
315 |
svg.area = 'Drawing' |
|
316 |
|
|
317 |
# set owner - 2018.07.20 added by humkyung |
|
318 |
matches = [searched for searched in searchedMap if searched[0] == symbol.owner] |
|
319 |
if len(matches) == 1: |
|
320 |
svg.owner = matches[0][1] |
|
321 |
searchedMap.append((symbol, svg)) |
|
322 |
# up to here |
|
323 |
|
|
324 |
# self.addSvgItemToScene(svg) |
|
325 |
app_doc_data.symbols.append(svg) |
|
326 |
app_doc_data.allItems.append(svg) |
|
327 |
else: |
|
328 |
item = QGraphicsBoundingBoxItem(pt[0], pt[1], size[0], size[1]) |
|
329 |
item.isSymbol = True |
|
330 |
item.angle = angle |
|
331 |
item.setPen(QPen(Qt.red, 5, Qt.SolidLine)) |
|
332 |
# self.graphicsView.scene().addItem(item) |
|
333 |
# appDocData.symbols.append(item) |
|
334 |
app_doc_data.allItems.append(item) |
|
335 |
# up to here |
|
336 |
except Exception as ex: |
|
337 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
338 |
sys.exc_info()[-1].tb_lineno) |
|
339 |
self.displayLog.emit(MessageType.Error, message) |
|
340 |
|
|
341 |
''' |
|
342 |
@history 2018.06.08 Jeongwoo Add parameter on round method |
|
343 |
@history 2018.11.02 euisung Add save note text item |
|
344 |
@history 2018.11.05 euisung delete save note text item and move to drawDetectedItems() |
|
345 |
2018.11.26 euisung remove scene dependency |
|
346 |
2018.11.29 euisung change name drawDetectedTextItem() -> createDetectedTextItem |
|
347 |
''' |
|
348 |
|
|
349 |
def create_detected_text_item(self, textInfoList): |
|
350 |
from TextItemFactory import TextItemFactory |
|
351 |
import math |
|
352 |
|
|
353 |
try: |
|
354 |
app_doc_data = AppDocData.instance() |
|
355 |
|
|
356 |
# parse texts |
|
357 |
for textInfo in textInfoList: |
|
358 |
x = textInfo.getX() |
|
359 |
y = textInfo.getY() |
|
360 |
width = textInfo.getW() |
|
361 |
height = textInfo.getH() |
|
362 |
angle = round(math.radians(textInfo.getAngle()), 2) |
|
363 |
text = textInfo.getText() |
|
364 |
if not text: continue |
|
365 |
|
|
366 |
item = TextItemFactory.instance().createTextItem(textInfo) |
|
367 |
if item is not None: |
|
368 |
item.loc = [x, y] |
|
369 |
item.size = (width, height) |
|
370 |
item.angle = angle |
|
371 |
item.area = 'Drawing' |
|
372 |
#item.transfer.onRemoved.connect(self.itemRemoved) |
|
373 |
# self.addTextItemToScene(item) |
|
374 |
# appDocData.texts.append(item) |
|
375 |
app_doc_data.allItems.append(item) |
|
376 |
except Exception as ex: |
|
377 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
378 |
sys.exc_info()[-1].tb_lineno) |
|
379 |
self.displayLog.emit(MessageType.Error, message) |
|
380 |
|
|
381 |
''' |
|
382 |
@brief draw detected texts except which in drawing area |
|
383 |
@history 2018.11.29 euisung change name drawDetectedOtherTextItem() -> createDetectedOtherTextItem |
|
384 |
''' |
|
385 |
|
|
386 |
def create_detected_other_text_item(self, otherTextInfoList): |
|
387 |
from TextItemFactory import TextItemFactory |
|
388 |
import math |
|
389 |
|
|
390 |
try: |
|
391 |
app_doc_data = AppDocData.instance() |
|
392 |
|
|
393 |
# parse notes |
|
394 |
for textInfoMap in otherTextInfoList: |
|
395 |
if textInfoMap[0] == 'Note' or textInfoMap[1] is None: |
|
396 |
pass |
|
397 |
|
|
398 |
for textInfo in textInfoMap[1]: |
|
399 |
x = textInfo.getX() |
|
400 |
y = textInfo.getY() |
|
401 |
width = textInfo.getW() |
|
402 |
height = textInfo.getH() |
|
403 |
angle = round(math.radians(textInfo.getAngle())) |
|
404 |
text = textInfo.getText() |
|
405 |
|
|
406 |
item = TextItemFactory.instance().createTextItem(textInfo) |
|
407 |
|
|
408 |
item.loc = [x, y] |
|
409 |
item.size = (width, height) |
|
410 |
item.angle = angle |
|
411 |
item.area = textInfoMap[0] |
|
412 |
item.transfer.onRemoved.connect(self.itemRemoved) |
|
413 |
# appDocData.texts.append(item) |
|
414 |
app_doc_data.allItems.append(item) |
|
415 |
except Exception as ex: |
|
416 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
417 |
sys.exc_info()[-1].tb_lineno) |
|
418 |
self.displayLog.emit(MessageType.Error, message) |
|
419 |
|
|
420 |
def create_detected_title_block_text_item(self, textInfoList): |
|
421 |
"""draw title block""" |
|
422 |
from TextItemFactory import TextItemFactory |
|
423 |
import math |
|
424 |
|
|
425 |
try: |
|
426 |
app_doc_data = AppDocData.instance() |
|
427 |
|
|
428 |
# parse texts |
|
429 |
for textInfos in textInfoList: |
|
430 |
if len(textInfos[1]) is 0: |
|
431 |
continue |
|
432 |
|
|
433 |
for textInfo in textInfos[1]: |
|
434 |
x = textInfo.getX() |
|
435 |
y = textInfo.getY() |
|
436 |
width = textInfo.getW() |
|
437 |
height = textInfo.getH() |
|
438 |
angle = round(math.radians(textInfo.getAngle()), 2) |
|
439 |
text = textInfo.getText() |
|
440 |
if not text: continue |
|
441 |
item = TextItemFactory.instance().createTextItem(textInfo) |
|
442 |
|
|
443 |
if item is not None: |
|
444 |
item.loc = [x, y] |
|
445 |
item.size = (width, height) |
|
446 |
item.angle = angle |
|
447 |
item.area = textInfos[0] |
|
448 |
# self.addTextItemToScene(item) |
|
449 |
# appDocData.texts.append(item) |
|
450 |
app_doc_data.allItems.append(item) |
|
451 |
except Exception as ex: |
|
452 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
453 |
sys.exc_info()[-1].tb_lineno) |
|
454 |
self.displayLog.emit(MessageType.Error, message) |
|
455 |
|
|
456 |
''' |
|
457 |
@brief draw unknown items |
|
458 |
@author humkyung |
|
459 |
@date 2018.06.12 |
|
460 |
@history 2018.06.14 Jeongwoo Change method to add unknown item |
|
461 |
2018.06.18 Jeongwoo Add connect on unknown item |
|
462 |
Add [transfer] for using pyqtSignal |
|
463 |
2018.11.26 euisung remove scene dependency |
|
464 |
2018.11.26 euisung isolate scene adding part -> drawDetectedItemsToScene() |
|
465 |
2018.11.27 euisung add save to xml |
|
466 |
2018.11.29 euisung change name drawUnknownItems() -> createUnknownItems |
|
467 |
''' |
|
468 |
|
|
469 |
def create_unknown_items(self, path): |
|
470 |
from QEngineeringFlowArrowItem import QEngineeringFlowArrowItem |
|
471 |
from EngineeringLineItem import QEngineeringLineItem |
|
472 |
from EngineeringUnknownItem import QEngineeringUnknownItem |
|
473 |
|
|
474 |
try: |
|
475 |
app_doc_data = AppDocData.instance() |
|
476 |
project = app_doc_data.getCurrentProject() |
|
477 |
windowSize = app_doc_data.getSlidingWindowSize() |
|
478 |
|
|
479 |
thickness = int(windowSize[1] / 2) |
|
480 |
|
|
481 |
""" |
|
482 |
if app_doc_data.needReOpening is not None: |
|
483 |
app_doc_data.needReOpening = True |
|
484 |
""" |
|
485 |
|
|
486 |
diffFilePath = os.path.join(project.getTempPath(), "DIFF_" + os.path.basename(path)) |
|
487 |
if os.path.isfile(diffFilePath): |
|
488 |
imgDiff = cv2.threshold(cv2.cvtColor(cv2.imread(diffFilePath, 1), cv2.COLOR_BGR2GRAY), 0, 255, |
|
489 |
cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1] |
|
490 |
|
|
491 |
# remove line from image |
|
492 |
lines = app_doc_data.lines |
|
493 |
for line in lines: |
|
494 |
line.drawToImage(imgDiff, 255, thickness) if line.thickness is None else \ |
|
495 |
line.drawToImage(imgDiff, 255, line.thickness) |
|
496 |
cv2.imwrite(diffFilePath, imgDiff) |
|
497 |
# up to here |
|
498 |
|
|
499 |
imgNot = np.ones(imgDiff.shape, np.uint8) |
|
500 |
cv2.bitwise_not(imgDiff, imgNot) |
|
501 |
configs = app_doc_data.getConfigs('Filter', 'ErodeSize') |
|
502 |
kernel = int(configs[0].value) if 1 == len(configs) else 3 |
|
503 |
imgNot = cv2.erode(imgNot, np.ones((kernel, kernel), np.uint8)) |
|
504 |
imgNot = cv2.dilate(imgNot, np.ones((8 + kernel, 8 + kernel), np.uint8)) |
|
505 |
|
|
506 |
contours, hierarchy = cv2.findContours(imgNot, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) |
|
507 |
|
|
508 |
## |
|
509 |
idx = 0 |
|
510 |
## |
|
511 |
smallContours = [] |
|
512 |
minimumSize = app_doc_data.getConfigs('Filter', 'MinimumSize') |
|
513 |
for contour in contours: |
|
514 |
[x, y, w, h] = cv2.boundingRect(contour) |
|
515 |
|
|
516 |
# remove too small one |
|
517 |
if len(minimumSize) is 1: |
|
518 |
if w * h < int(minimumSize[0].value) * int(minimumSize[0].value): |
|
519 |
smallContours.append(contour) |
|
520 |
idx += 1 |
|
521 |
continue |
|
522 |
|
|
523 |
''' |
|
524 |
rect = QRectF(x, y, w, h) |
|
525 |
items = [item for item in diffItems if item.boundingRect().contains(rect)] |
|
526 |
if len(items) > 0: continue |
|
527 |
|
|
528 |
items = [item for item in diffItems if rect.contains(item.boundingRect())] |
|
529 |
for item in items: |
|
530 |
diffItems.remove(item) |
|
531 |
''' |
|
532 |
|
|
533 |
# create unknown item |
|
534 |
epsilon = cv2.arcLength(contour, True) * 0.001 |
|
535 |
approx = cv2.approxPolyDP(contour, epsilon, True) |
|
536 |
approx = [pt[0] for pt in approx] |
|
537 |
resultStr, resultList = self.determine_remain_object(idx, contours, imgNot) |
|
538 |
if resultStr == 'LineIndicator': |
|
539 |
item = QEngineeringUnknownItem(approx, 'True', resultList[0], resultList[1]) |
|
540 |
app_doc_data.lineIndicators.append(item) |
|
541 |
elif resultStr == 'MissingLine': |
|
542 |
pass |
|
543 |
elif resultStr == 'Unknown': |
|
544 |
item = QEngineeringUnknownItem(approx, 'False') |
|
545 |
app_doc_data.unknowns.append(item) |
|
546 |
item.area = 'Drawing' |
|
547 |
app_doc_data.allItems.append(item) |
|
548 |
#item.transfer.onRemoved.connect(self.itemRemoved) |
|
549 |
idx += 1 |
|
550 |
# up to here |
|
551 |
|
|
552 |
imgNotRemoveSmall = cv2.drawContours(imgNot, smallContours, -1, 0, -1) |
|
553 |
notFilePath = os.path.join(project.getTempPath(), "NOT_" + os.path.basename(path)) |
|
554 |
cv2.imwrite(notFilePath, imgNotRemoveSmall) |
|
555 |
else: |
|
556 |
message = 'can\'t found {}'.format(diffFilePath) |
|
557 |
self.displayLog.emit(MessageType.Normal, message) |
|
558 |
except Exception as ex: |
|
559 |
message = 'error occurred({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, |
|
560 |
sys.exc_info()[-1].tb_lineno) |
|
561 |
self.displayLog.emit(MessageType.Error, message) |
|
562 |
|
|
563 |
def determine_remain_object(self, idx, contours, imgNot): |
|
564 |
"""determine remain objects -> line no indicator or unknown""" |
|
565 |
import math |
|
566 |
[x, y, w, h] = cv2.boundingRect(contours[idx]) |
|
567 |
|
|
568 |
if w < 250 and h < 250: |
|
569 |
return ('Unknown', []) |
|
570 |
|
|
571 |
fLines = [] |
|
572 |
maxDifAngle = 3 |
|
573 |
mask = np.zeros_like(imgNot) |
|
574 |
cv2.drawContours(mask, contours, idx, 123, -1) # Draw filled contour in mask |
|
575 |
out = np.zeros_like(imgNot) # Extract out the object and place into output image |
|
576 |
out[mask == 123] = imgNot[mask == 123] |
|
577 |
|
|
578 |
# Now crop |
|
579 |
##print(out) |
|
580 |
(x, y) = np.where(mask == 123) |
|
581 |
(topx, topy) = (np.min(x), np.min(y)) |
|
582 |
(bottomx, bottomy) = (np.max(x), np.max(y)) |
|
583 |
out = out[topx:bottomx + 1, topy:bottomy + 1] |
내보내기 Unified diff