openmv及图像处理知识基础备忘录

详情请参考https://book.openmv.cc/python-background.html 官方教程
https://docs.singtown.com/micropython/zh/latest/openmvcam/index.html 官方函数库
此处仅作备忘录,官方文档已经非常详尽了。

——

1前言

openmv算是我第一次接触到的图像处理入门设备,对于专业不涉及图像处理领域,但是需要应用相关功能的人来说,这小玩意算是物超所值,学习成本很低(相比树莓派+摄像头),你要做的只是熟悉一下mircopython语法。
想来openmv接触了有一个月(我觉得挺长了),也实现了不少小功能(可惜只是用了裸机操作)。 这篇文章算是对openmv的回顾,因为有相当一段时间没摸它了,毕竟花了这么常时间研究它,怕把这些经验遗忘了。

2关于openmv

在开始之前请先注意,openmv和opencv是两个完全不同的概念,几乎不存在相互移植的可能性。

2.1openmv基本概念

openmv简介

openmv是一个可以通过MicroPython语言进行编程的摄像头(实际上也只能使用MicroPython,并不能使用C语言,但是其运算速度是可以忍受的),内置了一些图像处理算法,使用时可以直接调用库实现功能,所有的功能基本上都是通过堆叠库实现的。
openmv通常用于DIY相关的项目制作(也就是说适合学生和爱好者)。

openmv的功能

openmv常用的功能有板级控制(略去不讲,但很重要)、画图(drawing)、图像滤波(image-filters)、拍摄(snapshot)、特征检测(feature-detection)、颜色追踪(color-tracking)、codes、测距等。

openmv的选购

尽可能选择OPENMV3 M7摄像头及以上版本的(如果出了的话),这是因为stm32系列处理图像能力有限,低版本会有很多功能无法实现,掉帧情况也会变得难以忍受。
由于是开源项目,对于硬件来说实际上不存在盗版产品,所以不需要特意追求授权商产品,但是建议购买正版key,用于支持国外研发团队。key用于激活IDE,没有key仍能够正常使用产品,但会出现恼人的提示弹窗。

2.2 mircopython

python是面向对象的图形语言(c语言是面向过程)。Python 的发展以 CPython 为主,MicroPython 和 CPython 在 Python3 语法上保持高度的一致性,包含Python标准库的一小部分,但常用的标准语法命令都已经支持。相比于python,mircopython通常用于资源有限的嵌入式设备。
对mircopython的学习点到即止,因为它不是用于嵌入式开发的常用语言。

2.3 OV摄像头

OV(omnivision,豪威科技)为美商半导体公司,专业开发高度集成CMOS影像技术。
openmv3/openmv4采用OV7725 sensor,其具体参数见下:

项目 指标
焦距 2.8mm
光圈 f2.0
尺寸 1/3’’
视场角 H视角:115° V视角:90°

在这里要特别关注视场角FOV指标,H视角指水平视场角,V视角指垂直视场角,示意图如下:
openmv及图像处理知识基础备忘录_第1张图片
当我们获取摄像头视场角参数后,即可将其套入公式计算被测物大小(已知距离情况下)亦或是被测物距离(已知大小情况下)。详见文末5.6物体测距与直径计算

3图像处理

3.1图像处理基本概念

LAB模式
Lab颜色空间中,L代表亮度;a的正数代表红色,负端代表绿色;b的正数代表黄色,负端代表l蓝色。
因此修改L分量可以调整亮度,修改a和b分量的输出色阶来做精确的颜色平衡。
openmv及图像处理知识基础备忘录_第2张图片

在与颜色处理有关的功能实现中,openmv使用的就是LAB模式或灰度模式。

噪声
噪声即噪点,是图像中一种亮度或颜色信息的随机变化,而被拍摄物体本身并没有,这给图像带来了错误和额外的信息。
只有当图像噪声影响到图像处理时,才需要进行图像滤波。

图像滤波

