学科竞赛|2021电赛F题数字识别和巡线部分

学科竞赛|2021电赛F题数字识别和巡线部分
文章图片

文章之前12月发了一次,但是我后来申请的免毕设后,用到了一些文字,所以删了这篇文章,但是还是查重了,于是我把一些程序讲解先删了,等毕设结束后再编辑加上。


这次电赛我没有准备多少东西,只提前准备了图像识别和坐标计算一类的。在20年的省赛帮过雪地调过k210后,自己后来为了比赛,也买了一个。参加了省物联网和交通科技比赛。

由于这边学校对竞赛支持力度不大,经费不多,所以我就用了一块k210.用它作识别和巡线其实是完全够用的。只需要写个判断分开就好。
识别这块我起初自己配的aconda和pycharm环境,不过出现各种问题,没耐下心去做(这学期课程依旧很多,而且还有别的事)。直接用了mxyolo这款软件,一键配置环境库,再加上英伟达cuda加速就可以了。
我用了总共600张图片,花了20分钟大概(我的老笔记本gtx1050,没有独显直连所以也没有出过视频了。) 对象的1650大概在10分钟出头。标记是门体力活,好在有了不错的识别效果,图片样本拍摄是在不同光线和距离情况下,最终模型识别成功率大概在80%左右,速度很快。只是,7容易识别成1,5有时候会识别成2,这是在距离不定的情况下,我想是训练数据集不够。迭代在30,loss挺低了。
在摄像头悬空情况下,正好可以识别2-3个数字。
软件图后续想起来再补吧,我突然想写文章时候发现当时并没有截图。
再说一说软件部分吧,k210我是在Maixpy下进行编写的,调用外设库非常方便,只是没有花括号的缩进,我看着很难受。

初始化程序打开了各个外设以及定义了灰度值,灰度值需要在菜单栏里的——工具——机器视觉——阈值编辑器,选择帧缓冲图像,拖动滚动条,把红线与地面的背景分隔开。红线为白,其它为黑。(麻了,我又没存图,当时只留意存了十字线和巡线的。)
import sensor,image,lcd,time import KPU as kpu from Maix import FPIOA, GPIO from fpioa_manager import fm from board import board_info from machine import UART from Maix import GPIOfm.register(17, fm.fpioa.GPIO0, force=True) s_flag = GPIO(GPIO.GPIO0, GPIO.OUT)flag=1GRAYSCALE_THRESHOLD = [(87, 255)]#划分的灰度值 THRESHOLD =(10, 34, -41, 74, -109, 127)#摄像头垂直于地面lcd.init(freq=15000000) sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) #sensor.set_hmirror(0)#镜像 #sensor.set_vflip(1)#翻转 lcd.rotation(2)#旋转方向 参数是0~3, 分别代表顺时针旋转 0度 90度 180度 270度 sensor.set_windowing((224, 224)) #sensor.set_brightness(2) sensor.run(1) clock = time.clock()fm.register(23,fm.fpioa.UART2_TX) uart_A = UART(UART.UART2, 115200, 8, None, 1, timeout=1000, read_buf_len=4096)task = kpu.load("/sd/tt.kmodel") f=open("anchors.txt","r") anchor_txt=f.read() L=[] for i in anchor_txt.split(","): L.append(float(i)) anchor=tuple(L) f.close() a = kpu.init_yolo2(task, 0.6, 0.3, 5, anchor)f=open("lable.txt","r") labels_txt=f.read() labels = labels_txt.split(",") f.close()


死循环中我是通过标志位来切换两种模式的。首先上电先进入数字识别,第一次完成后进入巡线程序。后续切换是通过另一个主控发送数据改变的。
主控那边我简单说下吧,是通过闭环加入编码器计里程和十字线辅助判断每个路口,自加是第几个路口,停下来发信号给k210,在开始数字判断。
下面程序是老版本的,少写一些通信,数字在屏幕的左右正负偏差坐标即是数字在病房路口的位置,通过这个信息去PWM差速转向。
使用的PD进行转向控制,能精确锁住中线行驶。主控我认为用什么都可以,stc12啊,stc8都可以。之前自己做亚克力小车,加升压,在智能车赛道上一圈开环也能跑个16-18秒(没有加三岔路和圆环)。
这次比赛我用的是GD32的芯片,因为便宜,他们家封装的库还是挺好用的。
【学科竞赛|2021电赛F题数字识别和巡线部分】

学科竞赛|2021电赛F题数字识别和巡线部分
文章图片


