基于OpenCV的巡线小车多赛道识别

该代码实现了一个基于OpenCV的赛道检测系统,通过识别摄像头拍摄的多赛道,找出赛道边缘的横坐标,计算赛道的角度和中点坐标。主要功能包括寻找赛道轮廓、判断赛道间距、计算角度等,用于小车导航或自动驾驶场景。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

对摄像头拍摄到的多赛道进行检测并输出每条赛道的角度和中点坐标

运行结果:

下面的代码都有注释

下面函数是先对整个画面进行扫描,选取合适的色块并排列得到他们的面积和对应的索引

def FindRoad():#在这里面寻找面积最大的4目标没有意义,这里我们主要用到的是没有找到目标时返回的结果
    area2 = []
    b = []
    Inf = -1
    if len(contour1) >= 1:                             #找到目标至少为一
        for i in range(len(contour1)):
            if cv2.contourArea(contour1[i])>50:
                area2.append(cv2.contourArea(contour1[i]))  #将找到目标面积储存到area2
        if len(area2)!=0:
            for j in range(4):   #只对前4个最大的面积进行操作
                b.append(area2.index(max(area2)))           #把目标按照面积大小从大到小存入列表b
                area2[area2.index(max(area2))] = Inf        #把刚刚存入列表的面积重新赋值为-1
        else:
            return 1

        b.sort()   #因为目标赛道检测到的面积有可能并不是按照顺序排列,所以在这里进行排列
        return b
    else:
        return 1

设置判断赛道之间的间距,根据的是得到的赛道边缘的横坐标

def JudgeRoad(n):
    s = []
    try:
        if n[2]-n[1]!=n[1]-n[0]:
            s.append(n[1])                    #列表s储存赛道边缘位置横坐标
        else:
            s.append(min(n))
        try:
            for i in range(len(n)):
                if n[i + 1] - n[i] >= 50:  #赛道的间距>50
                    s.append(n[i])
                    s.append(n[i + 1])
                if i==len(n)-2:
                    if n[len(n)-1] - n[len(n)-2]<5:
                        s.append(n[len(n)-1])
                        break
                    else:
                        s.append(n[len(n)-2])
                        break
        except:
            pass
        return s                   #返回赛道横坐标列表
    except Exception :
        return 1                   #错误时一定要返回值
        pass

计算赛道的角度

def calc_angle(x1,y1,x2,y2):
    angle = 0
    k = 0
    h = 0
    y = y1-y2
    x = x1-x2
    if x == 0:
        pass
    else:
        k = y/x
        h = math.atan(k)
        angle = 90 - abs(math.degrees(h))
    return angle

完整代码:

import cv2
import numpy as np
import math

# cap = cv2.VideoCapture('C:/Users/K2095/Desktop/777.mp4')(这是我提前拍摄的模拟小车运行时摄像头的画面)
cap = cv2.VideoCapture(0)

def FindRoad():
    area2 = []
    b = []
    Inf = -1
    if len(contour1) >= 1:                             #找到目标至少为一
        for i in range(len(contour1)):
            if cv2.contourArea(contour1[i])>50:
                area2.append(cv2.contourArea(contour1[i]))  #将找到目标面积储存到area2
        if len(area2)!=0:
            for j in range(4):   #只对前4个最大的面积进行操作
                b.append(area2.index(max(area2)))           #把目标按照面积大小从大到小存入列表b
                area2[area2.index(max(area2))] = Inf        #把刚刚存入列表的面积重新赋值为-1
        else:
            return 1
        b.sort()   #因为目标赛道检测到的面积有可能并不是按照顺序排列,所以在这里进行排列
        return b
    else:
        return 1

def JudgeRoad(n):
    s = []
    try:
        if n[2]-n[1]!=n[1]-n[0]:
            s.append(n[1])                    #列表s储存赛道边缘位置横坐标
        else:
            s.append(min(n))
        try:
            for i in range(len(n)):
                if n[i + 1] - n[i] >= 50:  #赛道的间距>50
                    s.append(n[i])
                    s.append(n[i + 1])
                if i==len(n)-2:
                    if n[len(n)-1] - n[len(n)-2]<5:
                        s.append(n[len(n)-1])
                        break
                    else:
                        s.append(n[len(n)-2])
                        break
        except:
            pass
        return s                   #返回赛道横坐标列表
    except Exception :
        return 1                   #错误时一定要返回值
        pass

def calc_angle(x1,y1,x2,y2):
    angle = 0
    k = 0
    h = 0
    y = y1-y2
    x = x1-x2
    if x == 0:
        pass
    else:
        k = y/x
        h = math.atan(k)
        angle = 90 - abs(math.degrees(h))
    return angle

