OpenMV(四)--STM32实现特征检测

STM32实现特征检测

      • 前言
      • 1. 边缘检测
          • 1.1 构造函数
          • 1.2 源码分析
      • 2. 圆形识别
          • 2.1 构造函数
          • 2.2 源码分析
      • 3. 特征点识别
          • 3.1 构造函数
          • 3.2 源码分析

OpenMV(一)–基础介绍与硬件架构
OpenMV(二)–IDE安装与固件下载
OpenMV(三)–实时获取摄像头图片

前言

本专栏基于以STM32H743为MCU的OpenMV-H7基板,结合OV7725卷帘快门摄像头进行相关机器视觉应用的开发。特征检测是机器视觉的基础,要做的内容包括边缘检测、各种形状识别、特征点识别等。特征检测是基于摄像头获取的图片进行的,在进行特征检测之间,我们需要了解如果在获取的图像上画标记。

OpenMV已经将图片处理封装成各类模块供我们使用:

  • image.draw_line( x 0 x_0 x0, y 0 y_0 y0, x 1 x_1 x1, y 1 y_1 y1, color, thickness = 1)
    画线段

    • x 0 x_0 x0, y 0 y_0 y0):起始坐标
    • x 1 x_1 x1, y 1 y_1 y1):终点坐标
    • color: 颜色,(255, 0, 0)表示红色
    • thickness: 粗细,默认值为1
  • image.draw_rectangle(x, y, w, h, color, thickness = 1, fill = false)
    画矩形

    • x x x, y y y):起始坐标
    • w: 宽度
    • h: 长度
    • color: 颜色,(255, 0, 0)表示红色
    • thickness: 粗细,默认值为1
    • fill: 是否填充
  • image.draw_circle(x, y, radius, color, thickness = 1, fill = false)
    画圆形

    • x x x, y y y):圆心
    • radius: 半径
    • color: 颜色,(255, 0, 0)表示红色
    • thickness: 粗细,默认值为1
    • fill: 是否填充
  • image.draw_cross(x, y, color, size = 5, thickness = 1)
    画十字交叉

    • x x x, y y y):交叉坐标
    • color: 颜色,(255, 0, 0)表示红色
    • size: 尺寸
    • thickness: 粗细,默认值为1
    • fill: 是否填充
  • image.draw_string(x, y, text, color,scale = 1, mono_space = True…)
    写字符

    • (x, y): 其实坐标
    • text: 字符内容
    • color: 颜色
    • scale: 字体大小
    • mono_space: 强制间距

1. 边缘检测

边缘检测就是轮廓检测,本节基于OpenMV官方源码edges.py来完成实时轮廓提取。

1.1 构造函数

OpenMV的库集成度非常高,只需要一个函数就可以进行图片的边缘检测。

  • image.find_edges(edge_type, threshold)
    轮廓检测,将图像变为黑白,保留边缘白色像素
    • edge_type: 处理方式
      • image.EDGE_SIMPLE: 简单的阈值高通滤波算法
      • image.EDGE_CANNY: canny边缘检测算法
    • thresold: 包含高、低阈值的二元数组,默认是(100, 200),仅支持灰度图像
1.2 源码分析
"""
实时特征检测例程:使用canny特征检测算法
"""
# 导入相应的库
import sensor, image, time

# 初始化摄像头
sensor.reset()

# 设置采集到照片的格式:灰色图像
sensor.set_pixformat(sensor.GRAYSCALE)

# 设置采集到照片的大小: 320 * 240
sensor.set_framesize(sensor.QVGA)

# 等待一段时间2s,等摄像头设置好
sensor.skip_frames(time = 2000)

# 设定摄像头增益上限
sensor.set_gainceiling(8)

# 创建一个时钟来计算摄像头每秒采集的帧数FPS
clock = time.clock()

# 实时显示摄像头拍摄的照片
while(True):
	# 更新FPS时钟
	clock.tick()
	
	# 拍摄图片并返回img
	img = sensor.snapshot()

	# 使用canny边缘检测
	img.find_edges(image.EDGE_CANNY, threshold = (50, 80))

	# 串口打印FPS参数
	print(clock.fps())

我们将板子连接到OpenMV IDE, 新建文件,并将上述代码copy进去,点击左下角的绿色按钮,我们就可以看到IDE右边的窗口在实时显示提取到的边缘特征图片:
OpenMV(四)--STM32实现特征检测_第1张图片
线段识别,直线识别与边缘识别原理近似,只是调用的函数不同,具体操作可以参考官方提供的源码。

2. 圆形识别

2.1 构造函数

本节的目标是识别摄像头采集图像中的圆形并画出来。构造函数如下:

  • image.find_circle(roi, x_stride=2, y_stride=1. threshold=2000, x_margin=10, y_margin=10, r_margin=10, r_min=2, r_max, r_step=2)
    找圆函数,返回一个image.circle的圆形对象,该对象有四个值:圆心(x,y), 半径( r), 量级(magnitude),量级越大表示可信度越高。大部分参数使用默认即可
    • roi: 识别区域(x, y, w, h),未指定则默认整张图片
    • threshold: 阈值,返回大于或等于threshold的圆,调整识别可信度
    • x_stride, y_stride: 霍夫变换时跳过x,y像素的量。霍夫变换是一种特征检测方法,是用来辨别找出物件中的特征,例如:线条。算法流程大致如下,给定一个物件、要辨别的形状的种类,算法会在参数空间中执行投票来决定物体的形状,而这是由累加空间里的局部最大值来决定。
    • x_margin, y_margin, r_margin: 控制所检测圆的合并
    • r_min, r_max: 控制识别圆形的半径范围
    • r_step:控制识别步骤
2.2 源码分析
"""
实时圆形特征检测例程:使用霍夫变换算法
"""
# 导入相应的库
import sensor, image, time

# 初始化摄像头
sensor.reset()

# 设置采集到照片的格式:彩色RGB,使用灰色图像会加快检测速度
sensor.set_pixformat(sensor.RGB565)

# 设置采集到照片的大小: 320 * 240
sensor.set_framesize(sensor.QQVGA)

# 等待一段时间2s,等摄像头设置好
sensor.skip_frames(time = 2000)

# 创建一个时钟来计算摄像头每秒采集的帧数FPS
clock = time.clock()

# 实时显示摄像头拍摄的照片
while(True):
	# 更新FPS时钟
	clock.tick()
	
	# 拍摄图片并返回img, lens_corr()目的是去畸变,1.8是默认值
	img = sensor.snapshot().lens_corr(1.8)

	# 检测圆形, 并在图像上画出。 parms时检测圆形返回的对象参数,包括圆心(x,y), 半径( r), 量级(magnitude)
	for params in img.find_circles(threshold = 2000,
								   x_margin = 10, y_margin = 10, r_margin = 10,
								   r_min = 2, r_max = 100,
								   r_step = 2):
		# 将圆画出来
		img.draw_circle(params.x(), params.y(), params.r(), color = (255, 0, 0))

		# 将圆的参数信息打印出来
		print(params)

	# 串口打印FPS参数
	print(clock.fps())

我们将板子连接到OpenMV IDE, 新建文件,并将上述代码copy进去,点击左下角的绿色按钮,我们就可以看到IDE右边的窗口在实时显示提取到的圆形特征:
OpenMV(四)--STM32实现特征检测_第2张图片
矩形识别与圆形识别原理近似,只是调用的函数不同,具体操作可以参考官方提供的源码。

3. 特征点识别

本小节实现的特征点识别,首先对采集到的图案或者物体进行学习识别,然后当摄像头重新抓捕到跟学习的目标特征点一样的图片时,就标记出来。

