目的
小车需要在跑道上进行做巡线运动。
步骤
一、
首先进行将图像转换为灰度图并且进行二值化、高斯模糊等处理。然后我首先创建一个空白图像,然后在其中绘制检测到的跑道线。遍历检测到的线段,计算每条线段与图像中心的距离,并确定最接近图像中心的左侧跑道线和右侧跑道线,根据线段的斜率判断跑道线的左右方向,并根据与图像中心的距离选择最接近的左右跑道线。同时绘制一条红色横线作为参考,用来指示跑道线的位置。
二、
写出'draw_center_line'函数计算跑道的中心线,并且绘制出来,同时计算出我们小车相对于中心线的偏移量。重复遍历检测到的线段操作,我筛选出位于红色横线这条参考线以上的跑道线线段,通过线段的斜率判断左右方向,并且计算每侧跑道线的平均x坐标。另外我还绘制了绿色线段,并在图像上计算显示出小车的偏移量Offset。这便于后续通过该偏移量精准判断小车的位置来调pid角度使得小车不会发生偏移并且准确的巡着跑道线前进。
代码示例
def process_image(image):
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
_, thresholded = cv2.threshold(gray, 185, 255, cv2.THRESH_BINARY)
blurred = cv2.GaussianBlur(thresholded, (3, 3), 30)
return blurred
def draw_lane_lines(image, lines, intersect_y):
line_image = np.zeros_like(image)
if lines is not None:
closest_left_line = None
closest_right_line = None
min_left_distance = float('inf')
min_right_distance = float('inf')
for index, line in enumerate(lines):
for x1, y1, x2, y2 in line:
if y1 < intersect_y and y2 < intersect_y:
distance_to_center = abs((x1 + x2) // 2 - image.shape[1] // 2)
if (y2 - y1) / (x2 - x1) < 0:
if distance_to_center < min_left_distance:
min_left_distance = distance_to_center
closest_left_line = index
else:
if distance_to_center < min_right_distance:
min_right_distance = distance_to_center
closest_right_line = index
for index, line in enumerate(lines):
for x1, y1, x2, y2 in line:
if index != closest_left_line and index != closest_right_line:
cv2.line(line_image, (x1, y1), (x2, y2), (255, 0, 0), 3) # 将其他线颜色修改为蓝色(BGR)
# 绘制横线
cv2.line(line_image, (0, intersect_y), (image.shape[1], intersect_y), (0, 0, 255), 3) # 红色
return line_image
def draw_center_line(image, lines, intersect_y):
center_line_image = np.zeros_like(image)
left_x = []
right_x = []
red_line_bottom_y = intersect_y # 红线的底部y坐标
if lines is not None:
for line in lines:
for x1, y1, x2, y2 in line:
if y1 > red_line_bottom_y and y2 > red_line_bottom_y:
if (y2 - y1) / (x2 - x1) < 0:
left_x.append((x1 + x2) // 2)
else:
right_x.append((x1 + x2) // 2)
if left_x and right_x:
left_avg_x = int(np.mean(left_x))
right_avg_x = int(np.mean(right_x))
cv2.line(center_line_image, (left_avg_x, image.shape[0]), (right_avg_x, image.shape[0]), (0, 255, 0), 50)
center_x = image.shape[1] // 2
offset = center_x - (left_avg_x + right_avg_x) // 2
# 限制 offset 在指定的区域内
if intersect_y - 40 < image.shape[0]: # 确保不超出图像的高度范围
offset = max(-200, min(200, offset))
font = cv2.FONT_HERSHEY_SIMPLEX
cv2.putText(center_line_image, f'Offset: {offset}', (10, 30), font, 1, (255, 255, 255), 2)
return center_line_image
if lines is not None:
filtered_lines = [] # 用于存储滤除异常线段后的线段列表
for line in lines:
for x1, y1, x2, y2 in line:
# 添加判断条件以滤除异常线段
if abs(y2 - y1) > -1 and abs((y2 - y1) / (x2 - x1)) < 100:
filtered_lines.append(line)
if filtered_lines:
left_x = []
right_x = []
for line in filtered_lines:
for x1, y1, x2, y2 in line:
if y1 < intersect_y and y2 < intersect_y:
if (y2 - y1) / (x2 - x1) < 0:
left_x.append((x1 + x2) // 2)
else:
right_x.append((x1 + x2) // 2)
if left_x and right_x:
left_avg_x = int(np.mean(left_x))
right_avg_x = int(np.mean(right_x))
intersection_x = (left_avg_x + right_avg_x) // 2
intersection_x_buffer.append(intersection_x)
if len(intersection_x_buffer) > moving_average_window:
intersection_x_buffer.pop(0)
smoothed_intersection_x = int(np.mean(intersection_x_buffer))
if abs(smoothed_intersection_x - prev_intersection_x if prev_intersection_x else 0) < 100:
offset = frame_width // 2 - smoothed_intersection_x
cv2.line(frame, (smoothed_intersection_x, intersect_y), (frame_width // 2, frame_height), (0, 255, 255), 4)
prev_intersection_x = smoothed_intersection_x
运行效果
由于之前在编写代码时的失败示例都被我不小心删除了呜呜呜~(>_<)~,不能进行参考撰写,所以最后只能给大家呈现出成功后的效果了 。以上是我尝试从我的角度分享了关于该源代码的一些基本概念和理解。虽然我还有很多需要学习和提高的地方,但我真诚地希望上述能够对初学者有所帮助,谢谢大家的阅读和支持!