文章目录
正好回家带了一篇H7的板子,想着先把openmv部分配置完再来整h7的开发,这个板子支持openmv的刷写,固件刷写提供内部flash和外部flah的方式,挺方便的。
板子如下,是weact家的,淘宝搜weact就能找到:
1、刷写固件
资料下载:
https://gitee.com/WeAct-TC
步骤如下:
- 让板子进入dfu模式准备烧写,连接typec端口,按住boot键上电,进入dfu模式,查看电脑是否检测到dfu的接口,如果检测到则一切顺利(如果没有检测到dfu的接口就安装dfu的驱动,多试几次)
- 使用官方批处理工具清楚flash(不知道是不是必须的反正我做了)
- 使用下载工具进行下载,将openmv.bin拖进下载框即可,这里说明,openmv.bin是结合引导文件和flash文件一起的,不用分别下载,直接在默认地址0x8000000处下载即可
- 下载完成可以看到绿灯闪烁,这个是openmv的自检的灯,打开串口助手,可以看到串口多出一个带openmv的串口
- 打开ide进行连接
- 运行helloword例程,一切顺利!
2、开始配置openmv
参考文档:
https://book.openmv.cc/
https://docs.singtown.com/micropython/zh/latest/openmvcam/index.html
3、图像获取与显示
使用摄像头获取图像并使用time获取帧率
import sensor,image,time
sensor.reset() # 复位摄像头
sensor.set_pixformat(sensor.RGB565) # 设置颜色格式为RGB565
sensor.set_framesize(sensor.QVGA) # 设置图像大小
sensor.skip_frames(time = 2000) # 开头跳一些帧
# sensor.skip_frames(10) # 直接指定跳过的帧数
clock = time.clock() # 主要是用来记录帧率
while(True):
clock.tick() # 这个可以记录帧率
img = sensor.snapshot() # 拍照+获取图像
print(clock.fps())
效果如下:
上面的函数总结
图像格式:
- GRAYSCALE
- RGB565
图像大小:(每次是向下除2)
- QVGA 320*240
- QQVGA 460*120
- QQQVGA 80*60
白平衡和自动增益
注意这两个都是为了使得图像更加真实,就是通过一些手段增强图像,其实没有改变了原始图像,结果是增强了视觉效果,就是给图像上增加了一些参数
sensor.set_auto_gain(True) # 自动增益
sensor.set_auto_whitebal(True) # 白平衡
sensor.set_auto_exposure(True) # 自动曝光
截取一段区域
import sensor,image,time
sensor.reset() # 复位摄像头
sensor.set_pixformat(sensor.RGB565) # 设置颜色格式为RGB565
sensor.set_framesize(sensor.VGA)
sensor.set_windowing((320, 240)) #取中间的320*240区域
sensor.skip_frames(time = 2000) # 开头跳一些帧
clock = time.clock() # 主要是用来记录帧率
while(True):
clock.tick() # 这个可以记录帧率
img = sensor.snapshot() # 拍照+获取图像
print(clock.fps())
镜头翻转
import sensor,image,time
sensor.reset() # 复位摄像头
sensor.set_pixformat(sensor.RGB565) # 设置颜色格式为RGB565
sensor.set_framesize(sensor.QVGA)
sensor.set_hmirror(True) # 水平翻转
sensor.set_vflip(True) # 垂直翻转
sensor.skip_frames(time = 2000) # 开头跳一些帧
clock = time.clock() # 主要是用来记录帧率
while(True):
clock.tick() # 这个可以记录帧率
img = sensor.snapshot() # 拍照+获取图像
print(clock.fps())
这里是针对摄像头的翻转,特别是对于有些摄像头结构设计不合理的地方而言,特别重要!!!!
4、修改图像,获取像素,添加元素
获取某个点的像素值并修改某个点的像素值
import sensor,image,time
sensor.reset() # 复位摄像头
sensor.set_pixformat(sensor.RGB565) # 设置颜色格式为RGB565
sensor.set_framesize(sensor.QVGA)
sensor.set_hmirror(True) # 水平翻转
sensor.set_vflip(True) # 垂直翻转
sensor.skip_frames(time = 2000) # 开头跳一些帧
clock = time.clock() # 主要是用来记录帧率
img = sensor.snapshot()
print(img.get_pixel(10,10)) # 获取该点像素值
img.set_pixel(10,10,(255,0,0)) # 修改
print(img.get_pixel(10,10) # 再次打印,像素值改变
获取区域像素值
ROI = (10,10,20,20)
while(True):
clock.tick() # 这个可以记录帧率
img = sensor.snapshot() # 拍照+获取图像
print(img.get_statistics(roi=ROI)) # 打印区域平均颜色值
print(clock.fps())
可以看出这个获取的区域像素值包含了很多东西,相比某个点的丰富了很多
返回的主要是灰度的一些值,然后还有lab的一些值,这里重点关注LAB的值,因为LAB在颜色追踪等方面有很大优势,关于颜色空间的介绍可以参见我的另一篇文章:opecv答题树记录
获取ROI区域的LAB值
#设置ROI区域大小
ROI = (10,10,20,20)
while(True):
clock.tick() # 这个可以记录帧率
img = sensor.snapshot() # 拍照+获取图像
# 获取三个区域的lab值(众数)
color_l= img.get_statistics(roi=ROI) .l_mode()
color_a= img.get_statistics(roi=ROI) .a_mode()
color_b= img.get_statistics(roi=ROI) .b_mode()
print(color_l,color_a,color_b)
img.draw_rectangle(ROI)
#print(clock.fps())
上面已经接触到了绘图函数,绘图函数其实在可视化中有很重要的作用,一般来说,代码的结果需要推敲下才能理清,使用绘图函数可以很好的可视化出来结果。
下面开始使用常见的绘图函数
while(True):
clock.tick() # 这个可以记录帧率
img = sensor.snapshot() # 拍照+获取图像
img.draw_line((100, 100, 200, 200), color=(255,0,0),thickness=3)
img.draw_rectangle((200, 30, 41, 51), color=(255,0,0),fill = True)
img.draw_circle(50, 200, 30,color=(0,255,0))
img.draw_cross(90,60,size=10,color=(0,0,255))
img.draw_arrow((80,100,120,50))
#img.draw_string(10,10, "hello world!",scale = 2,color=(0,0,255))
img.draw_string(10,10, "fps"+str(clock.fps()),mono_space = False,scale = 2,color=(0,0,255))
print(clock.fps())
更多的绘图函数及用法可以参考:image — 机器视觉 — MicroPython 1.9.2 文档 (singtown.com)
里面讲的非常详细,需要了解更多建议多多参考,主要是里面的一些缺省参数,很重要,可以实现很多想要的效果,特别注意:
- 这个图像的改变不会对原图有什么影响,他的颜色也不会对原图有什么影像
- 很多东西都只要一个很基本的参数,比如起点终点就OK,其他东西查文档基本都能很快获取
5、使用图像进行基本操作-颜色追踪
寻找色块,openmv提供了find—blob函数来寻找色块,这个原理是基于阈值的原理实现的,就是对符合阈值区域的搜寻,找到色块
- 暂停图像,对需要的区域框选
- 根据上面图中的LAB大致的区域范围找到图像
使用find_blobs函数来搜寻色块,文档描述如下:
寻找代码如下:
# 寻找色块阈值区域
red = (32, 43, 43, 55, 36, 51)
yellow = (45, 68, -14, -1, 42, 56)
blue = (18, 39, 2, 32, -58, -32)
green = (18, 39, -40, -20, 8, 21)
while(True):
clock.tick() # 这个可以记录帧率
img = sensor.snapshot() # 拍照+获取图像
blobs = img.find_blobs([red,yellow,blue,green],area_threshold = 80) # 添加了一个面积过滤,小于面积的值被过滤掉
for blob in blobs:
img.draw_rectangle(blob.rect())
print(clock.fps())
下面开始对找到的色块进行标注:
# 寻找色块阈值区域
red = (32, 43, 43, 55, 36, 51)
yellow = (45, 68, -14, -1, 42, 56)
blue = (18, 39, 2, 32, -58, -32)
green = (18, 39, -40, -20, 8, 21)
while(True):
clock.tick() # 这个可以记录帧率
img = sensor.snapshot() # 拍照+获取图像
blobs = img.find_blobs([red,yellow,blue,green],area_threshold = 80)
for blob in blobs:
#print(blob.code())
#print(blob.x,blob.y)
if blob.code() == 1:
img.draw_string(blob.x(),blob.y(), 'red',mono_space = False,scale = 2,color=(0,0,255))
elif blob.code() == 2:
img.draw_string(blob.x(),blob.y(), 'yellow',mono_space = False,scale = 2,color=(0,0,255))
elif blob.code() == 3:
img.draw_string(blob.x(),blob.y(), 'blue',mono_space = False,scale = 2,color=(255,0,0))
else:
img.draw_string(blob.x(),blob.y(), 'green',mono_space = False,scale = 2,color=(0,0,255))
img.draw_rectangle(blob.rect())
print(clock.fps())
就是使用遍历的方法,使用预先准备好的标识进行匹配然后使用绘图函数进行标识:
还有一些其他比较常用的比如面积,中心坐标什么的,也都还行,详情见参考文档使用
6,识别码
AprilTag码
下面开始AprilTag部分的追踪,这里不做介绍,直接使用
- 首先,AprilTag不是一个码,是一系列码,不同的码属于不同的家族
- 不同家族的码区别在于有效区域的不同,随着有效区域的变化,识别的准确率会变化
- 这里openmv推荐使用TAG36H11家族的
- 使用ide中的机器视觉工具可以直接生成AprilTag码
- 使用的时候要注意关闭白平衡和自动增益
寻找AprilTag和寻找小球有点像,也是有专门的函数来寻找
import sensor,image,time
sensor.reset() # 复位摄像头
sensor.set_pixformat(sensor.RGB565) # 设置颜色格式为RGB565
sensor.set_framesize(sensor.QQVGA)
sensor.set_auto_gain(False)
sensor.set_auto_whitebal(False)
sensor.skip_frames(time = 2000) # 开头跳一些帧
clock = time.clock() # 主要是用来记录帧率
while(True):
clock.tick() # 这个可以记录帧率
img = sensor.snapshot() # 拍照+获取图像
# 寻找标志
for tag in img.find_apriltags():
img.draw_rectangle(tag.rect(),color = (0,0,255))
img.draw_cross(tag.cx(),tag.cy(),color = (0,0,255))
degress = 180 * tag.rotation() / math.pi # 旋转角度
print(tag.id(),degrees())
#print(clock.fps())
可以看出这里除了识别出id之外,还可以识别出旋转角度其中角度是弧度值,使用数学函数进行了转换
二维码
获取图像后使用下面的代码:
img = sensor.snapshot()
for code in img.find_qrcodes():
print(code)
7、模版匹配
这里使用的是一种叫ncc模版匹配的方法,官方描述如下:
这里总结下我用的时候的感受:
- 使用需要灰度图,就是原来的rgb565要变为灰度输入,当然转成灰度给模版匹配用,然后原来的彩色图保留肯定也是可以的
- 要添加两个包,在image里面
- 模版选用pgm的图,官方不带这个图,需要自己转换
- 模版可以选择从flash或者sd卡中获取,不过不建议从flash,因为内存不够
框选获取模版,默认保存是bmp的无损格式
from image import SEARCH_EX, SEARCH_DS
import sensor,image,time
from image import SEARCH_EX, SEARCH_DS
sensor.reset() # 复位摄像头
sensor.set_pixformat(sensor.GRAYSCALE) # 设置颜色格式为灰度
sensor.set_framesize(sensor.QQVGA)
#sensor.set_auto_gain(False)
#sensor.set_auto_whitebal(False)
sensor.skip_frames(time = 2000) # 开头跳一些帧
template = image.Image("/1.pgm")
clock = time.clock() # 主要是用来记录帧率
while(True):
img = sensor.snapshot()
r = img.find_template(template, 0.70, step=4, search=SEARCH_EX)
if r:
img.draw_rectangle(r)
效果如下:
对多个模版进行匹配,先实地选取多个模版:
对模版进行检索
import sensor,image,time
from image import SEARCH_EX, SEARCH_DS
sensor.reset() # 复位摄像头
sensor.set_pixformat(sensor.GRAYSCALE) # 设置颜色格式为RGB565
sensor.set_framesize(sensor.QQVGA)
#sensor.set_auto_gain(False)
#sensor.set_auto_whitebal(False)
sensor.skip_frames(time = 2000) # 开头跳一些帧
templates = ["00.pgm","01.pgm","02.pgm","03.pgm"]
clock = time.clock() # 主要是用来记录帧率
while(True):
img = sensor.snapshot()
for t in templates:
template = image.Image(t)
r = img.find_template(template, 0.70, step=4, search=SEARCH_EX) #, roi=(10, 0, 60, 60))
if r:
img.draw_rectangle(r)
print(t)
经过我实测,效果不是很好
8、通过比例的方法来求解距离
这个其实挺简单的,基本都知道近大远小的原理,那么大小就是区域面积了,所有根据区域面积就可以比较出物体的距离,当然这个误差很大,只能作为一个感性的认识,结果会受很多因素影响
- 首先用之前的色块方法获取一个像素区域的面积
import sensor,image,time
sensor.reset() # 复位摄像头
sensor.set_pixformat(sensor.RGB565) # 设置颜色格式为RGB565
sensor.set_framesize(sensor.QVGA)
#sensor.set_auto_gain(False)
#sensor.set_auto_whitebal(False)
sensor.skip_frames(time = 2000) # 开头跳一些帧
clock = time.clock() # 主要是用来记录帧率
#red = (32, 43, 43, 55, 36, 51)
#yellow = (45, 68, -14, -1, 42, 56)
blue = (18, 39, 2, 32, -58, -32)
#green = (18, 39, -40, -20, 8, 21)
while(True):
clock.tick() # 这个可以记录帧率
img = sensor.snapshot() # 拍照+获取图像
blobs = img.find_blobs([blue],area_threshold = 80) # 添加了一个面积过滤,小于面积的值被过滤掉
for blob in blobs:
img.draw_rectangle(blob.rect())
print(blob.area())
可以看出打印像素值如下,这个就是最基本的比例系数了
- 使用比例来计算距离
import sensor,image,time
sensor.reset() # 复位摄像头
sensor.set_pixformat(sensor.RGB565) # 设置颜色格式为RGB565
sensor.set_framesize(sensor.QVGA)
#sensor.set_auto_gain(False)
#sensor.set_auto_whitebal(False)
sensor.skip_frames(time = 2000) # 开头跳一些帧
clock = time.clock() # 主要是用来记录帧率
#red = (32, 43, 43, 55, 36, 51)
#yellow = (45, 68, -14, -1, 42, 56)
blue = (18, 39, 2, 32, -58, -32)
#green = (18, 39, -40, -20, 8, 21)
k = 600
while(True):
clock.tick() # 这个可以记录帧率
img = sensor.snapshot() # 拍照+获取图像
blobs = img.find_blobs([blue],area_threshold = 80) # 添加了一个面积过滤,小于面积的值被过滤掉
if len(blobs) == 1: # 只有一个框的时候进行过寻找
b = blobs[0] # 就是获取这个框
img.draw_rectangle(b[0:4]) # 画矩形
img.draw_cross(b[5],b[6]) # 画十字中心
lm = (b[2]+b[3])/2 # 面积=宽*高
length = k/lm # 使用比例,因为最开始是10厘米,整数的原因
img.draw_string(0, 0,"length :%.2f"%(length),mono_space = False,scale = 2)
运行结果如下:
9、组合使用
这里主要是颜色和色块组合使用,使用就是先找到圆的区域然后在圆的区域里面寻找颜色阈值符合要求的
其中的寻找圆的函数参数如下:
代码如下:
import sensor,image,time
sensor.reset() # 复位摄像头
sensor.set_pixformat(sensor.RGB565) # 设置颜色格式为RGB565
sensor.set_framesize(sensor.QQVGA)
#sensor.set_auto_gain(False)
#sensor.set_auto_whitebal(False)
sensor.skip_frames(time = 2000) # 开头跳一些帧
clock = time.clock() # 主要是用来记录帧率
#red = (32, 43, 43, 55, 36, 51)
#yellow = (45, 68, -14, -1, 42, 56)
blue = (18, 39, 2, 32, -58, -32)
#green = (18, 39, -40, -20, 8, 21)
while(True):
clock.tick() # 这个可以记录帧率
img = sensor.snapshot() # 拍照+获取图像
for c in img.find_circles(r_min = 10):
area = (c.x()-c.r(), c.y()-c.r(), 2*c.r(), 2*c.r())
statistics = img.get_statistics(roi=area)
if 18<statistics.l_mode()<50 and 2<statistics.a_mode()<38 and -60<statistics.b_mode()<-22:
img.draw_circle(c.x(), c.y(), c.r(), color = (255, 0, 0),thickness=3)
else:
img.draw_rectangle(area, color = (255, 255, 255))
img.draw_string(0, 0,"FPS :%.2f"%(clock.fps()),mono_space = False,scale = 2)
效果如下: