1、测试平台:OpenMV4H7Plus开发板
使用的相机是 MT9V034 相机对应为752x480黑白图像,为全局快门
2、测速的时候,仅选取最大物体的抓取,这里采用了几个步骤:
①、直接计算灰度的帧差
②、对帧差进行阈值处理以获取motion mask
③、绘制出motion mask的轮廓和边界
④、通过与上一帧的坐标位置计算移动的像素速度(可以计算中心的坐标或者边界坐标(当物体过大不在整个相机的视野中有用),这里简单的延时中心坐标)
import sensor, image, time, math
# 初始化摄像头
sensor.reset()
sensor.set_pixformat(sensor.GRAYSCALE) # 设置为灰度模式
sensor.set_framesize(sensor.QVGA) # 设置帧大小
sensor.skip_frames(time = 2000) # 跳过前2秒的帧
# 初始化定时器
clock = time.clock()
# 捕获若干帧用于计算背景帧(将捕获的图像与当前的背景帧进行混合,更新背景帧)
background_frame = sensor.snapshot().copy()
num_background_frames = 50 # 捕获50帧用于背景计算
for i in range(num_background_frames):
img = sensor.snapshot()
background_frame = background_frame.blend(img, alpha=128)
# 初始化前一帧的位置为None
previous_blob = None
previous_time = None
while(True):
clock.tick()
# 捕获当前帧
current_frame = sensor.snapshot()
# 计算当前帧和背景帧的灰度差
frame_difference = current_frame.difference(background_frame)
# 对帧差进行阈值处理,生成运动掩码
motion_mask = frame_difference.binary([(50, 255)]) # 阈值设置为50
# 查找运动掩码中的轮廓
blobs = motion_mask.find_blobs([(50, 255)], pixels_threshold=100, area_threshold=100, merge=True)
# 如果找到轮廓,查找最大的轮廓
if blobs:
largest_blob = max(blobs, key=lambda b: b.pixels())
# 获取边界框
x, y, w, h = largest_blob.rect()
# 在当前帧上绘制边界框
current_frame.draw_rectangle(x, y, w, h)
print(f"x: {x}, y: {y}")
# 绘制中心点
current_frame.draw_cross(largest_blob.cx(), largest_blob.cy())
# 计算边框移动速度
current_time = time.ticks_ms()
if previous_blob and previous_time:
dx = largest_blob.cx() - previous_blob.cx()
dy = largest_blob.cy() - previous_blob.cy()
dt = time.ticks_diff(current_time, previous_time) / 1000.0 # 时间差转换为秒
# 计算x和y方向的速度
speed_x = dx / dt # x方向速度,单位为像素/秒
speed_y = dy / dt # y方向速度,单位为像素/秒
print("Speed X: %.2f pixels/sec" % speed_x)
print("Speed Y: %.2f pixels/sec" % speed_y)
# 更新前一帧的位置和时间
previous_blob = largest_blob
previous_time = current_time
# 显示FPS
print(clock.fps())
如图所示可以清楚的抓取到目标的边框可以计算出像素位移
注意:
1、此算法没有加入滤波算法,请自行添加卡尔曼滤波等算法。
2、次算法仅在开始抓取的时候获取了背景图像,因此建议加入动态背景更新的功能。