v5.0.0

v5.0.0 是一个重大版本。其核心亮点包括:重新构建的 OpenMV Protocol V2 主机链路、可扩展至多摄像头开发板的基于类的 csi 摄像头 API、可运行的 simulator(模拟器)目标、MoveNet 单姿态估计、MicroPython 1.28,以及一大批针对摄像头、机器学习和 ToF 的修复。它还带来了若干破坏性的 API 变更——自 v4.8.1 以来所有用户可见的变更都列在下方,并附有具体的迁移方法。

亮点

  • OpenMV Protocol V2。 主机/IDE 链路从头重建:采用分帧、序列化、CRC 校验,并为 stdio、流预览和用户数据提供多路复用通道。新的 protocol 模块允许脚本创建自己的传输层和数据通道。参见 protocol 模块变更

  • 基于类的 csi 摄像头 API。 import sensor 变为 import csi / csi.CSI,并原生支持多摄像头。参见 csi 迁移

  • Simulator 目标。 固件现在可以在 Arm FVP / QEMU 模拟器(MPS2/MPS3)下构建并运行,包括 NPU、ROMFS 和 PSRAM 仿真——视觉和机器学习脚本无需连接硬件即可运行。

  • MoveNet 姿态估计。 新增 MoveNet 后处理器,并在 OpenMV AE3 和 N6 上随附 movenet_singlepose_192.tflite 模型。

  • MicroPython 1.28ulab 6.12.0ST Edge AI 4.0 工具链,以及外置化的 OpenMV SDK(参见 构建/工具链变更)。

新功能

其他变更与改进

  • MicroPython 已从 v4.8.1 基线更新至 1.28.0。 增加了 H5/H7/N6 上的高速 SD 卡模式、低功耗模式下的 AHB5 时钟,以及 OPENMV_AE3 上可作为 GPIO 控制的 JTAG 引脚。

  • ulab 已更新至 6.12.0 —— 在 ndarray 上原生支持 % 运算符(ml.utils.mod() 辅助函数已移除;参见 机器学习库变更)。

  • ST Edge AI 工具链已更新至 4.0 —— 影响设备端 ST 模型的编译和部署。

  • ml.Model —— load_to_fb 关键字参数已移除;模型内存现由统一分配器自动管理。

  • image.Image.scale() 原地缩放 —— 原地放大图像(例如 img.scale(x_scale=2.0, y_scale=2.0))现在会扩展帧缓冲区以适应,而不会失败。

  • 更大的 stdio 缓冲区 —— 在 OpenMV 2/3/4、Nicla Vision、AE3 和 N6 上,发送到 IDE 的默认文本缓冲区从 512 字节增加到 1024 字节,因此较大的 print() 突发输出不会被截断。

  • 更流畅的主机事件流 —— 发送到主机的 stdout NOTIFY 事件现在被限制为每次主机读取最多一个,而不是每次 print() 越过环形缓冲区水位线时一个。

  • 可中断的长操作 —— 长时间的图像绘制、GPU(Nema/Dave2D)和 NPU 等待循环现在会按确定的间隔处理事件,因此在繁重工作期间脚本仍能响应 IDE 的 Stop 按钮。

错误修复

摄像头与传感器:

  • find_apriltags() 在 D-cache/GPU 开发板(N6、AE3)上不再损坏结果,并且现在可在 AE3 上正常工作。

  • 修复了切换像素格式后 STM32 N6 ISP 的 Bayer 图像输出。

  • 修复了明亮场景下绿色自动白平衡过曝的问题以及首帧 AWB 统计数据未初始化的情况;提高了 STM32 ISP 伽马钳位上限(从 32 提高到 63),以获得更宽的伽马/对比度/亮度范围。

  • PS5520 自动曝光在强光下不再振荡;PAG7936 的 AEC/AGC 行为经过重新设计(合并控制、修正增益上限)。

  • 恢复了 Portenta/Nicla 上的 OV5640 自动对焦固件上传(MIMXRT I2C SUSPEND 修复)。

  • 修复了帧率限制与 JPEG 捕获结合时出现的摄像头捕获死锁(STM32)。

  • GenX320 的 csi.IOCTL_GENX320_READ_EVENTS_RAW 读取不再扰乱 IDE 预览。

  • FLIR Lepton 通过 csi.CSI.ioctl() 调用的 csi.IOCTL_LEPTON_SET_MODE 现在在仅传入单个参数时也能正常工作。

