首页 > 其他分享 >2022年十月份电赛OpenMV巡线方案详细代码分析(1)

2022年十月份电赛OpenMV巡线方案详细代码分析(1)

时间:2023-07-31 14:02:00浏览次数:41  
标签:10 roi target 电赛 25 2022 sensor 巡线 OpenMV


前言

(1)马上要进行电赛了,机器识别是铁定会使用到的。为了防止出现去年十月份那种特殊的巡线方案。我在此分享出OpenMV巡线方案,并且进行讲解和分析如何更改。
(2)学习本文之前,需要学习:OpenMV串口通讯详解OpenMV图像处理之后给单片机通讯OpenMV的单颜色识别讲解
(3)版权申明:此代码借鉴了淘宝商家—无名创新的代码,已获得许可。未经允许,禁止商用!
(4)注意:他的代码自己创建了一个比较复杂的通讯协议,为了方便新手快速入门,我在他的代码上进行了微调。
(5)先给一颗定心丸,本文学习最多20分钟就能掌握。(前提,OpenMV的颜色识别感兴趣区串口通讯能够熟练使用)
(6)主控代码将会在下一篇中给出,因为C站编辑器字数超过1W字就卡的一批,没办法,只能分成两篇来写。

OpenMV全部代码

(1)先直接上代码,因为可能很多人都是开赛了才看到这一篇博客的,没多少时间了。
(2)OpenMV的函数入口是main.py,从第一行往下执行。所以这个文件要命名为main.py!!!

#main.py -- put your code here!
import cpufreq
import pyb
import sensor,image, time,math
from pyb import LED,Timer,UART

sensor.reset()                      # 重置感光元件,重置摄像机
sensor.set_pixformat(sensor.RGB565) # 设置颜色格式为RGB565,彩色,每个像素16bit。
sensor.set_framesize(sensor.QQQVGA)  # 图像大小为QQQVGA,大小80x60
sensor.skip_frames(time = 2000)     #延时跳过一些帧,等待感光元件变稳定
sensor.set_auto_gain(False)          #黑线不易识别时,将此处写False
sensor.set_auto_whitebal(False)     #颜色识别必须关闭白平衡,会影响颜色识别效果,导致颜色的阈值发生改变
clock = time.clock()                # 创建一个时钟对象来跟踪FPS。
#sensor.set_auto_exposure(True, exposure_us=5000) # 设置自动曝光sensor.get_exposure_us()

red_led = pyb.LED(1)    #下面这三个就是OpenMV上的LED初始化
green_led = pyb.LED(2)
blue_led = pyb.LED(3)
uart=UART(3,115200)   #初始化串口3,波特率为115200,P4为TX连接单片机RX,P5为RX连接单片机TX

class target_check(object):
    x=0          #int16_t,横线上被标记黑点的地方,从左到右依次减少
    y=0          #int8_t,竖线上被标记黑点的地方,从上到下依次减少

target=target_check()


# 绘制水平线
def draw_hori_line(img, x0, x1, y, color):
    for x in range(x0, x1):
        img.set_pixel(x, y, color)
# 绘制竖直线
def draw_vec_line(img, x, y0, y1, color):
    for y in range(y0, y1):
        img.set_pixel(x, y, color)
# 绘制矩形
def draw_rect(img, x, y, w, h, color):
    draw_hori_line(img, x, x+w, y, color)
    draw_hori_line(img, x, x+w, y+h, color)
    draw_vec_line(img, x, y, y+h, color)
    draw_vec_line(img, x+w, y, y+h, color)


#图像大小为QQQVGA,大小80x60
#roi的格式是(x, y, w, h)
track_roi=[(0,25,5,10),
           (5,25,5,10),
           (10,25,5,10),
           (15,25,5,10),
           (20,25,5,10),
           (25,25,5,10),
           (30,25,5,10),
           (35,25,5,10),
           (40,25,5,10),
           (45,25,5,10),
           (50,25,5,10),
           (55,25,5,10),
           (60,25,5,10),
           (65,25,5,10),
           (70,25,5,10),
           (75,25,5,10)]

target_roi=[(70,0,10,12),
           (70,12,10,12),
           (70,24,10,12),
           (70,36,10,12),
           (70,48,10,12)]


