跑道线检测——小车巡线

目的

小车需要在跑道上进行做巡线运动。

步骤

一、

首先进行将图像转换为灰度图并且进行二值化、高斯模糊等处理。然后我首先创建一个空白图像,然后在其中绘制检测到的跑道线。遍历检测到的线段,计算每条线段与图像中心的距离,并确定最接近图像中心的左侧跑道线和右侧跑道线,根据线段的斜率判断跑道线的左右方向,并根据与图像中心的距离选择最接近的左右跑道线。同时绘制一条红色横线作为参考,用来指示跑道线的位置。

二、

写出'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
运行效果

由于之前在编写代码时的失败示例都被我不小心删除了呜呜呜~(>_<)~,不能进行参考撰写,所以最后只能给大家呈现出成功后的效果了 。以上是我尝试从我的角度分享了关于该源代码的一些基本概念和理解。虽然我还有很多需要学习和提高的地方,但我真诚地希望上述能够对初学者有所帮助,谢谢大家的阅读和支持!

Scratchpad是一种编程语言和编程环境,它可用于创建交互式的媒体、教育项目和游戏。 "巡线"是指使用传感器或相机等设备对地面上的线进行扫描,并根据线路的特征进行移动或其他操作。因此,Scratchpad巡线就是利用Scratchpad编程环境来实现巡线机器人的功能。 要实现Scratchpad巡线,首先需要一个巡线机器人,它应该配备有适合巡线任务的传感器,例如光电传感器用于检测线路。然后,我们可以使用Scratchpad提供的编程环境来编写程序,使机器人能够根据传感器的反馈正确地跟随线路。 在Scratchpad中,我们可以使用图形化的积木块来编写程序。首先,我们可以使用"当绿旗被点击"积木块来启动程序。接下来,使用"重复无限"积木块来循环执行后续的操作。 在循环中,我们可以使用"如果...那么"积木块来判断机器人是否在线上。根据传感器检测到的光线可以设置一个阈值,判断当前是否在黑线上。如果在线上,就使用"前进"或"向左/向右转弯"的积木块控制机器人向前移动。如果不在线上,可以使用不同的积木块实现相应的调整动作,例如"左转一点"或"右转一点"。 除了巡线的基本功能,我们还可以在程序中加入其他功能,例如使用"当碰到...时"的积木块来检测和处理障碍物。另外,可以使用变量和控制积木块添加更复杂的逻辑和交互操作。 总结起来,Scratchpad巡线是利用Scratchpad编程环境和机器人的传感器来实现巡线功能。通过使用图形化的积木块编程,我们可以根据传感器检测到的线路特征控制机器人按照线路移动。这样的应用有助于培养编程和创造力的能力,并促进学习和娱乐的结合。
评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

凌同学的保温杯

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值