这题我选择后,第一天深夜我才确定用摄像头方案,以前没有试过巡线,凌晨3点从openmv那里速成,代码搬过来了。后续我想学学opencv。
发现这题坑真多,量很大,光靠我一个人肯定做不完,所以需要点取巧的方法。
开环直线行驶很稳定,但是到十字路口会被干扰,于是我加了判断,并且把左右两边的白色区域给忽略了,还是当作一条直线。(在主控上根据我经过的十字路口和数字进行综合判断的)
def c_line(): s_flag.value(1) #识别到数字后17口高电平s img = sensor.snapshot().binary([THRESHOLD]) lcd.display(img)roi0=(80, 0,30, 30)#给识别中线的位置标上兴趣框,并画下来,验证。 most_pixels=0 img.draw_rectangle(roi0, color =170) blob0 = img.find_blobs(GRAYSCALE_THRESHOLD, roi=roi0,pixels_threshold=100, area_threshold=100, merge=True) if blob0: for n in range(len(blob0)): #目标区域找到的颜色块(线段块)可能不止一个,找到最大的一个,作为本区域内的目标直线 if blob0[n].pixels() > most_pixels: most_pixels = blob0[n].pixels() #merged_blobs[i][4]是这个颜色块的像素总数,如果此颜色块像素总数大于 largest_blob = n R = 1else: R = 0roi1=(80, 200,30, 30) img.draw_rectangle(roi1, color =170) blob1 = img.find_blobs(GRAYSCALE_THRESHOLD, roi=roi1,pixels_threshold=100, area_threshold=100, merge=True) if blob1: for n in range(len(blob1)): if blob1[n].pixels() > most_pixels: most_pixels = blob1[n].pixels() largest_blob = n L = 1else: L = 0 uart_A.write('L') uart_A.write(str(L)) uart_A.write('Z')uart_A.write('R') uart_A.write(str(R)) uart_A.write('X')line=img.get_regression([(20, 250)],roi=(0,0,210,210),x_srtide=2,y_srtide=1,robust=False)#灰度 白黑 if(line): rho_err = abs(line.rho())-img.width()/2#piancha #print(int(rho_err)) uart_A.write('P') uart_A.write(str(int(rho_err))) uart_A.write('S') if line.theta()>90: theta_err = line.theta()-180 else: theta_err = line.theta() img.draw_line(line.line(), color = 127)print('R',R ,'L',L)#print(rho_err,line.magnitude(),theta_err)

下面部分是识别数字的,比较简单,都是框架。因为比赛自己做自己用的,串口没有用到多严格的格式,只加了头尾,确保传的数正确就好。主控那边我加了语音播报病房号,也算个额外加分点,这个屡试不爽~

def c_num(): global flag img = sensor.snapshot() code = kpu.run_yolo2(task, img) print(anchor) a = lcd.display(img) if code: for i in code: a=img.draw_rectangle(i.rect(),(0,255,0),2) a = lcd.display(img) for i in code: lcd.draw_string(i.x()+45, i.y()-5, labels[i.classid()]+" "+'%.2f'%i.value(), lcd.WHITE,lcd.GREEN) #print(labels[i.classid()]) #print('x',i.x(),y,'i.y()') if(labels[i.classid()]=='1'): #print('1') uart_A.write('N') uart_A.write('1') uart_A.write('M')if(labels[i.classid()]==' 2'): uart_A.write('N') uart_A.write('2') uart_A.write('M') if(labels[i.classid()]==' 3'): uart_A.write('N') uart_A.write('3') uart_A.write('M') if(labels[i.classid()]==' 4'): uart_A.write('N') uart_A.write('4') uart_A.write('M') if(labels[i.classid()]==' 5'): uart_A.write('N') uart_A.write('5') uart_A.write('M') if(labels[i.classid()]==' 6'): uart_A.write('N') uart_A.write('6') uart_A.write('M') if(labels[i.classid()]==' 7'): uart_A.write('N') uart_A.write('7') uart_A.write('M') if(labels[i.classid()]==' 8'): uart_A.write('N') uart_A.write('8') uart_A.write('M')flag=0 s_flag.value(0) else: a = lcd.display(img) #uart_A.write('N') #uart_A.write('0') #uart_A.write('M')

Python我并没有好好学过,几乎没写过几次,都是临时抱佛脚,代码写的很烂。 这次没有什么详细讲解,代码直接甩出去,(不负责的我,这次写完就不想补充完善了)留给大家自己慢慢研究了。我感觉除了那个灰度图像阈值需要自己调整外,其他没有什么太大问题。
额,这次比完赛并没有完赛资料,就没有参加立创开源,少拿一份奖金,不过问题不大,我懒。
立创的奖金比学校的还要高,学校又要降奖金,因为今年拿奖的、参赛的人多了,我笑了……这学校各种恶心人的事,摆烂等我毕业答辩完再说。真不如我在一个好专科待遇好。
白嫖个便携式示波器挺好的。
学科竞赛|2021电赛F题数字识别和巡线部分
文章图片



继19年电赛在专科拿过一次国一后,没想到在本科这边又拿了一次。唯一一次遗憾的就是智能车了,但那个是外在因素,等完全毕业之后再谈。


    推荐阅读