thresholds =(0, 30, -30, 30, -30, 30)  #黑色的颜色阈值

hor_bits=['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'] #记录横线16个感兴趣区是否为黑线
ver_bits=['0','0','0','0','0',]  #记录右边5个感兴趣区是否为黑线
#__________________________________________________________________
def findtrack():
    target.x=0
    target.y=0
    img=sensor.snapshot()

    #用于检测黑线
    for i in range(0,16):
        hor_bits[i]=0
        '''
        thresholds表示黑色线阈值,roi为感兴趣区
        merge=True,表示所有合并所有重叠的blob为一个
        margin 边界,如果设置为10,那么两个blobs如果间距10一个像素点,也会被合并。
        '''
        blobs=img.find_blobs([thresholds],roi=track_roi[i],merge=True,margin=10)
        #如果识别到了黑线,hor_bits对应位置1
        for b in blobs:
            hor_bits[i]=1

    #用于检测右侧的黑线
    for i in range(0,5):
        ver_bits[i]=0
        blobs=img.find_blobs([thresholds],roi=target_roi[i],merge=True,margin=10)
        for b in blobs:
            ver_bits[i]=1

    #绘制16个横线红色四个角
    for k in range(0,16):
        if  hor_bits[k]:
            target.x=target.x|(0x01<<(15-k))
            img.draw_circle(int(track_roi[k][0]+track_roi[k][2]*0.5),int(track_roi[k][1]+track_roi[k][3]*0.5),1,(255,0,0))
    #绘制右侧5个红色四个角
    for k in range(0,5):
        if  ver_bits[k]:
            target.y=target.y|(0x01<<(4-k))
            img.draw_circle(int(target_roi[k][0]+target_roi[k][2]*0.5),int(target_roi[k][1]+target_roi[k][3]*0.5),3,(0,255,0))
    #绘制16个横线感兴趣区
    for rec in track_roi:
        img.draw_rectangle(rec, color=(0,0,255))#绘制出roi区域
    #绘制右侧5个横线感兴趣区
    for rec in target_roi:
        img.draw_rectangle(rec, color=(0,255,255))#绘制出roi区域
           #大--小  从左到右                       从上到下
    print((target.x & 0xff00)>>8,target.x & 0xff,target.y)
    uart.write(str((target.x & 0xff00)>>8))
    #uart.write(str(target.x & 0xff))
    #uart.write(str(target.y))
    #uart.write("\r\n")

#__________________________________________________________________
def package_blobs_data():
    return bytearray([target.x >> 8,
                      target.x,
                      target.y])
#__________________________________________________________________
i = 0
while True:
    findtrack()
    uart.write(package_blobs_data())
    uart.write("\r\n")
    i = i + 1
    if i == 50:
        i = 0
        green_led.toggle()
    pyb.delay(10)
    #uart.write("Hello World!\r")
    #uart.write(1+'\n')
    #计算fps
    #print(clock.fps())
#__________________________________________________________________

代码分析

关注点1—图像大小设置

(1)下面这一部分代码,我只会讲解你需要进行更改的部分。
(2)sensor.set_framesize(sensor.QQQVGA)
<1>这个是用于设置图像大小的。首先我们需要知道,对于计算机而言,一个张图片到底是什么东西。
<2>大家都打电赛了,肯定是玩过常见的OLED,或者是点阵屏的。那么我们让OLED或者点阵屏画图是怎么做的呢?很简单,一个像素点一个像素点的画。
<3>比如常见的4脚0.96寸的OLED是128*64像素。这是什么意思呢?他说明了,这款OLED纵向有128个小型的LED,横向有64个小型LED。我们想要绘制一个图像,就是一个一个的点亮这些小型LED。
<3>OpenMV同样也是,不过他的像素大小是可以进行设置的。比如我这里是采用的QQQVGA画质,像素就是80x60,也就是说X轴80个像素点,Y轴60个像素点。
<4>这个有什么用呢?很简单,与后面的感兴趣区设置有关
<5>OpenMV画质设置相关资料:https://book.openmv.cc/image/sensor.html

2022年十月份电赛OpenMV巡线方案详细代码分析(1)_像素点

