|
1 |
import cv2
|
|
2 |
import numpy as np
|
|
3 |
import matplotlib.pyplot as plt
|
|
4 |
import math
|
|
5 |
import imutils
|
|
6 |
from shapely.geometry import LineString
|
|
7 |
from shapely.ops import linemerge
|
|
8 |
|
|
9 |
class LineVector:
|
|
10 |
def __init__(self, x1, y1, x2, y2):
|
|
11 |
self.x1 = x1
|
|
12 |
self.y1 = y1
|
|
13 |
self.x2 = x2
|
|
14 |
self.y2 = y2
|
|
15 |
|
|
16 |
dx = x2 - x1
|
|
17 |
dy = y2 - y1
|
|
18 |
self.Length = math.sqrt(dx*dx + dy*dy)
|
|
19 |
self.dx = dx/self.Length
|
|
20 |
self.dy = dy/self.Length
|
|
21 |
|
|
22 |
self.DrawFlag = True
|
|
23 |
|
|
24 |
"""
|
|
25 |
두 직선이 평행한지 판별한다.
|
|
26 |
"""
|
|
27 |
def IsParallel(self, rhs):
|
|
28 |
dx = math.fabs(self.dx) - math.fabs(rhs.dx)
|
|
29 |
dy = math.fabs(self.dy) - math.fabs(rhs.dy)
|
|
30 |
Length = math.sqrt(dx*dx + dy*dy)
|
|
31 |
|
|
32 |
cross = []
|
|
33 |
dx1 = rhs.x1 - self.x1
|
|
34 |
dy1 = rhs.y1 - self.y1
|
|
35 |
dx2 = rhs.x1 - self.x2
|
|
36 |
dy2 = rhs.y1 - self.y2
|
|
37 |
cross.append(dx1*dy1 - dy1*dx2)
|
|
38 |
dx1 = rhs.x2 - self.x1
|
|
39 |
dy1 = rhs.y2 - self.y1
|
|
40 |
dx2 = rhs.x2 - self.x2
|
|
41 |
dy2 = rhs.y2 - self.y2
|
|
42 |
cross.append(dx1*dy1 - dy1*dx2)
|
|
43 |
|
|
44 |
if cross[0] > 0 and cross[1] > 0: return False
|
|
45 |
|
|
46 |
return Length < 0.0001
|
|
47 |
|
|
48 |
"""
|
|
49 |
두 직선의 거리를 구한다.
|
|
50 |
"""
|
|
51 |
def DistanceTo(self, rhs):
|
|
52 |
dx = rhs.x1 - self.x1
|
|
53 |
dy = rhs.y1 - self.y1
|
|
54 |
dot = self.dx*dx + self.dy*dy
|
|
55 |
tmp = dot
|
|
56 |
x1 = self.x1 + tmp*self.dx
|
|
57 |
y1 = self.y1 + tmp*self.dy
|
|
58 |
dx = x1 - rhs.x1
|
|
59 |
dy = y1 - rhs.y1
|
|
60 |
return math.sqrt(dx*dx + dy*dy)
|
|
61 |
|
|
62 |
'''
|
|
63 |
두 직선의 사이를 가로지르는 직선을 구한다.
|
|
64 |
'''
|
|
65 |
def Merge(self, rhs):
|
|
66 |
dx1 = rhs.x1 - self.x1
|
|
67 |
dy1 = rhs.y1 - self.y1
|
|
68 |
dx2 = rhs.x1 - self.x2
|
|
69 |
dy2 = rhs.y1 - self.y2
|
|
70 |
|
|
71 |
candidates = []
|
|
72 |
candidates.append((self.x1, self.y1))
|
|
73 |
candidates.append((self.x2, self.y2))
|
|
74 |
|
|
75 |
Dir = []
|
|
76 |
cross = dx1*dy2 - dy1*dx2
|
|
77 |
if cross > 0:
|
|
78 |
dot = dx1*self.dx + dy1*self.dy
|
|
79 |
tmp = (self.x1 + dot*self.dx, self.y1 + dot*self.dy)
|
|
80 |
candidates.append(tmp)
|
|
81 |
Dir.append((rhs.x1 - tmp[0], rhs.y1 - tmp[1]))
|
|
82 |
|
|
83 |
dx1 = rhs.x2 - self.x1
|
|
84 |
dy1 = rhs.y2 - self.y1
|
|
85 |
dx2 = rhs.x2 - self.x2
|
|
86 |
dy2 = rhs.y2 - self.y2
|
|
87 |
cross = dx1*dy2 - dy1*dx2
|
|
88 |
if cross > 0:
|
|
89 |
dot = dx1*self.dx + dy1*self.dy
|
|
90 |
tmp = (self.x1 + dot*self.dx, self.y1 + dot*self.dy)
|
|
91 |
candidates.append(tmp)
|
|
92 |
Dir.append((rhs.x2 - tmp[0], rhs.y2 - tmp[1]))
|
|
93 |
|
|
94 |
MaxLength = None
|
|
95 |
Points = []
|
|
96 |
for i in range(len(candidates) - 1):
|
|
97 |
for j in range(i+1, len(candidates)):
|
|
98 |
dx = candidates[i][0] - candidates[j][0]
|
|
99 |
dy = candidates[i][1] - candidates[j][1]
|
|
100 |
Length = dx*dx + dy*dy
|
|
101 |
if MaxLength == None:
|
|
102 |
MaxLength = Length
|
|
103 |
Points.append(candidates[i])
|
|
104 |
Points.append(candidates[j])
|
|
105 |
elif MaxLength < Length:
|
|
106 |
MaxLength = Length
|
|
107 |
Points[0] = candidates[i]
|
|
108 |
Points[1] = candidates[j]
|
|
109 |
|
|
110 |
if len(Points) == 2 and len(Dir) > 0:
|
|
111 |
x1 = Points[0][0] + Dir[0][0]*0.5
|
|
112 |
y1 = Points[0][1] + Dir[0][1]*0.5
|
|
113 |
x2 = Points[1][0] + Dir[0][0]*0.5
|
|
114 |
y2 = Points[1][1] + Dir[0][1]*0.5
|
|
115 |
return LineVector(x1, y1, x2, y2)
|
|
116 |
else:
|
|
117 |
dx1 = rhs.x1 - self.x1
|
|
118 |
dy1 = rhs.y1 - self.y1
|
|
119 |
dot = dx1*self.dx + dy1*self.dy
|
|
120 |
tmp = (self.x1 + dot*self.dx, self.y1 + dot*self.dy)
|
|
121 |
Dir.append((rhs.x1 - tmp[0], rhs.y1 - tmp[1]))
|
|
122 |
x1 = Points[0][0] + Dir[0][0]*0.5
|
|
123 |
y1 = Points[0][1] + Dir[0][1]*0.5
|
|
124 |
x2 = Points[1][0] + Dir[0][0]*0.5
|
|
125 |
y2 = Points[1][1] + Dir[0][1]*0.5
|
|
126 |
return LineVector(x1, y1, x2, y2)
|
|
127 |
|
|
128 |
return LineVector(self.x1, self.y1, self.x2, self.y2)
|
|
129 |
|
|
130 |
def Draw(self, img, r, g, b):
|
|
131 |
cv2.line(img, (int(self.x1), int(self.y1)), (int(self.x2), int(self.y2)), (r, g, b), 1)
|
|
132 |
|
|
133 |
class LineDetector():
|
|
134 |
def __init__(self, image):
|
|
135 |
thresh = 127
|
|
136 |
self.Image = cv2.threshold(image, thresh, 255, cv2.THRESH_BINARY)[1]
|
|
137 |
w, h = image.shape[::-1]
|
|
138 |
self.Result = np.zeros((h,w,3), np.uint8)
|
|
139 |
|
|
140 |
##
|
|
141 |
## 이미지에서 직선을 검출한다.
|
|
142 |
##
|
|
143 |
def Detect(self):
|
|
144 |
kernel = np.ones((2, 2), np.uint8)
|
|
145 |
#erosion = cv2.dilate(self.Image, kernel, iterations=2)
|
|
146 |
erosion = cv2.morphologyEx(self.Image, cv2.MORPH_ERODE, kernel)
|
|
147 |
#erosion = self.Image
|
|
148 |
edge = cv2.bitwise_not(erosion)
|
|
149 |
#edge = cv2.Canny(erosion, 250, 500)
|
|
150 |
lines = cv2.HoughLinesP(edge, 1, np.pi/180, 500, 500, 100)
|
|
151 |
|
|
152 |
LineVectors = []
|
|
153 |
'''
|
|
154 |
LineVectors.append(LineVector(1984, 612, 1984, 987))
|
|
155 |
LineVectors.append(LineVector(1989, 615, 1989, 870))
|
|
156 |
'''
|
|
157 |
for line in lines:
|
|
158 |
x1, y1, x2, y2 = line[0]
|
|
159 |
line = LineString([(x1, y1), (x2, y2)])
|
|
160 |
#line = LineVector(x1, y1, x2, y2)
|
|
161 |
LineVectors.append(line)
|
|
162 |
|
|
163 |
'''
|
|
164 |
MergedLines = []
|
|
165 |
for i in range(len(LineVectors)):
|
|
166 |
if LineVectors[i].DrawFlag == False: continue
|
|
167 |
for j in range(i+1, len(LineVectors)):
|
|
168 |
if LineVectors[j].DrawFlag == False: continue
|
|
169 |
if LineVectors[i].IsParallel(LineVectors[j]) and (LineVectors[i].DistanceTo(LineVectors[j]) < 10):
|
|
170 |
MergedLines.append(LineVectors[i].Merge(LineVectors[j]))
|
|
171 |
Merged = True
|
|
172 |
LineVectors[i].DrawFlag = False
|
|
173 |
LineVectors[j].DrawFlag = False
|
|
174 |
break
|
|
175 |
if LineVectors[i].DrawFlag == True: MergedLines.append(LineVectors[i])
|
|
176 |
|
|
177 |
'''
|
|
178 |
#lines = linemerge(LineVectors)
|
|
179 |
#for line in list(lines):
|
|
180 |
# line.Draw(self.Result, 0, 255, 0)
|
|
181 |
|
|
182 |
'''
|
|
183 |
for line in MergedLines:
|
|
184 |
line.Draw(self.Result, 0, 0, 255)
|
|
185 |
'''
|
|
186 |
|
|
187 |
#contours는 point의 list형태. 예제에서는 사각형이 하나의 contours line을 구성하기 때문에 len(contours) = 1. 값은 사각형의 꼭지점 좌표.
|
|
188 |
#hierachy는 contours line의 계층 구조
|
|
189 |
image, contours, hierachy = cv2.findContours(erosion, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
|
|
190 |
image = cv2.drawContours(self.Result, contours, -1, (0,255,0), 3)
|
|
191 |
|
|
192 |
#b, g, r = cv2.split(src)
|
|
193 |
#pltSrc = cv2.merge([r, g, b])
|
|
194 |
#plt.imshow(pltSrc)
|
|
195 |
#plt.show()
|
|
196 |
#plt.imshow(erosion)
|
|
197 |
#plt.show()
|
|
198 |
cv2.imwrite("d:/Projects/DTIPID/DTI_PID/DTI_PID/res/lines.png", self.Result)
|
|
199 |
#resized = cv2.resize(edge, None, fx = 0.25, fy = 0.25)
|
|
200 |
#cv2.imshow('Canny', resized)
|
|
201 |
#cv2.imshow('Canny', erosion)
|