智能车巡线方案(双线方案,大残次品)


前言

参加智能车比赛,一周复制粘贴出来的代码。没有写函数,全放大循环里了,因为python是真的不是很会,真的很像一坨屎

一、核心思路

先将图像二值化(黑白地图),然后分别划分摄像头两侧的roi,分别计算两侧roi所看到的白色像素点总和,然后进行判断是否转弯。

话不多说,直接上代码

import time
import cv2
import numpy as np
import serial
from socket import *
#引入模板
img_leftcenter = cv2.imread('./left_26_2.png',0)
# 127.0.0.1表示本机的IP,用于测试,使用时需要改为服务端的ip
addr = ('192.168.106.54', 8080)
s = socket(AF_INET, SOCK_DGRAM) # 创建UDP套接字   //UDP视频流图传,有需要的或有想法的可以自行搜索
s.bind(('', 8081))
b=0
num=0
data='0'
cap = cv2.VideoCapture(0)
kernel = np.ones((3,3), np.uint8)
#模板函数     //模板函数是我队友添加上去的,为了识别路牌,但是时间太急没来得及调试,就只是写在了里面,没有用上,如果有兴趣的可以自行探索,这个识别率挺低的
def muban():
    ret,frame_mask = cap.read()
    frame_mask = cv2.cvtColor(frame_mask, cv2.COLOR_BGR2GRAY)  # 灰度
    # retval, line = cv2.threshold(frame, 180, 255, cv2.THRESH_BINARY)  # 二值
    frame_mask = cv2.GaussianBlur(frame_mask, (3,3), 1, 2)
    frame_mask = np.zeros_like(frame_mask)  # 获得一个与原矩阵相同的矩阵,画布
    frame_mask = cv2.fillPoly(frame_mask, np.array([[[390, 480], [390, 0], [640, 0], [640, 480]]]), color=255)  # 填充多边形的四个顶点
    frame_mask = cv2.bitwise_and(frame_mask, mask)
    result_left = cv2.matchTemplate(frame_mask,img_leftcenter,5)
    minVal,maxVal,minLoc,maxLoc = cv2.minMaxLoc(result_left)
     #"""左转"""
    print("左转最小:",minVal,"""左转最大:""",maxVal)
    if minVal <-0.55and minVal >-0.59and maxVal>0.61and maxVal<0.7 :
        print("left")
    elif minVal <-0.55and minVal >-0.59and maxVal>0.64and maxVal<0.9 :
        print("left")
        
#定义回调函数    //这是定义阈值按钮的回调函数,不需要特别关注,(因为我没看懂有啥作用)
def returnnum(x):
    pass 

cv2.namedWindow('two_fram')         #定义一个名叫 “two_fram”的窗口,为后面定义滑动条做一个前提准备
cv2.createTrackbar('two1','two_fram',190,255,returnnum)         #二值化的滑动条阈值一,第一个参数:滑动条名称,第二个参数:滑动条依附于哪个窗口,第三个参数:初始值,第四个参数:阈值滑动条最大值,第五个参数:回调函数
cv2.createTrackbar('two2','two_fram',255,255,returnnum)   
serial_port = serial.Serial(
    port="/dev/ttyUSB0",
    baudrate=115200,
    bytesize=serial.EIGHTBITS,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
)       #我们用的是nano来作为视觉判断向下位机(stm32)发送数据的端口   这里是打开并设置串口
serial_arduino= serial.Serial(
    port="/dev/ttyTHS1",
    baudrate=115200,
    bytesize=serial.EIGHTBITS,
    parity=serial.PARITY_NONE,
    stopbits=serial.STOPBITS_ONE,
)          #arduino串口设置,下位机向jetson nano发送数据
cx=0.0
cy=0.0
cxr=0.0
cyr=0.0  #这里都是用来初始化数据的
lo_blue = np.array([100,43,46])   #hsv颜色识别阈值
up_blue = np.array([124,255,255])  
green_up = np.array([35 ,43,46])
green_d= np.array([77,255,255])


global tinghs    #决定循环启动位置           
tinghs=0           #有限启动视频流图传      
serial_port.write('s\r\n'.encode())   #发送停止指令,默认让小车停止