<6>感兴趣区相关资料:https://book.openmv.cc/image/statistics.html
<7>可能有些人学颜色识别的时候没有注意看感兴趣区的相关资料。我在此进行简单的说明一下。
<8>我们上面说了,OpenMV可以对图像大小进行设置,如下图,我们将图像大小设置为16*16的像素点大小。
<9>我拍摄到了整个图像,是一朵花。但是如果我们进行特征识别,只想识别这朵花的中心部分(途中蓝色线标记的地方),那么在颜色识别的时候,传入感兴趣值roi=(5,2,6,4)。

2022年十月份电赛OpenMV巡线方案详细代码分析(1)_像素点_02

import cpufreq
import pyb
import sensor,image, time,math
from pyb import LED,Timer,UART

sensor.reset()                      # 重置感光元件,重置摄像机
sensor.set_pixformat(sensor.RGB565) # 设置颜色格式为RGB565,彩色,每个像素16bit。
sensor.set_framesize(sensor.QQQVGA)  # 图像大小为QQQVGA,大小80x60
sensor.skip_frames(time = 2000)     #延时跳过一些帧,等待感光元件变稳定
sensor.set_auto_gain(False)          #黑线不易识别时,将此处写False
sensor.set_auto_whitebal(False)     #颜色识别必须关闭白平衡,会影响颜色识别效果,导致颜色的阈值发生改变
clock = time.clock()                # 创建一个时钟对象来跟踪FPS。
#sensor.set_auto_exposure(True, exposure_us=5000) # 设置自动曝光sensor.get_exposure_us()

关注点2—串口波特率设置

(1)首先先说明,pyb.LED这个是什么。
<1>这个其实就是OpenMV上的那唯一一个RGB灯的初始化函数。
<2>为什么我需要初始化RGB呢?因为,为了防止OpenMV突然因为什么原因停止运行,最终没有给主控反馈数据,在排错过程中,无法定位问题。所以我设置了一个RGB闪烁的程序。如果OpenMV正常运转,那么RGB就会闪烁。这样出现问题,也方便定位问题。
(2)UART函数就是串口初始化函数
<1>注意,OpenMV只有一个串口3!请不要自作聪明改第一个参数!
<2>第二个参数是设置波特率的,这个波特率的值需要和主控的波特率值设置一致。
<3>连接方法是:OpenMV的TX(P4)——单片机RX,RX(P5)——单片机TX,GND——GND,3.3V——3.3V

red_led = pyb.LED(1)    #下面这三个就是OpenMV上的LED初始化
green_led = pyb.LED(2)
blue_led = pyb.LED(3)
uart=UART(3,115200)   #初始化串口3,波特率为115200,P4为TX连接单片机RX,P5为RX连接单片机TX

关注点3—巡线数据存储

(1)首先,我们需要知道22年10月份的电赛地图长什么样子。他就是一个倒车入库的题目。
(2)这个题目,明显不能使用光感循迹,否则就会超出车子大小而且不符合题意。
(3)所以我们的OpenMV要斜着放。

2022年十月份电赛OpenMV巡线方案详细代码分析(1)_计算机视觉_03

(4)如下为OpenMV实际检测到的结果。我们会看到,只要右边那一条Y轴线检测到了黑色,就说明可以开始准备倒车入库了。
(5)当中心位置的X轴线,右边5个识别区域有数据识别,说明已经车子要倒车入库了。

2022年十月份电赛OpenMV巡线方案详细代码分析(1)_像素点_04

(6)因此,我们这里创建了一个类,如果没有python基础的,可以理解为C语言的一个结构体。这个结构体存放x和y轴的数据。
(7)如果需要进行微调,你就看看你的感兴趣区怎么设置

class target_check(object):
    x=0          #int16_t,横线上被标记黑点的地方,从左到右依次减少
    y=0          #int8_t,竖线上被标记黑点的地方,从上到下依次减少

target=target_check()

无需关注的代码,做一个简单讲解

(1)我们能够看到上面的OpenMV识别代码里面,画有一些框框。这个其实只会出现在OpenMV IDE里面,方便我们进行调试。

# 绘制水平线
def draw_hori_line(img, x0, x1, y, color):
    for x in range(x0, x1):
        img.set_pixel(x, y, color)
# 绘制竖直线
def draw_vec_line(img, x, y0, y1, color):
    for y in range(y0, y1):
        img.set_pixel(x, y, color)
# 绘制矩形
def draw_rect(img, x, y, w, h, color):
    draw_hori_line(img, x, x+w, y, color)
    draw_hori_line(img, x, x+w, y+h, color)
    draw_vec_line(img, x, y, y+h, color)
    draw_vec_line(img, x+w, y, y+h, color)

关注点4—感兴趣区设置

(1)我们上面设置了OpenMV的图像大小为QQQVGA,这里像素点大小就是80x60。
(2)然后我们需要设置只识别规定部分,来进行循迹。
(3)先讲解中间的16个识别点,track_roi。
<1>我们X轴要建立16个识别点,而x轴一共有80个像素点,所以w都是5,而x每次以5进行递增
<2>因为我的整个图像y轴有60个像素点。h如果选取太小,主控的反应时间太短了,太大的话,又影响y轴的那8个数据识别,所以我们选取h固定为10。因为y轴60个像素点,所以中心位置像素点是30,因为h选取为10,所以y的起始位置是30-(10/2)=25
(4)现在讲解右侧的5个识别点,target_roi。
<1>理解了上面的讲解之后这里就很好理解了。首先为了防止x轴的宽度w设置太小,不利于识别,太大影响中心16个识别点,所以宽度w都设置为10,而x轴的像素点只有80个,所以x设置为80-10=70
<2>因为右边是5个识别点,然后y轴有60个像素点,所以h设置为60/6=12个,y轴每次递增12

#图像大小为QQQVGA,大小80x60
#roi的格式是(x, y, w, h)
track_roi=[(0,25,5,10),
           (5,25,5,10),
           (10,25,5,10),
           (15,25,5,10),
           (20,25,5,10),
           (25,25,5,10),
           (30,25,5,10),
           (35,25,5,10),
           (40,25,5,10),
           (45,25,5,10),
           (50,25,5,10),
           (55,25,5,10),
           (60,25,5,10),
           (65,25,5,10),
           (70,25,5,10),
           (75,25,5,10)]

target_roi=[(70,0,10,12),
           (70,12,10,12),
           (70,24,10,12),
           (70,36,10,12),
           (70,48,10,12)]

关注点5—黑线颜色阈值

(1)你们只需要按照下面的颜色阈值设置工具,将最终产生的数据传入给thresholds 即可。
(2)颜色阈值设置工具教程:OpenMV颜色阈值设置

thresholds =(0, 30, -30, 30, -30, 30)  #黑色的颜色阈值

关注点6—感兴趣区数组

(1)你有几种感兴趣区,就建立几个数组。
(2)每种感兴趣区有几个区域,就写几个’0’。

hor_bits=['0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0'] #记录横线16个感兴趣区是否为黑线
ver_bits=['0','0','0','0','0',]  #记录右边5个感兴趣区是否为黑线

关注点7—循迹部分

