OpenMV入门介绍

  • Post author:
  • Post category:其他




一、OpenMV是什么

OpenMV是一款具有图像处理功能的可编程摄像头模块,可以实现简单的机器视觉应用,例如人脸检测、Apriltag追踪、圆形检测、矩形检测等。



二、OpenART mini与OpenMV对比


(这里介绍另一款可编程摄像头模块OpenART mini,在功能上与OpenMV几乎无差别,但性能和价格都优于OpenMV)


OpenART mini是

逐飞科技



恩智浦

的OpenART套件的基础上,去除非视觉部分而制作出来的迷你版。虽说只是迷你版,但“麻雀虽小,五脏俱全”。OpenART mini 不仅可以很轻松的完成机器视觉应用,还可以完成神经网络模型的部署。

比较项目 OpenMV4 H7 Plus OpenART mini
价格 599 380
处理器 STM32H743II MIMXRT1064
主频 480MHz 600MHz
RAM 1M 1M
FLASH 2M 4M
编程环境 Micropython Micropython
OpenMV视觉库



三、图像处理背景知识



1.像素和分辨率

  • 像素:像素是数字图像中的

    最小单元

  • 分辨率:分辨率指

    单位长度内像素点的数量

    ,常用的度量为ppi(pixels per inch),即每英寸有多少像素点。

感光元件是由很多个感光点构成的,比如有



640

×

480

640×480






640




×








480





个点,每个点就是一个像素,把每个点的像素收集整理起来,就是一副图片,那么这张图片的分辨率就是



640

×

480

640×480






640




×








480





在这里插入图片描述



2. 帧率

帧率(FPS,Frames Per Second)就是每秒钟处理的图片数量,如果超过20帧,人眼就基本分辨不出卡顿。电影的帧率一般是24FPS,游戏的帧率一般都大于30FPS。



3.RGB三原色

RGB指的是红绿蓝三种颜色,是光学三原色,所有的颜色都可以由这三种色彩混合而成。

(三原色是依据人类视觉定义的,不存在绝对的三原色)



4.LAB颜色空间

Lab是由一个亮度通道和两个颜色通道组成的。在Lab颜色空间中,每个颜色用L、a、b三个数字表示,各个分量的含义是这样的:


  • L

    代表亮度

  • a

    代表从绿色到红色的分量

  • b

    代表从蓝色到黄色的分量

Lab是基于人对颜色的感觉来设计的,更具体地说,它是感知均匀(perceptual uniform)的。Perceptual uniform的意思是,如果数字(即前面提到的L、a、b这三个数)变化的幅度一样,那么它给人带来视觉上的变化幅度也差不多。

Lab相较于RGB与CMYK等颜色空间更符合人类视觉,也更容易调整:想要调节

亮度

就调节

L通道

,想要调节

色彩平衡

就分别调

a



b



四、OpenMV图像处理方法



1.感光元件

OpenMV中使用sensor模块来设置感光元件的参数,具体使用方法如下:

import sensor#引入感光元件的模块

# 设置摄像头
sensor.reset()#初始化感光元件
sensor.set_pixformat(sensor.RGB565)#设置为彩色
sensor.set_framesize(sensor.QVGA)#设置图像的大小
sensor.skip_frames()#跳过n张照片,在更改设置后,跳过一些帧,等待感光元件变稳定。

# 一直拍照
while(True):
    img = sensor.snapshot()#拍摄一张照片,img为一个image对象



自动增益/白平衡/曝光

  • sensor.set_auto_gain()

    自动增益开启(True)或者关闭(False)。在使用颜色追踪时,需要关闭自动增益。
  • sensor.set_auto_whitebal()

    自动白平衡开启(True)或者关闭(False)。在使用颜色追踪时,需要关闭自动白平衡。
  • sensor.set_auto_exposure(enable[, exposure_us])

    • enable 打开(True)或关闭(False)自动曝光。默认打开。
    • 如果 enable 为 False,则可以用 exposure_us 设置一个固定的曝光时间(以微秒为单位)。



窗口ROI

ROI:Region Of Interest,图像处理中的术语“感兴趣区”。就是在要处理的图像中提取出的要处理的区域。

  • sensor.set_windowing(roi)

    roi的格式是(x, y, w, h)

    • x:ROI区域中左上角的x坐标
    • y:ROI区域中左上角的y坐标
    • w:ROI的宽度
    • h:ROI的高度



2.画图

视觉系统通常需要给使用者提供一些反馈信息。直接在图像中显示出来,很直观。



画线

  • 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)

    在图像中写字 8×10的像素

    • x,y是坐标。
    • text是要写的字符串。



示例

# 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!")

在这里插入图片描述



3. 寻找色块(颜色识别)

OpenMV通过find_blobs()函数可以找到色块(带颜色的物体),返回色块的位置、高度、像素等信息。



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方法,来判断是什么颜色的色块。
    • x_stride(查找的色块的x方向上最小宽度的像素,默认为2)
    • y_stride(查找的色块的y方向上最小宽度的像素,默认为1)
    • invert(反转阈值,把阈值以外的颜色作为阈值进行查找)
    • area_threshold(面积阈值,如果色块被框起来的面积小于这个值,会被过滤掉)
    • pixels_threshold(像素个数阈值,如果色块像素数量小于这个值,会被过滤掉)
    • merge(合并,如果设置为True,那么合并所有重叠的blob为一个)

      注意:这会合并所有的blob,无论是什么颜色的。如果你想混淆多种颜色的blob,只需要分别调用不同颜色阈值的find_blobs。
    • margin(边界,如果设置为1,那么两个blobs如果间距1一个像素点,也会被合并)



find_blobs()返回值

  • for blob in img.find_blobs(thresholds):

    • blob.rect() 返回这个色块的外框——矩形元组(x, y, w, h)
    • blob.x() 返回色块的外框的x坐标(int)
    • blob.y() 返回色块的外框的y坐标(int)
    • blob.w() 返回色块的外框的宽度w(int)
    • blob.h() 返回色块的外框的高度h(int)
    • blob.pixels() 返回色块的像素数量(int)
    • blob.cx() 返回色块的外框的中心x坐标(int)
    • blob.cy() 返回色块的外框的中心y坐标(int)
    • blob.rotation() 返回色块的旋转角度(单位为弧度)(float)
    • blob.code() 返回一个16bit数字,每一个bit会对应每一个阈值
    • blob.count() 如果merge=True,那么就会有多个blob被合并到一个blob,这个函数返回的就是这个的数量
    • blob.area() 返回色块的外框的面积
    • blob.density() 返回色块的密度



示例

# Single Color RGB565 Blob Tracking Example
#
# This example shows off single color RGB565 tracking using the OpenMV Cam.

import sensor, image, time, math

threshold_index = 0 # 0 for red, 1 for green, 2 for blue

# Color Tracking Thresholds (L Min, L Max, A Min, A Max, B Min, B Max)
# The below thresholds track in general red/green/blue things. You may wish to tune them...
thresholds = [(30, 100, 15, 127, 15, 127), # generic_red_thresholds
              (30, 100, -64, -8, -32, 32), # generic_green_thresholds
              (0, 30, 0, 64, -128, 0)] # generic_blue_thresholds

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
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()

# Only blobs that with more pixels than "pixel_threshold" and more area than "area_threshold" are
# returned by "find_blobs" below. Change "pixels_threshold" and "area_threshold" if you change the
# camera resolution. "merge=True" merges all overlapping blobs in the image.

while(True):
    clock.tick()
    img = sensor.snapshot()
    for blob in img.find_blobs([thresholds[threshold_index]], pixels_threshold=200, area_threshold=200, merge=True):
        # These values depend on the blob not being circular - otherwise they will be shaky.
        if blob.elongation() > 0.5:
            img.draw_edges(blob.min_corners(), color=(255,0,0))
            img.draw_line(blob.major_axis_line(), color=(0,255,0))
            img.draw_line(blob.minor_axis_line(), color=(0,0,255))
        # These values are stable all the time.
        img.draw_rectangle(blob.rect())
        img.draw_cross(blob.cx(), blob.cy())
        # Note - the blob rotation is unique to 0-180 only.
        img.draw_keypoints([(blob.cx(), blob.cy(), int(math.degrees(blob.rotation())))], size=20)
    print(clock.fps())



4. 测距

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

# 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)
# 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

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
        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.



四、串口通道

在项目中,OpenMV通常只用来处理图像数据,而处理结果要传到MCU中做下一步处理。这个过程中需要用到串口来传送数据。

from machine import UART
uart = UART(1, baudrate=115200)     # 初始化串口 波特率设置为115200 TX是B12 RX是B13
uart.write("uart test\r\n")         # 发送字符串
uart_num = 0                        # 定义一个变量
uart_array = [48,49,50,51,52,53,54,55,56,57]  # 定义一个列表 保存数字
uart.write(bytearray(uart_array))   # 发送列表
uart.write(bytearray([0x41]))       # 发送一个十六进制数据
while(True):

    uart_num = uart.any()       # 获取当前串口数据数量
    if(uart_num):
        uart_str = uart.read(uart_num) # 读取串口数据
        uart.write(uart_str)    # 将读取到的串口数据发回
        # uart.read会自动在数据末尾添加\n的操作,如果想去掉可以用strip()去掉
        # 例如 uart_str = uart.read(uart_num).strip()
        # 这样 uart_str得到的数据就不会被自动添加\n



五、条形码、矩形码、二维码



1.条形码

  • find_barcodes([roi])

    查找 roi 内所有一维条形码并返回一个 image.barcode 对象列表
# 条形码识别例程
#
# 这个例子展示了使用OpenMV Cam M7来检测条形码是多么容易。条形码检测不适用于M4相机。

import sensor, image, time, math

sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE)
sensor.set_framesize(sensor.VGA) # High Res!
sensor.set_windowing((640, 80)) # V Res of 80 == less work (40 for 2X the speed).
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False)  # 必须关闭此功能,以防止图像冲洗…
sensor.set_auto_whitebal(False)  # 必须关闭此功能,以防止图像冲洗…
clock = time.clock()

# 条形码检测可以在OpenMV Cam的OV7725相机模块的640x480分辨率下运行。
# 条码检测也将在RGB565模式下工作,但分辨率较低。 也就是说,
# 条形码检测需要更高的分辨率才能正常工作,因此应始终以640x480的灰度运行。

def barcode_name(code):
    if(code.type() == image.EAN2):
        return "EAN2"
    if(code.type() == image.EAN5):
        return "EAN5"
    if(code.type() == image.EAN8):
        return "EAN8"
    if(code.type() == image.UPCE):
        return "UPCE"
    if(code.type() == image.ISBN10):
        return "ISBN10"
    if(code.type() == image.UPCA):
        return "UPCA"
    if(code.type() == image.EAN13):
        return "EAN13"
    if(code.type() == image.ISBN13):
        return "ISBN13"
    if(code.type() == image.I25):
        return "I25"
    if(code.type() == image.DATABAR):
        return "DATABAR"
    if(code.type() == image.DATABAR_EXP):
        return "DATABAR_EXP"
    if(code.type() == image.CODABAR):
        return "CODABAR"
    if(code.type() == image.CODE39):
        return "CODE39"
    if(code.type() == image.PDF417):
        return "PDF417"
    if(code.type() == image.CODE93):
        return "CODE93"
    if(code.type() == image.CODE128):
        return "CODE128"

while(True):
    clock.tick()
    img = sensor.snapshot()
    codes = img.find_barcodes()
    for code in codes:
        img.draw_rectangle(code.rect())
        print_args = (barcode_name(code), code.payload(), (180 * code.rotation()) / math.pi, code.quality(), clock.fps())
        print("Barcode %s, Payload \"%s\", rotation %f (degrees), quality %d, FPS %f" % print_args)
    if not codes:
        print("FPS %f" % clock.fps())



2.矩形码

# 矩形码识别例程
#
# 这个例子展示了使用OpenMV Cam M7来检测数据矩阵是多么容易。数据矩阵检测不适用于M4相机。

import sensor, image, time, math

sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time = 2000)
sensor.set_auto_gain(False)  # 必须关闭此功能,以防止图像冲洗…
sensor.set_auto_whitebal(False)  # 必须关闭此功能,以防止图像冲洗…
clock = time.clock()

while(True):
    clock.tick()
    img = sensor.snapshot()
    img.lens_corr(1.8) # 1.8的强度对于2.8mm的镜头来说是好的。

    matrices = img.find_datamatrices()
    for matrix in matrices:
        img.draw_rectangle(matrix.rect(), color = (255, 0, 0))
        print_args = (matrix.rows(), matrix.columns(), matrix.payload(), (180 * matrix.rotation()) / math.pi, clock.fps())
        print("Matrix [%d:%d], Payload \"%s\", rotation %f (degrees), FPS %f" % print_args)
    if not matrices:
        print("FPS %f" % clock.fps())



3.二维码

# 二维码例程
#
# 这个例子展示了OpenMV Cam使用镜头校正来检测QR码的功能(请参阅qrcodes_with_lens_corr.py脚本以获得更高的性能)。
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)  # 必须关闭此功能,以防止图像冲洗…
clock = time.clock()

while(True):
    clock.tick()
    img = sensor.snapshot()
    img.lens_corr(1.8) # 1.8的强度参数对于2.8mm镜头来说是不错的。
    for code in img.find_qrcodes():
        img.draw_rectangle(code.rect(), color = (255, 0, 0))
        print(code)
    print(clock.fps())

参考文章


OpenMV嵌入式图像处理


彻底搞懂Lab 颜色空间



版权声明:本文为python_plus原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。