Arduino案例实操 -- 智能巡防小车(二)OpenMV黑线检测

2024-01-08 01:50

本文主要是介绍Arduino案例实操 -- 智能巡防小车(二)OpenMV黑线检测,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

二、OpenMV黑线检测

      • 2.1 OpenMV简介
      • 2.2 OpenMV详细参数
      • 2.3 OpenMV IDE安装
      • 2.4 OpenMV Cam连接
      • 2.5 OpenMV项目搭建
        • 2.5.1 OpenMV工程新建
        • 2.5.2 OpenMV颜色识别相关函数
          • find_blobs函数
          • 阈值
          • 颜色阈值选择工具
          • blobs是一个列表
          • blob色块对象
        • 2.5.3 OpenMV黑线检测源码说明
        • 2.5.4 OpenMV固件上传

2.1 OpenMV简介

2.2 OpenMV详细参数

这两小节都有相关博文做过介绍,这里直接甩链接就好,减少文章篇幅
链接 → OpenMV新手上路1 – OpenMV简介、参数描述

2.3 OpenMV IDE安装

2.4 OpenMV Cam连接

同样的,甩博文链接
OpenMV新手上路2 – 驱动、IDE安装及简单使用(window环境)

2.5 OpenMV项目搭建

2.5.1 OpenMV工程新建

打开OpenMV IDE,点击左上角的“文件→新建文件”进行新的OpenMV项目创建。
在这里插入图片描述
创建成功后IDE页面将打开一个“untitled_1.py”文件,并带有OpenMV项目代码的初始代码(类似新建Arduino例程时的初始代码是setup()函数和loop()函数),初始代码运行的功能为初始化OpenMV传感器,并循环将传感器获取到的图像显示到IDE上,同时打印帧数。
在这里插入图片描述

2.5.2 OpenMV颜色识别相关函数

在智能巡防小车的项目中,OpenMV的主要功能是做黑线识别(即颜色识别)和坐标值发送,关于OpenMV的颜色识别功能,有以下几个知识点需要掌握。

find_blobs函数

追踪小球是OpenMV用得最多的功能,实质上是通过find_blobs函数去找到图像中的指定色块,即在OpenMV图像视野中分辨出需要查找的颜色。
接下来看一下find_blobs函数的细节:

image.find_blobs(thresholds, roi=Auto, x_stride=2, y_stride=1, invert=False, area_threshold=10, pixels_threshold=10, merge=False, margin=0, threshold_cb=None, merge_cb=None)

这里的参数比较多。

  • thresholds是颜色的阈值,注意:这个参数是一个列表,可以包含多个颜色。如果你只需要一个颜色,那么在这个列表中只需要有一个颜色值,如果你想要多个颜色阈值,那这个列表就需要多个颜色阈值。注意:在返回的色块对象blob可以调用code方法,来判断是什么颜色的色块。
	red = (xxx,xxx,xxx,xxx,xxx,xxx)blue = (xxx,xxx,xxx,xxx,xxx,xxx)yellow = (xxx,xxx,xxx,xxx,xxx,xxx)img=sensor.snapshot()red_blobs = img.find_blobs([red])color_blobs = img.find_blobs([red,blue, yellow])
  • roi是“感兴趣区”,相当于在OpenMV图像视野中框选一个范围作为颜色检测的区域,roi的参数为4个,分别是起始点x,起始点y,结束点x,结束点y。
	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。
	all_blobs = img.find_blobs([red,blue,yellow],merge=True)red_blobs = img.find_blobs([red],merge=True)blue_blobs = img.find_blobs([blue],merge=True)yellow_blobs = img.find_blobs([yellow],merge=True)
  • margin 边界,如果设置为1,那么两个blobs如果间距1一个像素点,也会被合并。
阈值

阈值即对某个特定颜色或某个色域规定的一组参数,一个颜色阈值的结构是这样的:

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

元组里面的数值分别是L A B 的最大值和最小值。
L A B参数可在图像直方图中直接看到数据。
在这里插入图片描述
在IDE里,还有更方便的阈值选择工具。

颜色阈值选择工具

OpenMV 的IDE里加入了阈值选择工具,极大的方便了对于颜色阈值的调试。
首先运行untitled_1.py让IDE里的帧缓冲区显示图案。
在这里插入图片描述然后打开“工具→机器视觉→阈值编辑器”。
在这里插入图片描述选择帧缓冲区可以获取IDE中的图像,选择图像文件可以另外选择一张图片进行阈值编辑。
在这里插入图片描述
选择帧缓冲区打开阈值编辑器,可看到如图中的二进制图像及原图像,拖动下方L A B最大值及最小值的滑轨改变参数可进行颜色阈值获取。
在这里插入图片描述想要获取源图像中蓝色小方块的阈值时,拖动L最小值与L最大值形成L值范围,确保在二进制图像中蓝色小方块所在的位置为白色,二进制图像中其他位置为黑色,A值与B值的调参方式也是如此,最后复制底部调参好的L A B数值。
在这里插入图片描述