总结自 http://www.ruanyifeng.com/blog/2017/12/image-and-wave-filters.html 图像与滤波 阮一峰
简洁明了。

图像本质上就是各种色彩波的叠加,可以用波的算法处理图像。色彩剧烈变化的地方,就是图像的高频区域;色彩稳定平滑的地方,就是低频区域。通过使用滤波器(filter)可以过滤掉某些波,保留另一些波。滤波在一定程度上会影响图像的清晰度,清晰图像无需进行滤波,一般都是有明显的噪点时才进行滤波处理。

图像处理算子
在数学中,当映射的作用是把函数映成函数,或者函数映成数的时候,这个映射常常叫做算子.图像处理里都把图像看成R²上的函数,每个像素只是这个函数的采样点。在这个意义下,算子就是把一个R²上的函数变化到另一个R²上的函数的一个变换。
常见的算子有morph算子,主要用于特征检测。

4 openmv通用配置

此处为常用功能都会涉及的通用设置。

4.1 感光元件配置

需引用sensor模块,用于设置感光元件的参数,几乎在所有程序中涉及。

import sensor#引入感光元件的模块

# 设置摄像头
sensor.reset()#初始化感光元件
sensor.set_pixformat()#设置像素模式,括号内可选sensor.GRAYSCALE: 灰度or sensor.RGB565: 彩色
sensor.set_framesize()#设置图像的大小
sensor.set_auto_gain()#自动增益开启(True)或者关闭(False)。在使用颜色追踪时,需要关闭自动增益。
sensor.set_auto_whitebal()#自动白平衡开启(True)或者关闭(False)。在使用颜色追踪时,需要关闭自动白平衡。
sensor.skip_frames()#跳过n张照片,在更改设置后,跳过一些帧,等待感光元件变稳定。

其中图像大小可设置为:
sensor.QQQVGA: 80×60
sensor.QQVGA: 160x120
sensor.HQVGA: 240x160
sensor.QVGA: 320x240
sensor.VGA: 640x480 (只用于OpenMV Cam M7 的灰度图处理图像,或者彩图采集图像)

图像处理要实现的功能越复杂,分辨率就要设置的越低,或者切换为灰度模式,以此来提高帧数。
openmv及图像处理知识基础备忘录_第3张图片

4.2拍摄(snapshot)

img = sensor.snapshot()#image=img
sensor.snapshot().save("example.jpg") # or "example.bmp" (or others)
#需要SD卡

4.3 ROI(region of interest)

ROI(region of interest),感兴趣区域。机器视觉、图像处理中,从被处理的图像以方框、圆、椭圆、不规则多边形等方式勾勒出需要处理的区域,称为感兴趣区域ROI。

ROI=(x0,y0,x1,y1)#设置roi位置
img.draw_rectangle(ROI)#在图像中标注感兴趣区域

若要获取ROI内图像统计数据,可调用下列代码:

statistics = image.get_statistics(roi=ROI)
print(statistics)

这将输出全部统计数据,实际上通常只需要输出LAB的众数值即可:

    statistics=img.get_statistics(roi=ROI)
    color_l=statistics.l_mode()
    color_a=statistics.a_mode()
    color_b=statistics.b_mode()
    print(color_l,color_a,color_b)

4.4帧率显示(fps)

需引入time模块

clock = time.clock()                # Create a clock object to track the FPS.返回一个时钟对象
#初始化时钟
clock.tick()                    # Update the FPS clock.开始追踪运行时间
print("FPS:", clock.fps())#可输出帧率.停止追踪运行时间,并返回当前FPS

也可以直接在图像中显示帧率,即构建HUD。
注意: 当连接电脑后,OpenMV会变成一半的速度。当不连接电脑,帧率会增加。

4.5阈值(thresholds)

阈值有LAB阈值和灰度阈值。
OpenMV 的IDE里加入了阈值选择工具(位于 工具 → Mechine Vision → Threshold Editor ,选中 Frame Buffer可以获取IDE中的图像)来确定阈值。使用方法为拖动六个滑块,将目标颜色变成白色,其他颜色全变为黑色。
阈值的格式为:

rgb = (minL, maxL, minA, maxA, minB, maxB)#彩色
grayscale = (min,max)#灰度

4.6镜头畸变矫正(lens correction)

img = sensor.snapshot()#image=img
img.lens_corr(1.8) # 该参数适用于2.8mm镜头.
#或者
 img = sensor.snapshot().lens_corr(strength = 1.8, zoom = 1.0)#二者纯粹是语法上的差异

用于扫码,形状识别等。

5具体功能的实现

某些函数省略了不常用的参数设置,详情请参考官方函数库文档。

5.1画图(drawing)

实现此功能需引入image(机器视觉)模块。
常用的可绘制图形有箭头arrow、圆形circle、十字cross、线段line、矩形rectangle、文字text

image.draw_xxx(x0, y0, x1, y1, color) #颜色可以是灰度值(0-255),或者是彩色值(r, g, b)

xxx内为上述加粗字中的黑体部分。

5.2图像滤波(image filters)

实现此功能需引入image(机器视觉)模块。

二值化( Image Binarization)

注意与灰度化的区分。

在数字图像处理中,二值图像占有非常重要的地位,图像的二值化使图像中数据量大为减少,从而能凸显出目标的轮廓。
分为颜色二值化灰度二值化

img.binary([threshold])#二值化分割
BINARY_VISIBLE = True or False #设置是否使用img.binary()函数进行图像分割
img = sensor.snapshot().binary([THRESHOLD]) if BINARY_VISIBLE else sensor.snapshot()#用来切换二值化视角或彩色/灰度视角

边缘检测(edge detection)

利用morph算子实现快速边缘检测,速度慢但效果好。

#设置核函数滤波,核内每个数值值域为[-128,127],核需为列表或元组
kernel_size = 1 # kernel width = (size*2)+1, kernel height = (size*2)+1
kernel = [-1, -1, -1,\
          -1, +8, -1,\
          -1, -1, -1]
img.morph(kernel_size, kernel)

在OV7725 sensor上, 边缘检测可以通过设置sharpness/edge寄存器来增强。

侵蚀函数

img.erode(1, threshold = 2)
    #侵蚀函数erode(size, threshold=Auto),去除边缘相邻处多余的点。threshold
    #用来设置去除相邻点的个数,threshold数值越大,被侵蚀掉的边缘点越多,边缘旁边白色杂点越少
  

快速边缘检测(feature Detection edges)

利用canny算子实现快速边缘检测,编程非常简单,速度快但效果差。

 img.find_edges(image.EDGE_CANNY, threshold=(a,b))

5.3特征检测(feature detection)

特征检测应用较多的有图形检测,如识别圆、识别线段、识别直线、识别矩形。应用上通常把特征检测和颜色追踪结合起来,并通过绘图将检测到的图形在图像中标出。
实现此功能需引入image(机器视觉)模块。

图形检测

通常是用霍夫变换(Hough transform)完成的。
霍夫变换是用来辨别找出物件中的特征,例如:线条。他的算法流程大致如下,给定一个物件、要辨别的形状的种类,算法会在参数空间(parameter space)中执行投票来决定物体的形状,而这是由累加空间(accumulator space)里的局部最大值(local maximum)来决定。

 for c in img.find_circles(threshold = 3500, x_margin = 10, y_margin = 10, r_margin = 10,r_min = 2, r_max = 100, r_step = 2): #threshold 控制从霍夫变换中监测到的圆,只返回大于或等于阈值的圆
 						#x/y/r_margin 控制所检测的圆的合并;
					 #r_min,r_max和r_step控制测试圆的半径,缩小测试圆半径的数量可以大大提升性能
        img.draw_circle(c.x(), c.y(), c.r(), color = (255, 0, 0)) #找到图像中所有的圆

线段
相比寻找无限长的直线,速度降低不少。

