2023年电赛---运动目标控制与自动追踪系统(E题)—— 视觉部分

一、前言

🌷此次电赛我负责的部分主要是视觉,所以我着重和详细讲解一下视觉部分,不止限于此次电赛,而是从这次电赛视觉部分更好得学习和了解视觉,以及如何去运用视觉,以便在下次比赛中能更好的理解和使用!

这次电赛我使用的视觉开发板是K210,这里先给出官方教程文档:MaixPy 文档

这是openmv的官方文档,其实它和k210都是使用python进行编写的,代码部分其实大差不差(串口方面书写会稍有差异),openmv的文档会更加详细,这里也给出:MicroPython 和 OpenMV Cam 中文文档

注意,下面的代码是根据功能分模块写的,实际结合运用时要稍作修改和整合。由于是视觉新手,可能会存在少许问题或者值得优化的地方,希望各位能在评论区或者私信指出,我会很高兴接收和与大家交流!

二、视觉部分

2.1:k210识别激光点

🌺识别激光的大体思路不难:使用find_blobs(函数即可,这里的难点是如何使识别到的激光灵敏且准确!
对图像进行了哪些处理可以看看以下代码,给出了详细解释!但是还是要根据具体情况来调,在我当时的场景下识别是非常准确和灵敏的。(绿色圈中的就是激光正中心,左边红色的是光影)
在这里插入图片描述

# Untitled - By: Yaoyao - 周四 8月 3 2023

import sensor, image, time, lcd

from machine import UART #串口库函数
from Maix import GPIO
from fpioa_manager import fm # GPIO重定向函数(引脚映射


fm.register(GPIO.GPIOHS10, fm.fpioa.UART1_TX)
fm.register(GPIO.GPIOHS11, fm.fpioa.UART1_RX)

uart = UART(UART.UART1, 115200, 8, None, 1, timeout=1000, read_buf_len=4096)


lcd.init(freq=15000000)
sensor.reset()                      # Reset and initialize the sensor. It will
                                    # run automatically, call sensor.run(0) to stop
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QVGA)   # Set frame size to QVGA (320x240)
sensor.set_windowing((176,176))
sensor.skip_frames(time = 2000)     # Wait for settings take effect.
#sensor.set_auto_whitebal(False) # turn this off..
sensor.set_auto_exposure(True, 80)#在这里调节曝光度,调节完可以比较清晰地看清激光点
#sensor.set_contrast(1) #设置对比度范围为[-2,+2]
sensor.set_auto_gain(False)#关闭自增益
sensor.set_brightness(-1) #摄像头亮度,范围为[-2,+2]
#水平方向翻转
sensor.set_hmirror(True)
# 垂直方向翻转
sensor.set_vflip(True)
clock = time.clock()                # Create a clock object to track the FPS.


clock = time.clock()
green_threshold=[(90, 100, -85, 29, 3, 90)]
red_threshold = [(60, 255, -20, 20, -20, 20)]
#red_threshold = [(44, 93, 7, 45, -8, 14)]


#识别激光点代码
def color_blob(threshold):

    blobs = img.find_blobs(threshold,x_stride=1, y_stride=1, area_threshold=0, pixels_threshold=0,merge=False,margin=1)

    if len(blobs)>=1 :#有色块
        # Draw a rect around the blob.
        b = blobs[0]
        #img.draw_rectangle(b[0:4]) # rect
        cx = b[5]
        cy = b[6]
        for i in range(len(blobs)-1):
            #img.draw_rectangle(b[0:4],color = (0,255,0)) # rect
            cx = blobs[i][5]+cx
            cy = blobs[i][6]+cy
        cx=int(cx/len(blobs))
        cy=int(cy/len(blobs))
        img.draw_cross(cx, cy,color = (255,0,0)) # cx, cy

        return int(cx), int(cy)
    return -1, -1 #表示没有找到


