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

相关文章

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La

MySQL中实现多表查询的操作方法(配sql+实操图+案例巩固 通俗易懂版)

《MySQL中实现多表查询的操作方法(配sql+实操图+案例巩固通俗易懂版)》本文主要讲解了MySQL中的多表查询,包括子查询、笛卡尔积、自连接、多表查询的实现方法以及多列子查询等,通过实际例子和操... 目录复合查询1. 回顾查询基本操作group by 分组having1. 显示部门号为10的部门名,员

使用Python实现表格字段智能去重

《使用Python实现表格字段智能去重》在数据分析和处理过程中,数据清洗是一个至关重要的步骤,其中字段去重是一个常见且关键的任务,下面我们看看如何使用Python进行表格字段智能去重吧... 目录一、引言二、数据重复问题的常见场景与影响三、python在数据清洗中的优势四、基于Python的表格字段智能去重

Spring AI集成DeepSeek三步搞定Java智能应用的详细过程

《SpringAI集成DeepSeek三步搞定Java智能应用的详细过程》本文介绍了如何使用SpringAI集成DeepSeek,一个国内顶尖的多模态大模型,SpringAI提供了一套统一的接口,简... 目录DeepSeek 介绍Spring AI 是什么?Spring AI 的主要功能包括1、环境准备2

Spring AI与DeepSeek实战一之快速打造智能对话应用

《SpringAI与DeepSeek实战一之快速打造智能对话应用》本文详细介绍了如何通过SpringAI框架集成DeepSeek大模型,实现普通对话和流式对话功能,步骤包括申请API-KEY、项目搭... 目录一、概述二、申请DeepSeek的API-KEY三、项目搭建3.1. 开发环境要求3.2. mav

Python3脚本实现Excel与TXT的智能转换

《Python3脚本实现Excel与TXT的智能转换》在数据处理的日常工作中,我们经常需要将Excel中的结构化数据转换为其他格式,本文将使用Python3实现Excel与TXT的智能转换,需要的可以... 目录场景应用:为什么需要这种转换技术解析:代码实现详解核心代码展示改进点说明实战演练:从Excel到

Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)

《Python爬虫selenium验证之中文识别点选+图片验证码案例(最新推荐)》本文介绍了如何使用Python和Selenium结合ddddocr库实现图片验证码的识别和点击功能,感兴趣的朋友一起看... 目录1.获取图片2.目标识别3.背景坐标识别3.1 ddddocr3.2 打码平台4.坐标点击5.图

Python如何实现PDF隐私信息检测

《Python如何实现PDF隐私信息检测》随着越来越多的个人信息以电子形式存储和传输,确保这些信息的安全至关重要,本文将介绍如何使用Python检测PDF文件中的隐私信息,需要的可以参考下... 目录项目背景技术栈代码解析功能说明运行结php果在当今,数据隐私保护变得尤为重要。随着越来越多的个人信息以电子形

使用Navicat工具比对两个数据库所有表结构的差异案例详解

《使用Navicat工具比对两个数据库所有表结构的差异案例详解》:本文主要介绍如何使用Navicat工具对比两个数据库test_old和test_new,并生成相应的DDLSQL语句,以便将te... 目录概要案例一、如图两个数据库test_old和test_new进行比较:二、开始比较总结概要公司存在多

SpringBoot实现动态插拔的AOP的完整案例

《SpringBoot实现动态插拔的AOP的完整案例》在现代软件开发中,面向切面编程(AOP)是一种非常重要的技术,能够有效实现日志记录、安全控制、性能监控等横切关注点的分离,在传统的AOP实现中,切... 目录引言一、AOP 概述1.1 什么是 AOP1.2 AOP 的典型应用场景1.3 为什么需要动态插