[K210]Maixpy self learning classifier 自学习分类器

硬件平台:K210 Sipeed Maix Dock

软件平台:maixpy

实现功能:自学习分类,无需在pc上训练分类,在K210上就可以

实现步骤

一、下载固件

maixpy固件

 其中,各文件说明如下:

一般就下载第一个 maixpy_*.bin文件,功能比较全,但文件比较大,看单片机Flash使用情况而定。

 得到bin文件后 直接打开kflash 烧录进板子里 注意地址为:0X00000

二、下载模型

 打开 maixhub 找到模型文件,输入机器码下载。(如何获取机器码 参考往期的博客。)

(最好每次都通过 keygen.bin的固件通过串口发一次机器码,因为 今天用手动输入的机器码 会导致模型运行的时候无法解密出现报错“[MAIXPY]kpu: load error:2002, ERR_KMODEL_VERSION: only support kmodel V3/V4 now”)

这里有两个模型, 其中较大的模型有 1.8MiB, lite 版本只有 800KiB, lite 版本在使用时初始化代码需要添加fea_len参数为512, 较大模型不需要设置这个参数:

classifier = kpu.classifier(model, class_num, sample_num, fea_len=512)
  • 注意模型烧录地址, 和加载地址,不要弄错了,比如代码model = kpu.load(0x300000)则需要使用 kflash_gui 烧录模型到 0x300000
  • 注意上面说的 lite 模型需要设置 fea_len 参数
  • MaixPy 固件版本应该至少大于 maixpy_v0.6.2_46_geafab8cfd (提交 eafab8cfdfe0aa233586b17d8bc72a266d1b2b61)

三、脚本

 包含示例脚本和加载脚本

①示例脚本 self_learning_classifier.py

需要自行修改 board_info 。方法:在官网资料中找到对应板子的 config_*.py文件,进入IDE中运行,即可以完成对板子的配置项(config.json)的导入,它会在flash上存储该配置文件。

运行配置代码后会自动重启,此时代码中才可以调用 board_info.BOOT_KEY , 实际上 board_info.BOOT_KEY 就是指 IO 16 ,对应的定义在 config.json 中可以得知,如果不存在的资源将会报错,如没有 LED 定义的硬件,运行 LED 点亮的时候就会报错“[Warning] Not loaded from /flash/config.json to board_info”。

下面是示例脚本代码

在IDE运行示例脚本后,按开发板上的 boot 按钮 来捕获 3 个类别 如:手机, 小车, 键盘, 每个类别只需要捕获一次
然后捕获 15 张图, 对顺序没有要求, 比如捕获 5 张 手机, 5 张 小车 , 5 张 键盘 的图片
然后它会自动学习这 15 张图的特征
最后识别到的图像类别会展示在左上角

import KPU as kpu
import sensor
import lcd
from Maix import GPIO,utils
from fpioa_manager import fm
#from board import board_info
import time
import gc

############### config #################
class_num = 3
sample_num = 15
THRESHOLD = 11
class_names = ['class1', 'class2', 'class3']
board_cube = 0
########################################

def draw_string(img, x, y, text, color, scale, bg=None ):
    if bg:
        img.draw_rectangle(x-2,y-2, len(text)*8*scale+4 , 16*scale, fill=True, color=bg)
    img = img.draw_string(x, y, text, color=color,scale=scale)
    return img

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((224, 224))
if board_cube == 1:
    sensor.set_vflip(True)
    sensor.set_hmirror(True)
    lcd.init(type=2)
    lcd.rotation(2)
else:
    lcd.init()

fm.register(16, fm.fpioa.GPIOHS0)
key = GPIO(GPIO.GPIOHS0, GPIO.PULL_UP)

try:
    del model
except Exception:
    pass
try:
    del classifier
except Exception:
    pass