while(True):
    clock.tick()
    img = sensor.snapshot()
    img.draw_cross((90,90),color = (0,0,255),size = 10, thickness=1)
    cx, cy = color_blob(red_threshold)
    dot_str = str(cx) + ',' + str(cy)+'+'
    uart.write( "@" + dot_str + "!")  # 使用换行符作为消息的结束,方便 Arduino 一次读取一个坐标
    #time.sleep_ms(20)
    #print("@" + dot_str + "!")
    #print("cx:",cx,"cy",cy)
    img.draw_circle(cx, cy, 5, color=127, thickness=2)
    lcd.display(img, x_scale=1, y_scale=1)
  • sensor.set_auto_exposure(True, 80\ sensor.set_brightness(-1):通过调整曝光度\亮度,可以控制图像的明暗程度,从而创造出不同的视觉效果
  • 关闭白平衡和自增益 sensor.set_auto_whitebal(False)和sensor.set_auto_gain(False)。但是如果调节出来没结果。可以尝试打开看看(所以还是说要看具体环境,根据具体环境进行调节!)
  • 提高分辨率,较高的分辨率,能够提供更好的效果。但是注意!分辨率太高会占用过多的图像处理内存,可能会导致爆内存!所以还是要根据实际效果进行调整!
  • 将图像画质设置成GRAYSCALE,好处在于:如果只有两个颜色,更容易进行分辨,而且每个像素所占空间也减少了,可以适当的增加分辨率。但是也有缺点,如果是多颜色识别就会出现问题。(这里因为我使用RGB565图像效果就已经很好了,就没有必要设置了)

2.2:k210识别方框和4个角点

🌻场景 : 在这次比赛中,我们的摄像头是始终固定不动的,其中k210一项重要的功能就是识别黑色方框矩形的四个顶点,并且把坐标发送给主控板。
此处先上代码

import sensor, image, lcd, time

from machine import UART #串口库函数
from Maix import GPIO
from fpioa_manager import fm # GPIO重定向函数(引脚映射


fm.register(GPIO.GPIOHS10, fm.fpioa.UART1_TX)
fm.register(GPIO.GPIOHS11, fm.fpioa.UART1_RX)

uart = UART(UART.UART1, 9600, 8, None, 1, timeout=1000, read_buf_len=4096)

lcd.init(freq=15000000)
sensor.reset()                      # Reset and initialize the sensor. It will
                                    # run automatically, call sensor.run(0) to stop
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QQVGA)   # Set frame size to 160x120 分辨率的相机传感器。

sensor.set_windowing((120,120))
#水平方向翻转
sensor.set_hmirror(True)
# 垂直方向翻转
sensor.set_vflip(True)
sensor.skip_frames(time = 10000)     # Wait for settings take effect.
clock = time.clock()                # Create a clock object to track the FPS.

flag = 0

x1 = 0
y1 = 0
x2 = 0
y2 = 0
x3 = 0
y3 = 0
x4 = 0
y4 = 0

while(True):
    clock.tick()                    # 更新FPS时钟
    img = sensor.snapshot()         # 拍摄图片并返回图像
    img.draw_cross((60,60),color = (255,0,0),size = 5, thickness=1)
    # -----矩形框部分-----
    print("寻找矩形")
    # 在图像中寻找矩形
    for r in  img.find_rects():

        # 判断矩形边长是否符合要求
        if r.w() >20  and r.h() > 20 and r.w() < 100 and r.w() < 100:

            flag += 1
            # 在屏幕上框出矩形
            print("找到了矩形",flag)
            #img.draw_rectangle(r.rect(), color = (255, 0, 0), thickness = 2, fill = False)

            # 获取矩形角点位置
            corner = r.corners()
            ## 在屏幕上圆出矩形角点;四个角点坐标, 角点1的数组是corner[0], 坐标就是(corner[0][0],corner[0][1])
            #img.draw_circle(corner[0][0], corner[0][1], 5, color = (0, 0, 255), thickness = 2, fill = False)
            #img.draw_circle(corner[1][0], corner[1][1], 5, color = (0, 0, 255), thickness = 2, fill = False)
            #img.draw_circle(corner[2][0], corner[2][1], 5, color = (0, 0, 255), thickness = 2, fill = False)
            #img.draw_circle(corner[3][0], corner[3][1], 5, color = (0, 255, 0), thickness = 2, fill = False)

            print("左下角:",corner[0][0], corner[0][1],",右下角 ",corner[1][0], corner[1][1],",右上角:",corner[2][0], corner[2][1],",左上角:",corner[3][0], corner[3][1])
            x1 += corner[0][0]
            y1 += corner[0][1]
            x2 += corner[1][0]
            y2 += corner[1][1]
            x3 += corner[2][0]
            y3 += corner[2][1]
            x4 += corner[3][0]
            y4 += corner[3][1]

    # 在屏幕上显示图像,此部分会降低帧率
    lcd.display(img)
    if(flag == 3):
        x1 = x1/3
        y1 = y1/3
        x2 = x2/3
        y2 = y2/3
        x3 = x3/3
        y3 = y3/3
        x4 = x4/4
        y4 = y4/4
        # 将四个角点的坐标数据打包成一个字符串b
        corner_str = str(x1) + ',' + str(y1) + ',' + str(x2) + ',' + str(y2) + ',' + str(x3) + ',' + str(y3) + ',' + str(x4) + ',' + str(y4)
        uart.write( "@" + corner_str + "!")  # 使用换行符作为消息的结束,方便 Arduino 一次读取一个坐标
        print("@" + corner_str + "!")
        # 停止1秒钟
        time.sleep(1)
        break

    # 打印帧率
    #print(clock.fps())

