v5.0.0

v5.0.0 — крупный релиз. Его главные особенности: переработанное хост-соединение OpenMV Protocol V2, основанный на классах API камеры csi, масштабируемый на платы с несколькими камерами, исполняемая цель симулятора, оценка одиночной позы MoveNet, MicroPython 1.28 и большой набор исправлений для камер, ML и ToF. Релиз также вносит ряд несовместимых изменений API — каждое видимое пользователю изменение с момента v4.8.1 перечислено ниже вместе с точными инструкциями по миграции.

Главное

  • OpenMV Protocol V2. Соединение хост/IDE было переработано с нуля: фреймированное, секвенированное, с проверкой CRC, с мультиплексированными каналами для stdio, предпросмотра потока и пользовательских данных. Новый модуль protocol позволяет скриптам создавать собственные транспорты и каналы данных. См. изменения модуля protocol.

  • Основанный на классах API камеры csi. import sensor заменяется на import csi / csi.CSI, со встроенной поддержкой нескольких камер. См. миграцию на csi.

  • Цель симулятора. Прошивка теперь собирается и запускается под симулятором Arm FVP / QEMU (MPS2/MPS3), включая эмуляцию NPU, ROMFS и PSRAM — скрипты машинного зрения и ML могут работать без подключённого оборудования.

  • Оценка позы MoveNet. Новый постпроцессор MoveNet плюс встроенная модель movenet_singlepose_192.tflite на OpenMV AE3 и N6.

  • MicroPython 1.28 и ulab 6.12.0, инструментарий ST Edge AI 4.0 и вынесенный наружу OpenMV SDK (см. изменения сборки / инструментария).

Новые возможности

  • Модуль protocol — создавайте собственные транспорты и каналы данных из Python: protocol.init(), protocol.register(), protocol.is_active() и класс protocol.ProtocolChannel с send_event(), плюс константы CHANNEL_FLAG_* и CHANNEL_ID_*. Окончательная сигнатура protocol.init() задокументирована в изменениях модуля protocol.

  • protocol.CBORChannel — замороженный пакет-расширение protocol, который сериализует именованные поля в CBOR с виджетами отображения (метка, глубина) и интерактивными элементами управления (переключатель, ползунок, выбор).

  • Интроспекция памяти хоста и потока — новая команда протокола SYS_MEMORY предоставляет IDE статистику памяти времени выполнения по каждому пулу, а новый ioctl потока STREAM_SOURCE позволяет хосту выбирать, какая камера передаёт предпросмотр на платах с несколькими камерами (версия протокола 1.0.1).

  • Потоковая передача с нескольких камерcsi.CSI принимает аргумент stream=, который выбирает, какой датчик передаёт предпросмотр в IDE; заголовок кадра потока теперь несёт сглаженный по EMA показатель FPS, поэтому IDE отображает частоту кадров без шаблонного кода clock.fps(). См. миграцию на csi и доработки csi.

  • Событийный датчик GenX320 — новый пространственно-временной контрастный фильтр (csi.IOCTL_GENX320_SET_STC с режимами csi.GENX320_STC_DISABLE, csi.GENX320_STC_ONLY, csi.GENX320_STC_TRAIL_ONLY и csi.GENX320_STC_TRAIL) и чтение необработанных событий (csi.IOCTL_GENX320_READ_EVENTS_RAW), с новыми примерами скриптов.

  • MoveNet — новый постпроцессор одиночной позы MediaPipe (именованные аргументы threshold, nms_threshold, nms_sigma), возвращающий ((x, y, w, h), score, keypoints) с массивом ключевых точек COCO из 17 суставов; модель movenet_singlepose_192.tflite и пример встроены в AE3 и N6.

  • ml.utils.draw_predictions() — новый необязательный аргумент scores= добавляет уверенность по каждой метке, шрифт и толщина обводки рамки теперь автоматически масштабируются по ширине изображения, а новый режим format="point" рисует центральный маркер для детекторов центральной точки/пика.

  • Новый класс display.TVDisplay (с обобщённым ioctl()) заменяет отдельный модуль tv. См. изменения модуля display.

  • Новый детектор find_line_segments() (ED-Lines) — теперь доступен во всех сборках, с новым аргументом threshold=. См. изменения модуля image.

Прочие изменения и улучшения

  • MicroPython обновлён до 1.28.0 относительно базы v4.8.1. Добавляет высокоскоростной режим SD-карты на H5/H7/N6, тактирование AHB5 в режиме низкого энергопотребления и управляемые выводы JTAG в роли GPIO на OPENMV_AE3.

  • ulab обновлён до 6.12.0 — встроенный оператор % для ndarray (вспомогательная функция ml.utils.mod() удалена; см. изменения библиотеки ML).

  • Инструментарий 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 — текстовый буфер по умолчанию для IDE вырос с 512 до 1024 байт на OpenMV 2/3/4, Nicla Vision, AE3 и N6, поэтому крупные всплески print() не обрезаются.

  • Более плавный поток событий хоста — события NOTIFY для stdout, отправляемые хосту, ограничены не более чем одним на каждое чтение хоста, вместо одного на каждый print(), пересекающий отметку кольцевого буфера.

  • Прерываемые длительные операции — длинные циклы рисования изображений, ожидания GPU (Nema/Dave2D) и NPU теперь обслуживают события через детерминированный интервал, поэтому скрипты остаются отзывчивыми к кнопке Stop в IDE во время тяжёлой работы.

Исправления ошибок

Камеры и датчики:

  • find_apriltags() больше не портит результаты на платах с D-кэшем/GPU (N6, AE3) и теперь работает на AE3.

  • Исправлен вывод изображения Bayer от ISP STM32 N6 после переключения форматов пикселей.

  • Исправлена засветка зелёного при автобалансе белого на ярких сценах и случай неинициализированной статистики AWB первого кадра; поднят порог гамма-ограничения ISP STM32 (с 32 до 63) для более широкого диапазона гаммы/контраста/яркости.

  • Автоэкспозиция PS5520 больше не осциллирует при ярком свете; поведение AEC/AGC у PAG7936 было переработано (объединённое управление, исправленный потолок усиления).

  • Восстановлена загрузка прошивки автофокуса OV5640 на Portenta/Nicla (исправление MIMXRT I2C SUSPEND).

  • Исправлена взаимоблокировка захвата камеры при сочетании ограничения частоты кадров с захватом JPEG (STM32).

  • Чтения GenX320 csi.IOCTL_GENX320_READ_EVENTS_RAW больше не искажают предпросмотр в IDE.

  • FLIR Lepton csi.IOCTL_LEPTON_SET_MODE через csi.CSI.ioctl() теперь работает при вызове с одним аргументом.

Обработка изображений:

  • Исправлено альфа-смешивание draw_image() / blend() при наличии маски.

  • Исправлен порядок бит при кодировании/декодировании 1-битного (BINARY) PNG и декодирование оттенков серого из 1-битного.

  • Исправлены метаданные длительности/FPS записи mjpeg.Mjpeg.

  • Исправлено переполнение стека при программном декодировании JPEG на платах с малым стеком (OpenMV M7).

  • Исправлено автоопределение формата файла JPEG/PNG на не-ARM хостах (симулятор).

Time-of-Flight:

  • tof.read_depth() больше не выбрасывает исключение при временных ошибках измерения дальности и автоматически восстанавливается после сбоев шины; тайм-аут по умолчанию для tof.read_depth() / tof.snapshot() теперь составляет 100 мс (см. изменения tof).

  • Исправлено повреждение данных глубины в нескольких зонах для VL53L5CX / VL53L8CX.

ML и система:

  • NPU теперь корректно очищается при прерывании вывода на N6.

  • Восстановлено пробуждение из глубокого сна / режима ожидания на N6; исправлено зависание перехода в загрузчик на AE3.

  • Исправлены утечки памяти при программном сбросе (STM32 Nema GPU) и преждевременно собранный вспомогательный буфер кадра.

  • Пользовательские каналы протокола Python теперь переживают программную перезагрузку, транспорт USB восстанавливается после сброса шины / зависших конечных точек, а наводнение прерываниями USB SOF исправлено.

Поддержка оборудования и плат

  • OpenMV N6 — включён Ethernet (проводная сеть); NPU AXI SRAM (1,75 МБ) объединена в общий временный пул для большего объёма RAM между выводами; пробуждение из глубокого сна/режима ожидания; встроенные модели TFLite и каскады Haar в ROMFS.

  • OpenMV AE3 — встроенные модели и каскады в ROMFS; cbor2 заморожен в прошивке.

  • Alif (AE3, N6) — пробуждение machine.RTC в режиме низкого энергопотребления.

  • AprilTags высокого разрешенияfind_apriltags() на полном разрешении датчика на AE3, Arduino Giga и Arduino Portenta H7.

  • Цели симулятора — MPS2_AN500 / MPS3_AN547 (Arm FVP / QEMU), с эмуляцией NPU, ROMFS и PSRAM.

Несовместимые изменения API

Видимые пользователю нарушения совместимости API между v4.8.1 и v5.0.0. Область: Python C-модули в modules/ и библиотеки Python в scripts/libraries/.

Каждое изменение помечено своим влиянием:

  • major — большинству скриптов нужны правки.

  • minor — узкий API; затрагивает только использовавшие его скрипты.

  • behavior — тот же API, другие результаты; перепроверьте настроенные скрипты.

  • tooling — затрагивает только сборку из исходников / форки.

Изменения сгруппированы по влиянию в этом порядке — сначала major, затем minor, behavior и tooling. Если вы хотите просто перенести свой код, перейдите к контрольному списку миграции в конце для краткого перечня дел. Каждый хеш коммита ссылается на свой diff на GitHub.

sensor заменён на csi (major)

Каждый официальный пример был переписан, чтобы убрать import sensor в пользу import csi. Устаревший функциональный API уровня модуля (sensor.reset(), sensor.set_pixformat(), …) заменён основанным на классах API csi.CSI, который естественно масштабируется на платы с несколькими камерами (csi0, csi1, …) и требуется для всех новых возможностей (именованный аргумент stream=, потоковая передача с нескольких датчиков, …).

Qstr sensor всё ещё подключён в modules/py_csi.c для обратно совместимых сборок прошивки, но он не получит новых возможностей, и все примеры, документация и код библиотек теперь предполагают csi.

Коммиты: 945c5853c, 61f835b7e

Модуль в класс

До (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()

Пары сеттер/геттер объединены в комбинированные аксессоры

В новом 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() — пропуск кадров встроен в snapshot через его аргументы time= / frames=.

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

Новое в csi.CSI

  • csi.CSI(stream=True|False) — селектор времени конструирования, который выбирает, какой CSI передаёт буфер кадра предпросмотра (заменяет именованный аргумент update= для каждого снимка, см. доработки csi).

  • csi.CSI(cid=N) / csi.devices() — поддержка нескольких CSI для плат с более чем одним датчиком изображения.

Модуль image — пересмотр сигнатур (major)

Модуль image претерпел самое широкое изменение API после csi — изменились сигнатуры рисования, объекты результатов и несколько детекторов.

Аргументы координат должны быть кортежами

modules/py_image.c был переписан поверх mp_arg_parse_all. Все методы рисования / работы с пикселями, которые раньше принимали отдельные позиционные аргументы x, y, ..., теперь требуют упаковки этих координат в один кортеж.

Коммиты: d18bbc472, 0c60c94b9 (PR #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: similarity, statistics, percentile, threshold, line, circle, rect, qrcode, apriltag, datamatrix, barcode, displacement, kptmatch. Доступ к атрибутам без скобок теперь является каноническим.

Коммит: 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)

blob и histogram не изменились — они сохраняют свои существующие типы и аксессоры () (attrtuple не может выразить ленивые вычисляемые значения блоба или принимающие аргументы аксессоры гистограммы).

Переименование haar-параметра find_features

image.Image.find_features()scale_factor= был переименован в scale=.

Коммит: be4c5cd73

get_regression — теперь всегда робастная, добавлен target_size

image.Image.get_regression() теперь всегда использует робастную регрессию (Тейла-Сена). Старый быстрый путь наименьших квадратов был удалён, поэтому именованный аргумент robust= исчез — то, что раньше требовало robust=True, теперь является единственным поведением. Новый именованный аргумент target_size=(w, h) (по умолчанию (80, 60)) масштабирует область интереса по площади перед подгонкой Тейла-Сена с O(N^2), чтобы она всегда выполнялась на разумном размере изображения; конечные точки подогнанной линии отображаются обратно в исходные координаты. Пример linear_regression_robust.py был удалён, а linear_regression_fast.py переименован в linear_regression.py.

Коммиты: c7c2e69a0, 0ff2afa72

find_line_segments — новый алгоритм

image.Image.find_line_segments() — старый детектор LSD был заменён на ED-Lines, и он получил новый именованный аргумент threshold=50. Вывод ранее настроенных скриптов будет отличаться.

Коммиты: 87da2a7b7, 2c47b5735

Библиотека AprilTag заменена

image.Image.find_apriltags() — детектор AprilTag был заменён новой реализацией. Набор семейств изменился:

Удалено

Добавлено

image.TAG25H7, image.ARTOOLKIT

image.TAGCIRCLE21H7, image.TAGCIRCLE49H12, image.TAGCUSTOM48H12, image.TAGSTANDARD41H12, image.TAGSTANDARD52H13

Коммит: e813bada7

Доработка модуля csi (minor)

Небольшие доработки csi поверх миграции на csi.

snapshot(update=…) удалён

Именованный аргумент update у csi.CSI.snapshot() исчез. Чтобы устройство CSI не передавало буфер кадра предпросмотра, откажитесь от этого во время конструирования:

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

Коммиты: 9a8077827, 26b79a2c5

Аргумент expand у framebuffers() удалён

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

Коммиты: 8a0635e8c, 95a290607

protocol.poll() удалён

Задача протокола теперь планируется внутренне. Вызовы protocol.poll() будут выбрасывать AttributeError.

Коммит: 8a0635e8c

Аргумент конфигурации soft_reboot удалён

protocol.init() — аргумент soft_reboot исчез. Все текущие транспорты переносят программные перезагрузки, поэтому это поведение теперь безусловно.

Коммит: 0bf766aa2

Модули display (minor)

Вывод на ТВ теперь идёт через объект display.TVDisplay вместо отдельного модуля tv. display также получил обобщённый ioctl().

Коммиты: f0accb389, 1a5a87121, 920c097a0, 9eac55098

Модуль tof (behavior)

Тот же API, что и раньше; изменились значения по умолчанию и обработка ошибок. См. tof.

Изменён тайм-аут по умолчанию

tof.read_depth() и tof.snapshot() (вызванные с timeout=-1) теперь по умолчанию ждут 100 мс вместо бесконечного ожидания. Передайте явное большее значение, если вам нужно прежнее поведение.

Коммит: b6772b80d

Автоматическое восстановление

Драйвер теперь жёстко сбрасывает шину I2C и датчик при ошибках измерения дальности/тайм-аута. Примеры больше не вызывают tof.reset() в своих обработчиках исключений — пользовательский код, который делал ручное восстановление, должен убрать его (оно будет конфликтовать с новым автовосстановлением).

Коммиты: b6772b80d, 80ffaa5c3

Библиотека ML (behavior)

Тот же API, другие числа — перепроверьте любой настроенный конвейер ML.

Предобработка теперь растягивает вместо леттербоксинга

Normalization теперь использует image.SCALE_ASPECT_IGNORE (растяжение) вместо image.SCALE_ASPECT_EXPAND (леттербокс). Постобработка NMS также переключилась на независимое масштабирование по x/y.

Примечание

Влияние. Детекторы в стиле YOLO и регрессоры ключевых точек обычно улучшаются. Примеры BlazeFace, BlazePalm, FaceLandmarks и HandLandmarks теперь требуют ручной квадратной обрезки входной области интереса — примеры скриптов были обновлены; пользовательский код должен сделать то же самое.

Коммит: 68dc29a33

Вспомогательная функция ml.utils.mod() удалена

ulab 6.12.0 поддерживает % для ndarray нативно. Код, который импортировал mod из ml.utils, должен использовать a % b.

Коммиты: 35ece5728, 82fbd858c

Сборка / инструментарий (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. Переименуйте timer_mspoll_ms в вызовах protocol.init(); удалите protocol.poll() и soft_reboot= (изменения модуля protocol).

  6. Для рабочих процессов ML: пересмотрите любую модель, которой требовался леттербоксированный вход (изменения библиотеки ML).