while True:
    success , img = cap.read()
    img = cv2.resize(img, (640, 480))
    imgHSV = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    lowerblack = np.array([0, 0, 0])
    upperblack = np.array([255, 255, 120])
    maskblack = cv2.inRange(imgHSV, lowerblack, upperblack)
    contour1, hierarchy1 = cv2.findContours(maskblack, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    color = maskblack[380]                          #遍历掩膜第380行全部像素值
    color2 = maskblack[420]

    blackindex = np.where(color == 255)                      #储存像素为255的索引值
    blackindex2 = np.where(color2 == 255)
    npindex = np.array(blackindex)
    npindex2 = np.array(blackindex2)
    a = npindex.ravel()                                 #将数组维度拉成一维数组
    c = npindex2.ravel()

    FindRoad()
    o = FindRoad()  #为赛道的索引
    b = JudgeRoad(a)  #赛道边缘的横坐标,为偶数个
    b1 = []   #储存赛道中点横坐标
    blackindex2 = JudgeRoad(c)

    npindex2 = []

    if o == 1:
        print('未找到赛道')
        pass
    else:
        if len(str(b)) <= 1:       #b类型转换成字符串(防止报错)
            b1.append(1)
        else:
            for i in range(len(b)):
                if i % 2 == 0:
                    b1.append((b[i] + b[i + 1]) / 2)
                else:
                    pass
        if len(str(blackindex2)) <= 1:
            npindex2.append(1)
        else:
            for i in range(len(blackindex2)):
                if i % 2 == 0:
                    npindex2.append((blackindex2[i] + blackindex2[i + 1]) / 2)
                else:
                    pass
        if len(b1)==len(npindex2):
            for i in range(len(b1)):
                angle = calc_angle(npindex2[i], 420, b1[i], 380)
                cv2.circle(img, (int(npindex2[i]), 420), 3, 255, -1)
                cv2.circle(img, (int(b1[i]), 380), 3, 255, -1)
                print('赛道{}角度:{},中点横坐标:{}'.format(i+1,angle,b1[i]))
        else:
            pass
    cv2.imshow('s',maskblack)
    cv2.imshow('s1', img)
    if cv2.waitKey(30) & 0xFF == 27:  # 按Esc关闭
        break

### OpenCV 实现机器人或车辆的巡线算法 要实现基于 OpenCV 的机器人或车辆巡线功能,可以按照以下方法完成: #### 数据预处理 首先需要对摄像头捕获的图像进行必要的预处理。通常情况下,赛道的颜色可以通过 HSV 颜色空间中的特定范围来区分背景和其他物体[^4]。 ```python import cv2 import numpy as np def preprocess_image(image): hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV) # 转换到HSV颜色空间 lower_black = np.array([0, 0, 0]) # 黑色下限 upper_black = np.array([180, 255, 30]) # 黑色上限 mask = cv2.inRange(hsv, lower_black, upper_black) # 创建掩码 return mask ``` #### 图像分割与二值化 通过设定合适的阈值,将图像转化为黑白两部分,其中黑色代表赛道线条,白色代表其他区域。此过程有助于简化后续计算并提高效率。 ```python def threshold_image(mask): _, binary = cv2.threshold(mask, 1, 255, cv2.THRESH_BINARY) # 应用固定阈值 return binary ``` #### 扫描策略 对于二值化的图像,采用从底部中心向两侧扫描的方式寻找黑线位置。这种方法能够快速定位当前车道方向,并据此调整行驶路径。 ```python def find_line(binary_img, width=640, height=480): bottom_row = binary_img[height - 1, :] # 获取最下面一行像素 center_index = int(width / 2) # 向左扫描找第一个非零点 left_edge = None for i in range(center_index, 0, -1): if bottom_row[i]: left_edge = i break # 向右扫描找第一个非零点 right_edge = None for j in range(center_index, width): if bottom_row[j]: right_edge = j break return (left_edge, right_edge) ``` #### 控制逻辑 依据找到的边缘坐标决定转向角度或者速度差值,从而控制电机驱动轮子转动达到自动循迹目的[^2]。 ```python def control_vehicle(left_edge, right_edge, max_speed=100): if not left_edge and not right_edge: # 如果两边都找不到,则认为偏离轨道较大程度 turn_angle = 90 # 原地旋转直到重新发现线路为止 elif not left_edge or abs((right_edge-left_edge)/width*max_speed)>threshold_value: # 只有一侧可见时采取相应措施纠正偏差 pass else: mid_point=(left_edge+right_edge)//2 error=mid_point-width//2 kp=-0.5 #比例系数可以根据实际情况调节优化效果最佳 speed_difference=kp *error left_motor_speed=max_speed-speed_difference right_motor_speed=max_speed+speed_difference ``` 以上即为利用OpenCV库构建简单有效的视觉引导系统的核心流程概述[^1]^。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值