(1)这里只会讲解可能需要进行微调的部分
2)arget.x 和 target.y
<1>arget.x和target.y是用于记录x轴16个感兴趣区和y轴右侧的那5个感兴趣区的数据。每次调用这个函数需要进行清零操作,否则数据会受到上一次结果干扰。
<2>这里需要根据你之前设置的关注点3部分的数据信息有关,你设置了几个量,就需要清零几个。
3)for i in range(0,16): 和 for i in range(0,5):
<1>range(0,16)这个就是将就是将0到15这16个数据传递给i。这里的两个for语句内容其实是一样的。你有几中类型数据,就写几个for,然后只需要更改一下range(0,x)中的x。
<2>hor_bits[i]=0首先我们需要将这些数组的数据清空,防止上一次数据造成干扰。不用改。
<3>find_blobs()这个函数,只需要更改roi感兴趣区,将roi设置为你要的感兴趣区即可。
4)for k in range(0,16): 和for k in range(0,5):
<1>这两个for语句作用就是如果识别到了黑线,将数组中的数据存入target.x和target.y。(0x01<<(4-k)和(0x01<<(15-k)部分,这个(0x01<<(x-k)中的x是根据你这个类型感兴趣区有几个决定,比如x轴的有16个,那么x就是15。y轴的有5个,那么x就是4。
<2>draw_circle()函数就是识别到黑线之后OpenMV IDE上就会出现提示,我们如果需要更改,就把传入的四个target_roi[]设置为自己的,如下:

2022年十月份电赛OpenMV巡线方案详细代码分析(1)_计算机视觉_05


5

)for rec in track_roi: 和 for rec in target_roi:


<1>这个就是画出我们会进行颜色识别的区域,我们如果想要改,只需要将 for语句后面的in 条件改成自己设置的感兴趣区

def findtrack():
    target.x=0
    target.y=0
    img=sensor.snapshot() #这个必须存在,是用于获取图像数据的

    #用于检测黑线
    for i in range(0,16):
        hor_bits[i]=0
        '''
        thresholds表示黑色线阈值,roi为感兴趣区
        merge=True,表示所有合并所有重叠的blob为一个
        margin 边界,如果设置为10,那么两个blobs如果间距10一个像素点,也会被合并。
        '''
        blobs=img.find_blobs([thresholds],roi=track_roi[i],merge=True,margin=10)
        #如果识别到了黑线,hor_bits对应位置1
        for b in blobs:
            hor_bits[i]=1

    #用于检测右侧的黑线
    for i in range(0,5):
        ver_bits[i]=0
        blobs=img.find_blobs([thresholds],roi=target_roi[i],merge=True,margin=10)
        for b in blobs:
            ver_bits[i]=1

    #绘制16个横线红色四个角
    for k in range(0,16):
        if  hor_bits[k]:
            target.x=target.x|(0x01<<(15-k))
            img.draw_circle(int(track_roi[k][0]+track_roi[k][2]*0.5),int(track_roi[k][1]+track_roi[k][3]*0.5),1,(255,0,0))
    #绘制右侧5个红色四个角
    for k in range(0,5):
        if  ver_bits[k]:
            target.y=target.y|(0x01<<(4-k))
            img.draw_circle(int(target_roi[k][0]+target_roi[k][2]*0.5),int(target_roi[k][1]+target_roi[k][3]*0.5),3,(0,255,0))
    #绘制16个横线感兴趣区
    for rec in track_roi:
        img.draw_rectangle(rec, color=(0,0,255))#绘制出roi区域
    #绘制右侧5个横线感兴趣区
    for rec in target_roi:
        img.draw_rectangle(rec, color=(0,255,255))#绘制出roi区域
           #大--小  从左到右                       从上到下
    print((target.x & 0xff00)>>8,target.x & 0xff,target.y)
    uart.write(str((target.x & 0xff00)>>8))

关注点8—OpenMV给串口发送数据

(1)这个函数就是将OpenMV识别到的黑线信息传递给主控。每次发送8bit的数据。
(2)如果需要更改,只需要根据你的需求,更改bytearray函数中的[]。
(3)这里注意一下,数据发送的内容到底是什么,target.x的数据从大到小,是从左到右。target.y的数据从大到小是从上往下的位置。
(4)可能有些人会问为什么,原因很简单,这个和你设置感兴趣区的时候,放置顺序有关。

2022年十月份电赛OpenMV巡线方案详细代码分析(1)_python_06

def package_blobs_data():
    return bytearray([target.x >> 8,
                      target.x,
                      target.y])

无需关注,有一个简单了解

(1)最后就是一个死循环了。我设置了OpenMV上的RGB灯每隔500ms翻转一次。用于查看OpenMV是否在正常运行。
(2)uart.write()就是将循迹数据传递给主控,因为我采用了正点原子的通讯协议,所以数据帧以"\r\n"结尾。主控代码也要同理采用这个方案。

i = 0
while True:
    findtrack()
    uart.write(package_blobs_data())
    uart.write("\r\n")
    i = i + 1
    if i == 50:
        i = 0
        green_led.toggle()
    pyb.delay(10)   #延时10ms


标签:10,roi,target,电赛,25,2022,sensor,巡线,OpenMV
From: https://blog.51cto.com/zyxfighting/6907977

相关文章

  • 【CMU15-445 FALL 2022】Project #1 - Buffer Pool
    About实验官网Project#1-BufferPool在线评测网站gradescopeLabTask#1-ExtendibleHashTable详见——【CMU15-445FALL2022】Project#1-ExtendableHashing如果链接失效,请查看当前平台我之前发布的文章。Task#2-LRU-KReplacementPolicyConcept相关参考LRU-K和2Q......
  • 【专题】2022母婴行业洞察报告PDF合集分享(附原数据表)
    报告链接:http://tecdat.cn/?p=32654原文出处:拓端数据部落公众号在这一特别的环境下,我国的母婴消费市场将会发生什么新的变化?面对这一代又一代交替的母亲与母亲,他们的消费观念与养育模式又有什麽新的标记?面对怎样的新挑战,新的机会?报告从母婴行业现状与趋势、母婴人群精准画像、母......
  • Dapr中国社区活动之 分布式运行时开发者日 (2022.09.03)
    自2019年10月首次发布以来,Dapr(DistributedApplicationRuntime,分布式应用运行时)因其“更稳定”、“更可靠”、“更一致”、“更简单”,吸引了大量的关注和喜爱,至今在GitHub上已有近1.9万Stars,俨然已成为开发者圈的新晋“网红”。Dapr具备先天的跨语言优势,其设计更是从根基上兼......
  • 2022年买房总结
    去年开始就寻摸房子,想给我爸妈买一套2居室的小房子给他们住,由于各种原因去年没出手,今年5月份迎来了政策利好,所以综合分析后,心甘情愿的去做吧……2022年购房买房不买优点缺点......
  • 稳扎稳打,坚定前行 | 一文带你回顾 StoneDB 的 2022 年
    2022年6月29号,StoneDB正式宣布开源,自开源以来,StoneDB开源团队在用心打磨产品的同时,也在积极地拥抱开源社区,与万千数据库开发者共同成长,我们从day1就励志要做一款立足中国、面向全球的开源数据库,内核代码已经在Github上完全开源,欢迎大家前往关注:https://github.com/stone......
  • StoneDB 开源社区月刊 | 2022122期
    StoneDB开源社区第六期月刊来啦!StoneDB开源社区12月月度会议暨2022年度会议在1月10日晚上准时跟社区的小伙伴们见面了。本次会议是StoneDB在2022年月份中的最后一次月会,也是我们的第一次年度会议。特别感谢大家在2022年的陪伴和支持,也期待大家更多的参与到开源社区中来,新的一年......
  • 产品再受认可,StoneDB 荣获“2022 年度创新产品奖”
    12月29日,由中国权威的数据库及架构技术社区ITPUB、业界知名IT垂直门户媒体IT168联合主办的第18届《技术改变世界 创新引领未来——2022技术卓越奖》评选结果正式揭晓,StoneDB凭借优秀创新的产品架构荣获"2022年度创新产品奖"。“技术卓越奖”由行业CIO/CTO大咖、技术......
  • Visual Studio 2022 密钥永久激活(亲测有效)
    分享一下VisualStudioProfessional2022版安装和激活教程。教程如下,含免费密钥,亲测有效,下面是详细文档哦~申明:本教程VisualStudioProfessional2022激活密钥均收集于网络,请勿商用,仅供个人学习使用,如有侵权,请联系作者删除。若条件允许,希望大家购买正版!PS:本教程最新更......
  • 文字处理软件InCopy 2022(IC2022中文mac版
    AdobeInCopy(IC2022)是Adobe的专业文字处理软件,可用于处理各种专业字体,图片和其他文件。它是一款完全集成的字体处理软件,可用于许多其他工作,包括文字编辑。它提供了一种以新的方式为不同类型的文本创建出色的图像和其他图形的方法。同时,在该版本中增加了一个新功能“SharePoint......
  • 2022软考系统架构师下午案例分析及答案
    试题一(25分)某电子商务公司拟升级其会员与促销管理系统,向用户提供个性化服务,提高用户的粘性。在项目立项之初,公司领导层一致认为本次升级的主要目标是提升会员管理方式的灵活性,由于当前用户规模不大,业务也相对简单,系统性能方面不做过多考虑。新系统除了保持现有的四级固定会员制......