直线
霍夫变换将二维空间中所有的直线映射到以theta&rho为坐标轴的二维空间中,theta代表直线与Y轴负方向的夹角,以Y轴负轴为起始轴,逆时针旋转到直线的角度。rho表示原点到直线的距离,Y轴截距大于0的均为正,Y轴截距小于0则rho为负。

min_degree = 
max_degree =

for l in img.find_lines(threshold = 1000, theta_margin = 25, rho_margin = 25):
        if (min_degree <= l.theta()) and (l.theta() <= max_degree):
            img.draw_line(l.line(), color = (255, 0, 0))

矩形

for r in img.find_rects(threshold = 10000):
        img.draw_rectangle(r.rect(), color = (255, 0, 0))
        for p in r.corners(): img.draw_circle(p[0], p[1], 5, color = (0, 255, 0)) #标注4个角

rect.corners()
返回一个由矩形对象的四个角组成的四个元组(x,y)的列表。四个角通常是按照从左上角开始沿顺时针顺序返回的。

线性回归(linear regression)

线性回归分为鲁棒线性回归(linear regression robust)和快速线性回归(linear regression fast)。线性回归通常用于机器人巡线。快速线性回归的原理是使用最小二乘法来拟合线。

line = img.get_regression(threshold, robust = True or False) #robust为1时开启鲁棒线性回归
if (line): img.draw_line(line.line(), color ) #标注检测出的直线

5.4颜色追踪(color-tracking)

实现此功能需引入image(机器视觉)模块。

单色识别

分为单灰度识别和单彩色识别。

for blob in img.find_blobs([threshold])

多颜色识别

for blob in  img.find_blobs([threshold0,threshold1,threshold2,...]) #最多有16个阈值

5.5扫码识别

使用前需进行镜头畸变矫正。
可测量条形码barcodes、二维码qrcodes、矩形码datamatrices等。
条形码的代码相对复杂很多,最简单的是二维码。

 for code in img.find_qrcodes(): #识别二维码
        img.draw_rectangle(code.rect(), color = (255, 0, 0))
        print(code)

5.6物体测距与直径计算

openmv及图像处理知识基础备忘录_第4张图片
图中:

  1. a—— 视场角
  2. Lm——物距
  3. Apix——摄像头图像像素
  4. Bpix——被测物直径像素
  5. Rm——被测物直径

5.6.1 物体测距

虽然可以使用Apriltag进行3D定位,但通常情况下我们只能使用裸机测距(特别是距离目标物较远时,低成本测距传感器将无法派上用场)。
OpenMV采用的是单目摄像头,需要利用参照物的大小比例来计算距离。
其公式为:距离 = 一个常数/直径的像素
该常数的测量方法为:让被测物距离摄像头 n cm,打印出摄像头里直径的像素值,然后相乘,就得到了常数的值。

官网例程已经足够清晰,故本文不再进行公式推算。

5.6.2物体直径计算

仍引用上图,使用单目摄像头实现物体直径测量,需要获取镜头视场角和物距,然后通过三角函数计算尺寸。
由镜头左侧几何关系得:
t a n ( a ) = A p i x 2 L ′ tan(a)=\frac{Apix}{2L'} tan(a)=2LApix
t a n ( b ) = B p i x 2 L ′ tan(b)=\frac{Bpix}{2L'} tan(b)=2LBpix
故:
t a n ( a ) t a n ( b ) = A p i x B p i x \frac{tan(a)}{tan(b)}=\frac{Apix}{Bpix} tan(b)tan(a)=BpixApix
由镜头右侧几何关系得:
t a n ( b ) = R m L m tan(b)=\frac{Rm}{Lm} tan(b)=LmRm
代入(3)式得:
R m = t a n ( a ) ∗ L m ∗ B p i x A p i x Rm=tan(a)*Lm*\frac{Bpix}{Apix} Rm=tan(a)LmApixBpix

你可能感兴趣的:(嵌入式,计算机视觉,python,机器学习,算法)