图像处理:

  • 修复了提供掩码时 draw_image() / blend() 的 alpha 混合问题。

  • 修复了 1 位(BINARY)PNG 编码/解码的位序问题以及从 1 位解码灰度图像的问题。

  • 修复了 mjpeg.Mjpeg 录制时长/FPS 元数据。

  • 修复了小栈开发板(OpenMV M7)上的软件 JPEG 解码栈溢出问题。

  • 修复了非 ARM 主机(模拟器)上的 JPEG/PNG 文件格式自动检测。

Time-of-Flight:

机器学习与系统:

  • 在 N6 上中断推理时,NPU 现在会被正确清理。

  • 恢复了 N6 上的深度睡眠/待机唤醒;修复了 AE3 跳转到 bootloader 时的挂起问题。

  • 修复了软复位时的内存泄漏(STM32 Nema GPU)以及辅助帧缓冲区被过早回收的问题。

  • 自定义的 Python 协议通道现在可以在软重启后保留,USB 传输层能够从总线复位/端点停滞中恢复,USB SOF 中断泛滥的问题也已修复。

硬件与开发板支持

  • OpenMV N6 —— 启用以太网(有线网络);将 NPU AXI SRAM(1.75 MB)合并到共享的瞬态内存池,从而在两次推理之间获得更多 RAM;深度睡眠/待机唤醒;在 ROMFS 中随附 TFLite 模型和 Haar 级联分类器。

  • OpenMV AE3 —— 在 ROMFS 中随附模型和级联分类器;将 cbor2 固化进固件。

  • Alif(AE3、N6) —— 低功耗 machine.RTC 唤醒。

  • 高分辨率 AprilTag —— 在 AE3、Arduino Giga 和 Arduino Portenta H7 上提供全传感器分辨率的 find_apriltags()

  • Simulator 目标 —— MPS2_AN500 / MPS3_AN547(Arm FVP / QEMU),带有 NPU、ROMFS 和 PSRAM 仿真。

破坏性 API 变更

v4.8.1 与 v5.0.0 之间用户可见的 API 破坏性变更。范围:modules/ 中的 Python C 模块和 scripts/libraries/ 中的 Python 库。

每项变更都标注了其影响:

  • major(重大)—— 大多数脚本需要修改。

  • minor(次要)—— 较窄的 API;仅影响用到它的脚本。

  • behavior(行为)—— 同样的 API,不同的结果;请重新检查已调优的脚本。

  • tooling(工具链)—— 仅影响从源码构建/下游分支。

变更按影响顺序分组—— 先是 major,然后是 minorbehaviortooling。如果你只想移植代码,请跳到末尾的 迁移检查清单 查看精简的待办列表。每个提交哈希都链接到其在 GitHub 上的 diff。

sensorcsi 取代 (major)

每个官方示例都已重写,弃用 import sensor 而改用 import csi。旧版模块级函数式 API(sensor.reset()sensor.set_pixformat()……)已被基于类的 csi.CSI API 取代,后者可自然扩展到具有多个摄像头的开发板(csi0csi1……),并且是所有新功能的必备条件(stream= 关键字参数、多传感器流……)。

为向后兼容的固件构建,sensor qstr 仍在 modules/py_csi.c 中保留,但它不会获得新功能,并且所有示例、文档和库代码现在都假定使用 csi

提交: 945c5853c61f835b7e