如何寻找矩形并且得到四个坐标角点这个不难,这里的问题是:因为在实际中我们除了运行找矩形的代码,还要在K210上运行找激光(可能还有其它图像处理的代码),因为k210的算力不是很高,可能直接导致这个错误MemoryError: Out of fast Frame Buffer Stack Memory! Please reduce the resolution of the image you are running this algorithm on to bypass this issue!# Hello World Example,是因为openmv/k210处理图像部分的内存不够了

可以通过以下措施来解决看看:

  • 减少图像的分辨率:降低图像分辨率可以减少所需的内存量。您可以使用 sensor.set_framesize() 函数来设置图像帧大小。

  • 减少图像处理的区域:使用 sensor.set_windowing() 函数设置感兴趣的图像区域,只处理所需的部分图像。

  • 减少使用Frame Buffer:Frame Buffer Stack Memory是OpenMV处理图像时使用的内存,因此您可以尝试减少使用Frame Buffer。例如,您可以使用 img.copy() 函数来创建图像的副本,而不是直接在原始图像上进行处理。

  • 优化代码:您可以尝试优化代码以减少内存使用量。例如,您可以使用 img.draw_rectangle() 函数的 merge 参数来减少绘制矩形时所需的内存。

从这个场景和功能下,其实四个坐标顶点只需要获取一次即可,不需要持续运行这个代码,于是在上面代码中加入了一个flag标志变量,当在最开始运行代码时,识别三次矩形,将坐标平均值求出(包装准确性),然后通过串口发送给主控。这样一来只有最开始很少一段时间在进行“寻找矩形”这部分代码,后面就可以进行其他操作,这样可以减少Frame Buffer的使用。(个人认为上面提到的使用 img.copy() 函数也是可行的,大家可以自行尝试!)

三、总结

这次电赛是我第一次参加这种大型比赛,四天三夜的时间学习了很多,有泪水、有压力也有焦虑,但是重要的是坚持自己的内心不后悔和坚定的走下。

同时这次比赛让我学习到理论和实践之间的距离其实是很遥远的,以及经验和实践的重要性。一些看起来很合理的理论,但是实现却和理想差很多,你要考虑到硬件的性能、这个函数的参数有哪些作用,如何去调节、环境的影响…

所以接下来的学习和比赛中,要更深入的学习,去更好的理解,才能更好的运用,并且勤加实践,才能更好的将理论和实践结合!!

最后,借用史铁生先生的一句话结束这篇文章吧:“命定的局限尽可永在,不屈的挑战却不可须臾或缺 ”

  • 7
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
2023电赛 E 运动目标控制自动追踪系统. 使用jetson nano进行目标检测, 使用舵机进行控制, 使用串口进行通信 本项目为 矩形框识别 外围边线查找 部分 教育部认可的大生竞赛备赛资料代码,源码,竞赛总结,所有源码均经过严格测试,可以直接运行,可以放心下载使用。有任何使用问欢迎随时与博主沟通 全国电子设计大赛、全国大生智能汽车竞赛、蓝桥杯、集成电路创新创业大赛、光电设计竞赛、挑战杯、大创项目、互联网+、三创赛、计算机设计竞赛、创新创业大赛、ACM-ICPC国际大生程序设计竞赛、全国大生数建模竞赛、全国大生电子商务“创新、创意及创业”挑战赛、全国大生节能减排社会实践与科技竞赛、全国大生工程训练综合能力竞赛、全国大生机器人大赛-RoboMaster、RoboCon、“西门子杯”中国智能制造挑战赛、中国大生计算机设计大赛、世界技能大赛、中国高校计算机大赛-大数据挑战赛、团体程序设计天梯赛、移动应用创新赛、网络技术挑战赛、全国大生信息安全竞赛、“中国软件杯”大生软件设计大赛、全国大生光电设计竞赛、中国机器人及人工智能大赛、“大唐杯”全国大生移动通信5G技术大赛、华为ICT大赛、全国大生嵌入式芯片与系统设计竞赛、中国高校智能机器人创意大赛

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

是瑶瑶子啦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值