番外(一):基于K210的颜色识别和数字识别


前言

近期笔者有一个小项目需要进行视觉识别这部分,于是先暂时学习更新一下这部分内容。

一、K210的引入

  目前对于我们嵌入式来说,较成熟的视觉识别方案大致为以下三种:

  1. Openmv(现在最火的嵌入式机器视觉模块,使用 MicroPython 驱动,可以把它当成一个可编程摄像头)
  2. K210是国内厂家勘智研发的一款采用 RISC-V 处理器架构,典型设备功耗 1w,算力1TOPS 的 AI 芯片,自带SRAM,可以在本地完成数据的处理和存储,国内厂家也根据 openmv 的 IDE 重新制作了 Canmv IDE 和 Maixpy IDE,可以在上面直接运行。
  3. OpenCV,进行循迹和数字识别,性能比上面两个都强得多,但是开发难度也是最大的,它可以用很高清的摄像头,用它来参赛简直可以说是降维打击。

   由于第一次搞这个方向,这里还是选用保险点的国产K210 了,他在性能上比 openmv 强,但是他的软件库要比 openmv 落后不少,有些能在 openmv 上执行的语句在 K210 上是执行不了的,不对对于找色块对它来说就是小菜一碟。了解了如何获取到色块中心坐标后,就再运行一下他提供的串口例程然后修改它让他可以传输色块的中心坐标,可以用串口助手在电脑上收到 k210 发送过来的色块坐标信息后基本就可以了。

二、颜色识别

   颜色识别的本质是在寻找色块,而色块是指图像中具有相同或相近颜色的连续区域。这些色块可以通过CanMV的图像处理算法进行识别和检测,从而实现多种有趣和实用的功能,例如物体追踪、自动分类等。

1. 引入库

代码如下(示例):

import sensor,lcd,time

2. 初始化摄像头

   首先导入摄像头(sensor)、LCD(lcd)和时间(time)模块。

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_vflip(1)

接下来我们分别介绍一下这部分函数:

  1. sensor.reset( )
      这个函数用于重置摄像头传感器到默认状态。在初始化摄像头或者需要重新配置摄像头参数时,这个函数非常有用。调用sensor.reset()后,摄像头将恢复到初始设置,所有之前通过其他函数设置的参数(如分辨率、像素格式等)都会被清除。
    • 参数:无
    • 返回值:无
  2. sensor.set_pixformat( )
      这个函数用于设置摄像头传感器的像素格式。像素格式决定了每个像素的颜色信息是如何表示的。在这个例子中,sensor.RGB565表示每个像素由16位组成,其中红色占5位,绿色占6位,蓝色占5位。这种格式可以节省存储空间,但颜色深度相对较低。
    • 参数:sensor.RGB565 或 sensor.GRAYSCALE
    • 返回值:无
  3. sensor.set_framesize( )
      这个函数用于设置摄像头传感器的帧大小,也就是摄像头的分辨率。sensor.QVGA是一个预定义的分辨率,通常为320x240像素。
    • 参数:sensor.QVGA、sensor.VGA、sensor.HD 等
    • 返回值:无
  4. sensor.set_vflip( )
      这个函数用于垂直翻转摄像头传感器的图像。参数1表示启用垂直翻转,0表示禁用。在某些应用中,可能需要根据摄像头安装的方向来调整图像的方向,这时这个函数就非常有用了。
    • 参数:0 或 1
    • 返回值:无

3. 初始化屏幕

#lcd初始化
lcd.init()
#用于获取当前的时间,并将其赋值给变量 clock
clock=time.clock()

4. 定义用于颜色识别的阈值

   这些阈值分别用于识别红色、绿色和蓝色区域,这也是我们在进行采集的时候需要不断调整的。

#颜色识别阈值 (L Min, L Max, A Min, A Max, B Min, B Max) LAB模型
#下面的阈值元组是用来识别 红、绿、蓝三种颜色,当然你也可以调整让识别变得更好。
thresholds = [(30, 100, 15, 127, 15, 127), # 红色阈值
             (30, 100, -64, -8, -32, 32), # 绿色阈值
             (0, 30, 0, 64, -128, -20)] # 蓝色阈值

   在给定的阈值中,通常使用LAB色彩空间来表示颜色范围,以便在图像处理中识别特定的颜色。通过调整阈值的L、A、B值,可以选择性地识别不同的颜色。Lab色彩空间的主要优势在于其色域广阔,比RGB空间还要大,这意味着RGB和CMYK所能描述的色彩信息,在Lab颜色空间中都能得以体现。此外,Lab色彩空间具有跨平台兼容性,是一种独立于设备和操作系统的颜色模型,因此在制造业中,通过使用Lab色彩空间,可以对不同颜色的产品进行精确的颜色比较和质量控制。
   在图像处理中,Lab色彩空间具有很大的应用价值。由于其均匀分布的颜色模型,它能更准确地表示图像中的颜色信息,从而实现更好的图像处理效果。其中,L表示亮度(从黑到白的变化),A和B表示色度。A通道表示从绿色到红色的变化,负值表示绿色,正值表示红色。B通道表示从蓝色到黄色的变化,负值表示蓝色,正值表示黄色。

5. img.find_blobs( )函数

   这是一个在 micropython-opencv 库中用于图像处理的函数,主要用于在图像中查找和识别特定的颜色块(blobs)。
函数的常见参数包括:

  • threshold:一个颜色阈值元组,用于确定哪些颜色被认为是 blob 的一部分。
  • area_threshold:一个整数值,用于过滤掉小于此面积阈值的 blob。
  • merge:一个布尔值,如果为 True,则合并相近的 blob。
       函数的返回值是一个包含所有找到的 blob 的列表。每个 blob 都是一个对象,其中包含有关该 blob 的信息,例如其位置、大小和颜色。

6. 主循环

while True:
 
    clock.tick()
 
    img=sensor.snapshot()
 
    blobs = img.find_blobs([thresholds[0]]) # 0,1,2分别表示红,绿,蓝色。
    if blobs:
        for b in blobs:
            tmp=img.draw_rectangle(b[0:4])
            tmp=img.draw_cross(b[5], b[6])
 
    lcd.display(img)     #LCD显示图片
    print(clock.fps())   #打印FPS

识别结果:
   下图是K210拍到的画面,笔者这里选择识别红色,可以看到这里的红色区块已经被标记出来了。
在这里插入图片描述

三、数字识别

1. KPU的引入

   在CanMV K210模块中,KPU(Kendryte Processing Unit)是嘉楠科技为K210这款AI芯片设计的一种专门用于加速神经网络计算的协处理器,可以简单理解为K210的显卡,可以给模型的运算提提速。KPU的存在极大地提升了K210在神经网络推理方面的性能,使得该芯片能够高效地完成图像识别、目标检测等AI任务。
   KPU的设计以功能核作为基本单元,直接对应用中的计算密集性应用进行抽象和高层综合,实现以应用为中心的架构“定制”。这种设计使得KPU能够针对特定的神经网络模型进行优化,从而在保证计算精度的同时,实现高效的计算性能。
   可以利用 import KPU as kpu 在工程中引入KPU,并使用
kpu.init_yolo2( ) 对其进行初始化,以下是他的一些参数。

参数说明
anchor(必选)锚点参数,和模型高度绑定,不可以更改
anchor_numanchor的锚点数
threshold概率阈值,大于这个数才会输出结果,范围为0~1
nms_valuebox_iou门限,当同时出现多个重叠框时,如果两个框的重叠面积小于这个值时选择概率大的一个框
classes要分辨的目标数量,该值由训练的模型决定