gc.collect()
utils.gc_heap_size(0x40000)
kpu.memtest()  #由于使用的是完整固件,加载smodel会 memory not enough,所以利用utils从gc分配些内存给sys.
model = kpu.load(0x300000)
classifier = kpu.classifier(model, class_num, sample_num)
cap_num = 0
train_status = 0
last_cap_time = 0
last_btn_status = 1
while 1:
    img = sensor.snapshot()
    if board_cube:
        img = img.rotation_corr(z_rotation=90)
        img.pix_to_ai()
    # capture img
    if train_status == 0:
        if key.value() == 0:
            time.sleep_ms(30)
            if key.value() == 0 and (last_btn_status == 1) and (time.ticks_ms() - last_cap_time > 500):
                last_btn_status = 0
                last_cap_time = time.ticks_ms()
                if cap_num < class_num:
                    index = classifier.add_class_img(img)
                    cap_num += 1
                    print("add class img:", index)
                elif cap_num < class_num + sample_num:
                    index = classifier.add_sample_img(img)
                    cap_num += 1
                    print("add sample img:", index)
            else:
                img = draw_string(img, 2, 200, "release boot key please", color=lcd.WHITE,scale=1, bg=lcd.RED)
        else:
            time.sleep_ms(30)
            if key.value() == 1 and (last_btn_status == 0):
                last_btn_status = 1
            if cap_num < class_num:
                img = draw_string(img, 0, 200, "press boot key to cap "+class_names[cap_num], color=lcd.WHITE,scale=1, bg=lcd.RED)
            elif cap_num < class_num + sample_num:
                img = draw_string(img, 0, 200, "boot key to cap sample{}".format(cap_num-class_num), color=lcd.WHITE,scale=1, bg=lcd.RED)
    # train and predict
    if train_status == 0:
        if cap_num >= class_num + sample_num:
            print("start train")
            img = draw_string(img, 30, 100, "training...", color=lcd.WHITE,scale=2, bg=lcd.RED)
            lcd.display(img)
            classifier.train()
            print("train end")
            train_status = 1
    else:
        res_index = -1
        try:
            res_index, min_dist = classifier.predict(img)
            print("{:.2f}".format(min_dist))
        except Exception as e:
            print("predict err:", e)
        if res_index >= 0 and min_dist < THRESHOLD :
            print("predict result:", class_names[res_index])
            img = draw_string(img, 2, 2, class_names[res_index], color=lcd.WHITE,scale=2, bg=lcd.RED)
        else:
            print("unknown, maybe:", class_names[res_index])
            img = draw_string(img, 2, 2, 'maybe {}'.format(class_names[res_index]), color=lcd.WHITE,scale=2, bg=lcd.RED)
    lcd.display(img)
    classifier.save("3_classes.classifier") #保存训练集到flash里
#classifier.save("3_classes.classifier")放置到 lcd.display(img)下面以保存特征值。
# You can save trained data to file system by:
#classifier.save("3_classes.classifier")

# Then load :
# model = kpu.load(0x300000)
# classifier = kpu.classifier.load(model, "3_class.classifier")

② 加载脚本 self_learning_classifier_load.py

运行加载脚本 不需要再次 按BOOT按键进行拍照学习,

此脚本直接提取 示例脚本 保存到 flash里面的3_classes.classifier数据集,进行目标分类。

下面是加载脚本代码
修改class_name以匹配检测物体(训练模型时,使用的是class来命名)
class_names = ['people', 'xiaoai', 'tf']

import KPU as kpu
import sensor
import lcd
import gc

############### config #################
saved_path = "3_classes.classifier"
#如果你使用sd卡:saved_path = "/sd/3_classes.classifier"
THRESHOLD = 11
class_names = ['class1', 'class2', 'class3']
########################################

def draw_string(img, x, y, text, color, scale, bg=None ):
    if bg:
        img.draw_rectangle(x-2,y-2, len(text)*8*scale+4 , 16*scale, fill=True, color=bg)
    img = img.draw_string(x, y, text, color=color,scale=scale)
    return img

lcd.init()
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_windowing((224, 224))

try:
    del model
except Exception:
    pass
try:
    del classifier
except Exception:
    pass
gc.collect()
model = kpu.load(0x300000)
classifier, class_num, sample_num = kpu.classifier.load(model, saved_path)

while 1:
    img = sensor.snapshot()
    res_index = -1
    try:
        res_index, min_dist = classifier.predict(img)
        print("{:.2f}".format(min_dist))
    except Exception as e:
        print("predict err:", e)
    if res_index >= 0 and min_dist < THRESHOLD :
        print("predict result:", class_names[res_index])
        img = draw_string(img, 2, 2, class_names[res_index], color=lcd.WHITE,scale=2, bg=lcd.RED)
    else:
        print("unknown, maybe:", class_names[res_index])
        img = draw_string(img, 2, 2, 'maybe {}'.format(class_names[res_index]), color=lcd.WHITE,scale=2, bg=lcd.RED)
    lcd.display(img)

四、效果

 

五、拓展

示例脚本只捕捉了3个物体,我们可以修改class_num等来提高物体数量

class_num = 5 #5个物体
sample_num = 25 #25张训练集
class_names = ['class1', 'class2', 'class3','class4','class5']#物体标签 