while tinghs==0:        #     当tinghs=0时,先执行这个循环,将jetson nano 获得的视频传输到电脑上                     
    _, img = cap.read()
    img = cv2.flip(img, 1)
    _, send_data = cv2.imencode('.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 50])
    s.setsockopt(SOL_SOCKET, SO_REUSEADDR,1)
    s.sendto(send_data, addr)
    recv_data,addr = s.recvfrom(1024)
    recv_data = str(recv_data,'UTF-8')
    if recv_data == "green" :
        print("green")
        serial_port.write('g\r\n'.encode())  #识别到绿色后,程序退出前让车动起来
        tinghs=1   
        break

while tinghs==1:
    ret, frame = cap.read()
    two1=cv2.getTrackbarPos('two1','two_fram')
    two2=cv2.getTrackbarPos('two2','two_fram')
    if ret is True:
        #VideoCapture set
        gray_fram=cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)        #图像灰度
        retval,two_fram=cv2.threshold(gray_fram, two1, two2, cv2.THRESH_BINARY)  #二值化
        two_fram = cv2.morphologyEx(two_fram, op=cv2.MORPH_OPEN,kernel=kernel, iterations=1)         #开运算,腐蚀膨胀消除噪声
        #rio set
        roib=frame[430:480,0:640]       #蓝色识别(弃用)
        roil=two_fram[310:480,20:300]  #左侧roi划分
        roir=two_fram[310:480,340:640]  #右侧roi划分
        #findContours and draw it
        contourl, hierarchyl= cv2.findContours(roil,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)     #寻找白线并且定位白线中心位置,确定小车在大拐弯处的状态
        cv2.drawContours(frame,contourl,-1,(0,0,255),3)    #测试用,是否寻找出白线轮廓
        contourr, hierarchyr = cv2.findContours(roir,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)  
        cv2.drawContours(frame,contourr,-1,(0,0,255),3) 
        #if else:
        if serial_arduino.inWaiting()>0:       #如果arduino串口有数据,执行避障(避障是stm32写死的)
            data=serial_arduino.readline()
            if data==b'6\r\n':
                serial_port.write('s\r\n'.encode())
                things=2
                break
            else:
                pass
        else:
            if len(contourl) & (len(contourr))==0:       #防止找不到轮廓报错
                pass
            else:            
                M= cv2.moments(contourl[-1])        #寻找轮廓并且画出来,标出中心坐标
                cx = int(M['m10']/(M['m00']+0.01) )
                cy = int(M['m01']/(M['m00']+0.1) )
                cv2.circle(frame ,(cx,cy),2,(0,0,255),4) 
                print('cx=',cx,'cy=',cy,type(cy))
                Mr= cv2.moments(contourr[-1]) 
                cxr = int(Mr['m10']/(Mr['m00']+0.01) )
                cyr = int(Mr['m01']/(Mr['m00']+0.01) )
                cv2.circle(frame ,(cxr,cyr),2,(0,0,255),4) 
                print('cxr=',cxr,'cyr=',cyr)
            #hsv
            # hsv = cv2.cvtColor(roib,cv2.COLOR_BGR2HSV)
            # blue = cv2.inRange(hsv,lo_blue,up_blue)
            # blue=cv2.morphologyEx(blue, op=cv2.MORPH_OPEN,kernel=kernel, iterations=2)

            # hsvg= cv2.cvtColor(frame,cv2.COLOR_BGR2HSV)
            # green = cv2.inRange(hsvg,green_d,green_up)
            # green=cv2.morphologyEx(blue, op=cv2.MORPH_OPEN,kernel=kernel, iterations=2)
            # print('green',green)
            #data 
            white_l = np.sum(roil== 255)/5500    #找到白色点,并且计算总和数量,/5500是为了计算比例范围。这个根据实际场地调试,可以先输出白色点数量,寻找最大值后,再除以一定的数即可   。  
            white_r = np.sum(roir ==255)/5500
            print(white_l,white_r)
            #下面就是一堆判断了,思路可能会很乱,当时直接是上场地,遇到问题就硬调的。所以判断思路有些混乱
            if serial_arduino.inWaiting() ==0:
                if (0.0<=white_l<=0.23) &(0.0<=white_r<=0.23):
                    print('run')
                    serial_port.write('z\r\n'.encode())
                elif (0.18<white_l<0.45)&(white_r==0):
                    print('run')
                    serial_port.write('z\r\n'.encode())
                elif (white_l==0)&(white_r==0):
                    printf('left')
                    serial_port.write('l\r\n'.encode())  #以上就是在直走的情况下判断是否在大拐弯处转弯过晚,导致误判,(核心思想就是哪边白色像素点越多,就说明越靠近那一边,如:右侧白色像素点多于左侧,说明小车靠近右侧道路,所以应该左转,特别提醒!!我们的小车底盘是阿克曼结构,所以底层需要修改一下,转弯范围也需要修改)
                else:
                    if(white_l>white_r):
                        if (cy<cyr) &(cy>0.02):
                            print('big left')
                            serial_port.write('l\r\n'.encode())
                        else:
                            print('right')
                            serial_port.write('r\r\n'.encode())
                    else:
                        if (cy>cyr) & (cyr>0.02):
                            print('big right')
                            serial_port.write('r\r\n'.encode())
                        else:
                            print('left')
                            serial_port.write('l\r\n'.encode())
            
                """      # elif white_l>white_r:   #这一块是以前弃用的方案,判断的方法不一样,核心思路是一样的

                #     print('right')
                #     serial_port.write('-2\r\n'.encode())
                # elif white_r>white_r:
                #     print('left')
                #     serial_port.write('+2\r\n'.encode())
                # elif (white_r<0.2)&(white_l>0.2):
                #     if white_r<0.12:
                #         print('right')
                #         serial_port.write('r\r\n'.encode())
                #     else:
                #         print('run')
                #         serial_port.write('z\r\n'.encode())

                # elif (white_l<0.2)&(white_r>0.3):
                #     print('left')
                #     serial_port.write('l\r\n'.encode())
                # elif (white_r>0.6) :
                #     if (white_l>0.55) & (white_r>white_l):
                #         print('right')
                #         serial_port.write('r\r\n'.encode())
                #     elif (white_l>white_r):

                #         print('left')
                #         serial_port.write('l\r\n'.encode())
                #     elif(white_l<0.2):
                #         rint('right')
                #         serial_port.write('r\r\n'.encode())
                # elif  (white_r>0.5) :
                #     if white_l>0.2:
                #         print('left')
                #         serial_port.write('l\r\n'.encode())
                #     else:
                #         print('right')
                #         serial_port.write('r\r\n'.encode())

                # elif (white_r<0.09) &(white_l<0.09):
                #     print('run')
                #     serial_port.write('z\r\n'.encode())

                        """
				#这一块都是显示输出
            	#cv2.imshow("line_fram",frame)
                cv2.imshow("roil", roil)
                cv2.imshow('roir',roir)
                cv2.imshow('two_fram',two_fram) 
                #cv2.imshow('roib',roib)
            else:
                serial_port.write('s\r\n'.encode())  #这句似乎没用,不知道为啥小车停不下来,可能是我的流程有问题

        if cv2.waitKey(10) ==27:
            break