3.1 构造函数
  • image.find_keypoints(roi, threshold=20, normalized=False, scale_factor=1.5, max_keypoints=100, corner_detector=image.CORNER_AGAST)
    特征点识别函数,返回一个image.rect矩形对象列表

    • roi: 识别区域(x, y, w, h),未指定则默认整张图片
    • threshold: 控制提取的数量的数字(取值0-255),对于默认的AGAST角点检测器,该值应该在20左右。对于FAST角点检测器,该值约为60-80.阈值越低,提取的角点越多。
    • normalized: 布尔值。如果为True, 在多分辨率下关闭提取关键点,如果不关心处理扩展问题,且希望算法运行更快,就可以设置为True
    • scale_factor: 一个必须大于1.0的浮点数。该数越大,运行越快,但是图像匹配相应较差。理想值介于1.35~1.5之间。
    • max_keypoints: 关键点对象所能容纳的最大数量,如果对象过大可能会导致内存问题,需要降低该值。
    • corner_detector: 角点检测方法,分为AGAST角点检测算法和FAST角点检测算法
  • image.match_descriptor(descriptor0, descriptor1, threshold=70, filter_outliers=False)
    特征点对比函数,用于比较两个特征点的相似程度。返回的是一个kptmatch对象。

    • descriptor0, descriptor1: 要对比的2个特征点
    • threshold: 控制匹配程度
    • 对于返回的kptmatch对象,我们可以使用以下方法:
      • kptmatch.rect():返回特征点的边界框,是一个矩形元组(x, y, w, h)
      • kptmatch.cx(): 返回特征点中心x坐标位置,也可以通过索引[0]获取该值
      • kptmatch.cy(): 返回特征点中心y坐标位置,也可以通过索引[1]获取该值
3.2 源码分析

特征点识别的步骤如下:
导入相应库–> 初始化相机模块–>拍摄图像并学习特征点K1–>实时采集当前特征点K2–>对比K1和K2是否一致–>如果一致则标记特征点位置

"""
实时特征点检测例程
"""
# 导入相应的库
import sensor, image, time

# 初始化摄像头
sensor.reset()

# 设置相机对比度
sensor.set_contrast(3)

# 设定摄像头增益上限
sensor.set_gainceiling(16)

# 设置采集到照片的大小
sensor.set_framesize(sensor.VGA)

# 设置相机分辨率
sensor.set_windowing((320, 240))

# 设置采集到照片的格式:灰色图像
sensor.set_pixformat(sensor.GRAYSCALE)

# 等待一段时间2s,等摄像头设置好
sensor.skip_frames(time = 2000)

# 关闭摄像头自动增益并设定固定增益值为100
sensor.set_auto_gain(False, value = 100)

"""
定义画特征点函数
"""
def draw_keypoints(img, kpts):
	if kpts:
		print(kpts)
		img.draw_keypoints(kpts)
		img = sensor.snapshot()
		time.sleep(1000)
		
# 初始化特征点
kpts1 = None
kpts2 = None

"""
我们也可以从文件中导入特征点
kpts1 = image.load_descriptor("/desc.orb")
img = sensor.snapshot()
draw_keypoints(img, kpts1)
"""
while(True):
	# 拍摄图片并返回img
	img = sensor.snapshot()
	# 如果特征点K1不存在,就学习摄像头所拍摄图片的特征点
	if(kpts1 == None):
		kpts1 = img.find_keypoints(max_keypoints=150, threshold=10, scale_factor=1.2)
		# 画出特征点
		draw_keypoints(img,kpts1)
	# 如果特征点K1存在,就检测特征点K2,然后比较二者是否一致
	else:
		kpts2 = img.find_keypoints(max_keypoints=150, threshold=10, normalized=True)
        if (kpts2):
        	# 如果特征点K2存在,匹配两个特征
            match = image.match_descriptor(kpts1, kpts2, threshold=85)
            # 大于10可以判断为两个特征点一致,这个值可以调节
            if(match.count()>10):
            	# 将一致的特征用十字交叉和矩形圈出
                img.draw_rectangle(match.rect())
                img.draw_cross(match.cx(), match.cy(), size = 10)

我们将板子连接到OpenMV IDE, 新建文件,并将上述代码copy进去,点击左下角的绿色按钮,我们首先看到摄像头在学习特征点,并标记了出来:
OpenMV(四)--STM32实现特征检测_第3张图片
然后,再次进行检测,并标记特征点相同的地方:
OpenMV(四)--STM32实现特征检测_第4张图片

你可能感兴趣的:(•OpenMV,•嵌入式AI)