Skip to content

Commit bf649ac

Browse files
committed
Finalized Vector Code
1 parent c567c27 commit bf649ac

File tree

4 files changed

+90
-83
lines changed

4 files changed

+90
-83
lines changed

src/autonomous_kart/autonomous_kart/nodes/opencv_pathfinder/angle_calculator.py

Lines changed: 0 additions & 14 deletions
This file was deleted.

src/autonomous_kart/autonomous_kart/nodes/opencv_pathfinder/label.py

Lines changed: 83 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,16 @@
33
import time
44
import math
55

6+
KERNEL = np.ones((3,3), np.uint8)
7+
LOWER_RED = np.array([0,0,70])
8+
UPPER_RED = np.array([200,50,255])
9+
610
# @param: Video
7-
# @ret: Mask of the video's road
8-
def get_video_mask(vid, debug=False, percent=0.65, optimize=True, pixel_range=6, pic_offset=5, steps=20):
11+
# @param: Percent of the road (top down)
12+
# @param: Optimize if you want or dont want vectorized
13+
#
14+
# Note the rest of params are for search based algo
15+
def get_video_mask(vid, debug=False, percent=0.0, optimize=True, pixel_range=3, pic_offset=5, steps=40):
916
if vid is None:
1017
print("Error opening video")
1118
return None
@@ -45,7 +52,7 @@ def get_video_mask(vid, debug=False, percent=0.65, optimize=True, pixel_range=6,
4552
width = w - 1 - pic_offset
4653
y_index = int(height * percent)
4754

48-
presult[y_index:height-10, pic_offset:width] = result
55+
presult[y_index:height, pic_offset:width] = result
4956

5057
right_deg = get_angle((width, pic_offset), (width // 2, pic_offset), prev_right)
5158
left_deg = get_angle((pic_offset, pic_offset), (width // 2, pic_offset), prev_left)
@@ -66,11 +73,26 @@ def get_video_mask(vid, debug=False, percent=0.65, optimize=True, pixel_range=6,
6673
video.release()
6774
cv.destroyAllWindows()
6875

76+
# Takes parameters for get_img_mask
77+
# Return Coords and their angles
78+
def get_img_angles(img, debug=False, percent=0.0, prev_right=None, prev_left=None, optimize=True, pixel_range=3, pic_offset=5, steps=40):
79+
image, right, left = get_img_mask(img, debug=debug, optimize=optimize, percent=percent, prev_right=prev_right, prev_left=prev_left, pixel_range=pixel_range, pic_offset=pic_offset, steps=steps)
80+
81+
w = img.shape[1]
82+
width = w - 1 - pic_offset
83+
84+
right_deg = get_angle((width, pic_offset), (width // 2, pic_offset), right)
85+
left_deg = get_angle((pic_offset, pic_offset), (width // 2, pic_offset), left)
86+
87+
return (right_deg, left_deg)
88+
6989

7090
# @param img: Image Matrix
71-
# @param y_cutoff: Only consider y percent of image
72-
# @ret: Mask of the road
73-
def get_img_mask(img: np.ndarray, debug=False, percent=0.65, prev_right=None, prev_left=None, optimize=True, pixel_range=6, pic_offset=5, steps=20):
91+
# @param: Percent of the road (top down)
92+
# @param: Optimize if you want or dont want vectorized
93+
#
94+
# @ret: Right and left angles of track
95+
def get_img_mask(img: np.ndarray, debug=False, percent=0.0, prev_right=None, prev_left=None, optimize=True, pixel_range=3, pic_offset=5, steps=40):
7496
if img is None:
7597
print ('Error opening image!')
7698
return None, None, None
@@ -80,16 +102,13 @@ def get_img_mask(img: np.ndarray, debug=False, percent=0.65, prev_right=None, pr
80102
height, width = h - 1 - pic_offset, w - 1 - pic_offset
81103
y_index = int(height * percent)
82104

83-
roi_image = img[y_index:height-pic_offset, pic_offset:width]
105+
roi_image = img[y_index:height, pic_offset:width]
84106

85107
# Get hue mask
86108
image_hsv = get_hsv(roi_image)
87-
lower_red = np.array([0, 0, 70])
88-
higher_red = np.array([200, 50, 255])
89-
mask_red = cv.inRange(image_hsv, lower_red, higher_red)
109+
mask_red = cv.inRange(image_hsv, LOWER_RED, UPPER_RED)
90110

91-
kernel = np.ones((3, 3), np.uint8)
92-
result = cv.morphologyEx(mask_red, cv.MORPH_OPEN, kernel)
111+
result = cv.morphologyEx(mask_red, cv.MORPH_OPEN, KERNEL)
93112

94113
if prev_right is None:
95114
prev_right = (width, height)
@@ -107,6 +126,7 @@ def get_img_mask(img: np.ndarray, debug=False, percent=0.65, prev_right=None, pr
107126
right = vectorized_road_coord(result, True)
108127
left = vectorized_road_coord(result, False)
109128
else:
129+
# Old algo logic, being included for future uses just in case
110130
right = find_road_coord(img, prev_right, True, optimize=optimize, pixel_range=pixel_range, pic_offset=pic_offset, steps=steps)
111131
left = find_road_coord(img, prev_left, False, optimize=optimize, pixel_range=pixel_range, pic_offset=pic_offset, steps=steps)
112132

@@ -115,6 +135,8 @@ def get_img_mask(img: np.ndarray, debug=False, percent=0.65, prev_right=None, pr
115135

116136
return (result, right, left)
117137

138+
# Fast road lookup
139+
# @ret: Rigth and left road coords
118140
def vectorized_road_coord(img, right_side, pic_offset=5):
119141
h, w = img.shape[:2]
120142
height, width = h - 1 - pic_offset, w - 1 - pic_offset
@@ -124,7 +146,7 @@ def vectorized_road_coord(img, right_side, pic_offset=5):
124146
h_start = height
125147
h_end = pic_offset
126148

127-
if img[h_start, w_start].any():
149+
if img[h_start, w_start] != 0:
128150
column = img[h_end:h_start + 1, w_start]
129151
inv = np.logical_not(column[::-1])
130152
idx = np.argmax(inv)
@@ -139,42 +161,7 @@ def vectorized_road_coord(img, right_side, pic_offset=5):
139161
idx = np.argmax(row)
140162
return (w_start + idx, h_start)
141163

142-
143-
def find_road_coord(img, prev_pixel, right_side: bool, optimize=True, pixel_range=6, pic_offset=5, steps=20):
144-
h, w = img.shape[:2]
145-
height, width = h - 1 - pic_offset, w - 1 - pic_offset
146-
147-
if (optimize):
148-
new_pixel = lookup_road_coord(img, prev_pixel, right_side, pixel_range=pixel_range, pic_offset=pic_offset)
149-
if new_pixel:
150-
return new_pixel
151-
152-
steps_h = -1 * steps
153-
steps_w = -1 * steps if right_side else steps
154-
slow_step_h = 1
155-
slow_step_w = 1 if right_side else -1
156-
157-
h_start = height
158-
h_end = pic_offset
159-
w_start = width if right_side else pic_offset
160-
w_end = width // 2
161-
162-
if img[h_start, w_start].any():
163-
for i in range(h_start, h_end, steps_h):
164-
if not img[i, w_start].any():
165-
for j in range(i, h_start + 1, slow_step_h):
166-
if img[j, w_start].any():
167-
return (w_start, j)
168-
else:
169-
for i in range(w_start, w_end, steps_w):
170-
if img[h_start, i].any():
171-
for j in range(i, w_start + slow_step_w, slow_step_w):
172-
if not img[h_start, j].any():
173-
return (j, h_start)
174-
175-
return prev_pixel
176-
177-
164+
# O(1) road lookup
178165
def lookup_road_coord(img, prev_pixel, right_side, pixel_range=6, pic_offset=5):
179166
h, w = img.shape[:2]
180167
height, width = h - 1 - pic_offset, w - 1 - pic_offset
@@ -218,12 +205,44 @@ def lookup_road_coord(img, prev_pixel, right_side, pixel_range=6, pic_offset=5):
218205

219206
return None
220207

221-
def get_angle_vector(middle_coord, road_coord):
222-
dx = road_coord[0] - middle_coord[0]
223-
dy = road_coord[1] - middle_coord[1]
224-
angle_rad = math.atan2(dy, dx)
225-
return math.degrees(angle_rad)
226208

209+
# Old algorithm to find the road coord
210+
# Very optimized but still slower than vectorized operations
211+
def find_road_coord(img, prev_pixel, right_side: bool, optimize=True, pixel_range=6, pic_offset=5, steps=20):
212+
h, w = img.shape[:2]
213+
height, width = h - 1 - pic_offset, w - 1 - pic_offset
214+
215+
if (optimize):
216+
new_pixel = lookup_road_coord(img, prev_pixel, right_side, pixel_range=pixel_range, pic_offset=pic_offset)
217+
if new_pixel:
218+
return new_pixel
219+
220+
steps_h = -1 * steps
221+
steps_w = -1 * steps if right_side else steps
222+
slow_step_h = 1
223+
slow_step_w = 1 if right_side else -1
224+
225+
h_start = height
226+
h_end = pic_offset
227+
w_start = width if right_side else pic_offset
228+
w_end = width // 2
229+
230+
if img[h_start, w_start].any():
231+
for i in range(h_start, h_end, steps_h):
232+
if not img[i, w_start].any():
233+
for j in range(i, h_start + 1, slow_step_h):
234+
if img[j, w_start].any():
235+
return (w_start, j)
236+
else:
237+
for i in range(w_start, w_end, steps_w):
238+
if img[h_start, i].any():
239+
for j in range(i, w_start + slow_step_w, slow_step_w):
240+
if not img[h_start, j].any():
241+
return (j, h_start)
242+
243+
return prev_pixel
244+
245+
# Angle calc
227246
def get_angle(zero_coord, middle_coord, road_coord):
228247
a = get_distance(road_coord, zero_coord)
229248
b = get_distance(zero_coord, middle_coord)
@@ -235,12 +254,13 @@ def get_angle(zero_coord, middle_coord, road_coord):
235254
rads = math.acos( numerator / denominator)
236255
return math.degrees(rads)
237256

238-
257+
# Distance calc
239258
def get_distance(point1, point2):
240259
dx = point1[0] - point2[0]
241260
dy = point1[1] - point2[1]
242261
return math.sqrt(dx*dx + dy *dy)
243262

263+
# If coords are within a certain threshold of each other
244264
def within_difference(r_coord, l_coord, threshold):
245265
c1, r1 = r_coord
246266
c2, r2 = l_coord
@@ -263,14 +283,22 @@ def draw_lines(img, r_coord, l_coord, middle=None):
263283
cv.line(img, (middle, 0), l_coord, (200, 0, 200), 3)
264284
return img
265285

286+
287+
# @param: Image
288+
# @ret: Adaptive Gaussain threshold
266289
def get_threshold(img):
267290
return cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C, cv.THRESH_BINARY,11,2)
268291

292+
293+
# @param: Threshold
294+
# @ret: Traditional contours
269295
def get_contours(thresh):
270296
contours, hierachy = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_SIMPLE)
271297

272298
return contours
273299

300+
# @param: Image
301+
# @ret: Gaussian
274302
def get_gradient(img):
275303
h, w = img.shape[:2]
276304
gradient = np.linspace(0, 1, h).reshape(h, 1)

src/autonomous_kart/autonomous_kart/nodes/opencv_pathfinder/opencv_pathfinder_node.py

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@
1010
from sensor_msgs.msg import Image
1111
from std_msgs.msg import Float32MultiArray
1212

13-
from autonomous_kart.nodes.opencv_pathfinder.angle_calculator import (
14-
calculate_track_angles,
15-
)
13+
from label import get_img_angles
1614

1715

1816
class OpenCVPathfinderNode(Node):
@@ -70,13 +68,8 @@ def image_callback(self, msg):
7068
self.frames_since_last_log = 0
7169

7270
# Publish angles
73-
angles = calculate_track_angles(frame)
74-
if not self.angle_msg:
75-
self.angle_msg = Float32MultiArray(data=angles)
76-
else:
77-
# self.angle_pub.publish(Float32MultiArray(data=angles))
78-
self.angle_msg.data = angles
79-
self.angle_pub.publish(self.angle_msg)
71+
right_angle, left_angle = get_img_angles(frame, percent=0.65)
72+
self.angle_pub.publish((right_angle, left_angle))
8073

8174

8275
def main(args=None):

src/autonomous_kart/autonomous_kart/nodes/opencv_pathfinder/profiler.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def get_avg_time(vid, trips=1, optimize=True, percent=0.70, steps=40, pixel_rang
1616
for i in range(min(trips, 2)):
1717
start = time.perf_counter()
1818
for j in frames:
19-
img, right, left = label.get_img_mask(j, debug=False, prev_right=right, prev_left=left, optimize=optimize, percent=percent, steps=steps, pixel_range=pixel_range, pic_offset=pic_offset)
19+
right, left, right_angle, left_angle = label.get_img_angles(j, debug=False, prev_right=right, prev_left=left, optimize=optimize, percent=percent, steps=steps, pixel_range=pixel_range, pic_offset=pic_offset)
2020
end = time.perf_counter()
2121
t = (end - start) / len(frames)
2222
total_time += t
@@ -45,8 +45,8 @@ def get_frames(vid):
4545
# photo = label.get_image("/ws/data/internet_test_footage/driver-pov-img.png")
4646

4747
# cProfile.run('label.get_img_mask(photo)')
48-
original_video = label.get_video("/ws/data/EVC_test_footage/video.mp4")
48+
# original_video = label.get_video("/ws/data/EVC_test_footage/video.mp4")
4949

50-
avg = get_avg_time(original_video, trips=1, optimize=True, percent=0.7, steps=40, pixel_range=4, pic_offset=5)
50+
# avg = get_avg_time(original_video, trips=1, optimize=True)
5151

52-
print(avg)
52+
# print(avg)

0 commit comments

Comments
 (0)