从模块到类

之前(sensor):

import sensor
sensor.reset()
sensor.set_pixformat(sensor.RGB565)
sensor.set_framesize(sensor.QVGA)
sensor.skip_frames(time=2000)
img = sensor.snapshot()

之后(csi):

import csi
csi0 = csi.CSI()
csi0.reset()
csi0.pixformat(csi.RGB565)
csi0.framesize(csi.QVGA)
csi0.snapshot(time=2000)
img = csi0.snapshot()

setter/getter 对合并为统一访问器

在新 API 中,不带参数调用方法时返回当前值;带值调用时则进行设置。set_*/get_* 前缀已被去除。在多余的情况下方法名也去掉了 ing 后缀(windowingwindow)。新 API 列链接到参考文档。

sensor(旧)

csi.CSI(新)

set_pixformat(fmt) / get_pixformat()

pixformat([fmt])

set_framesize(sz) / get_framesize()

framesize([sz])

set_framerate(fps) / get_framerate()

framerate([fps])

set_windowing(roi) / get_windowing()

window([roi])

set_framebuffers(n) / get_framebuffers()

framebuffers([n])

set_gainceiling(g)

gainceiling([g])

set_brightness(v)

brightness([v])

set_contrast(v)

contrast([v])

set_saturation(v)

saturation([v])

set_quality(v)

quality([v])

set_colorbar(b)

colorbar([b])

set_special_effect(e)

special_effect([e])

set_lens_correction(...)

lens_correction(...)

set_hmirror(b) / get_hmirror()

hmirror([b])

set_vflip(b) / get_vflip()

vflip([b])

set_transpose(b) / get_transpose()

transpose([b])

set_auto_rotation(b) / get_auto_rotation()

auto_rotation([b])

set_auto_gain(b, [db, ceiling]) / get_gain_db()

auto_gain(...) / gain_db()

set_auto_exposure(b, [us]) / get_exposure_us()

auto_exposure(...) / exposure_us()

set_auto_whitebal(b, [rgb]) / get_rgb_gain_db()

auto_whitebal(...) / rgb_gain_db()

set_auto_blc(b, [regs]) / get_blc_regs()

auto_blc(...) / blc_regs()

set_color_palette(p) / get_color_palette()

color_palette([p])

set_frame_callback(cb)

frame_callback(cb)

set_vsync_callback(cb)

vsync_callback(cb)

get_id()

cid()

没有直接对应项的函数

sensor(已移除)

改用的替代方案

sensor.alloc_extra_fb(w, h, pixfmt) / sensor.dealloc_extra_fb()

image.Image (w, h, pixfmt) —— 一个常规的堆分配图像。帧缓冲区不再被切分用作用户缓冲区。

sensor.skip_frames(time=..., frames=...)

csi.CSI.snapshot() —— 跳帧功能已通过其 time= / frames= 参数折叠进 snapshot

sensor.disable_delays(...) / sensor.disable_full_flush(...)

已移入 csi.CSI 构造函数:csi.CSI(delays=False) / csi.CSI(fflush=False)

sensor.get_frame_available()

csi.CSI.readable()

sensor.get_fb()

已移除。csi.CSI.snapshot() 返回的图像即为规范句柄。

sensor.set_framebuffers(n, expand=True)

csi.CSI.framebuffers() —— expand 参数已移除(参见 csi 后续改进)。

New on csi.CSI

  • csi.CSI(stream=True|False) —— 一个构造时选择器,用于选定由哪个 CSI 馈送预览帧缓冲区(取代了逐快照的 update= 关键字参数,参见 csi 后续改进)。

  • csi.CSI(cid=N) / csi.devices() —— 为具有多个图像传感器的开发板提供多 CSI 支持。

image 模块 —— 签名全面调整 (major)

csi 之后,image 模块经历了最广泛的 API 变更—— 绘制方法签名、结果对象以及若干检测器都发生了变化。

坐标参数必须为元组

modules/py_image.c 已基于 mp_arg_parse_all 重写。所有此前接受独立 x, y, ... 位置参数的绘制/像素方法,现在都要求将这些坐标打包进单个元组。

提交: d18bbc4720c60c94b9PR #3061

之前

之后

img.draw_arrow(x0, y0, x1, y1, color=...)

img.draw_arrow((x0, y0, x1, y1), color=...)

img.draw_line(x0, y0, x1, y1, ...)

img.draw_line((x0, y0, x1, y1), ...)

img.draw_cross(x, y, ...)

img.draw_cross((x, y), ...)

img.draw_circle(x, y, r, ...)

img.draw_circle((x, y, r), ...)

img.draw_rectangle(x, y, w, h, ...)

img.draw_rectangle((x, y, w, h), ...)

img.draw_string(x, y, "txt", ...)

img.draw_string((x, y), "txt", ...)

img.draw_ellipse(x, y, rx, ry, rot, ...)

img.draw_ellipse((x, y, rx, ry, rot), ...)

img.flood_fill(x, y, ...)

img.flood_fill((x, y), ...)

img.get_pixel(x, y, rgbtuple=...)

img.get_pixel((x, y), rgbtuple=...)

img.set_pixel(x, y, color)

img.set_pixel((x, y), color)

它们都是 image.Image 的方法。

结果对象转换为 attrtuple

以下类型现在是 MicroPython 的 attrtuple 对象:similaritystatisticspercentilethresholdlinecirclerectqrcodeapriltagdatamatrixbarcodedisplacementkptmatch。现在以不带括号的属性访问方式为规范。

提交: 3399d302e

之前(方法风格):

img.draw_cross(match.cx(), match.cy())
img.draw_rectangle(blob.rect())

之后(属性风格):

img.draw_cross((match.cx, match.cy))
img.draw_rectangle(blob.rect)

blobhistogram 保持不变—— 它们保留各自现有的类型和 () 访问器(attrtuple 无法表达色块的惰性计算值或直方图带参数的访问器)。

find_features 的 haar 参数重命名

image.Image.find_features() —— scale_factor= 已重命名为 scale=

提交: be4c5cd73

get_regression —— 现在始终采用稳健回归,新增 target_size

image.Image.get_regression() 现在始终使用稳健(Theil-Sen)回归。旧的快速最小二乘路径已移除,因此 robust= 关键字也随之消失—— 过去需要 robust=True 才能得到的行为现在是唯一的行为。新增的 target_size=(w, h) 关键字参数(默认 (80, 60))会在执行 O(N^2) 的 Theil-Sen 拟合之前按面积缩小 ROI,使其始终在合理的图像尺寸上运行;拟合出的直线端点会被映射回源坐标。linear_regression_robust.py 示例已删除,linear_regression_fast.py 已重命名为 linear_regression.py

提交: c7c2e69a00ff2afa72

find_line_segments —— 新算法

image.Image.find_line_segments() —— 旧的 LSD 检测器已被 ED-Lines 取代,并新增了 threshold=50 关键字参数。此前已调优脚本的输出将有所不同。

提交: 87da2a7b72c47b5735

AprilTag 库已替换

image.Image.find_apriltags() —— AprilTag 检测器已替换为新的实现。族集合发生了变化:

提交: e813bada7

csi 模块后续改进 (minor)

csi 迁移 基础上的较小型 csi 后续改进。

snapshot(update=...) 已移除

csi.CSI.snapshot() 上的 update 关键字参数已移除。要让某个 CSI 设备不馈送预览帧缓冲区,请在构造时选择退出:

csi0 = csi.CSI(stream=False)                  # was: csi0.snapshot(update=False)
csi1.snapshot(blocking=False, image=fir_img)  # was: ...(update=False, ...)

提交: 9a807782726b79a2c5

framebuffers() 的 expand 参数已移除

