hytos / DTI_PID / DTI_PID / LineDetector.py @ 528bc774
이력 | 보기 | 이력해설 | 다운로드 (9.03 KB)
1 |
import sys |
---|---|
2 |
import cv2 |
3 |
import numpy as np |
4 |
import matplotlib.pyplot as plt |
5 |
import math |
6 |
import imutils |
7 |
from shapely.geometry import LineString |
8 |
from shapely.ops import linemerge |
9 | |
10 |
class LineVector: |
11 |
def __init__(self, x1, y1, x2, y2): |
12 |
self.x1 = x1
|
13 |
self.y1 = y1
|
14 |
self.x2 = x2
|
15 |
self.y2 = y2
|
16 | |
17 |
dx = x2 - x1 |
18 |
dy = y2 - y1 |
19 |
self.Length = math.sqrt(dx*dx + dy*dy)
|
20 |
self.dx = dx/self.Length |
21 |
self.dy = dy/self.Length |
22 | |
23 |
self.DrawFlag = True |
24 | |
25 |
"""
|
26 |
두 직선이 평행한지 판별한다.
|
27 |
"""
|
28 |
def IsParallel(self, rhs): |
29 |
dx = math.fabs(self.dx) - math.fabs(rhs.dx)
|
30 |
dy = math.fabs(self.dy) - math.fabs(rhs.dy)
|
31 |
Length = math.sqrt(dx*dx + dy*dy) |
32 | |
33 |
cross = [] |
34 |
dx1 = rhs.x1 - self.x1
|
35 |
dy1 = rhs.y1 - self.y1
|
36 |
dx2 = rhs.x1 - self.x2
|
37 |
dy2 = rhs.y1 - self.y2
|
38 |
cross.append(dx1*dy1 - dy1*dx2) |
39 |
dx1 = rhs.x2 - self.x1
|
40 |
dy1 = rhs.y2 - self.y1
|
41 |
dx2 = rhs.x2 - self.x2
|
42 |
dy2 = rhs.y2 - self.y2
|
43 |
cross.append(dx1*dy1 - dy1*dx2) |
44 | |
45 |
if cross[0] > 0 and cross[1] > 0: return False |
46 | |
47 |
return Length < 0.0001 |
48 | |
49 |
"""
|
50 |
두 직선의 거리를 구한다.
|
51 |
"""
|
52 |
def DistanceTo(self, rhs): |
53 |
dx = rhs.x1 - self.x1
|
54 |
dy = rhs.y1 - self.y1
|
55 |
dot = self.dx*dx + self.dy*dy |
56 |
tmp = dot |
57 |
x1 = self.x1 + tmp*self.dx |
58 |
y1 = self.y1 + tmp*self.dy |
59 |
dx = x1 - rhs.x1 |
60 |
dy = y1 - rhs.y1 |
61 |
return math.sqrt(dx*dx + dy*dy)
|
62 | |
63 |
'''
|
64 |
두 직선의 사이를 가로지르는 직선을 구한다.
|
65 |
'''
|
66 |
def Merge(self, rhs): |
67 |
dx1 = rhs.x1 - self.x1
|
68 |
dy1 = rhs.y1 - self.y1
|
69 |
dx2 = rhs.x1 - self.x2
|
70 |
dy2 = rhs.y1 - self.y2
|
71 | |
72 |
candidates = [] |
73 |
candidates.append((self.x1, self.y1)) |
74 |
candidates.append((self.x2, self.y2)) |
75 | |
76 |
Dir = [] |
77 |
cross = dx1*dy2 - dy1*dx2 |
78 |
if cross > 0: |
79 |
dot = dx1*self.dx + dy1*self.dy |
80 |
tmp = (self.x1 + dot*self.dx, self.y1 + dot*self.dy) |
81 |
candidates.append(tmp) |
82 |
Dir.append((rhs.x1 - tmp[0], rhs.y1 - tmp[1])) |
83 |
|
84 |
dx1 = rhs.x2 - self.x1
|
85 |
dy1 = rhs.y2 - self.y1
|
86 |
dx2 = rhs.x2 - self.x2
|
87 |
dy2 = rhs.y2 - self.y2
|
88 |
cross = dx1*dy2 - dy1*dx2 |
89 |
if cross > 0: |
90 |
dot = dx1*self.dx + dy1*self.dy |
91 |
tmp = (self.x1 + dot*self.dx, self.y1 + dot*self.dy) |
92 |
candidates.append(tmp) |
93 |
Dir.append((rhs.x2 - tmp[0], rhs.y2 - tmp[1])) |
94 | |
95 |
MaxLength = None
|
96 |
Points = [] |
97 |
for i in range(len(candidates) - 1): |
98 |
for j in range(i+1, len(candidates)): |
99 |
dx = candidates[i][0] - candidates[j][0] |
100 |
dy = candidates[i][1] - candidates[j][1] |
101 |
Length = dx*dx + dy*dy |
102 |
if MaxLength == None: |
103 |
MaxLength = Length |
104 |
Points.append(candidates[i]) |
105 |
Points.append(candidates[j]) |
106 |
elif MaxLength < Length:
|
107 |
MaxLength = Length |
108 |
Points[0] = candidates[i]
|
109 |
Points[1] = candidates[j]
|
110 | |
111 |
if len(Points) == 2 and len(Dir) > 0: |
112 |
x1 = Points[0][0] + Dir[0][0]*0.5 |
113 |
y1 = Points[0][1] + Dir[0][1]*0.5 |
114 |
x2 = Points[1][0] + Dir[0][0]*0.5 |
115 |
y2 = Points[1][1] + Dir[0][1]*0.5 |
116 |
return LineVector(x1, y1, x2, y2)
|
117 |
else:
|
118 |
dx1 = rhs.x1 - self.x1
|
119 |
dy1 = rhs.y1 - self.y1
|
120 |
dot = dx1*self.dx + dy1*self.dy |
121 |
tmp = (self.x1 + dot*self.dx, self.y1 + dot*self.dy) |
122 |
Dir.append((rhs.x1 - tmp[0], rhs.y1 - tmp[1])) |
123 |
x1 = Points[0][0] + Dir[0][0]*0.5 |
124 |
y1 = Points[0][1] + Dir[0][1]*0.5 |
125 |
x2 = Points[1][0] + Dir[0][0]*0.5 |
126 |
y2 = Points[1][1] + Dir[0][1]*0.5 |
127 |
return LineVector(x1, y1, x2, y2)
|
128 | |
129 |
return LineVector(self.x1, self.y1, self.x2, self.y2) |
130 | |
131 |
def Draw(self, img, r, g, b): |
132 |
cv2.line(img, (int(self.x1), int(self.y1)), (int(self.x2), int(self.y2)), (r, g, b), 1) |
133 | |
134 |
class LineDetector(): |
135 |
def __init__(self, image): |
136 |
thresh = 127
|
137 |
self.image = cv2.threshold(image, thresh, 255, cv2.THRESH_BINARY)[1] |
138 |
self.width, self.height = self.image.shape[::-1] |
139 |
self.Result = np.zeros((self.width, self.height, 3), np.uint8) |
140 | |
141 |
'''
|
142 |
@brief symbol을 기준으로 양쪽으로 이미지에서 직선을 검출한다.
|
143 |
@author humkyung
|
144 |
@date 2018.04.??
|
145 |
'''
|
146 |
def Detect(self, symbol, offsetX, offsetY): |
147 |
res = [] |
148 | |
149 |
try:
|
150 |
pool = [] |
151 |
if (0 == symbol.angle) or (3.14 == symbol.angle): |
152 |
right = int(symbol.rect().right())
|
153 |
left = int(symbol.rect().left())
|
154 | |
155 |
pt = [right - offsetX, int(symbol.center.y()) - offsetY]
|
156 |
pool.append([[1,0], pt]) |
157 |
pt = [left - offsetX, int(symbol.center.y()) - offsetY]
|
158 |
pool.append([[-1,0], pt]) |
159 |
elif (1.57 == symbol.angle) or (4.71 == symbol.angle): # rotated by 90 or 270 degree |
160 |
bottom = int(symbol.rect().bottom())
|
161 |
top = int(symbol.rect().top())
|
162 | |
163 |
pt = [int(symbol.center.x()) - offsetX, bottom - offsetY]
|
164 |
pool.append([[0,1], pt]) |
165 |
pt = [int(symbol.center.x()) - offsetX, top - offsetY]
|
166 |
pool.append([[0,-1], pt]) |
167 | |
168 |
while len(pool) > 0: |
169 |
dir, pt = pool.pop()
|
170 |
line = self.detectLine(pt,dir) |
171 |
if line is not None: |
172 |
res.append(line) |
173 |
if ([1,0] == dir) or ([-1,0] == dir): # turn up/down |
174 |
pt[0] = line[1][0] |
175 |
pool.append([[0,1], pt]) |
176 |
pool.append([[0,-1], pt]) |
177 |
elif ([0,1] == dir) or ([0,-1] == dir): # turn left/right |
178 |
pt[1] = line[1][1] |
179 |
pool.append([[1,0], pt]) |
180 |
pool.append([[-1,0], pt]) |
181 | |
182 |
return res
|
183 |
except Exception as ex: |
184 |
print('error occured({}) in {}:{}'.format(ex, sys.exc_info()[-1].tb_frame.f_code.co_filename, sys.exc_info()[-1].tb_lineno)) |
185 | |
186 |
'''
|
187 |
@brief detect a line along given direction
|
188 |
@author humkyung
|
189 |
@date 2018.04
|
190 |
'''
|
191 |
def detectLine(self, pt, dir): |
192 |
from AppDocData import AppDocData |
193 | |
194 |
white = [255]
|
195 |
windowSize = AppDocData.instance().getSlidingWindowSize() |
196 |
xHalf = int(windowSize[0]*0.5) |
197 |
yHalf = int(windowSize[1]*0.5) |
198 | |
199 |
if ([1,0] == dir): |
200 |
image = self.image[(pt[1]-yHalf):(pt[1]+yHalf), pt[0]:self.width] |
201 |
imgWidth, imgHeight = image.shape[::-1]
|
202 |
for i in range(imgWidth-windowSize[0]): |
203 |
window = image[0:windowSize[1], i:i+windowSize[0]] |
204 |
if (white == window[0:windowSize[1],0:windowSize[0]]).all(): break |
205 |
if i > windowSize[0]: |
206 |
self.image[(pt[1]-yHalf):(pt[1]+yHalf), pt[0]:(pt[0]+i)] = white |
207 |
return [(pt[0], pt[1]), (pt[0] + i, pt[1])] |
208 |
elif ([-1,0] == dir): |
209 |
image = self.image[(pt[1]-yHalf):(pt[1]+yHalf), 0:pt[0]] |
210 |
imgWidth, imgHeight = image.shape[::-1]
|
211 |
for i in range(imgWidth-windowSize[0], -1, -1): |
212 |
window = image[0:windowSize[1], i:i+windowSize[0]] |
213 |
if (white == window[0:windowSize[1],0:windowSize[0]]).all(): break |
214 |
if abs(pt[0] - i) > windowSize[0]: |
215 |
self.image[int(pt[1]-yHalf):int(pt[1]+yHalf), (i+windowSize[0]):pt[0]] = white |
216 |
return [(pt[0], pt[1]), (i+windowSize[0], pt[1])] |
217 |
elif ([0,1] == dir): |
218 |
windowSize.reverse() |
219 |
xHalf = int(windowSize[0]*0.5) |
220 |
yHalf = int(windowSize[1]*0.5) |
221 | |
222 |
image = self.image[pt[1]:self.height, int(pt[0]-xHalf):int(pt[0]+xHalf)] |
223 |
imgWidth, imgHeight = image.shape[::-1]
|
224 |
for i in range(imgHeight-windowSize[1]): |
225 |
window = image[i:i+windowSize[1], 0:windowSize[0]] |
226 |
if (white == window[0:windowSize[1],0:windowSize[0]]).all(): break |
227 |
if i > windowSize[1]: |
228 |
self.image[(pt[1]):(pt[1]+i), (pt[0]-xHalf):(pt[0]+xHalf)] = white |
229 |
return [(pt[0], pt[1]), (pt[0], pt[1] + i)] |
230 |
elif ([0,-1] == dir): |
231 |
windowSize.reverse() |
232 |
xHalf = int(windowSize[0]*0.5) |
233 |
yHalf = int(windowSize[1]*0.5) |
234 | |
235 |
image = self.image[0:pt[1], int(pt[0]-xHalf):int(pt[0]+xHalf)] |
236 |
imgWidth, imgHeight = image.shape[::-1]
|
237 |
for i in range(imgHeight-windowSize[1], -1, -1): |
238 |
window = image[i:i+windowSize[1], 0:windowSize[0]] |
239 |
if (white == window[0:windowSize[1],0:windowSize[0]]).all(): break |
240 |
if abs(pt[1] - i) > windowSize[1]: |
241 |
self.image[(i+windowSize[1]):pt[1], (pt[0]-xHalf):(pt[0]+xHalf)] = white |
242 |
return [(pt[0], pt[1]), (pt[0], i+windowSize[1])] |
243 | |
244 |
return None |
245 | |
246 |
def save(self): |
247 |
cv2.imwrite('d:\\test.png', self.image) |