-
Notifications
You must be signed in to change notification settings - Fork 0
/
lane_detection.py
178 lines (153 loc) · 7.05 KB
/
lane_detection.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
# author: Robert Krook (guskrooro@student.gu.se)
# You may use this code for educational purposes if you keep these three lines
# as they are currently.
import numpy as np
import scipy.misc
from imageproc import imageproc
from util import util
import cv2 as cv
from sklearn import linear_model
# only want to pick up lines from a certain region of the videostream
def setROI(img_full):
mask = np.zeros(img_full.shape, dtype=np.uint8)
roi_corners = np.array([[(0,360),
(0,230),
(340,180),
(360,180),
(640,240),
(640,360)]], dtype=np.int32)
channel_count = img_full.shape[2]
ignore_mask_color =(255,)*channel_count
cv.fillPoly(mask, roi_corners, ignore_mask_color)
img_roi = cv.bitwise_and(img_full, mask)
return img_roi
# filters out lines that don't match the slope_treshold, and
# splits them up in respective x and y lists.
def handleLines(lines, lower_slope_threshold, upper_slope_threshold):
left_x = []
left_y = []
right_x = []
right_y = []
for line in lines:
x1,y1,x2,y2 = line
coef = float(x1-x2)/(y1-y2)
if (abs(coef) >= abs(lower_slope_threshold) and
abs(coef) <= abs(upper_slope_threshold)):
if coef < 0:
left_x.append(x1)
left_x.append(x2)
left_y.append(y1)
left_y.append(y2)
else:
right_x.append(x1)
right_x.append(x2)
right_y.append(y1)
right_y.append(y2)
return left_x, left_y, right_x, right_y
# create instances to the python library that calls futhark
ip = imageproc()
ut = util()
cap = cv.VideoCapture('green.mp4')
if cap.isOpened() == False:
print('error opening video')
# if you don't like ugly mega while-loops, this is where i advice
# you to look at something else. This is not my proudest moment.
# viewer discretion is adviced
while(cap.isOpened()):
ret,frame = cap.read()
# make a copy to draw on
final = np.array(frame)
if ret == True:
# set region of interest
roi = setROI(frame)
# grayscale the image
gray = ut.grayscale(np.int32(roi)).get()
# equalize the histogram. As calculating a histogram in a functional
# setting with immutable data is fruitless, this is done in openCV.
histEq = cv.equalizeHist(np.array(gray, dtype=np.uint8))
# binarize the image, keeping only those pixels that have a value
# greater than 240. You might need to tweak this depending on what
# setting your image is captured in.
binarized = ut.binarization(np.int32(histEq), 240).get()
# Now that hopefully only the lanes are left, perform canny edge
# detection to keep only the edges of the lanes. Change the first
# argument (std_dev) to change how well the image is blurred before
# edges are extracted. The following two arguments are the lower and
# upper threshold for the double thresholding. Should typically be 1:2
# format, and might also need to be changed to suit your image.
# Without all the preprocessing i do here, i need as low as 5 10 to get
# good lines.
edge = ip.canny_edge_detection(binarized, 5, 20, 40).get()
# The undesired data is (hopefully) gone from the image, now perform
# the probabilistic hough transform to extract the data. This is also
# done in openCV as this would probably also be fruitless in a
# functional setting. The blob extraction alone would be very heavy in
# memory traffic.
minLineLength = 5
maxLineGap = 20
lines = cv.HoughLinesP(np.array(edge, dtype=np.uint8),
1,
np.pi/180,
80,
minLineLength,
maxLineGap)
if lines is None:
lines = [[]]
print("no lines")
else:
left_x, left_y, right_x, right_y = handleLines(lines[0], 0.3, 4)
# basically, if we wish to draw a center line. We only do this if
# both lines are present
exists_both = False
l_x1 = 0
l_x2 = 0
r_x1 = 0
r_x2 = 0
# fit a linear model to the left lines and draw it on the image
if len(left_x) > 0 and len(left_y) > 0:
exists_both = True
regr_left = linear_model.LinearRegression()
regr_left.fit(np.reshape(left_y, (-1, 1)), left_x)
l_x1 = int(regr_left.predict(360)[0])
l_x2 = int(regr_left.predict(180)[0])
cv.line(final, (l_x1, 360), (l_x2, 180), (0,255,0), 2)
# fit a linear model to the right lines and draw it on the image
if len(right_x) > 0 and len(right_y) > 0:
exists_both = exists_both and True
regr_right = linear_model.LinearRegression()
regr_right.fit(np.reshape(right_y, (-1,1)), right_x)
r_x1 = int(regr_right.predict(360)[0])
r_x2 = int(regr_right.predict(180)[0])
cv.line(final, (r_x1, 360), (r_x2, 180), (2,255,0), 2)
# if both lines exists, draw the center line
if exists_both:
cv.line(final, (l_x1, 360), (r_x1, 360), color=3)
cv.line(final, (l_x2, 180), (r_x2, 180), color=3)
mid_x_top = l_x1 + abs(l_x1 - r_x1)/2
mid_x_bot = l_x2 + abs(l_x2 - r_x2)/2
cv.line(final, (mid_x_top, 360), (mid_x_bot, 180), color=5)
# change the dimensions of the images so they can all be
# printed in the same frame without becoming too big
frame = cv.resize(np.array(frame, dtype=np.uint8),
(0,0), None, .65, .65)
roi = cv.resize(roi, (0,0), None, .65, .65)
histEq = cv.resize(histEq, (0,0), None, .65, .65)
binarized = cv.resize(np.array(binarized, dtype=np.uint8),
(0,0), None, .65, .65)
edge = cv.resize(np.array(edge, dtype=np.uint8),
(0,0), None, .65, .65)
final = cv.resize(final, (0,0), None, .65, .65)
# make the 1 channel images have 3 channels, so we can stack
# and concatenate them however we like
histEq = cv.cvtColor(histEq, cv.COLOR_GRAY2BGR)
binarized = cv.cvtColor(binarized, cv.COLOR_GRAY2BGR)
edge = cv.cvtColor(edge, cv.COLOR_GRAY2BGR)
# stack and concatenate pictures to achieve one mega-picture
top_row = np.hstack((frame, roi, histEq))
bot_row = np.hstack((binarized, edge, final))
result = np.vstack((top_row, bot_row))
cv.imshow('edge-detection', np.array(result, dtype = np.uint8 ))
if cv.waitKey(20) & 0xFF == ord('q'):
break
else:
break