Mrli
别装作很努力,
因为结局不会陪你演戏。
Contacts:
QQ博客园

Openmv使用

2019/11/07 嵌入式
Word count: 3,115 | Reading time: 15min

Openmv使用

下载Openmv IDE

推荐下载星瞳的,这个是中文版的,并且其他两个下载非常慢。

捕捉图片设置:

设置彩色/黑白

  • sensor.set_pixformat() 设置像素模式。
    • sensor.GRAYSCALE: 灰度,每个像素8bit。
    • sensor.RGB565: 彩色,每个像素16bit。

设置图像大小

  • 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

    设置窗口ROI

    sensor.set_windowing(roi)

    设置翻转

    sensor.set_hmirror(True)
    水平方向翻转

    sensor.set_vflip(True)
    垂直方向翻转

Demo例程:

openmv虽然比较贵,但是它的功能非常强大,已经提供了相当多的例程了。具体例程可以去星瞳的官网上查看,说明非常详细。

在此,我只介绍点我们这次需要用到的功能。

我使用的是OPENMV-H7 R1,芯片是STM32H743,镜头为IR 1080P 2.8mm

Hello World

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 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() # Reset and initialize the sensor.
sensor.set_pixformat(sensor.RGB565) # Set pixel format to RGB565 (or GRAYSCALE)
sensor.set_framesize(sensor.QVGA) # Set frame size to QVGA (320x240)
sensor.skip_frames(time = 2000) # Wait for settings take effect.
clock = time.clock() # Create a clock object to track the FPS.

while(True):
clock.tick() # Update the FPS clock.
img = sensor.snapshot() # Take a picture and return the image.
print(clock.fps()) # Note: OpenMV Cam runs about half as fast when connected
# to the IDE. The FPS should increase once disconnected.

二维码识别

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# QRCode Example
#
# This example shows the power of the OpenMV Cam to detect QR Codes
# using lens correction (see the qrcodes_with_lens_corr.py script for higher performance).

import sensor, image, time

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False) # must turn this off to prevent image washout...
clock = time.clock()

while(True):
clock.tick()
img = sensor.snapshot()
img.lens_corr(1.8) # strength of 1.8 is good for the 2.8mm lens.
for code in img.find_qrcodes():
img.draw_rectangle(code.rect(), color = (255, 0, 0))
print(code)
print(clock.fps())

代码是用python编写的,文件系统为microPython,具有Cpython解释器翻译成机器码。需要脱机运行的文件命名为main.py即可(具体详情见microPython规范)。可放于flash或者32GB以下的SD卡中,SD卡读取优先级高于Flash,且flash内容容易丢失,且擦写次数有限,建议使用SD卡。

主要需要用的库:

  • sersor:通过这个对象可以控制摄像头及相关配置;
  • image:处理图像的功能函数都在这个库里
    • sensor.snapshot()会返回一个<class ‘Image’>
  • time:跟Python自带的time模块不同,这个是专门用来记录摄像头用时的

颜色追踪

颜色阈值需要使用LAB色彩空间

LAB的范围选择,个人比较快截的方法是通过IDE右边的帧缓冲区来获取,即框出ROI区域后,再打开“工具->机器视觉->阈值编辑器->帧缓冲区”,然后根据直方图中的数据就可以筛选出想要的对象辣(白色是选出,黑色是过滤,好像跟PS的蒙版是反的?)

▲颜色识别时,一定要关闭自动增益、白平衡

  • sensor.set_auto_gain() 自动增益开启(True)或者关闭(False)。在使用颜色追踪时,需要关闭自动增益。
  • sensor.set_auto_whitebal() 自动白平衡开启(True)或者关闭(False)。在使用颜色追踪时,需要关闭自动白平衡。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
# Measure the distance
#
# This example shows off how to measure the distance through the size in imgage
# This example in particular looks for yellow pingpong ball.

import sensor, image, time, lcd

# For color tracking to work really well you should ideally be in a very, very,
# very, controlled enviroment where the lighting is constant...
#yellow_threshold = (22, 74, -12, 31, 23, 62)

box_threshold = (40, 80, -4, 21, 14, 51)


red_threshold = (40, 59, 61, 84, 30, 79)
# You may need to tweak the above settings for tracking green things...
# Select an area in the Framebuffer to copy the color settings.

sensor.reset() # Initialize the camera sensor.
sensor.set_pixformat(sensor.RGB565) # use RGB565.
sensor.set_framesize(sensor.QVGA) # use QQVGA for speed.
sensor.skip_frames(10) # Let new settings take affect.
sensor.set_auto_whitebal(False) # turn this off.
clock = time.clock() # Tracks FPS.

#lcd.init() # Initialize the lcd screen.


K=5000#the value should be measured

while(True):
clock.tick() # Track elapsed milliseconds between snapshots().
img = sensor.snapshot() # Take a picture and return the image.

