OpenMV入门

article/2025/9/28 3:50:18

1. 什么是OpenMV

OpenMV  是一个开源,低成本,功能强大的   机器视觉模块

OpenMV上的机器视觉算法包括  寻找色块、人脸检测、眼球跟踪、边缘检测、标志跟踪  等。

以STM32F427CPU为核心,集成了OV7725摄像头芯片,在小巧的硬件模块上,用C语言高效地实现了核心机器视觉算法,提供Python编程接口

(这也就意味着,我们可以通过python来对他进行编程,所以我们就需要学习一点基础的python知识)

————————————————

2. 关于OpenMV 和 OpenCV

OpenMV是 开源的机器视觉框架,而 OpenMV  是一种 开源计算机视觉库,两者都是实现视觉应用的工具,不同的是 OpenMV 可以运行在  MCU 上,而OpenCV可以运行在多种框架的 CPU上,OpenMV的优势在于轻量化,但是处理高复杂图形信息和告诉图像能力的时候明显弱于OpenCV

————————————————

3. OpenMV的教程

序言 · OpenMV中文入门教程

以上链接为 星瞳官方 所给我们的上手教程,我们接下来的内容也是对视频内容的笔记

Home - 廖雪峰的官方网站

以上链接为 Python 语法的学习网址,适合对其他语言有一些基础的同学

————————————————

4. OpenMV IDE 界面介绍

 上面是我们下载完 IDE 后进入的界面

 中间的这一块是我们的代码编辑框,我们可以在这里写代码

 右上角是 Frame Buffer,可以用来查看OpenMV的摄像头的头像

右下方是 图像的直方图,可以查看图像不同的颜色阈值 

当我们连接OpenMV后,点击连接,就可以看到 图像显示出来了

 左上角的菜单栏 File

 在下面了 示例 里面,有一些官方给的历程

 ————————————

 控制一些 基本的外设

————————————————

画图,画十字,画线,画框

————————————————

 与图像相关的滤波

————————————————

图像的截图保存等

————————————————

录制视频等

————————————————

人脸识别,人脸追踪

————————————————

这里面有一些特征点匹配:

直线线段 ,圆识别, 边缘检测,模板匹配等等

————————————————

瞳孔识别,人眼识别

————————————————

 与颜色识别有关: 自动灰度颜色识别 ,自动彩图颜色识别,红外颜色识别 等等

————————————————

运行LCD程序,当我们外接LCD显示屏的时候使用

————————————————

红外热成像的一个例程 

____________________________

 蓝牙 , WIFI ,舵机拓展板 例程

——————————————

条码,二维码相关的扫描识别

____________________________________________________

然后 Edit 里面,就是我们最经常使用的复制 黏贴等

———————————————————————————

5. 基础程序的讲解

# Hello World Example
#
# Welcome to the OpenMV IDE! Click on the green run arrow button below to run the script!import sensor, image, timesensor.reset()                      # Reset and initialize the sensor.
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QVGA)   # Set frame size to QVGA (320x240)
sensor.skip_frames(time = 2000)     # Wait for settings take effect.
clock = time.clock()                # Create a clock object to track the FPS.while(True):clock.tick()                    # Update the FPS clock.img = sensor.snapshot()         # Take a picture and return the image.print(clock.fps())              # Note: OpenMV Cam runs about half as fast when connected# to the IDE. The FPS should increase once disconnected.

 上面这段代码,也就是我们刚进入 IDE 时,直接给我们的,我们对他先来进行分析

· 首先 import 是导入此代码所依赖的模块,在 hellow world 这个代码中主要依赖

sensor感光元件模块
image图像处理相关模块
time时钟
sensor.reset()   重置感光元件
RGB565彩图
sensor.set_pixformat(sensor.RGB565)设置感光元件的图像的色彩
sensor.set_framesize(sensor.QVGA)设置感光元件的分辨率的大小
sensor.skip_frames(time = 2000)使图像跳过几帧
clock = time.clock() 设置时钟

我们进入一个while大循环,在这里 image 在不断的截图保存图像,而截取的图像我们就可以在右上角看到

最后一句 也就是打印的帧率,我们可以在下面的框Terminal看到 

——————————————————————————————————

5. 如何进行OpenMV的脱机运行程序

而我们想把我们的代码在我们不连接电脑的时候使用,我们就需要用到脱机运行

把代码保存的 OpenMV内置的 flash 内存 里面(也就是OpenMV连接电脑时,弹出的U盘,我们把文件保存在那里面,我们在那里面存储代码或图片)

我们使用 工具 里的 一键下载 

当写入成功时,我们的灯会亮一下,就代表脱机完成,脱机成功后,我们给OpenMV重新上电(也就是重新启动一下),就可以自动运行里面的代码。我们也可以在 OpenMV的U盘里面看到我们刚刚保存的代码

OpenMV保存的 时候 会把我们的代码默认保存为 main.py,我们也可以在保存之后重新保存为其他的名称 .py

但需要注意的是,我们上电之后,他会自动执行我们 main.py的程序,而不是其他的程序

关于我们如何查看是否正确保存了我们的代码,我们可以将示例代码中闪灯的代码,作为测试,保存到我们的  main.py  里面,然后上电之后看看有没正确闪灯即可

如果我们发现,有时候并没有正确的把代码保存进去,我们就可以把U盘格式化一下,再重新保存

——————————————————————————————————

6. 颜色识别

前面我们知道,OpenMV里面有很多的颜色识别,我们就来看一下 单颜色彩色识别

# Single Color RGB565 Blob Tracking Example
#
# This example shows off single color RGB565 tracking using the OpenMV Cam.import sensor, image, time, maththreshold_index = 0 # 0 for red, 1 for green, 2 for blue# Color Tracking Thresholds (L Min, L Max, A Min, A Max, B Min, B Max)
# The below thresholds track in general red/green/blue things. You may wish to tune them...
thresholds = [(30, 100, 15, 127, 15, 127), # generic_red_thresholds(30, 100, -64, -8, -32, 32), # generic_green_thresholds(0, 30, 0, 64, -128, 0)] # generic_blue_thresholdssensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking
clock = time.clock()# Only blobs that with more pixels than "pixel_threshold" and more area than "area_threshold" are
# returned by "find_blobs" below. Change "pixels_threshold" and "area_threshold" if you change the
# camera resolution. "merge=True" merges all overlapping blobs in the image.while(True):clock.tick()img = sensor.snapshot()for blob in img.find_blobs([thresholds[threshold_index]], pixels_threshold=200, area_threshold=200, merge=True):# These values depend on the blob not being circular - otherwise they will be shaky.if blob.elongation() > 0.5:img.draw_edges(blob.min_corners(), color=(255,0,0))img.draw_line(blob.major_axis_line(), color=(0,255,0))img.draw_line(blob.minor_axis_line(), color=(0,0,255))# These values are stable all the time.img.draw_rectangle(blob.rect())img.draw_cross(blob.cx(), blob.cy())# Note - the blob rotation is unique to 0-180 only.img.draw_keypoints([(blob.cx(), blob.cy(), int(math.degrees(blob.rotation())))], size=20)print(clock.fps())

最开始也是导入代码所需要的模块


import sensor, image, time, math

接下来设置颜色的阈值

threshold_index = 0 # 0 for red, 1 for green, 2 for blue

然后 重置感光元件,摄像头。设置颜色格式为RGB565, 图像大小为QVGA,设置帧率

关闭颜色识别中的白平衡和自动增益(打开可能会使颜色的阈值发生改变)

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking
clock = time.clock()

在 while 循环里面

首先先截取感光元件的一张图片

 for blob in img.find_blobs([thresholds[threshold_index]], pixels_threshold=200, area_threshold=200, merge=True):

这是 python的语法,在下面进行判断。

它的意思是 在这个函数中,我们进行颜色识别,find_blobs 这个函数会返回一个列表

roi是“感兴趣区”。left_roi = [0,0,160,240]
blobs = img.find_blobs([red],roi=left_roi)x_stride 就是查找的色块的x方向上最小宽度的像素,默认为2,如果你只想查找宽度10个像素以上的色块,那么就设置这个参数为10:blobs = img.find_blobs([red],x_stride=10)y_stride 就是查找的色块的y方向上最小宽度的像素,默认为1,如果你只想查找宽度5个像素以上的色块,那么就设置这个参数为5:blobs = img.find_blobs([red],y_stride=5)invert 反转阈值,把阈值以外的颜色作为阈值进行查找area_threshold 面积阈值,如果色块被框起来的面积小于这个值,会被过滤掉pixels_threshold 像素个数阈值,如果色块像素数量小于这个值,会被过滤掉merge 合并,如果设置为True,那么合并所有重叠的blob为一个。
注意:这会合并所有的blob,无论是什么颜色的。如果你想混淆多种颜色的blob,只需要分别调用不同颜色阈值的find_blobs。

在这,我们是默认查找红色

他把红色给我们框出来了

find_blobs对象返回的是多  blob  的列表。(注意区分blobs和blob,这只是一个名字,用来区分多个色块,和一个色块)。
列表类似与C语言的数组,一个blobs列表里包含很多blob对象,blobs对象就是色块,每个blobs对象包含一个色块的信息

blob有多个方法:blob.rect() 返回这个色块的外框——矩形元组(x, y, w, h),可以直接在image.draw_rectangle中使用。blob.x() 返回色块的外框的x坐标(int),也可以通过blob[0]来获取。blob.y() 返回色块的外框的y坐标(int),也可以通过blob[1]来获取。blob.w() 返回色块的外框的宽度w(int),也可以通过blob[2]来获取。blob.h() 返回色块的外框的高度h(int),也可以通过blob[3]来获取。blob.pixels() 返回色块的像素数量(int),也可以通过blob[4]来获取。blob.cx() 返回色块的外框的中心x坐标(int),也可以通过blob[5]来获取。blob.cy() 返回色块的外框的中心y坐标(int),也可以通过blob[6]来获取。blob.rotation() 返回色块的旋转角度(单位为弧度)(float)。如果色块类似一个铅笔,那么这个值为0~180°。如果色块是一个圆,那么这个值是无用的。如果色块完全没有对称性,那么你会得到0~360°,也可以通过blob[7]来获取。blob.code() 返回一个16bit数字,每一个bit会对应每一个阈值。举个例子:blobs = img.find_blobs([red, blue, yellow], merge=True)如果这个色块是红色,那么它的code就是0001,如果是蓝色,那么它的code就是0010。注意:一个blob可能是合并的,如果是红色和蓝色的blob,那么这个blob就是0011。这个功能可以用于查找颜色代码。也可以通过blob[8]来获取。blob.count() 如果merge=True,那么就会有多个blob被合并到一个blob,这个函数返回的就是这个的数量。如果merge=False,那么返回值总是1。也可以通过blob[9]来获取。blob.area() 返回色块的外框的面积。应该等于(w * h)blob.density() 返回色块的密度。这等于色块的像素数除以外框的区域。如果密度较低,那么说明目标锁定的不是很好。
比如,识别一个红色的圆,返回的blob.pixels()是目标圆的像素点数,blob.area()是圆的外接正方形的面积。

————————

阈值

red = (minL, maxL, minA, maxA, minB, maxB)

 以上是一个 颜色阈值的结构

元组里面的数值分别是L A B 的最小值和最大值。

OpenMV 的IDE里加入了阈值选择工具,极大的方便了对于颜色阈值的调试。

                                                                                   

————————————————————————————

7. 视觉小车

控制视觉小车,对于OpenMV / K210 这端来说 最重要的就是识别元素,并且 把元素发送给我们的主控单片机,让主控来控制小车,这才是我们最需要的

所以接下来我主要从识别的区域和发送的区域来重新理解

(接下来的内容 以 2021电赛f题 送药小车为主体,参考了多个up主以博客,在后续我会一一标注上)

1. 关于OpenMV的循迹

#uart = UART(1, 115200)   # 串口配置      P1   P0(TX RX)
#uart = UART(3, 115200)   #               P4   P5THRESHOLD = (20, 47, 21, 57, 11, 47)
import sensor, image, time,ustruct
from pyb import UART,LED
import pybsensor.reset()
#sensor.set_vflip(True)
#sensor.set_hmirror(True)
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQQVGA)
#sensor.set_windowing([0,20,80,40])
sensor.skip_frames(time = 2000)
clock = time.clock()#32通信
uart = UART(1,115200)     #定义串口3变量
uart.init(115200, bits=8, parity=None, stop=1) # init with given parameters#识别区域,绘图区域 左右上区域
roi1 = [(0, 17, 15, 25),           #  左  x y w h(65,17,15,25),         #  右(30,0,20,15),          #  上(0,0,80,60)]           #  停车def send_data_w(x,a,f_x,f_a):global uart;data = ustruct.pack("<bbhhhhb",      #格式为俩个字符俩个短整型(2字节)0x2C,                      #帧头1 001011000x12,                      #帧头2 00010010#下面的4个数据存到上面的情况里面,进行一个打包int(x),   # rho 截距int(a),   # theat 角度int(f_x), # 位置判断信息int(f_a), # 位置判断信息0x5B)     # 帧尾 01011011uart.write(data);while(True):clock.tick()img = sensor.snapshot().binary([THRESHOLD])line = img.get_regression([(100,100)], robust = True)left_flag,right_flag,up_flag=(0,0,0)#三个区域块的值,和下面的判断相关for rec in roi1:img.draw_rectangle(rec, color=(255,0,0))#绘制出roi区域if (line):rho_err = abs(line.rho())-img.width()/2if line.theta()>90:theta_err = line.theta()-180else:theta_err = line.theta()#直角坐标调整img.draw_line(line.line(), color = 127)#画出直线x=int(rho_err)a=int(theta_err)f_x=0f_a=0if x<0:x=-xf_x=1if a<0:a=-af_a=1if line.magnitude()>8:outdata=[x,a,f_x,f_a]print(outdata)send_data_w(x,a,f_x,f_a)  #outuart发送的就是 x,a,flag,对应的就是截距,角度if img.find_blobs([(96, 100, -13, 5, -11, 18)],roi=roi1[0]):  #leftleft_flag=1if img.find_blobs([(96, 100, -13, 5, -11, 18)],roi=roi1[1]):  #rightright_flag=1if img.find_blobs([(96, 100, -13, 5, -11, 18)],roi=roi1[2]):  #upup_flag=1if left_flag==1 and right_flag==1:send_data_w(0,0,2,2)time.sleep_ms(100)send_data_w(0,0,2,2)print(0,0,2,2)print('shizi')continueelse:passelse:send_data_w(0,0,3,3)print('3')print('stop')

在其中最重要的就是我们的 打包函数

def send_data_w(x,a,f_x,f_a):global uart;data = ustruct.pack("<bbhhhhb",      #格式为俩个字符俩个短整型(2字节)0x2C,                      #帧头1 001011000x12,                      #帧头2 00010010#下面的4个数据存到上面的情况里面,进行一个打包int(x),   # rho 截距int(a),   # theat 角度int(f_x), # 位置判断信息int(f_a), # 位置判断信息0x5B)     # 帧尾 01011011uart.write(data);

我们来解读一下这个函数,在首先,我们需要看一张图

我们定义的打包函数 bbhhhhb 也就是发送 2个字符(1 个 字节,所以我们在STM32上面接收到的前两个就会是 2C 12

而下面的短整型也会和上面一样被转化(如 1 就会被换为 01 00),所以就需要我们注意一下读取的位数

我们利用感兴趣区来进行标记,以此来判断十字以及停止(同时发送特殊数据,加了延时以保证识别的特殊情况处理的时间)

2. K210的数字识别


import sensor, image, lcd, time
import KPU as kpu
import gc, sys
import ustruct
from machine import Timer
from fpioa_manager import fm
from machine import UARTfm.register(7, fm.fpioa.UART1_TX, force=True)
fm.register(6, fm.fpioa.UART1_RX, force=True)
uart = UART(UART.UART1, 115200, 8, 1, 0, timeout=1000, read_buf_len=4096)def lcd_show_except(e):import uioerr_str = uio.StringIO()sys.print_exception(e, err_str)err_str = err_str.getvalue()img = image.Image(size=(224,224))img.draw_string(0, 10, err_str, scale=1, color=(0xff,0x00,0x00))lcd.display(img)def main(anchors, labels = None, model_addr=0x500000, sensor_window=(224, 224), lcd_rotation=0, sensor_hmirror=False, sensor_vflip=False):sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.QVGA)sensor.set_windowing(sensor_window)sensor.set_hmirror(sensor_hmirror)sensor.set_vflip(sensor_vflip)sensor.run(1)lcd.init(type=1)lcd.rotation(lcd_rotation)lcd.clear(lcd.WHITE)if not labels:with open('labels.txt','r') as f:exec(f.read())if not labels:print("no labels.txt")img = image.Image(size=(320, 240))img.draw_string(90, 110, "no labels.txt", color=(255, 0, 0), scale=2)lcd.display(img)return 1try:img = image.Image("startup.jpg")lcd.display(img)except Exception:img = image.Image(size=(320, 240))img.draw_string(90, 110, "loading model...", color=(255, 255, 255), scale=2)lcd.display(img)task = kpu.load(model_addr)kpu.init_yolo2(task, 0.5, 0.3, 5, anchors) # threshold:[0,1], nms_value: [0, 1]try:flag=1#num=0while flag:img = sensor.snapshot()t = time.ticks_ms()objects = kpu.run_yolo2(task, img)t = time.ticks_ms() - tif objects:for obj in objects:pos = obj.rect()img.draw_rectangle(pos)img.draw_string(pos[0], pos[1], "%s : %.2f" %(labels[obj.classid()], obj.value()), scale=2, color=(255, 0, 0))objx = int((obj.x()+obj.w())/2)if labels[obj.classid()] == "1" :uart.write('s')uart.write('z')uart.write('1')uart.write('e') # >95 右转 <95 左转print(1)if labels[obj.classid()] == "2":uart.write('s')uart.write('z')uart.write('2')uart.write('e')print(2)if labels[obj.classid()] == "3" and objx >= 92 and objx <= 98:# num = 3uart.write('s')uart.write('z')uart.write('3')uart.write('T')uart.write('e')print('T')print(3)# time.sleep(3)if labels[obj.classid()] == "3" and objx >98:num =0uart.write('s')uart.write('z')uart.write('3')uart.write('R')uart.write('e')print('R')print(3)if labels[obj.classid()] == "3" and objx <92:uart.write('s')uart.write('z')uart.write('3')uart.write('L')uart.write('e')print('L')print(3)if labels[obj.classid()] == "4" and objx >95:uart.write('s')uart.write('z')uart.write('4')uart.write('R')uart.write('e')print(4)if labels[obj.classid()] == "4" and objx <95:uart.write('s')uart.write('z')uart.write('4')uart.write('L')uart.write('e')print(4)if labels[obj.classid()] == "5" and objx >95:uart.write('s')uart.write('z')uart.write('5')uart.write('R')uart.write('e')print(5)if labels[obj.classid()] == "5" and objx <95:uart.write('s')uart.write('z')uart.write('5')uart.write('L')uart.write('e')print(5)if labels[obj.classid()] == "6" and objx >95:uart.write('s')uart.write('z')uart.write('6')uart.write('R')uart.write('e')print(6)if labels[obj.classid()] == "6" and objx <95:uart.write('s')uart.write('z')uart.write('6')uart.write('L')uart.write('e')print(6)if labels[obj.classid()] == "7" and objx >95:uart.write('s')uart.write('z')uart.write('7')uart.write('R')uart.write('e')print(7)if labels[obj.classid()] == "7" and objx <95:uart.write('s')uart.write('z')uart.write('7')uart.write('L')uart.write('e')print(7)if labels[obj.classid()] == "8" and objx >95:uart.write('s')uart.write('z')uart.write('8')uart.write('R')uart.write('e')print(8)if labels[obj.classid()] == "8" and objx <95:uart.write('s')uart.write('z')uart.write('8')uart.write('L')uart.write('e')print(8)img.draw_string(0, 200, "t:%dms" %(t), scale=2, color=(255, 0, 0))lcd.display(img)except Exception as e:raise efinally:kpu.deinit(task)if __name__ == "__main__":try:labels = ['1', '2', '3', '4', '5', '6', '7', '8']anchors = [1.40625, 1.8125000000000002, 5.09375, 5.28125, 3.46875, 3.8124999999999996, 2.0, 2.3125, 2.71875, 2.90625]#main(anchors = anchors, labels=labels, model_addr="/sd/m.kmodel", lcd_rotation=2, sensor_window=(224, 224))main(anchors = anchors, labels=labels, model_addr=0x500000, lcd_rotation=2, sensor_window=(224, 224))except Exception as e:sys.print_exception(e)lcd_show_except(e)finally:gc.collect()

   

2. 由大哥帮忙修改的代码,但是还需要在后续调整

#目前缺点:  第一次识别会直接发送出方向
import sensor, image, lcd, time
import KPU as kpu
import gc, sys
import ustruct
from Maix import GPIO
from machine import Timer
from fpioa_manager import fm
from machine import UARTfm.register(12, fm.fpioa.GPIO0,force=True)
fm.register(7, fm.fpioa.UART1_TX, force=True)
fm.register(6, fm.fpioa.UART1_RX, force=True)
uart = UART(UART.UART1, 115200, 8, 1, 0, timeout=1000, read_buf_len=4096)LED_B = GPIO(GPIO.GPIO0, GPIO.OUT) #构建 LED 对象def lcd_show_except(e):import uioerr_str = uio.StringIO()sys.print_exception(e, err_str)err_str = err_str.getvalue()img = image.Image(size=(224,224))img.draw_string(0, 10, err_str, scale=1, color=(0xff,0x00,0x00))lcd.display(img)def await_num(num_await,num_input,objx):"""等待数字 num_await 的出现#  不需要了:如果出现了 num_await, 则返回 None, 可以接收新的数字输入了(进入recognize_num)没有出现 num_await,那么就无限循环"""if num_input == num_await:if objx >110:uart.write('s')uart.write('z')uart.write(num_await)uart.write('R')uart.write('e')print('R')print(num_await)elif objx <80:uart.write('s')uart.write('z')uart.write(num_await)uart.write('L')uart.write('e')print('L')print(num_await)#return None   # 下一次不用识别这个数字了#修改:如果不返回值,这样就不会重新输入新的数字,也就是不会等待新数字,这样就会避免出现程序刷新弄到新的数字return num_await# 调用函数给下面的主函数,返回出识别的值# 如果想要识别新的数字就可以通过重新上电来执行def recognize_num(num,objx):"""识别输入的数字返回值: 接下来需要识别的数"""# 识别输入的数字# 不管识别到什么数字,其实操作是类似的,所以可以用一个函数概括这些操作,不用写很多遍if num == '1' or num == '2':# 这两个的操作类似,所以用一个 if 就可以了; 看代码读到这两个数字的时候,并不需要等待下一次继续出现这个数字?uart.write('s')uart.write('z')uart.write(num)uart.write('G')uart.write('e') # >95 右转 <95 左转print(num)return None # 不需要等待任何数字elif objx >= 80 and objx <= 110:uart.write('s')uart.write('z')uart.write(num)uart.write('T')uart.write('e')#time.sleep(1)#time.sleep_ms(500)print(num)print('T')return num # 下一次需要等待的数字def main(anchors, labels = None, model_addr=0x500000, sensor_window=(224, 224), lcd_rotation=0, sensor_hmirror=False, sensor_vflip=False):sensor.reset()sensor.set_pixformat(sensor.RGB565)sensor.set_framesize(sensor.QVGA)sensor.set_windowing(sensor_window)sensor.set_hmirror(sensor_hmirror)sensor.set_vflip(sensor_vflip)sensor.run(1)lcd.init(type=1)lcd.rotation(lcd_rotation)lcd.clear(lcd.WHITE)if not labels:with open('labels.txt','r') as f:exec(f.read())if not labels:print("no labels.txt")img = image.Image(size=(320, 240))img.draw_string(90, 110, "no labels.txt", color=(255, 0, 0), scale=2)lcd.display(img)return 1try:img = image.Image("startup.jpg")lcd.display(img)except Exception:img = image.Image(size=(320, 240))img.draw_string(90, 110, "loading model...", color=(255, 255, 255), scale=2)lcd.display(img)task = kpu.load(model_addr)kpu.init_yolo2(task, 0.5, 0.3, 5, anchors) # threshold:[0,1], nms_value: [0, 1]try:flag=1num=Nonewhile flag:img = sensor.snapshot()t = time.ticks_ms()objects = kpu.run_yolo2(task, img)t = time.ticks_ms() - tif num != 0:LED_B.value(0)if objects:for obj in objects:pos = obj.rect()img.draw_rectangle(pos)img.draw_string(pos[0], pos[1], "%s : %.2f" %(labels[obj.classid()], obj.value()), scale=2, color=(255, 0, 0))objx = int((obj.x()+obj.w())/2)# 识别新的数字if num is None:num = recognize_num(labels[obj.classid()],objx)else:num = await_num(num,labels[obj.classid()],objx)img.draw_string(0, 200, "t:%dms" %(t), scale=2, color=(255, 0, 0))lcd.display(img)except Exception as e:raise efinally:kpu.deinit(task)if __name__ == "__main__":try:labels = ['1', '2', '3', '4', '5', '6', '7', '8']anchors = [1.40625, 1.8125000000000002, 5.09375, 5.28125, 3.46875, 3.8124999999999996, 2.0, 2.3125, 2.71875, 2.90625]main(anchors = anchors, labels=labels, model_addr="/sd/m.kmodel", lcd_rotation=2, sensor_window=(224, 224))# main(anchors = anchors, labels=labels, model_addr=0x500000, lcd_rotation=2, sensor_window=(224, 224))except Exception as e:sys.print_exception(e)lcd_show_except(e)finally:gc.collect()

——————————————

8. 寻找最大色块       

寻找最大色块与上面寻找模板的区别是,它是以颜色进行区分,如果所需要寻找的东西不是 固定物体,就可以用颜色来区别

并且在寻找的时候就可以通过更改阈值来改变需要区分的物体:

测试代码如下:


import sensor,lcd,time
import gc,sys
import ustructfrom machine import UART,Timer
from fpioa_manager import fm#映射串口引脚
fm.register(6, fm.fpioa.UART1_RX, force=True)
fm.register(7, fm.fpioa.UART1_TX, force=True)
uart = UART(UART.UART1, 115200, read_buf_len=4096)#摄像头初始化
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.set_vflip(1) #后置模式,所见即所得
sensor.set_auto_whitebal(False)#白平衡关闭#lcd初始化
lcd.init()
# 颜色识别阈值 (L Min, L Max, A Min, A Max, B Min, B Max) LAB模型
# 此处识别为橙色,调整出的阈值,全部为红色
barries_red = (20, 100, -5, 106, 36, 123)clock=time.clock()#打包函数
def send_data_wx(x,a):global uart;data = ustruct.pack("<bbhhhhb",0x2c,0x12,int(x),int(a),0x5B)uart.write(data);#找到最大色块函数
def find_max(blods):max_size=0for blob in blobs:if blob.pixels() > max_size:max_blob=blobmax_size=blob.pixels()return max_blobwhile True:clock.tick()img=sensor.snapshot()#过滤blods = img.find_blobs([barries_red],x_strid=50)blods = img.find_blobs([barries_red],y_strid=50)blods = img.find_blobs([barries_red],pixels_threshold=100)blods = img.find_blobs([barries_red],area_threshold=60)blobs = img.find_blobs([barries_red])  #找到阈值色块cx=0;cy=0;if blobs:max_blob = find_max(blobs) #找到最大色块cx=max_blob[5]cy=max_blob[6]cw=max_blob[2]ch=max_blob[3]img.draw_rectangle(max_blob[0:4])img.draw_cross(max_blob[5],max_blob[6])lcd.display(img)     #LCD显示图片print(max_blob[5],max_blob[6])send_data_wx(max_blob[5],max_blob[6])

                                                                             

 ==========>  (To be contnue.......)


http://chatgpt.dhexx.cn/article/WX8xvM1N.shtml

相关文章

OpenMV零基础教程

一、资料导航 “工欲善其事&#xff0c;必先利其器”。在正式学习OpenMV之前&#xff0c;你必须知道一条或几条OpenMV的学习途径。这里推荐星瞳科技的中文官网教程&#xff0c;这个教程里面包括了OpenMV IDE的下载和安装、OpenMV上手教程、OpenMV中文文档、OpenMV详细参数以及O…

C++版本OpenCv教程

C版本OpenCv教程(一)Mat—基本的图像容器 目标 我们有多种方法从现实世界获取数字图像:数码相机、扫描仪、计算机断层扫描和磁共振成像等等。在以上任何情况下&#xff0c;我们(人类)看到的都是图像。然而&#xff0c;当将其转换到我们的数字设备时&#xff0c;我们所记录的是…

VS配置OpenCV教程(超详细)

目录 安装环境说明 下载OpenCV 配置OpenCV开发环境 属性表 测试 可能存在的问题 安装环境说明 操作系统&#xff1a;Windows10 OpenCV版本&#xff1a;OpenCV2和OpenCV3 VS版本&#xff1a;VS2015或者VS2017 下载OpenCV OpenCV下载地址&#xff1a;http://opencv.org…

伺服控制原理 及RT and IRT

什么是伺服系统&#xff1f; 以物体的位置、方向、速度等为控制量&#xff0c;以跟踪输入给定制的任意变化为目的&#xff0c;所构成的自动闭环控制系统。 伺服系统组成&#xff1a; 伺服系统是具有负反馈的闭环自动控制系统&#xff0c;由控制器、伺服驱动器、伺服电机和反…

ERTEC200P-2 PROFINET设备完全开发手册(3-1)

3. 读写周期数据 PROFINET的基本通讯模型如下图&#xff1a; Profinet 是基于标准以太网技术的应用层协议&#xff0c;支持4种类型的数据通道 标准通道&#xff1a;参数化及配置&#xff0c;读诊断数据&#xff0c;设备信息(I&M)&#xff0c;资产信息 (AMR) ;&#xff08…

ERTEC200P-2 PROFINET设备完全开发手册(8-2)

8.2 IRT通讯原理及API PROFINET RT通讯的特点&#xff1a; 典型的PROFINET网络如下图所示。 其中&#xff1a; T1: 采样输入 T2: IO背板周期 T3: Profinet I/O 通讯周期 T4: CPU组织块OB1执行周期 T5: Profinet I/O 通讯周期 T6: IO背板周期 T7: 建立输出 在PRO…

多维IRT模型的EM估计

多维IRT模型的EM估计 MIRT &#xff08;Multidimensional Item Response Theory&#xff09;多维项目反应理论。与一维项目反应理论的区别只是在于对于潜在变量的 θ i \theta_{i} θi​ 的建模&#xff0c;一个是unidimensional latent trait θ i \theta_{i} θi​&#xf…

R语言IRT理论:扩展Rasch模型等级量表模型lltm、 rsm 和 pcm模型分析心理和教育测验数据可视化

最近我们被客户要求撰写关于IRT理论的研究报告&#xff0c;包括一些图形和统计输出。 摘要 我们首先介绍扩展 Rasch 模型的方法论&#xff0c;然后是一般程序描述和应用主题,包括简单的 Rasch 模型、评级量表模型、部分信用模型及其线性扩展。这种线性结构的结合允许对协变量…

ERTEC200P-2 PROFINET设备完全开发手册(8-1)

8.1 IRT通讯实验 这里我们使用APP3 IsoApp&#xff0c;修改源代码usrapp_cfg.h的宏为 #define EXAMPL_DEV_CONFIG_VERSION 3 使能App3&#xff0c;对应的主程序为“usriod_main_isoapp.c” 编译后下载运行。打开4.2建立的TIA项目&#xff0c;添加等时模式组织块&#xff0c…

ERTEC200P-2 PROFINET设备完全开发手册(9-2)

9.2 运行AC1/AC4参考代码 修改源代码usrapp_cfg.h的宏为 #define EXAMPL_DEV_CONFIG_VERSION 44 编译后下载到评估板运行AC4示例程序 在TIA中导入GSDML-V2.35-Siemens-ERTEC200pApp44-20210623.xml。新建项目&#xff0c;添加PLC和Devkit设备。 按照如下图所示配置模块&am…

可解释知识追踪(整理更新)

微观角度的可解释性&#xff0c;一个深度学习模型的可解释性是其内 在的固有性质&#xff0c;指模型的决策在多大程度上可以被人类预测和理解。模型的可解释性越强&#xff0c;代表模 型的行为对人类越透明&#xff0c;模型的不确定性也就越低&#xff1b;反之模型的可解释性越…

IRT模型估计-EM算法

IRT模型中参数估计 IRT(Item Response Theory) 项目反应理论。是教育评估与心理测量理论中的重要模型。主要目的是通过被试(examinees) 的对于一套试题的反应(responses), 对被试 的能力(ability parameters) 参数 θ \theta θ 和题目(item parameters) 作出估计。由于被试的…

技术话题(2)实时通讯RT和同步实时通讯IRT的区别

目前西门子 S7-1200 PLC仅支持RT通讯&#xff0c;与 V90 PN 连接做位置控制和速度控制均是通过PROFINET通讯来实现的。 而 S7-1500 PLC 支持IRT通讯&#xff0c;与 V90 PN 做位置控制和速度控制也是由PROFINET通讯来实现的。 下面我们为大家介绍一下RT通讯的特点&#xff1a;…

IRT模型

IRT模型是用来分析考试成绩或者问卷调查数据的数学模型。这些模型的目标是来确定的潜在心理特征&#xff08;latent trait&#xff09;是否可以通过测试题被反应出来&#xff0c;以及测试题和被测试者之间的互动关系。在IRT模型的理念是一个学生回答一个问题是否正确这个结果是…

浅谈知识追踪(BKT、IRT、DKT)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、知识追踪是什么&#xff1f;二、具体内容1.基于贝叶斯的知识追踪&#xff08;BKT&#xff09;项目反应理论&#xff08;IRT&#xff09;深度知识追踪&#…

IRT

文章目录 CTT(classical test theory)历史定义parallel testCronbachs α \alpha α 项目评估P-valueitem-total correlation 缺点 IRT(Item response theory)对于CTT的改进定义三大假设IRF3PL(three parameter logistic model)IRF形态PL模型分类 逻辑正态模型 模型拟合分析项…

Deep-IRT Make Deep Learning Based Knowledge Tracing Explainable Using Item Response Theory

写在前面&#xff1a; 本文在DKVMN的基础上结合项目IRT&#xff0c;加入了student ability network 和 difficulty network两个网络&#xff0c;增加深度知识追踪的可解释性 1 摘要 基于深度学习的知识追踪模型已被证明在不需要人工设计特征的情况下优于传统的知识追踪模型&…

IRT模型学习小结

文章目录 IRT模型学习小结关于IRT模型 IRT模型原理模型介绍参数估计 应用场景 IRT模型学习小结 关于IRT模型 与IRT模型相对应的经典测量理论CCT。经典测量理论与项目反应理论在测量领域均占有重要地位。经典测量理论形成较早&#xff0c;但是经典测量理论却有一些难以克服的缺…

自适应学习系列(一)IRT简介

2019独角兽企业重金招聘Python工程师标准>>> 自适应学习之IRT简介 一、近端发展区(ZPD) Zone of Proximal Development&#xff08;ZPD&#xff09;是由心理学家Vygotsky提出来的一种学习理论&#xff0c;是目前自适应学习常用的思考模型。他认为&#xff0c;能力高…

IRT模型的参数估计方法(EM算法和MCMC算法)

1、IRT模型概述   IRT&#xff08;item response theory 项目反映理论&#xff09;模型。IRT模型用来描述被试者能力和项目特性之间的关系。在现实生活中&#xff0c;由于被试者的能力不能通过可观测的数据进行描述&#xff0c;所以IRT模型用一个潜变量 θθ 来表示&#xff…