cap.release()
cv2.destroyAllWindows()


while things==2:         #弃用方案,想法是:小车遇到障碍物后会一直输出停止的指令,直到没有数据后会结束此循环跳到主循环里去
            if serial_arduino.inWaiting()>0:
                data=serial_arduino.readline()
                if  data==b'6\r\n':
                    serial_port.write('s\r\n'.encode())
                    print(data)

            else:
                things=1
                serial_port.write('g\r\n'.encode())
                break
        


总结

此代码是大大的大残次品(本人python也是略知皮毛,就不会使用函数啥的,opencv也才没学多久几乎是用到才会去学,而且也就只知道调用函数,代码几乎是复制粘贴的,没有涉及算法,全是判断,所以会有误判的情况),发出来是为了给自己留个记录的同时也给正在对双线巡线毫无头绪的同学提供一点点小启发…

  • 4
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
通过引用,我们知道在智能车竞赛中,使用了两套方案来完成巡线任务:一套是基于传统opencv的巡线,一套是用paddle搭建神经网络框架。然而,由于时间有限,只能利用假期的闲余时间来继续完善未完成的opencv巡线方案。 引用中提到了利用opencv完成视觉巡线的具体步骤。在白色地面上,通过摄像头检测黑色的车道线,来完成巡线任务。为了保持小车的稳定性,行驶速度被分为四个等级。在直道上,小车会逐渐加速,当加到最高速时保持匀速行驶。当检测到弯道时,小车会立即减速,并根据弯道的程度来调整速度和转向。 然而,在引用中提到了扫线方法在处理锐角时不适用的问题。但是在该赛道上,锐角只会在图片的上方出现,且只会出现左锐角,并且占比较小。因此,可以通过判断锐角的方式来避免扫描锐角的线。 综上所述,通过opencv实现智能车巡线的方法是,在白色地面上通过摄像头检测黑色的车道线,同时根据检测到的弯道和锐角来调整小车的速度和转向,以完成巡线任务。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [基于opencv的巡线方案](https://blog.csdn.net/weixin_64583557/article/details/126489522)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [智能小车视觉巡线python代码](https://download.csdn.net/download/LY2996944198/12646227)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [智能车巡线python-opencv](https://blog.csdn.net/m0_58644391/article/details/124382394)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值