blobs = img.find_blobs([red_threshold])
if len(blobs) == 1:
# Draw a rect around the 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
#print(length)
b = blobs[0]
img.draw_rectangle(b[0:4])
img.draw_cross(b[5], b[6])
#lcd.display(sensor.snapshot()) # Take a picture and display the image.
#print(clock.fps()) # Note: Your OpenMV Cam runs about half as fast while
# connected to your computer. The FPS should increase once disconnected.

识别圆

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
# 圆形检测例程
#
# 这个例子展示了如何用Hough变换在图像中找到圆。
# https://en.wikipedia.org/wiki/Circle_Hough_Transform
#
# 请注意,find_circles()方法将只能找到完全在图像内部的圆。圈子之外的
# 图像/ roi被忽略...

import sensor, image, time

sensor.reset()
sensor.set_pixformat(sensor.RGB565) # grayscale is faster
sensor.set_framesize(sensor.QQVGA)
sensor.skip_frames(time = 2000)
clock = time.clock()

while(True):
clock.tick()

#lens_corr(1.8)畸变矫正
img = sensor.snapshot().lens_corr(1.8)

# Circle对象有四个值: x, y, r (半径), 和 magnitude。
# magnitude是检测圆的强度。越高越好

# roi 是一个用以复制的矩形的感兴趣区域(x, y, w, h)。如果未指定,
# ROI 即图像矩形。操作范围仅限于roi区域内的像素。

# x_stride 是霍夫变换时需要跳过的x像素的数量。若已知圆较大,可增加
# x_stride 。

# y_stride 是霍夫变换时需要跳过的y像素的数量。若已知直线较大,可增加
# y_stride 。

# threshold 控制从霍夫变换中监测到的圆。只返回大于或等于阈值的圆。
# 应用程序的阈值正确值取决于图像。注意:一条圆的大小是组成圆所有
# 索贝尔滤波像素大小的总和。

# x_margin 控制所检测的圆的合并。 圆像素为 x_margin 、 y_margin 和
# r_margin的部分合并。

# y_margin 控制所检测的圆的合并。 圆像素为 x_margin 、 y_margin 和
# r_margin 的部分合并。

# r_margin 控制所检测的圆的合并。 圆像素为 x_margin 、 y_margin 和
# r_margin 的部分合并。

# r_min,r_max和r_step控制测试圆的半径。
# 缩小测试圆半径的数量可以大大提升性能。
# threshold = 3500比较合适。如果视野中检测到的圆过多,请增大阈值;
# 相反,如果视野中检测到的圆过少,请减少阈值。
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):# (80,60,80,60)
img.draw_circle(c.x(), c.y(), c.r(), color = (255, 0, 0))
print(c)


for r in img.find_rects(threshold = 3500):
img.draw_rectangle(r.rect(), color=(255,0,0))
for p in r.corners():
img.draw_circle(p[0], p[1], 5, color=(0,255,0))
print(r)

print("FPS %f" % clock.fps())

测距和测量物块大小

由于 OpenMV采用的是单目摄像头,想要实现测距,就需要选参照物,利用参照物的大小比例来计算距离。

Len1pixelconutLen ∝ \frac{1}{pixelconut}>dist=Cpixeldist = \frac{C}{pixel}实际长度和摄像头里的像素成反比 **>** 距离 = 一个常数/直径的像素

  1. 先测出这个常数的值,怎么测不用说了吧,就是先让球距离摄像头10cm,打印出摄像头里直径的像素值,然后相乘,就得到了k的值!
  2. 就可以算出距离了(=这个常数/摄像头里像素点数)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# Measure the distance
#
# This example shows off how to measure the distance through the size in imgage
# This example in particular looks for yellow pingpong ball.

import sensor, image, time

# For color tracking to work really well you should ideally be in a very, very,
# very, controlled enviroment where the lighting is constant...
yellow_threshold = ( 56, 83, 5, 57, 63, 80)
# box_threshold = (40, 80, -4, 21, 14, 51)
# red_threshold = (40, 59, 61, 84, 30, 79)

# You may need to tweak the above settings for tracking green things...
# Select an area in the Framebuffer to copy the color settings.

sensor.reset() # Initialize the camera sensor.
sensor.set_pixformat(sensor.RGB565) # use RGB565.
sensor.set_framesize(sensor.QQVGA) # use QQVGA for speed.
sensor.skip_frames(10) # Let new settings take affect.
sensor.set_auto_whitebal(False) # turn this off.
clock = time.clock() # Tracks FPS.

K=5000#the value should be measured
# K = 36*10

while(True):
clock.tick() # Track elapsed milliseconds between snapshots().
img = sensor.snapshot() # Take a picture and return the image.

blobs = img.find_blobs([yellow_threshold])
if len(blobs) == 1:
# Draw a rect around the 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 # 像素点数
# index 2 is length, 3 is width
length = K/Lm # 距离
print(length)

#print(clock.fps()) # Note: Your OpenMV Cam runs about half as fast while
# connected to your computer. The FPS should increase once disconnected.

LCD显示