注:kpu.init_yolo2( )仅可以对yolo2网络进行初始化。

  YOLOv2(You Only Look Once version 2)是一种基于深度学习的实时物体检测算法。相较于其前身YOLOv1,YOLOv2在速度和精度上都进行了显著的优化,使得它在目标检测任务中表现出色。

  • 模型结构
      YOLOv2采用了Darknet-19作为其主干网络,这是一个在性能和速度之间进行了平衡的卷积神经网络。这种设计使得YOLOv2能够在保持高速度的同时,提升检测的精度。
  • 模型优化点
    • Batch Normalization:YOLOv2引入了Batch Normalization技术,该技术可以对每一层的输入进行归一化,使得模型训练更加稳定,收敛速度更快。同时,它还能在一定程度上解决模型过拟合的问题。
    • 高分辨率分类器:在YOLOv1中,训练通常使用224x224分辨率的图像,而测试使用448x448分辨率。这种分辨率的不一致可能导致模型性能下降。YOLOv2在整个训练过程中使用了统一的448x448高分辨率,使得模型能够更好地适应并检测小物体。
    • 锚点框(Anchor Boxes):YOLOv2引入了锚点框的概念,通过聚类方法得到不同宽高比的锚点框,使得模型能更好地预测不同形状和大小的物体。
    • 细粒度特征:YOLOv2通过一种称为passthrough layer的结构,将更细粒度的特征从较早的层传递到后面的层,以增强对小物体的检测能力。
    • 多尺度训练:为了使模型对不同尺度的输入具有鲁棒性,YOLOv2在训练过程中随机改变输入图像的尺寸。

   KPU调用模型路径的方式有两种:

方式说明
KPU = kpu.load(“/sd/mx.kmodel”)从SD卡中加载模型
KPU = kpu.load(0x300000,278440)从Flash中0x300000的位置加载模型,模型的大小为278440

2. 数据采集

   本次的实验简单来说就是三步:采集数据集、对数据集进行标注、开始训练并得到。但是,因为我们运算是在 K210 本地的,图像来源也是 K210 自带的摄像头,为了让拍照结果结果更接近实际K210“看到”的图像,可以用 python 编写一个 K210 的拍照程序,采集固定的 224*224 图像并保存到 TF 卡里面,再用读卡器把 K210的TF 卡里面采集到的训练集保存到电脑上。

#引入库
import sensor, image, time, lcd, struct, ustruct
from Maix import GPIO,utils
import gc,os
from machine import Timer,PWM,I2C
from fpioa_manager import fm
#初始化屏幕
lcd.init()                          # Init lcd display
lcd.clear(lcd.RED)                  # Clear lcd screen.
#初始化摄像头
sensor.reset()                      # Reset and initialize the sensor.
sensor.reset(freq=24000000, dual_buff=1)                # 设置摄像头频率 24M 开启双缓冲模式 会提高帧率 但内存占用增加
sensor.set_auto_exposure(1)         # 设置自动曝光
sensor.set_auto_gain(False) # 颜色跟踪必须关闭自动增益
sensor.set_auto_whitebal(False) # 颜色跟踪必须关闭白平衡
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((224,224)) # 分辨率为B224X224

sensor.set_vflip(1)

sensor.skip_frames(time = 2000)     # Wait for settings take effect.
clock = time.clock()                # Create a clock object to track the FPS.

#要拍摄不同的数字就切换这里的数字
need_number_ficture= 1
#保存文件名计数
save_count =0

#注册IO,注意高速GPIO口才有中断
fm.register(35, fm.fpioa.GPIO0)
fm.register(16, fm.fpioa.GPIOHS0)
#构建案件对象
KEY=GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP)

#按键标志位
key_node = 0
key_press_long = 0

#中断回调函数
def fun(KEY):
    global state,key_node,need_number_ficture
    temp_count = 0

    time.sleep_ms(10) #消除抖动
    while KEY.value()== 0: #按键检测
        key_node = 1
        time.sleep_ms(10) #长按延时
        #长按检测计数
        temp_count=temp_count+1
    if temp_count >= 50:
        key_node = 0

        beep.duty(50)
        time.sleep_ms(500)
        beep.duty(0)
        time.sleep_ms(100)

        need_number_ficture=need_number_ficture+1
        if(need_number_ficture == 9):
            need_number_ficture=0



#开启中断,下降沿触发
KEY.irq(fun, GPIO.IRQ_FALLING)