csi.CSI.framebuffers() —— 第三个位置参数(expand)已移除;签名现在为 framebuffers([count])

提交: 86cb3a5de

protocol 模块 (minor)

仅影响直接驱动主机链路的脚本。参见 protocol

timer_ms 重命名为 poll_ms

protocol.init() —— timer_ms 参数已重命名为 poll_ms

protocol.init(..., poll_ms=10)   # was: timer_ms=10

提交: 8a0635e8c95a290607

protocol.poll() 已移除

协议任务现在在内部调度。调用 protocol.poll() 将抛出 AttributeError

提交: 8a0635e8c

soft_reboot 配置参数已移除

protocol.init() —— soft_reboot 参数已移除。所有当前传输层都能容忍软重启,因此该行为现在是无条件的。

提交: 0bf766aa2

display 模块 (minor)

TV 输出现在通过 display.TVDisplay 对象进行,而非独立的 tv 模块。display 还新增了一个通用的 ioctl()

提交: f0accb3891a5a87121920c097a09eac55098

tof 模块 (behavior)

API 与之前相同;默认值和错误处理发生了变化。参见 tof

默认超时已更改

tof.read_depth()tof.snapshot()(以 timeout=-1 调用时)现在默认为 100 ms,而不再无限期等待。如果你需要旧的行为,请显式传入更大的值。

提交: b6772b80d

自动恢复

驱动程序现在会在出现测距/超时错误时对 I2C 总线和传感器进行硬复位。示例不再在其异常处理程序中调用 tof.reset()—— 此前进行手动恢复的用户代码应将其移除(否则会与新的自动恢复机制冲突)。

提交: b6772b80d80ffaa5c3

机器学习库 (behavior)

API 相同,数值不同—— 请重新检查任何已调优的机器学习流程。

预处理现在改为拉伸而非加黑边

Normalization 现在使用 image.SCALE_ASPECT_IGNORE(拉伸)而非 image.SCALE_ASPECT_EXPAND(加黑边)。NMS 后处理也改为独立的 x/y 缩放。

备注

影响。 YOLO 风格的检测器和关键点回归器通常会有所改善。BlazeFaceBlazePalmFaceLandmarksHandLandmarks 示例现在需要对输入 ROI 进行手动方形裁剪—— 示例脚本已更新;自定义用户代码也必须照做。

提交: 68dc29a33

ml.utils.mod() 辅助函数已移除

ulab 6.12.0 原生支持在 ndarray 上使用 %。从 ml.utils 导入 mod 的代码必须改用 a % b

提交: 35ece572882fbd858c

构建/工具链 (tooling)

这些都不会影响 MicroPython 脚本。现在从源码构建固件需要外部 OpenMV SDK(1.6.0,此前在源码树内)。若干源码树内的构建工具已被移除,N6 已迁移到 TinyUSB 协议栈;下游分支应查阅 固件仓库 的历史记录—— 尤其是 file_open() 签名去掉了其 buffered 参数。

迁移检查清单

要干净地移植到 v5.0.0,典型的工作是:

  1. import sensor 替换为 import csi; csi0 = csi.CSI(),并将每个 set_*/get_* 调用转换为其对应的 csi.CSI 访问器(csi 迁移)。

  2. 将传给 img.draw_*get_pixel()set_pixel() 的坐标参数包装进元组(image 模块变更)。

  3. 如果你想采用新的惯用形式,请从 attrtuple 结果访问器中去掉 ();或者保持旧风格不变,因为 attrtuple 仍然支持可调用的访问器(image 模块变更)。

  4. 审查 find_line_segments()get_regression() 以及任何 find_apriltags() 族的选择(image 模块变更)。

  5. protocol.init() 调用中将 timer_mspoll_ms 重命名;移除 protocol.poll()soft_reboot=protocol 模块变更)。

  6. 对于机器学习工作流:重新审视任何需要加黑边输入的模型(机器学习库变更)。