OpenMV 线性回归方法的优点和缺点
MultiMCU EDU 2022-09-28

背景介绍:
通过 能知道视觉就是在图片上找目标。通过能知道怎么找目标。

本篇继续这个话题,说说找目标是为了做什么。

提取赛道

线性回归方法的优点是能在视场中的任何位置找到线,缺点是慢。巡线设置为“灰度”、“QQQVGA”来加快速度,由于不跟踪颜色,所以不需要闭自动白平衡。

使用histeq()方法提高图像的对比度,以便接下来将图像二值化分离出赛道。

下面用 OpenMV IDE 提取赛道的灰度阀值,如下:

因为 Sugar 从柜子里翻出的老赛道充满了褶皱,所以噪点特别多。下面用mean(2)方法消个噪,再看下效果:

现在看上去好多了,接下来把图像通过binary()方法二值化,提取出赛道,如下:

赛道有点细,可以通过erode(1)让赛道粗一点,如下:

找赛道

1、车灯

小车前放车灯减小环境光对图像的影响,灯选用 WS2812 灯条(8 个灯珠)。WS2812 的驱动代码如下:

   		
# -*- coding: utf-8 -*- import gcimport pyb ON = 255OFF = 0 class WS2812: """ Driver for WS2812 RGB LEDs. May be used for controlling single LED or chain of LEDs.  Example of use:  chain = WS2812(spi_bus=1, led_count=4) data = [ (255, 0, 0), # red (0, 255, 0), # green (0, 0, 255), # blue (85, 85, 85), # white ] chain.show(data)  Version: 1.0 """ buf_bytes = (0x88, 0x8e, 0xe8, 0xee)  def __init__(self, spi_bus=1, led_count=1, intensity=1): """ Params: * spi_bus = SPI bus ID (1 or 2) * led_count = count of LEDs * intensity = light intensity (float up to 1) """ self.led_count = led_count self.intensity = intensity  # prepare SPI data buffer (4 bytes for each color) self.buf_length = self.led_count * 3 * 4 self.buf = bytearray(self.buf_length)  # SPI init self.spi = pyb.SPI(spi_bus, pyb.SPI.MASTER, baudrate=3200000, polarity=0, phase=1)  # turn LEDs off self.show([])  def show(self, data): """ Show RGB data on LEDs. Expected data = [(R, G, B), ...] where R, G and B are intensities of colors in range from 0 to 255. One RGB tuple for each LED. Count of tuples may be less than count of connected LEDs. """ self.fill_buf(data) self.send_buf()  def send_buf(self): """ Send buffer over SPI. """ self.spi.send(self.buf) gc.collect()  def update_buf(self, data, start=0): """ Fill a part of the buffer with RGB data.  Order of colors in buffer is changed from RGB to GRB because WS2812 LED has GRB order of colors. Each color is represented by 4 bytes in buffer (1 byte for each 2 bits).  Returns the index of the first unfilled LED  Note: If you find this function ugly, it's because speed optimisations beated purity of code. """  buf = self.buf buf_bytes = self.buf_bytes intensity = self.intensity  mask = 0x03 index = start * 12 for red, green, blue in data: red = int(red * intensity) green = int(green * intensity) blue = int(blue * intensity)  buf[index] = buf_bytes[green >> 6 & mask] buf[index+1] = buf_bytes[green >> 4 & mask] buf[index+2] = buf_bytes[green >> 2 & mask] buf[index+3] = buf_bytes[green & mask]  buf[index+4] = buf_bytes[red >> 6 & mask] buf[index+5] = buf_bytes[red >> 4 & mask] buf[index+6] = buf_bytes[red >> 2 & mask] buf[index+7] = buf_bytes[red & mask]  buf[index+8] = buf_bytes[blue >> 6 & mask] buf[index+9] = buf_bytes[blue >> 4 & mask] buf[index+10] = buf_bytes[blue >> 2 & mask] buf[index+11] = buf_bytes[blue & mask]  index += 12  return index // 12  def fill_buf(self, data): """ Fill buffer with RGB data.  All LEDs after the data are turned off. """ end = self.update_buf(data)  # turn off the rest of the LEDs buf = self.buf off = self.buf_bytes[0] for index in range(end * 12, self.buf_length): buf[index] = off index += 1 def on(): data = [] for i in range(0,8): data.append((ON, ON, ON)) WS2812(spi_bus=2, led_count=8).show(data) def off(): data = [] for i in range(0,8): data.append((OFF, OFF, OFF)) WS2812(spi_bus=2, led_count=8).show(data)

将上述代码放置在ws2812.py文件中供其他程序调用。

2、找车道并画线
(1) 首先了解线性回归算法 API 接口image.get_regression(阀值)函数:

此函数对图像所有阀值像素进行线性回归计算,返回一个image.line对象,可以用image.draw_line()画出返回的线条。

对于线性回归使用的最小二乘法这里不需要深究,但需要了解返回值的意义。首先来看两个实验现象:

通过这两个现象,能够总结出image.get_regression(阀值)返回值的意义,如下:

当我们了解这个规律后,就可以这样算出轨道的方向和角度:

   		
def line_to_theta_and_dir(line): angle_deg = 0 direct = 0 if line.theta() > 90: angle_deg = 180 - line.theta() direct = 1 elif line.theta() < 90: angle_deg = line.theta() if line.theta() == 0: direct = 0 else: direct = -1 return (direct, angle_deg)