blobs是一个列表

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

	blobs = img.find_blobs([red])

blobs就是很多色块。
可以用for循环把所有的色块找一遍。

	for blob in blobs:print(blob.cx())
blob色块对象

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()是圆的外接正方形的面积。

2.5.3 OpenMV黑线检测源码说明

下面以智能巡防小车的OpenMV源码做分段说明。
相关调用模块引入。

	import sensor, image, time   # 引入感光元件模块、图片处理模块、时间模块from pyb import UART          # 引入串口模块import json                     # 引入json字符串模块from pyb import LED           # 引入LED控制模块

设置项目中黑线检测的阈值,以及在图像中的感兴趣区(ROI)。

	user_threshold = (0, 32, -128, 127, -128, 127)  # 设置黑线阈值参数ROIS = (0,100,320,40)                                # 设置roi感兴趣区

设置串口及串口波特率。

#设置串口号及串口波特率uart = UART(3,115200)

初始化摄像头参数,包括感光元件复位,设置图像色彩,图像大小,以及在寻找色块(巡线)功能下需要关闭自动增益功能和白平衡功能。

#设置摄像头sensor.reset()                                    # 初始化感光元件sensor.set_pixformat(sensor.RGB565)           # 设置像素模式为彩色sensor.set_framesize(sensor.QVGA)             # 设置图像大小为QVGA:320*240sensor.skip_frames(time = 2000)                # 跳过前几帧的图片sensor.set_auto_gain(False)                     # 关闭自动增益 -- 巡线模式下需要关闭sensor.set_auto_whitebal(False)                # 关闭白平衡 -- 巡线模式下需要关闭

取得系统时间,并点亮板载RGB灯为白色,加强图像颜色识别。

# 获取系统时间clock = time.clock()# 打开板载LED灯(白色)LED(1).on()LED(2).on()LED(3).on()

新建全局变量。

	# 新建全局变量dis_sum = 0sum_count = 0value_get = False

进入while循环,开始计算运行时间,并用OpenMV摄像头进行拍照将图像传至IDE中,随后新建局部变量。

	while(True):clock.tick()                  # 开始计算运行时间img = sensor.snapshot()     # 获取一张图像# 新建变量distance = 0distance_send = False

在获取的图像中进行roi区域划分和黑线颜色阈值检测,并把找到的黑线用矩形和矩形中心坐标表示出来,判断找到的黑线是否符合要求。

# 将find_blobs返回的blob对象赋值给bfor b in img.find_blobs([user_threshold],roi=ROIS[0:4], merge=True):# 判断黑线色块大小,排除图像干扰if (b[4] >= 30) and (b[3] >= 30):img.draw_rectangle(b[0:4],color=(255,0,0))      # 画矩形img.draw_cross(b.cx(),b.cy(),color=(0,0,0))     # 画中心十字# 判断所检测到的黑线是否在图像范围内if b[5]< 0 or b[5] > 320:distance = 0distance_send = Falseelse:distance = b[5]distance_send = True

将获取到的中心坐标每10次取一次平均值再取整,使用json脚本将角度值转换成字符串通过串口发送出去。

# 判断正确获取到黑线位置if distance_send == True:dis_sum += distancesum_count += 1# 取10次的坐标平均值if sum_count == 10:AngleValue = round(dis_sum/sum_count - 160)     # 计算角度值并取整数# LastAngleValue进行角度赋值if not value_get:LastAngleValue = AngleValuevalue_get = True# 对比角度是否发生变化if (LastAngleValue != AngleValue):ubuffer = json.dumps(AngleValue)            # 将新角度转换成字符串LastAngleValue = AngleValue                 # 将角度值进行赋值uart.write(ubuffer+'\n')                    # 串口发送角度值字符串dis_sum = 0sum_count = 0

