前言: 视觉小车最重要的是视觉功能,其实现方式主要有:
博主刚开始为了准备项目,了解尝试过前两种方式,最后才终于接触到OpenMV这种主控板,因为其开发简单、结构简单、非常适合用于智能小车,入门虽然简单,功能却十分强大。
OpenMV简介:
OpenMV的目标是成为“机器视觉世界的Arduino ",有自己的IDE,采用Python二次开发简单易用,可扩展,开源,详细教程和技术手册。
OpenMV3是主要以STM32F427CPU为核心,集成了OV7725摄像头的模块。
OpenMV的功能:
颜色追踪、路线识别、形状识别、二维码识别、人脸识别、瞳孔追踪等。
上图来源
OpenMV采用 Python 给用户开发,而Python简单易学,简洁强大,在视觉开发方面十分突出。下文是初步学习使用 OpenMV 模块和入门到拓展学习Python语法
其实初步学习使用的话,官网的十分钟上手教程已经非常详细,推荐大家去看。(其实博主不是懒,是怕不专业误导你们~)
其中需要注意的是LAB颜色空间:
LAB:L亮度。 范围: 0-100, 0白,L=50时,就相当于50%的黑
A表示从洋红色至绿色的范围。范围:-128至+127, -128绿色 ,+127就是红色
B表示从黄色至蓝色的范围。 范围:-128至+127,-128 b是蓝色。+127 b是黄色
推荐学习Python的网站:
主要克隆之前的文章:【OpenMv】学习笔记之初入江湖
Print
我们的魔教口号是什么?
print('hello, world')
print()函数也可以接受多个字符串,用逗号“,”隔开,print()会依次打印每个字符串,遇到逗号“,”会输出一个空格,就可以连成一串输出:
print('I am a', 'handsome', 'boy')
print(300)#直接打印整数300
print('100 + 200 =', 100 + 200)#‘字符串’
#
py
:以屁眼.py结尾的就是一个模块
import 语句,引入模块,需要在开始就引用,就是c语言的头文件吧
import 模块名.函数名
import sys
from…import
:Python 的 from 语句让你从模块中导入一个指定的部分到当前命名空间中。语法如下:
#例如,要导入模块 fib 的 fibonacci 函数,使用如下语句:
from fib import fibonacci
函数就是可以实现功能的方式,可重复调用。
类型有:
以下源代码实现功能:定义一个plus(x,y)
函数,将x+y的结果输出。
def plus(x,y):
a=x+y
return(a)
#输入参数x,y,求出x+y
#有入口参数和返回值
使用截图:
以下源代码实现功能:定义一个求平方的power(x)
函数,将 x 的平方输出。
#定义一个求平方的函数
def power(x):
return x * x
以下源代码实现功能:定义一个n次方的power(x, n)
函数,将 x 的 n 次方输出。
#定义一个求n次方的函数
def power(x, n):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
if
:用法:
if <条件判断1>:
<执行1>
elif <条件判断2>:
<执行2>
elif <条件判断3>:
<执行3>
else:
<执行4>
以下源代码实现功能:输入年龄,用 if 判断是 kid 还是 teenager 还是 adult 。
age = 20
#age=0;
#age=input('Input your age: ')
#input()读取用户的输入
if age >= 6 and age <18:
print('teenager')
elif age >= 18:
print('adult')
else:
print('kid')
while
和 For x in range(y)
:以下源代码实现功能:采用 for x in range(100)
计算 0+1+2+...+99
的和。
# 注意从0开始加,没有加100。
sum = 0
for x in range(100):# range()函数生成一个整数序列
sum = sum + x
print(sum)
以下源代码实现功能:采用 while循环
计算100以内所有奇数之和。
#算100以内所有奇数之和
sum = 0
n = 99
while n > 0:
sum = sum + n
n = n - 2
print(sum)
int
:以下源代码实现功能:调用int
函数将浮点型转化为整形。
>>> int(12.34)
12
classmates = ['Michael', 'Bob', 'Tracy']
classmates
#结果:['Michael', 'Bob', 'Tracy']
classmates[-2]#索引访问,顺序和倒序访问
len(classmates)=3 #长度
classmates.insert(1, 'Jack')#插入修改
classmates[1] = 'Sarah'#替换修改
>>> List = ['Michael', 'Sarah', 'Tracy', 'Bob', 'Jack']
>>> List[1:3] #从索引1开始取,直到索引3为止,不包括3
['Sarah', 'Tracy']
+= 加法赋值运算符 c += a 等效于 c = c + a
*= 乘法赋值运算符 c *= a 等效于 c = c * a
/= 除法赋值运算符 c /= a 等效于 c = c / a
%= 取模赋值运算符 c %= a 等效于 c = c % a
<< 左移动运算符:运算数的各二进位全部左移若干位,由 << 右边的数字指定了移动的位数,高位丢弃,低位补0。a=60, a << 2 输出结果 240 ,二进制解释: 1111 0000
右移动运算符:把">>"左边的运算数的各二进位全部右移若干位,>> 右边的数字指定了移动的位数
a = 60 # 60 = 0011 1100
c = 0
c = a << 2; # 240 = 1111 0000
print "5 - c 的值为:", c
5 - c 的值为: 240
&& || ~
:Python是面向对象编程的,比如一个LED灯
LED是一个类,red_led就是一个对象,可以对这个对象进行操作,比如点亮on,关掉off,查看value。
from pyb import LED
red_led = LED(1)
red_led.on()
类是抽象的模板!!!,而实例是根据类创建出来的一个个具体的“对象”,每个对象都拥有相同的方法,但各自的数据可能不同。
#类定义一个叫Student的对象,继承于object类,这是所有类最终都会继承的类
class Student(object):
pass
定义好了Student类,就可以根据Student类创建出Student的实例,创建实例是通过类名+()
实现的:
>>> me = Student()
>>> me
<__main__.Student object at 0x10a67a590> #0x10a67a590是内存地址,每个object的地址都不一样
>>> Student
<class '__main__.Student'>
自由地给一个实例变量绑定属性
>>>me.name = 'Iron'
>>>me.name
'Iron'
类可以起到模板的作用。因此,可以在创建实例的时候,把一些我们认为必须绑定的属性强制填写进去。通过定义一个特殊的__init__方法,在创建实例的时候,就把name,score等属性绑上去:
class Student(object):
#__init__方法的第一个参数永远是self,表示创建的实例本身
def __init__(self, name, score): #前后分别有两个下划线!!!
self.name = name
self.score = score
self不需要传参数
>>> me = Student('Iron', 59.9)
>>> me.name
'Iron'
>>> me.score
59.9
封装-内
class Student(object):
def __init__(self, name, score):
self.name = name
self.score = score
#调用方法: name.print_score(),结果 name:99
def print_score(self):
print('%s: %s' % (self.name, self.score))
#对分数分级,class类可以自由加入新的模块
#封装的另一个好处是可以给Student类增加新的方法,比如get_grade:
def get_grade(self):
if self.score >= 90:
return 'A'
elif self.score >= 60:
return 'B'
else:
return 'C'
>>>me = Student('Iron',90)
>>>you= Student('Rose',69)
>>>print(me.name, me.get_grade())
Iron A
>>>me.print_score()
Iron:90
以下是开始主要用到的源代码例子以及拓展。
# 色块监测例子 这个例子展示了如何通过find_blobs()函数来查找图像中的色块
import sensor, image, time
#threshold翻译为阈值
# 颜色追踪的例子,一定要控制环境的光,保持光线是稳定的。
#green_threshold = ( 0, 80, -70, -10, -0, 30)
#green_threshold = ( 0, 80, -20, -0, -80, -30)#蓝色
green_threshold = ( 0, 80, 40, 100, 2, 60)#红色
#(minL, maxL, minA, maxA, minB, maxB)
#设置绿色的阈值,括号里面的数值分别是L A B 的最大值和最小值(minL, maxL, minA,
# maxA, minB, maxB),LAB的值在图像左侧三个坐标图中选取。如果是灰度图,则只需
#设置(min, max)两个数字即可。
sensor.reset() # 初始化摄像头
sensor.set_pixformat(sensor.RGB565) # 格式为 RGB565.
sensor.set_framesize(sensor.QQVGA) # 使用 QQVGA 速度快一些
sensor.skip_frames(time = 2000) # 跳过2000s,使新设置生效,并自动调节白平衡
sensor.set_auto_gain(False) # 关闭自动自动增益。默认开启的,在颜色识别中,一定要关闭白平衡。
sensor.set_auto_whitebal(False)
#关闭白平衡。白平衡是默认开启的,在颜色识别中,一定要关闭白平衡。
clock = time.clock() # 追踪帧率
while(True):
clock.tick() # Track elapsed milliseconds between snapshots().
img = sensor.snapshot() # 从感光芯片获得一张图像
blobs = img.find_blobs([green_threshold])
#find_blobs(thresholds, invert=False, roi=Auto),thresholds为颜色阈值,
#是一个元组,需要用括号[ ]括起来。invert=1,反转颜色阈值,invert=False默认
#不反转。roi设置颜色识别的视野区域,roi是一个元组, roi = (x, y, w, h),代表
#从左上顶点(x,y)开始的宽为w高为h的矩形区域,roi不设置的话默认为整个图像视野。
#这个函数返回一个列表,[0]代表识别到的目标颜色区域左上顶点的x坐标,[1]代表
#左上顶点y坐标,[2]代表目标区域的宽,[3]代表目标区域的高,[4]代表目标
#区域像素点的个数,[5]代表目标区域的中心点x坐标,[6]代表目标区域中心点y坐标,
#[7]代表目标颜色区域的旋转角度(是弧度值,浮点型,列表其他元素是整型),
#[8]代表与此目标区域交叉的目标个数,[9]代表颜色的编号(它可以用来分辨这个
#区域是用哪个颜色阈值threshold识别出来的)。
if blobs:
#如果找到了目标颜色
for b in blobs:
#迭代找到的目标颜色区域
# Draw a rect around the blob.
img.draw_rectangle(b[0:4]) # rect tupe格式(x, y, w, h)
#b[0:4]断片b中 0,1,2,3四个元素, [0]代表识别到的目标颜色区域左上顶
#点的x坐标 [1]代表左上顶点y坐标,
#[2]代表目标区域的宽,[3]代表目标区域的高
#用矩形标记出目标颜色区域
img.draw_cross(b[5], b[6]) # cx, cy
#在目标颜色区域的中心画十字形标记
#b[5], b[6]是中心坐标
print(clock.fps()) # 注意: 你的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颜色的阈值
img=sensor.snapshot()
red_blobs = img.find_blobs([red])
#roi=Auto感兴趣区
left_roi = [0,0,160,240]
blobs = img.find_blobs([red],roi=left_roi)
#x_stride=2, y_stride=1,最小像素
blobs = img.find_blobs([red],x_stride=10)#改为10
#invert 反转阈值,把阈值以外的颜色作为阈值进行查找
invert=False
#area_threshold框面积阈值,如果色块被框起来的面积小于这个值,会被过滤掉
area_threshold=10,
#pixels_threshold 像素个数阈值,如果色块像素数量小于这个值,会被过滤掉
pixels_threshold=10,
#merge=True合并,如果设置为True,那么合并所有重叠的blob为一个。
merge=False
#margin 边界,如果设置为1,那么两个blobs如果间距1一个像素点,也会被合并。
margin=0, threshold_cb=None, merge_cb=None
blob.cx() 返回色块的外框的中心x坐标(int),也可以通过blob[5]来获取。
blob.cy() 返回色块的外框的中心y坐标(int),也可以通过blob[6]来获取。
# Hello World Example
#
# Welcome to the OpenMV IDE! Click on the green run arrow button below to run the script!
import sensor, image, time
sensor.reset() # 初始化摄像头
sensor.set_pixformat(sensor.RGB565) # 格式为 RGB565.
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(10) # 跳过10帧,使新设置生效
while(True):
img = sensor.snapshot() # Take a picture and return the image.
img.draw_line((20, 30, 40, 50))
img.draw_line((80, 50, 100, 100), color=(255,0,0))
img.draw_rectangle((20, 30, 41, 51), color=(255,0,0))
img.draw_circle(50, 50, 30)
img.draw_cross(90,60,size=10)
img.draw_string(10,10, "hello world!")
画圆image.draw_circle(x, y, radius, color=White)
x,y是圆心坐标radius是圆的半径
画十字 image.draw_cross(x, y, size=5, color=White)
x,y是坐标 size两侧的尺寸
画矩形框 image.draw_rectangle(rect_tuple, color=White)
画一个矩形框 rect_tuple> 的格式是 (x, y, w, h)。
import sensor, image, time
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False) # must be turned off for color tracking
sensor.set_auto_whitebal(False) # must be turned off for color tracking
clock = time.clock()
while(True):
clock.tick()
img = sensor.snapshot().lens_corr(1.8)
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):
area = (c.x()-c.r(), c.y()-c.r(), 2*c.r(), 2*c.r())
#area为识别到的圆的区域,即圆的外接矩形框
statistics = img.get_statistics(roi=area)#像素颜色统计
print(statistics)
#(0,100,0,120,0,120)是红色的阈值,所以当区域内的众数(也就是最多的颜色),范围在这个阈值内,就说明是红色的圆。
#l_mode(),a_mode(),b_mode()是L通道,A通道,B通道的众数。
if 0<statistics.l_mode()<100 and 0<statistics.a_mode()<127 and 0<statistics.b_mode()<127:#if the circle is red
img.draw_circle(c.x(), c.y(), c.r(), color = (255, 0, 0))#识别到的红色圆形用红色的圆框出来
else:
img.draw_rectangle(area, color = (255, 255, 255))
#将非红色的圆用白色的矩形框出来
print("FPS %f" % clock.fps())
距离 = 一个常数/直径的像素
#测量距离
#这个例子展示了如何通过行李中的尺寸来测量距离
#这个例子特别寻找黄色的乒乓球。
import sensor, image, time
#为了使色彩跟踪工作得非常好,理想情况下应该非常非常
#非常受控的环境,照明是恒定的......
yellow_threshold =(0,80,40,100,2,60)
#(56,83,5,57,63,80)
#您可能需要调整以上设置以跟踪绿色事物......
#在Framebuffer中选择一个区域以复制颜色设置。
sensor.reset()#初始化相机传感器。
sensor.set_pixformat(sensor.RGB565)#使用RGB565。
sensor.set_framesize(sensor.QQVGA)#使用QQVGA获取速度。
sensor.skip_frames(10)#让新设置生效。
sensor.set_auto_whitebal(False)#关闭它。
clock = time.clock()#追踪FPS。
K = 5000#应该测量的值
while(True):
clock.tick()#跟踪快照之间经过的毫秒数()。
img = sensor.snapshot()#拍摄照片并返回图像。
blobs = img.find_blobs([yellow_threshold])
if len(blobs) == 1:
#在blob周围画一个矩形。
b = blobs [0]
img.draw_rectangle(b [0:4])#rect
img.draw_cross(b [5],b [6])#cx,cy
Lm = (b[2]+b[3])/2
length = K/Lm #距离=常数K/球像素直径
print(length)
#print(clock.fps())
#注意:你的OpenMV Cam运行速度快一半
#已连接到您的计算机。一旦断开连接,FPS应该增加。
设置图像大小
sensor.set_framesize() 设置图像的大小
sensor.QQVGA: 160x120
sensor.QQVGA2: 128x160 (用于 lcd 扩展板)
sensor.HQVGA: 240x160
sensor.QVGA: 320x240
sensor.VGA: 640x480 (只用于OpenMV Cam M7 的灰度图处理图像,或者彩图采集图像)
sensor.QQCIF: 88x72
sensor.QCIF: 176x144
sensor.CIF: 352x288
OpenMV非常适用于视觉识别,开发简单,功能强大。学好 Python 是学好 OpenMV 的基础,而如何学好 Python 并不是一蹴而就的事情。
骐骥一跃,不能十步;驽马十驾,功在不舍。——《荀子》
此篇收录于专栏【手把手教你做OpenMV小车】,总篇链接:https://blog.csdn.net/qq_42807924/article/details/86585757
完。
(本文为吾本虚无原创,禁止任何形式转载)
全文完。