目前找出赛道的完整程序如下:

   		
import sensor, image, time, math GRAYSCALE_THRESHOLD = (42, 255)MAG_THRESHOLD = 4 def line_to_theta_and_dir(line): angle_deg = 0 direct = 0 if line.theta() > 90: angle_deg = 180 - line.theta() direct = 1 elif line.theta() < 90: angle_deg = line.theta() if line.theta() == 0: direct = 0 else: direct = -1 return (direct, angle_deg) def line_track(track_color): direct = 0 angle_deg = 0 line_magnitude = 0  img = sensor.snapshot() img.mean(2) img.binary([GRAYSCALE_THRESHOLD]) img.crop([0,15,80,60]) img.erode(1) line = img.get_regression([track_color], robust=True)  if line and (line.magnitude() >= MAG_THRESHOLD): line_magnitude = line.magnitude() if line_magnitude >= MAG_THRESHOLD: line_color = 0 if track_color[0] == 0: line_color = 255 img.draw_line(line.line(), line_color) direct, angle_deg = line_to_theta_and_dir(line)  return direct, angle_deg, line_magnitude




本文源自微信公众号:MultiMCU EDU,不代表用户或本站观点,如有侵权,请联系nick.zong@aspencore.com 删除!

声明: 本文转载自其它媒体或授权刊载,目的在于信息传递,并不代表本站赞同其观点和对其真实性负责,如有新闻稿件和图片作品的内容、版权以及其它问题的,请联系我们及时删除。(联系我们,邮箱:evan.li@aspencore.com )
0
评论
  • 相关技术文库
  • C语言
  • 编程
  • 软件开发
  • 程序
  • 浅谈单片机调试方法

    [导读]浅谈单片机调试方法

    昨天
  • STM32如何移植uCGUI,看这里!

    [导读]第一部分:在UCGUI移植之前在移植之前,首先要了解在网上下的UCGUI 3.98源码的文件结构是。UCGUI 3.98源码中有三个文件夹:1)“too

    11-22
  • 嵌入式汇编语言学习经验

    [导读]最近参与了一个项目,需要用嵌入式汇编写测试程序。汇编程序写过,C程序也写过,但是将它们混合起来写还是第一次,完全没有概念。只能上网找资料,自己慢慢摸索。

    11-22
  • 数字示波器在高频信号采集中的应用

    1 高频信号的采集 当要对一个高频信号(比如高达100MHz的雷达波形)进行采集和处理的时候。通常会设计一个高速或者超高速硬件采集电路,包括放大部分、滤波部分;A/D和D/A转换部分等,这种电路的要求非常高,要求边采集边存储,电路速度高,而且要考虑各种辐射干扰等,同时,目前市场上成品价格很难承受。并且根据采样定理,一个最高频率为/的连续信号,完全可以用时间上相隔了=1/2f的一系列离散采样值来表示...

    11-22
  • 单片机C语言static属性和数码管显示程序

    简介:static从英文上翻译是静态的意思,在C语言中static所起的作用也正是静态。对于局部变量而言,其作用域是局部的如某一子函数体,程序在每次执行时调用该

    11-21
  • LEMO产品进入EPLAN Data Portal绘图平台部件数据库

      EPLANDataPortal是一个基于web网络的平台,可以让工程师即时访问众多部件制造商的电气原理图,从现在开始,LEMO的连接器也加入了EPLANDa

    11-21
  • DAC0832三种波形的C语言程序

    波形发生器作为一种常用的应用电子仪器设备,传统的波形发生器可以完全用硬件电路搭建,如应用555 振荡电路可以产生正弦波,三三角波,方波等波形,传统的波形发生器多

    11-17
  • 虚拟仪器发展趋势及其对军用测试技术的影响

    1 引言从1986年NI公司提出VI概念到现在,经过十几年的发展,不仅VI技术本身的内涵不断丰富,外延不断扩展,在军事和民用领域均得到了广泛的应用,而且对现代测控技术产生了深远的影响。例如,VI原来最核心的思想是利用计算机的强大资源使本来需要硬件实现的技术软件化,以便最大限度地降低系统成本,增强系统功能与灵活性。由IT产业特征决定了VI技术也必须走标准化、开放性这条技术路线,目前VI已发展成具有G...

    11-16
  • 漫画:什么是 “跳表” ?

    —————  第二天  ————— 如何进行二分查找呢? 首先根据数组下标,定位到数组的中间元素: 由于要查找的元素20,大于中间元素12,再次定位到数组右半部分的中间元素: 这一次定位到的元素正好是20,查找成功。 如果数组的长度

    11-03
  • 总结4个Python数据读取的常见问题

    read_csv()是python数据分析包pandas里面使用频次较高的函数之一。它包括的参数差不多20个,可能一开始未必需要完整知道每个参数作用。不过,随着

    10-26
  • AWTK能为现代GUI编程带来何种改变?

    AWTK是一个伸缩性极强的嵌入式图形框架,它的诞生会给GUI编程研发工程师带来哪些改变?AWTK是一个伸缩性极强的嵌入式图形框架,可在Cortex-M3这样低端

    10-26
下载排行榜
更多
广告