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 = Nonewhile(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_blobprevious_time = current_time# 显示FPSprint(clock.fps())
如图所示可以清楚的抓取到目标的边框可以计算出像素位移
注意:
1、此算法没有加入滤波算法,请自行添加卡尔曼滤波等算法。
2、次算法仅在开始抓取的时候获取了背景图像,因此建议加入动态背景更新的功能。