由于正好有个LCD显示屏,那就也记录下LCD的代码把

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# LCD Example
#
# Note: To run this example you will need a LCD Shield for your OpenMV Cam.
#
# The LCD Shield allows you to view your OpenMV Cam's frame buffer on the go.

import sensor, image, lcd

sensor.reset() # Initialize the camera sensor.
sensor.set_pixformat(sensor.RGB565) # or sensor.GRAYSCALE
sensor.set_framesize(sensor.QQVGA2) # Special 128x160 framesize for LCD Shield.
lcd.init() # Initialize the lcd screen.

while(True):
lcd.display(sensor.snapshot()) # Take a picture and display the image.

串口通信

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# UART Control
#
# This example shows how to use the serial port on your OpenMV Cam. Attach pin
# P4 to the serial input of a serial LCD screen to see "Hello World!" printed
# on the serial LCD display.

import time
from pyb import UART

# Always pass UART 3 for the UART number for your OpenMV Cam.
# The second argument is the UART baud rate. For a more advanced UART control
# example see the BLE-Shield driver.
uart = UART(3, 19200)

while(True):
# 发送数据
uart.write("Hello World!\r")
time.sleep(1000)
# 接收数据
if uart.any():
a=uart.readline()
print(a)

与STM32通信

openmv

1
2
3
4
5
6
7
8
9
10
11
12
13
14
import time,sensor, image
from pyb import UART


uart = UART(3, 115200)
uart.init(115200, bits=8, parity=None, stop=1)

while(True):
# 由于正点原子提供的串口通信协议需要以\r\n结尾,所以,这边必须也要写\r\n
uart.write("Hello World!\r\n")
# 中文好像解析不了
if uart.any():
a=uart.readline()
print(a)

main.c

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include "led.h"
#include "delay.h"
#include "key.h"
#include "sys.h"
#include "usart.h"

int main(void){
u16 t;
u16 len;
u16 times=0;
delay_init(); //延时函数初始化
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //设置NVIC中断分组2:2位抢占优先级,2位响应优先级
uart_init(115200); //串口初始化为115200
LED_Init(); //LED端口初始化
KEY_Init(); //初始化与按键连接的硬件接口
while(1){
if(USART_RX_STA&0x8000){
len=USART_RX_STA&0x3fff;//得到此次接收到的数据长度
printf("Your message is:\r\n\r\n");
for(t=0;t<len;t++){
USART_SendData(USART1, USART_RX_BUF[t]);//向串口1发送数据
while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);//等待发送结束
}
//printf("\r\n\r\n");//插入换行
USART_RX_STA=0;
}else{
times++;
if(times%200==0) printf("Waiting for input.2333\r\n");
if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
delay_ms(10);
}
}
}

测试结果(暂时还没理解):

uart

补充:

openmv 发送16进制数

附录:

OpenMV中文入门教程

视频教程:

B站的清晰度和加载速度比较快,星瞳官网的还有额外的教程(他家的拓展版)

画图:

1
2
image.draw_line((10,10,20,30), color=(255,0,0))
image.draw_rectangle(rect_tuple, color=(255,0,0))

画线

  • image.draw_line(line_tuple, color=White) 在图像中画一条直线。
    • line_tuple的格式是(x0, y0, x1, y1),意思是(x0, y0)到(x1, y1)的直线。
    • 颜色可以是灰度值(0-255),或者是彩色值(r, g, b)的tupple。默认是白色

画框

  • image.draw_rectangle(rect_tuple, color=White) 在图像中画一个矩形框。
    • rect_tuple 的格式是 (x, y, w, h)。

画圆

  • 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_string(x, y, text, color=White) 在图像中写字 8x10的像素
    • x,y是坐标。使用\n, \r, and \r\n会使光标移动到下一行。
    • text是要写的字符串。

需要调参的地方:

  1. 测大小的常数k
  2. 形状检测的阈值
  3. 颜色识别的阈值

Author: Mrli

Link: https://nymrli.top/2019/10/06/Openmv使用/

Copyright: All articles in this blog are licensed under CC BY-NC-SA 3.0 unless stating additionally.

< PreviousPost
Python多进程
NextPost >
TD-afterstate
CATALOG
  1. 1. Openmv使用
    1. 1.1. 下载Openmv IDE
    2. 1.2. 捕捉图片设置:
    3. 1.3. Demo例程:
      1. 1.3.1. 二维码识别
      2. 1.3.2. 颜色追踪
      3. 1.3.3. 识别圆
      4. 1.3.4. 测距和测量物块大小
      5. 1.3.5. LCD显示
      6. 1.3.6. 串口通信
        1. 1.3.6.1. 与STM32通信
    4. 1.4. 附录:
      1. 1.4.1. 画图:
        1. 1.4.1.1. 画线
        2. 1.4.1.2. 画框
        3. 1.4.1.3. 画圆
        4. 1.4.1.4. 画十字
        5. 1.4.1.5. 写字
      2. 1.4.2. 需要调参的地方: