2021年电赛 F题 视觉部分 (openMV4 plus)记录
记录下比赛
emmmm选了F题,别的都没思路,哈哈哈哈哈,对小车比较亲切
赛题一出,就确定了大概率是F题了,看了看题认为是“数字识别”+“巡线小车” 扩展部分的话就是“无线通信”+“路径规划(或者路线记忆?😂)”
刚开始是想把“地图数据”存在32里面:规划好每个病房路线,到时候通过摄像头识别并返回实际病房数字,与已规划路线匹配,这样回来的就更精准了。
以下部分摄像头仅负责1-8识别以及识别”病房虚线“
说说图像识别(openMV4 plus)
在edge impulse训练数字识别,很多人都是这么想的,但是在运动中不可行。帧率太低,跟不上反应。(此处可以使用停车识别数字)尽管显示98%正确率(数据集1800张,重拍数据集了好多次),但是考虑到环境等因素对其检测的不利因素,改用其他方案,当然有很多组是识别成功了的。
改为模板识别,采用灰度以提高帧率,识别效果还行,但是局限的是:摄像头角度、距离不能有太大变化,且处理8张照帧率真的很一般,行进中识别肯定不行。
根据赛道结构易知需对(“1”“2”)(“3”-“8”)不同处理,且需重点处理4位数
通过将各种情况模块化,将计算量分散,帧率上去了!
思路大概是这样:
“”"
先写个初始亮红灯
把1-8的图像遍历 # 用来识别目标值,帧率不需要很高
return 目标值
传回目标值到32
openmv判断目标值
灭红灯
进入对应模块(增加帧率)
传回转向方式到32
“”"
“”"
当aim为1或2时,将aim发送给stm32,使stm32在到达第一个路口时,直接进行左转或右转。
当aim为3-8时,进行行进中识别。
在行进中只对识别到2个或3个数(可补充4位数的情况)的情况进行处理(因为小车限高以及为保持识别准确率,摄像头的角度需要合理调整;由于同时匹配到4个数的概率很小(图像在边缘时匹配率较低),在匹配识别到3个数的时候就可以根据其相对位置判断左转还是右转)
“”"
组合调第一个车,速度与图像识别不可兼得,最后还好。
返回给32的是 目标值 和 行为指令(左,右,停)
之后时间就是双车链接,以不同目标位置把第二辆车的转向方式稍作修改以及其他…
当然用树莓派或别的平台处理效果更好
代码
匆忙写的,没有优化:无需停车识别数字,但仍有部分小问题
方案的缺陷在于摆放的数字需要紧挨在一起
{aim}
(1)左
(2)右
(3)停
import time, sensor, image, math, pyb
from image import SEARCH_EX, SEARCH_DS
from pyb import UART,LED
import json
# Reset sensor
sensor.reset()
# Set sensor settings
sensor.set_contrast(1)
sensor.set_gainceiling(16)
# Max resolution for template matching with SEARCH_EX is QQVGA
sensor.set_framesize(sensor.QQVGA)
# You can set windowing to reduce the search image.
#sensor.set_windowing(((640-80)//2, (480-60)//2, 80, 60))
sensor.set_pixformat(sensor.GRAYSCALE)
uart = UART(3,115200)
uart.init(115200,bits=8,parity=None,stop=1)
led1 = pyb.LED(1)
led2 = pyb.LED(2)
# Load template.
# Template should be a small (eg. 32x32 pixels) grayscale image.
template1 = image.Image("/1b.pgm")
template2 = image.Image("/2b.pgm")
template3 = image.Image("/3b.pgm")
template4 = image.Image("/4b.pgm")
template5 = image.Image("/5b.pgm")
template6 = image.Image("/6b.pgm")
template7 = image.Image("/7b.pgm")
template8 = image.Image("/8b.pgm")
template0 = image.Image("/s1.pgm")
clock = time.clock()
aim=0
flag=0 # 此变量没有用处
ma=[1,160,0,0] # [数字值,x方向坐标,在屏幕左或右(1或2),是否被检测到(0或1)]
mb=[2,160,0,0]
mc=[3,160,0,0]
md=[4,160,0,0]
me=[5,160,0,0]
mf=[6,160,0,0]
mg=[7,160,0,0]
mh=[8,160,0,0]
def sum_list(items): # 列表求和
sum_numbers = 0
for x in items:
sum_numbers += x
return sum_numbers
def find_list(items,a): # 用于查找已检测到的数
itemss=[]
for i in range(len(items)):
if a in items:
itemss.append(items.index(a)+i)
items.pop(items.index(a))
return itemss
def Tablefun(list): #暂时用不到
list_set = set(list)
frequency_dict = {}
for i in list_set:
frequency_dict[i] = list.count(i) # 创建dict; new_dict[key]=value
grade_mode = []
for key, value in frequency_dict.items(): # 遍历dict的key and value。key:value
if value == max(frequency_dict.values()):
grade_mode.append(key)
break
return grade_mode
def Temp_recogn1(): # 1-8,程序开始时对目标值的识别
# Initial target recognition # 待调roi # 待取众值
template1 = image.Image("/kk1_70_.pgm")
template2 = image.Image("/kk2_70_.pgm")
template3 = image.Image("/kk3_70_.pgm")
template4 = image.Image("/kk4_70_.pgm")
template5 = image.Image("/kk5_70_.pgm")
template6 = image.Image("/kk6_70_.pgm")
template7 = image.Image("/kk7_70_.pgm")
template8 = image.Image("/kk8_70_.pgm")
kim = 0 # mean is stop
mz=[0,159] # 只要检测到数其x必然小于160,此处设置159是为了在没有识别到数字1-8时返回0
ma=[1,160]
mb=[2,160]
mc=[3,160]
md=[4,160]
me=[5,160]
mf=[6,160]
mg=[7,160]
mh=[8,160]
mk=[0,0,0,0,0,0,0,0,0]
r1 = img.find_template(template1, 0.65, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
r2 = img.find_template(template2, 0.63, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
r3 = img.find_template(template3, 0.65, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
r4 = img.find_template(template4, 0.67, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
r5 = img.find_template(template5, 0.69, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
r6 = img.find_template(template6, 0.67, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
r7 = img.find_template(template7, 0.65, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
r8 = img.find_template(template8, 0.67, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if r1:
img.draw_string(0,4,"1")
ma[1]=r1[0]
if r2:
img.draw_string(0,15,"2")
mb[1]=r2[0]
if r3:
img.draw_string(0,25,"3")
mc[1]=r3[0]
if r4:
img.draw_string(0,35,"4")
md[1]=r4[0]
if r5:
img.draw_string(0,55,"5")
me[1]=r5[0]
if r6:
img.draw_string(0,65,"6")
mf[1]=r6[0]
if r7:
img.draw_string(0,75,"7")
mg[1]=r7[0]
if r8:
img.draw_string(0,85,"8")
mh[1]=r8[0]
nj=[mz,ma,mb,mc,md,me,mf,mg,mh]
mk=sorted(nj,key=lambda x:x[1]) # 目的将数字以x坐标值大小排列
ml=[a[0] for a in mk] # 抓出排好序的数字
print(mk)
kim = ml[0]
print(kim) # kim是目标值,会传给aim
return kim
def Temp_recog2(m0): # 循环匹配3-8 m0为aim
ma=[1,160,0,0]
mb=[2,160,0,0]
mc=[3,160,0,0]
md=[4,160,0,0]
me=[5,160,0,0]
mf=[6,160,0,0]
mg=[7,160,0,0]
mh=[8,160,0,0]
ml=[0,0,0,0,0,0,0,0]
mm=[0,0,0,0,0,0,0,0]
mlsum = 0 # 已识别到的数字数量
r3 = img.find_template(template3, 0.66, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
r4 = img.find_template(template4, 0.65, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
r5 = img.find_template(template5, 0.67, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
r6 = img.find_template(template6, 0.67, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
r7 = img.find_template(template7, 0.65, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
r8 = img.find_template(template8, 0.66, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if r3:
img.draw_rectangle(r3)
img.draw_string(0,25,"3")
mc[2] = 1 if r3[0]+int(r3[2]*0.5) > 80 else 2
mc[3] = 1
if r4:
img.draw_rectangle(r4)
img.draw_string(0,35,"4")
md[2] = 1 if r4[0]+int(r4[2]*0.5) > 80 else 2
md[3] = 1
if r5:
img.draw_rectangle(r5)
img.draw_string(0,55,"5")
me[2] = 1 if r5[0]+int(r5[2]*0.5) > 80 else 2
me[3] = 1
if r6:
img.draw_rectangle(r6)
img.draw_string(0,65,"6")
mf[2] = 1 if r6[0]+int(r6[2]*0.5) > 80 else 2
mf[3] = 1
if r7:
img.draw_rectangle(r7)
img.draw_string(0,75,"7")
mg[2] = 1 if r7[0]+int(r7[2]*0.5)> 80 else 2
mg[3] = 1
if r8:
img.draw_rectangle(r8)
img.draw_string(0,85,"8")
mh[2] = 1 if r8[0]+int(r8[2]*0.5) > 80 else 2
mh[3] = 1
mj=[ma,mb,mc,md,me,mf,mg,mh] #
ml=[a[3] for a in mj] # 判断是否检测到
mm=[b[2] for b in mj] # 方向列表
mlsum=sum_list((ml)) # 已识别到的数字数量
if (ml[m0-1] == 1)and(mlsum==2) : # 识别到目标数且识别到两个数
print(mm[m0-1])
uart.write("({})".format(mm[m0-1])+"/r/n")
elif (ml[m0-1] == 0)and(mlsum == 3): # 未识别到目标数且识别到三个数
kk=find_list(ml,1)
kl=[mm[kk[0]],mm[kk[1]],mm[kk[2]]]
if kl.count(1)==1: # 方向判断
print(1)
uart.write("(1)"+"/r/n")
else:
print(2)
uart.write("(2)"+"/r/n")
else:
print(0)
def Temp_stop(): # 匹配到虚线
rs = img.find_template(template0, 0.70, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if rs:
uart.write("(3)"+"/r/n")
print(3)
# Run template matching
while (True):
clock.tick()
img = sensor.snapshot()
led1.on()
while (True):
img = sensor.snapshot()
aim = Temp_recogn1()
if aim:
print("#########################")
led1.off()
uart.write("[{}]".format(aim)+"/r/n")
led2.on()
break
# 加一个TEN
print("[",aim,"]")
if aim !=1:
if aim != 2:
while (True):
img = sensor.snapshot()
Temp_recog2(aim)
time.sleep_ms(1200) # 加时延,防误判(可用换s1.pgm解决)
Temp_stop() # 无奖竞猜,这里的 bug 是什么
else:
time.sleep_ms(1200)
Temp_stop()
else:
time.sleep_ms(1200)
Temp_stop()
led2.off()
# 写此文时有两个 bug 没做修正哦
# 在判断4位数后还应再进行一次2位数字的检测