개정판 988b20a2
merge connected lines
DTI_PID/DTI_PID/App.py | ||
---|---|---|
129 | 129 |
@date 2018.??.?? |
130 | 130 |
''' |
131 | 131 |
def openImageDrawing(self, MainWindow): |
132 |
import random |
|
133 |
|
|
132 | 134 |
try: |
135 |
self.graphicsView.clearImage() |
|
133 | 136 |
self.graphicsView.scene.clear() |
134 | 137 |
self.path = self.graphicsView.loadImageFromFile() |
135 | 138 |
baseName = os.path.basename(self.path) |
... | ... | |
145 | 148 |
detector = LineDetector(img) |
146 | 149 |
for item in self.graphicsView.scene.items(): |
147 | 150 |
if type(item) is SymbolSvgItem: |
151 |
color = QColor(random.randrange(0,255), random.randrange(0,255), random.randrange(0,255)) |
|
148 | 152 |
res = detector.detectConnectedLine(item, 0, 0) |
149 |
for pts in res: |
|
150 |
line = QEngineeringLineItem() |
|
151 |
line._pol.append(QPointF(pts[0][0], pts[0][1])) |
|
152 |
line._pol.append(QPointF(pts[1][0], pts[1][1])) |
|
153 |
line._path.addPolygon(line._pol) |
|
154 |
line.setPath(line._path) |
|
155 |
self.graphicsView.scene.addItem(line) |
|
153 |
if res is not None: |
|
154 |
for pts in res: |
|
155 |
processLine = QEngineeringLineItem() |
|
156 |
for pt in pts: |
|
157 |
processLine._pol.append(QPointF(pt[0], pt[1])) |
|
158 |
processLine._path.addPolygon(processLine._pol) |
|
159 |
processLine.setPath(processLine._path) |
|
160 |
processLine.setPen(QPen(color, 5, Qt.SolidLine)) |
|
161 |
self.graphicsView.scene.addItem(processLine) |
|
156 | 162 |
|
157 | 163 |
detector.save() |
158 | 164 |
''' |
... | ... | |
213 | 219 |
self.loadRecognitionResult(self.xmlPath[0]) |
214 | 220 |
|
215 | 221 |
# detect line |
216 |
#img = cv2.imread(self.path) |
|
217 | 222 |
area = AppDocData.instance().getArea('Drawing') |
218 | 223 |
detector = LineDetector(area.img) |
219 | 224 |
for item in self.graphicsView.scene.items(): |
220 | 225 |
if (type(item) is SymbolSvgItem): |
221 | 226 |
res = detector.detectConnectedLine(item, int(area.x), int(area.y)) |
222 | 227 |
for pts in res: |
223 |
line = QEngineeringLineItem()
|
|
224 |
line._pol.append(QPointF(pts[0][0] + int(area.x), pts[0][1] + int(area.y)))
|
|
225 |
line._pol.append(QPointF(pts[1][0] + int(area.x), pts[1][1] + int(area.y)))
|
|
226 |
line._path.addPolygon(line._pol)
|
|
227 |
line.setPath(line._path)
|
|
228 |
self.graphicsView.scene.addItem(line)
|
|
228 |
processLine = QEngineeringLineItem()
|
|
229 |
for pt in pts:
|
|
230 |
processLine._pol.append(QPointF(pt[0] + int(area.x), pts[1] + int(area.y)))
|
|
231 |
processLine._path.addPolygon(processLine._pol)
|
|
232 |
processLine.setPath(processLine._path)
|
|
233 |
self.graphicsView.scene.addItem(processLine)
|
|
229 | 234 |
# up to here |
230 | 235 |
except Exception as ex: |
231 | 236 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
DTI_PID/DTI_PID/DTI_PID.py | ||
---|---|---|
871 | 871 |
area = AppDocData.instance().getArea('Drawing') |
872 | 872 |
if area is not None: |
873 | 873 |
area.img = srcGray[int(area.y):int(area.y+area.height), int(area.x):int(area.x+area.width)] |
874 |
cv2.imwrite(os.path.dirname(os.path.realpath(__file__)) + "\\res\\Result\\result_fslo_rect_"+srcName+"_600dpi.png", src)
|
|
874 |
cv2.imwrite(project.getTempPath() + "/rect_" + os.path.basename(path), src)
|
|
875 | 875 |
|
876 | 876 |
imgLineList = [] |
877 | 877 |
|
DTI_PID/DTI_PID/LineDetector.py | ||
---|---|---|
23 | 23 |
self.DrawFlag = True |
24 | 24 |
|
25 | 25 |
""" |
26 |
두 직선이 평행한지 판별한다. |
|
26 |
@brief 두 직선이 평행한지 판별한다. |
|
27 |
@author humkyung |
|
28 |
@date 2018.??.?? |
|
27 | 29 |
""" |
28 | 30 |
def IsParallel(self, rhs): |
29 | 31 |
dx = math.fabs(self.dx) - math.fabs(rhs.dx) |
... | ... | |
35 | 37 |
dy1 = rhs.y1 - self.y1 |
36 | 38 |
dx2 = rhs.x1 - self.x2 |
37 | 39 |
dy2 = rhs.y1 - self.y2 |
38 |
cross.append(dx1*dy1 - dy1*dx2)
|
|
40 |
cross.append(dx1*dy2 - dy1*dx2)
|
|
39 | 41 |
dx1 = rhs.x2 - self.x1 |
40 | 42 |
dy1 = rhs.y2 - self.y1 |
41 | 43 |
dx2 = rhs.x2 - self.x2 |
42 | 44 |
dy2 = rhs.y2 - self.y2 |
43 |
cross.append(dx1*dy1 - dy1*dx2)
|
|
45 |
cross.append(dx1*dy2 - dy1*dx2)
|
|
44 | 46 |
|
45 |
if cross[0] > 0 and cross[1] > 0: return False
|
|
47 |
if abs(cross[0]) > 0 and abs(cross[1]) > 0: return False
|
|
46 | 48 |
|
47 | 49 |
return Length < 0.0001 |
48 | 50 |
|
... | ... | |
142 | 144 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
143 | 145 |
|
144 | 146 |
''' |
145 |
@brief symbol을 기준으로 양쪽으로 이미지에서 직선을 검출한다. |
|
147 |
@brief check if given two lines are connected |
|
148 |
@author humkyung |
|
149 |
@date 2018.04.11 |
|
150 |
''' |
|
151 |
def isConnected(self, lhs, rhs): |
|
152 |
length = [] |
|
153 |
|
|
154 |
# check if share one point |
|
155 |
dx = (lhs[0][0] - rhs[0][0]) |
|
156 |
dy = (lhs[0][1] - rhs[0][1]) |
|
157 |
length.append(math.sqrt(dx*dx + dy*dy)) |
|
158 |
dx = (lhs[-1][0] - rhs[0][0]) |
|
159 |
dy = (lhs[-1][1] - rhs[0][1]) |
|
160 |
length.append(math.sqrt(dx*dx + dy*dy)) |
|
161 |
dx = (lhs[0][0] - rhs[-1][0]) |
|
162 |
dy = (lhs[0][1] - rhs[-1][1]) |
|
163 |
length.append(math.sqrt(dx*dx + dy*dy)) |
|
164 |
dx = (lhs[-1][0] - rhs[-1][0]) |
|
165 |
dy = (lhs[-1][1] - rhs[-1][1]) |
|
166 |
length.append(math.sqrt(dx*dx + dy*dy)) |
|
167 |
matches = [len for len in length if len == 0] |
|
168 |
# up to here |
|
169 |
|
|
170 |
return (len(matches) == 1) |
|
171 |
|
|
172 |
""" |
|
173 |
@brief check if given two lines lie on one line and share one point |
|
174 |
@author humkyung |
|
175 |
@date 2018.04.11 |
|
176 |
""" |
|
177 |
def isCollinear(self, lhs, rhs): |
|
178 |
if self.isConnected(lhs, rhs): |
|
179 |
cross = [] |
|
180 |
dx1 = rhs[0][0] - lhs[0][0] |
|
181 |
dy1 = rhs[0][1] - lhs[0][1] |
|
182 |
dx2 = rhs[0][0] - lhs[-1][0] |
|
183 |
dy2 = rhs[0][1] - lhs[-1][1] |
|
184 |
cross.append(dx1*dy2 - dy1*dx2) |
|
185 |
dx1 = rhs[-1][0] - lhs[0][1] |
|
186 |
dy1 = rhs[-1][1] - lhs[0][1] |
|
187 |
dx2 = rhs[-1][0] - lhs[-1][0] |
|
188 |
dy2 = rhs[-1][1] - lhs[-1][1] |
|
189 |
cross.append(dx1*dy2 - dy1*dx2) |
|
190 |
|
|
191 |
if abs(cross[0]) == 0 and abs(cross[1]) == 0: return True |
|
192 |
|
|
193 |
return False |
|
194 |
|
|
195 |
''' |
|
196 |
@brief merge given lines |
|
146 | 197 |
@author humkyung |
147 |
@date 2018.04.?? |
|
198 |
@date 2018.04.11 |
|
199 |
''' |
|
200 |
def mergeLines(self, lines): |
|
201 |
res = [] |
|
202 |
|
|
203 |
if len(lines) == 2: |
|
204 |
lhs = lines[0] |
|
205 |
rhs = lines[1] |
|
206 |
|
|
207 |
# start - start |
|
208 |
dx = lhs[0][0] - rhs[0][0] |
|
209 |
dy = lhs[0][1] - rhs[0][1] |
|
210 |
if (dx == 0) and (dy == 0): |
|
211 |
for i in reversed(range(len(lhs))): |
|
212 |
res.append(lhs[i]) |
|
213 |
for i in range(1,len(rhs)): |
|
214 |
res.append(rhs[i]) |
|
215 |
return res |
|
216 |
|
|
217 |
# end - start |
|
218 |
dx = lhs[-1][0] - rhs[0][0] |
|
219 |
dy = lhs[-1][1] - rhs[0][1] |
|
220 |
if (dx == 0) and (dy == 0): |
|
221 |
for i in range(len(lhs)): |
|
222 |
res.append(lhs[i]) |
|
223 |
for i in range(1,len(rhs)): |
|
224 |
res.append(rhs[i]) |
|
225 |
return res |
|
226 |
|
|
227 |
# start - end |
|
228 |
dx = lhs[0][0] - rhs[-1][0] |
|
229 |
dy = lhs[0][1] - rhs[-1][1] |
|
230 |
if (dx == 0) and (dy == 0): |
|
231 |
for i in reversed(range(len(lhs))): |
|
232 |
res.append(lhs[i]) |
|
233 |
for i in reversed(range(len(rhs)-1)): |
|
234 |
res.append(rhs[i]) |
|
235 |
return res |
|
236 |
|
|
237 |
# end - end |
|
238 |
dx = lhs[-1][0] - rhs[-1][0] |
|
239 |
dy = lhs[-1][1] - rhs[-1][1] |
|
240 |
if (dx == 0) and (dy == 0): |
|
241 |
for i in range(len(lhs)): |
|
242 |
res.append(lhs[i]) |
|
243 |
for i in reversed(range(len(rhs)-1)): |
|
244 |
res.append(rhs[i]) |
|
245 |
return res |
|
246 |
|
|
247 |
pass |
|
248 |
''' |
|
249 |
elif len(lines) > 2: |
|
250 |
bLoop = True |
|
251 |
while bLoop and (len(lines) > 1): |
|
252 |
bLoop = False |
|
253 |
for line in lines[:]: |
|
254 |
matches = [param for param in lines if (line != param) and self.isConnected(line, param)] |
|
255 |
if len(matches) > 0: |
|
256 |
matches.append(line) |
|
257 |
mergedLine = self.mergeLines(matches) |
|
258 |
lines.append(mergedLine) |
|
259 |
for match in matches: |
|
260 |
lines.remove(match) |
|
261 |
|
|
262 |
bLoop = True |
|
263 |
break |
|
264 |
return lines |
|
265 |
''' |
|
266 |
|
|
267 |
return lines |
|
268 |
|
|
269 |
''' |
|
270 |
@brief symbol을 기준으로 양쪽으로 이미지에서 직선을 검출한다. |
|
271 |
@author humkyung |
|
272 |
@date 2018.04.?? |
|
273 |
@history humkyung 2018.04.11 merge lines which are collinear or connected |
|
148 | 274 |
''' |
149 | 275 |
def detectConnectedLine(self, symbol, offsetX, offsetY): |
150 | 276 |
res = [] |
... | ... | |
182 | 308 |
pool.append([[1,0], pt]) |
183 | 309 |
pool.append([[-1,0], pt]) |
184 | 310 |
|
311 |
# merge lines which are collinear or connected |
|
312 |
''' |
|
313 |
if len(res) > 1: |
|
314 |
for line in res[:]: |
|
315 |
matches = [param for param in res if (line != param) and self.isCollinear(line, param)] |
|
316 |
if len(matches) > 0: |
|
317 |
matches.append(line) |
|
318 |
mergedLine = self.mergeLines(matches) |
|
319 |
res.append(mergedLine) |
|
320 |
for match in matches: res.remove(match) |
|
321 |
''' |
|
322 |
bLoop = True |
|
323 |
while bLoop and (len(res) > 1): |
|
324 |
bLoop = False |
|
325 |
for line in res[:]: |
|
326 |
matches = [param for param in res if (line != param) and self.isConnected(line, param)] |
|
327 |
if len(matches) == 1: |
|
328 |
matches.append(line) |
|
329 |
mergedLine = self.mergeLines(matches) |
|
330 |
if mergedLine is not None: res.append(mergedLine) |
|
331 |
for match in matches: |
|
332 |
res.remove(match) |
|
333 |
|
|
334 |
bLoop = True |
|
335 |
break |
|
336 |
# up to here |
|
337 |
|
|
185 | 338 |
return res |
186 | 339 |
except Exception as ex: |
187 | 340 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
... | ... | |
207 | 360 |
window = image[0:windowSize[1], i:i+windowSize[0]] |
208 | 361 |
if (white == window[0:windowSize[1],0:windowSize[0]]).all(): break |
209 | 362 |
if i > windowSize[0]: |
210 |
self.image[(pt[1]-yHalf):(pt[1]+yHalf), pt[0]:(pt[0]+i)] = white
|
|
211 |
return [(pt[0], pt[1]), (pt[0] + i, pt[1])] |
|
363 |
self.image[(pt[1]-yHalf*2):(pt[1]+yHalf*2), pt[0]:(pt[0]+i)] = white
|
|
364 |
return [(pt[0], pt[1]), (pt[0] + i - yHalf, pt[1])]
|
|
212 | 365 |
elif ([-1,0] == dir): |
213 | 366 |
image = self.image[(pt[1]-yHalf):(pt[1]+yHalf), 0:pt[0]] |
214 | 367 |
imgWidth, imgHeight = image.shape[::-1] |
... | ... | |
216 | 369 |
window = image[0:windowSize[1], i:i+windowSize[0]] |
217 | 370 |
if (white == window[0:windowSize[1],0:windowSize[0]]).all(): break |
218 | 371 |
if abs(pt[0] - i) > windowSize[0]: |
219 |
self.image[int(pt[1]-yHalf):int(pt[1]+yHalf), (i+windowSize[0]):pt[0]] = white
|
|
372 |
self.image[int(pt[1]-yHalf*2):int(pt[1]+yHalf*2), (i+windowSize[0]+yHalf):pt[0]] = white
|
|
220 | 373 |
return [(pt[0], pt[1]), (i+windowSize[0], pt[1])] |
221 | 374 |
elif ([0,1] == dir): |
222 | 375 |
windowSize.reverse() |
... | ... | |
229 | 382 |
window = image[i:i+windowSize[1], 0:windowSize[0]] |
230 | 383 |
if (white == window[0:windowSize[1],0:windowSize[0]]).all(): break |
231 | 384 |
if i > windowSize[1]: |
232 |
self.image[(pt[1]):(pt[1]+i), (pt[0]-xHalf):(pt[0]+xHalf)] = white
|
|
385 |
self.image[(pt[1]):(pt[1]+i), (pt[0]-xHalf*2):(pt[0]+xHalf*2)] = white
|
|
233 | 386 |
return [(pt[0], pt[1]), (pt[0], pt[1] + i)] |
234 | 387 |
elif ([0,-1] == dir): |
235 | 388 |
windowSize.reverse() |
... | ... | |
242 | 395 |
window = image[i:i+windowSize[1], 0:windowSize[0]] |
243 | 396 |
if (white == window[0:windowSize[1],0:windowSize[0]]).all(): break |
244 | 397 |
if abs(pt[1] - i) > windowSize[1]: |
245 |
self.image[(i+windowSize[1]):pt[1], (pt[0]-xHalf):(pt[0]+xHalf)] = white
|
|
398 |
self.image[(i+windowSize[1]):pt[1], (pt[0]-xHalf*2):(pt[0]+xHalf*2)] = white
|
|
246 | 399 |
return [(pt[0], pt[1]), (pt[0], i+windowSize[1])] |
247 | 400 |
except Exception as ex: |
248 | 401 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
DTI_PID/DTI_PID/Shapes/QEngineeringLineItem.py | ||
---|---|---|
19 | 19 |
def __init__(self, parent=None): |
20 | 20 |
QGraphicsPolylineItem.__init__(self, parent) |
21 | 21 |
|
22 |
self.setPen(QPen(Qt.blue, 10, Qt.SolidLine))
|
|
22 |
self.setPen(QPen(Qt.blue, 5, Qt.SolidLine))
|
|
23 | 23 |
self.setFlags(QGraphicsItem.ItemIsSelectable) |
24 | 24 |
|
25 | 25 |
self.setAcceptHoverEvents(True) |
... | ... | |
61 | 61 |
return clone |
62 | 62 |
|
63 | 63 |
def hoverEnterEvent(self, event): |
64 |
print('Enter')
|
|
64 |
pass
|
|
65 | 65 |
|
66 | 66 |
def hoverLeaveEvent(self, event): |
67 |
print('Leave')
|
|
67 |
pass
|
|
68 | 68 |
|
69 | 69 |
def hoverMoveEvent(self, event): |
70 |
return #print('Moving') |
|
70 |
pass |
DTI_PID/DTI_PID/Shapes/QGraphicsPolylineItem.py | ||
---|---|---|
16 | 16 |
QGraphicsPathItem.__init__(self, parent) |
17 | 17 |
#self.setFlag(QGraphicsItem.ItemIsMovable) |
18 | 18 |
self.setFlags(QGraphicsItem.ItemIsSelectable) |
19 |
self.setBrush(QBrush(Qt.red)) |
|
19 |
#self.setBrush(QBrush(Qt.red))
|
|
20 | 20 |
|
21 | 21 |
self._vertices = [] |
22 | 22 |
self.isCreated = False |
내보내기 Unified diff