#先把文件路径切换到文件卡里面
os.chdir("/sd")
#os.mkdir("img/0")
#os.mkdir("img/1")
#os.mkdir("img/2")
#os.mkdir("img/3")
#os.mkdir("img/4")
#os.mkdir("img/5")
#os.mkdir("img/6")
#os.mkdir("img/7")
#os.mkdir("img/8")




#PWM通过定时器配置,接到IO15引脚
tim = Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PWM)
beep = PWM(tim, freq=1000, duty=0, pin=9)


clock = time.clock()                # 创建一个clock对象,用来计算帧率
while True:
    clock.tick()                    # 更新计算帧率的clock
    img=sensor.snapshot()
    #按键按下进入
    if key_node == 1:

        save_count=save_count+1
        img.save("img/"+str(need_number_ficture)+"/"+str(save_count)+".jpg")

        beep.duty(50)
        time.sleep_ms(100)
        beep.duty(0)
        time.sleep_ms(100)

        key_node = 0 #清除按键标志位
    # 在图像上画字符串
    img.draw_string(0, 10,str(need_number_ficture)+"/"+str(save_count)+".jpg", color = (200, 0, 0), scale = 2, mono_space = False,
                    char_rotation = 0, char_hmirror = False, char_vflip = False,
                    string_rotation = 0, string_hmirror = False, string_vflip = False)
    lcd.display(img)

注:这部分主要是为了采集图像数据,将这部分代码拷贝到SD卡并插入K210中会自动开始拍照,按下按键会进行拍摄。

3. 数据标记及训练

  这部分笔者也是一窍不通,大家可以仿照这个视频来搞:https://www.bilibili.com/video/BV1Pb4y1V7XFp=8&vd_source=937f3264dce76f586bc0a69ee24dfafa
软件下载地址:https://mc.dfrobot.com.cn/thread-308750-1-1.html
  找到里面的V4.0.0下载下来安装后就可以使用了。
  打开Mx-yolo里面工具集中的图片标注助手,打开保存采集数据的文件夹。详细教程请查看这个链接:https://mc.dfrobot.com.cn/forum.phpmod=viewthread&tid=312205&highlight=mx
注:labellmg左边的打开文件夹是打开你准备标注图片的文件夹,打开保存文件夹是标注信息文件需要保存到的文件夹路径。

三、识别模式切换

  K210目前不支持同时进行多种识别方式,所以需要我们进行工作模式的切换,此时我们可以选择利用按键进行手动切换(也可以使用串口方式等进行切换)。这里我们需要利用到外部中断,但是K210 只有高速 GPIO 才有外部中断,这点尤为关键。

from Maix import GPIO
from fpioa_manager import fm
import utime

# 注册高速I/O口
fm.register(16, fm.fpioa.GPIOHS0)

#构建案件对象
KEY=GPIO(GPIO.GPIOHS0, GPIO.IN, GPIO.PULL_UP)

#按键标志位
key_node = 0
key_press_long = 0

#中断回调函数
def fun(KEY):
    global work_mode,key_node,key_press_long
    temp_count = 0
    #消抖操作
    time.sleep_ms(10) 
    while KEY.value()== 0:
        key_node = 1
        time.sleep_ms(10) #长按延时
        #长按检测计数
        temp_count=temp_count+1
        print(temp_count)
    if temp_count >= 50:
        beep.duty(50)
        time.sleep_ms(500)
        beep.duty(0)
        time.sleep_ms(100)

        print(temp_count)
        key_node = 0
        key_press_long = 1

#开启中断,下降沿触发
KEY.irq(fun, GPIO.IRQ_FALLING)

  K210的外部中断相关函数如下所示:

#开启并设置中断
GPIO.irq(callback_fun, trigger_mode)
  • 参数
    • callback_fun:回调函数
    • trigger_mode:触发方式
      • GPIO.IRQ_FALLING:下降沿触发
      • GPIO.IRQ_RISING:上升沿触发
      • GPIO.IRQ_BOTH:双沿触发
#关闭中断
GPIO.disirq( )
  • 21
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值