为了用OpenMV做黑线检测,博主也是简单学了一门新语言(Micropython),并用简单的逻辑将摄像头捕捉到的黑线坐标变化通过串口进行发送,因为OpenMV为32位处理器,对每一帧图像的处理速度是比较快的,同时将坐标数据发送到8位处理器(UNO)上可能造成UNO的串口数据堵塞,处理不来,所以博主在OpenMV坐标发送前也是做了取平均值的操作,每10个坐标数据折算成1个平均值进行发送,减少UNO串口数据接收压力,坐标数据也相对更加稳定、准确(初学micropython对相关数学函数及逻辑使用方面不熟,Python大神勿喷

2.5.4 OpenMV固件上传

OpenMV IDE除了可以在线进行脚本运行仿真,也能将调试好的py脚本上传至OpenMV Cam成为OpenMV Cam的上电运行脚本。
调试好OpenMV脚本之后,断开脚本运行,在菜单栏“工具 → 将打开的脚本保存到OpenMV Cam(作为main.py)”,在OpenMV Cam中main.py为上电运行脚本,此操作相当于把OpenMV Cam内存中main.py文件进行替换。
在这里插入图片描述
在脚本正确上传过程中,OpenMV Cam板载的RGB灯会是红色状态,在上传完成后,RGB灯熄灭,如果不能正确上传脚本,请检查IDE是否正常连接了OpenMV Cam。

这篇关于Arduino案例实操 -- 智能巡防小车(二)OpenMV黑线检测的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/581951

相关文章

深度解析Java @Serial 注解及常见错误案例

《深度解析Java@Serial注解及常见错误案例》Java14引入@Serial注解,用于编译时校验序列化成员,替代传统方式解决运行时错误,适用于Serializable类的方法/字段,需注意签... 目录Java @Serial 注解深度解析1. 注解本质2. 核心作用(1) 主要用途(2) 适用位置3

Java 正则表达式的使用实战案例

《Java正则表达式的使用实战案例》本文详细介绍了Java正则表达式的使用方法,涵盖语法细节、核心类方法、高级特性及实战案例,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录一、正则表达式语法详解1. 基础字符匹配2. 字符类([]定义)3. 量词(控制匹配次数)4. 边

Python Counter 函数使用案例

《PythonCounter函数使用案例》Counter是collections模块中的一个类,专门用于对可迭代对象中的元素进行计数,接下来通过本文给大家介绍PythonCounter函数使用案例... 目录一、Counter函数概述二、基本使用案例(一)列表元素计数(二)字符串字符计数(三)元组计数三、C

Spring Boot 整合 SSE(Server-Sent Events)实战案例(全网最全)

《SpringBoot整合SSE(Server-SentEvents)实战案例(全网最全)》本文通过实战案例讲解SpringBoot整合SSE技术,涵盖实现原理、代码配置、异常处理及前端交互,... 目录Spring Boot 整合 SSE(Server-Sent Events)1、简述SSE与其他技术的对

Python脚本轻松实现检测麦克风功能

《Python脚本轻松实现检测麦克风功能》在进行音频处理或开发需要使用麦克风的应用程序时,确保麦克风功能正常是非常重要的,本文将介绍一个简单的Python脚本,能够帮助我们检测本地麦克风的功能,需要的... 目录轻松检测麦克风功能脚本介绍一、python环境准备二、代码解析三、使用方法四、知识扩展轻松检测麦

MySQL 临时表与复制表操作全流程案例

《MySQL临时表与复制表操作全流程案例》本文介绍MySQL临时表与复制表的区别与使用,涵盖生命周期、存储机制、操作限制、创建方法及常见问题,本文结合实例代码给大家介绍的非常详细,感兴趣的朋友跟随小... 目录一、mysql 临时表(一)核心特性拓展(二)操作全流程案例1. 复杂查询中的临时表应用2. 临时

MySQL 数据库表与查询操作实战案例

《MySQL数据库表与查询操作实战案例》本文将通过实际案例,详细介绍MySQL中数据库表的设计、数据插入以及常用的查询操作,帮助初学者快速上手,感兴趣的朋友跟随小编一起看看吧... 目录mysql 数据库表操作与查询实战案例项目一:产品相关数据库设计与创建一、数据库及表结构设计二、数据库与表的创建项目二:员

C#中的Drawing 类案例详解

《C#中的Drawing类案例详解》文章解析WPF与WinForms的Drawing类差异,涵盖命名空间、继承链、常用类及应用场景,通过案例展示如何创建带阴影圆角矩形按钮,强调WPF的轻量、可动画特... 目录一、Drawing 是什么?二、典型用法三、案例:画一个“带阴影的圆角矩形按钮”四、WinForm

setsid 命令工作原理和使用案例介绍

《setsid命令工作原理和使用案例介绍》setsid命令在Linux中创建独立会话,使进程脱离终端运行,适用于守护进程和后台任务,通过重定向输出和确保权限,可有效管理长时间运行的进程,本文给大家介... 目录setsid 命令介绍和使用案例基本介绍基本语法主要特点命令参数使用案例1. 在后台运行命令2.

使用Python构建智能BAT文件生成器的完美解决方案

《使用Python构建智能BAT文件生成器的完美解决方案》这篇文章主要为大家详细介绍了如何使用wxPython构建一个智能的BAT文件生成器,它不仅能够为Python脚本生成启动脚本,还提供了完整的文... 目录引言运行效果图项目背景与需求分析核心需求技术选型核心功能实现1. 数据库设计2. 界面布局设计3