在加载脚本处也修改
 

class_names = ['people', 'xiaoai', 'tf', 'box','mouse']

  • 2
    点赞
  • 32
    收藏
    觉得还不错? 一键收藏
  • 9
    评论
以下是一个示例代码,演示了如何在k210 maixpy平台上使用多线程运行两个模型: ```python import gc import sensor import image import lcd import KPU as kpu import time from machine import I2C from fpioa_manager import fm from board import board_info from Maix import GPIO from machine import UART from machine import Timer # 初始化I2C总线 fm.register(board_info.PIN10, fm.fpioa.GPIO0) i2c = I2C(I2C.I2C0, freq=400000, scl=10, sda=11) devices = i2c.scan() if devices: print("I2C addresses found:", [hex(i) for i in devices]) else: print("No I2C devices found") # 初始化GPIO口 fm.register(board_info.BUTTON_A, fm.fpioa.GPIO1) button_a = GPIO(GPIO.GPIO1, GPIO.IN, GPIO.PULL_UP) # 初始化LCD显示 lcd.init(freq=15000000) lcd.rotation(2) # 初始化摄像头 sensor.reset() sensor.set_pixformat(sensor.RGB565) sensor.set_framesize(sensor.QVGA) sensor.set_vflip(1) sensor.run(1) # 初始化串口 fm.register(board_info.PIN4, fm.fpioa.UART1_TX, force=True) fm.register(board_info.PIN5, fm.fpioa.UART1_RX, force=True) uart1 = UART(UART.UART1, 115200, timeout=1000, read_buf_len=4096) # 初始化定时 tim = Timer(Timer.TIMER0, Timer.CHANNEL0, mode=Timer.MODE_PERIODIC, period=1000, unit=Timer.UNIT_MS, callback=lambda timer: print("tick")) # 加载人脸检测模型 task_detect = kpu.load('/sd/models/multi_face.kmodel') anchor = (1.889, 2.5245, 2.9465, 3.94056, 3.99987, 5.3658, 5.155437, 6.92275, 6.718375, 9.01025) kpu.init_yolo2(task_detect, 0.5, 0.3, 5, anchor) # 加载分类模型 task_classify = kpu.load('/sd/models/mobilenet.kmodel') # 定义多线程函数 def detect_thread(): while True: img = sensor.snapshot() t_start = time.ticks_ms() # 运行人脸检测模型 faces = kpu.run_yolo2(task_detect, img) t_stop = time.ticks_ms() print('Detection time: %dms' % (t_stop - t_start)) # 在LCD上绘制检测结果 lcd.display(img) lcd.draw_string(0, 0, 'face count: %d' % len(faces), lcd.WHITE, lcd.BLACK) for i in range(len(faces)): x, y, w, h = faces[i].rect() lcd.draw_rectangle(x, y, w, h, lcd.RED, thickness=2) face_img = img.cut(x, y, w, h) # 运行分类模型 t_start = time.ticks_ms() p = kpu.run(task_classify, face_img) t_stop = time.ticks_ms() print('Classification time: %dms' % (t_stop - t_start)) # 发送分类结果到串口 uart1.write('face %d: %s\r\n' % (i, p)) def button_thread(): while True: if button_a.value() == 0: print("Button A pressed!") # 开始多线程 import _thread _thread.start_new_thread(detect_thread, ()) _thread.start_new_thread(button_thread, ()) # 释放资源 gc.collect() ``` 该示例代码中,我们通过多线程的方式,同时运行了人脸检测和分类两个模型。其中,`detect_thread`函数用于运行人脸检测模型,并在LCD上绘制检测结果;`button_thread`函数用于监听按钮按下事件。在`detect_thread`函数中,我们首先调用`sensor.snapshot()`方法获取摄像头采集到的图像,然后使用`kpu.run_yolo2`方法运行人脸检测模型,获取检测结果。接着,我们在LCD上绘制检测结果,并针对每个人脸,使用`img.cut`方法获取人脸图像,然后使用`kpu.run`方法运行分类模型,获取分类结果。最后,我们将分类结果发送到串口中。在`button_thread`函数中,我们使用`button_a.value()`方法获取按钮状态,如果按钮被按下,则打印一条提示信息。 需要注意的是,由于k210 maixpy平台内存较小,因此在使用多线程时需要注意内存管理,尤其是在同时运行多个模型时。在示例代码中,我们通过`gc.collect()`方法释放内存。如果需要同时运行更多的模型或任务,可以考虑引入操作系统或使用更高级的开发框架。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值