v5.0.1#

v5.0.1 — это корректирующий выпуск поверх v5.0.0: устаревший модуль sensor становится слоем совместимости на Python поверх csi, изображения, загруженные в буфер кадра, теперь показываются в предпросмотре как кадры камеры, кодировщики JPEG избавились от ограничения выходного буфера в 1 МБ и корректно обрабатывают переполнение, а также есть набор исправлений камер, протокола, сети и библиотеки ML. Он не вносит несовместимых изменений API для скриптов, написанных под csi; несколько изменений поведения перечислены в разделе несовместимые изменения API.

Главное#

  • Модуль sensor теперь является замороженным модулем Python, построенным поверх csi. При импорте он выводит предупреждение об устаревании; несколько функций, которые модуль csi не может поддерживать, теперь вызывают OSError. См. изменения модуля sensor.

  • Загруженные изображения показываются в предпросмотре как кадры камеры. Изображение, помещённое в буфер кадра с copy_to_fb=True (image.Image, image.ImageIO.read(), fir.snapshot(), tof.snapshot()), сбрасывается в IDE — вместе со всем, что на нём нарисовано, — когда следующее изображение перезаписывает буфер кадра, а не немедленно. См. изменения предпросмотра.

  • Переработка кодировщика JPEG. Ограничение выходного буфера в 1 МБ убрано (размер буфера определяется свободной памятью), переполнение как на программном, так и на аппаратном пути обрабатывается вместо записи усечённых файлов, а сохранение сжатого изображения под другим сжатым расширением вызывает исключение вместо записи мусора.

  • Новая protocol.poll() и шесть новых виджетов CBOR (text, lineedit, pushbutton, spinbox, radio, waveform) для protocol.CBORChannel.

  • Постпроцессор YOLO Pro, поддержка FLIR Lepton 3.1R / UW, пакетные чтения IMU, CAN на OpenMV N6 и цель симулятора с поддержкой сети.

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

  • YoloPro — новый постпроцессор для моделей обнаружения объектов Edge Impulse YOLO Pro, плюс пример yolo_pro_detector.py. (f3f150ebd, ea7bbb398)

  • protocol.poll() — выполняет одну итерацию задачи протокола по требованию, для собственных транспортов, которые не обслуживаются USB-прерыванием или таймером poll_ms. protocol.init() теперь также можно вызвать повторно для переинициализации стека. (c00c215f9, f849ffb1b)

  • Больше виджетов канала CBOR — protocol.CBORChannel.add() получает text (статическая строка), lineedit (записываемая строка), pushbutton (одномоментное действие), spinbox (пошаговый числовой ввод), radio (группа вариантов) и waveform (одномерный временной ряд с аргументами sample_rate, series и typecode; для потоковой передачи присваивайте байты чередующихся отсчётов). (8016d29ba)

  • csi.CUSTOM — csi.CSI.framesize() теперь возвращает пригодную к использованию константу после установки пользовательского разрешения (w, h) вместо безымянного целого числа. (af8841654)

  • Пакетное чтение IMU — imu.__read_reg() принимает необязательный записываемый буфер и заполняет его из последовательных регистров за одну транзакцию. (244ca480a)

  • FLIR Lepton 3.1R и Lepton UW распознаются драйвером Lepton, включая их радиометрические режимы усиления. (0fc356632)

  • Сеть в симуляторе — цель QEMU MPS2_AN500 теперь имеет lwIP и сетевой адаптер в пользовательском режиме, с замороженными requests, mqtt и sensor, а также сетевой модульный тест. (23546dfb1, 61d187305, 15096c3a2)

  • Пример OpenAI-совместимого API — openai_compatible.py делает снимок в JPEG и отправляет его на конечную точку chat-completions для описания сцены. (79033c6aa)

  • Примеры SX126x LoRa — драйвер lora-sx126x из micropython-lib (вместе с lora-sync / lora-async) заморожен в прошивку OpenMV RT1062, с примерами отправителя/приёмника/пинг-понга/потока изображений для подключения модуля SX1261 или SX1262 к шине SPI. Это поддержка, предоставленная сообществом; OpenMV не продаёт оборудование LoRa. (19576e1b1)

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

  • Библиотека requests переписана заново — ответы с фрагментированной передачей (chunked) декодируются, добавлен аргумент timeout (по умолчанию 5 с), тела JSON и строк корректно сериализуются/кодируются, заголовки разбираются без учёта регистра, а строка состояния — по позиции, словарь headers вызывающей стороны копируется (так что auth больше не просачивается в последующие запросы), а тело читается блоками в bytearray. (889f0b096)

  • mqtt импортирует ssl отложенно, поэтому модуль и обычные (без TLS) соединения работают на сборках без поддержки SSL. (c2e0899e8)

  • Размер выходного буфера JPEG определяется свободной памятью вместо фиксированного ограничения в 1 МБ; кодировщики обрезают буфер до размера закодированных данных перед записью изображения, поэтому снимки с крупных датчиков при высоком качестве больше не завершаются ошибкой. (aa1ca6776)

  • Чистка постобработки ML — генерация ограничивающих рамок стандартизирована в постпроцессорах Darknet, Edge Impulse и Ultralytics, а выход YOLOv8 транспонируется после порогового отбора, так что он хранится по одной строке на обнаружение, как и у других моделей. (b5c7853f2, c45f99cad)

  • Безопасное выключение PAG7936 — новый флаг остановки датчика переводит PAG7936 в спящий режим перед переключением RESET/PWDN, что исправляет зависания при использовании датчика на удлинительном кабеле. Драйвер также выбирает набор регистров MIPI CSI-2 или параллельного интерфейса по I2C-адресу датчика во время выполнения, а не во время сборки. (10026530c, f6acf14ec, 5f0251c74)

  • Регулировка темпа воспроизведения ImageIO теперь обслуживает ожидающие события во время ожидания межкадрового интервала вместо сна в WFI. (a54790193)

  • Обновления подмодуля MicroPython — полная поддержка сети в порте QEMU, machine.mem_backup на STM32 через резервную SRAM/регистры BKP, аппаратное управление потоком SDIO оставлено отключённым на STM32F4, а также переиспользование атрибутов MPU для некэшируемых областей. (31ada5626, ab61d27a6, 06bddf13a)

  • differential-translation.py захватывает кадры через свой объект csi.CSI вместо устаревшего модуля sensor, а интервалы между импортами в примерах нормализованы. (68c866e7f, 9ceff4513)

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

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

  • Установка двух пользовательских разрешений (w, h) подряд оставляла датчик на первом размере, тогда как csi.CSI.width() / height() сообщали второй; быстрый путь «без изменений» теперь исключает пользовательские размеры. (cfbb70156)

  • csi.CSI.lens_correction() разбирал radi и coef как логические значения, поэтому в драйвер передавались не те значения, что были заданы. (ab44b3a77)

  • PAG7936: установка экспозиции и усиления друг за другом затирала друг друга (оба используют один ручной режим, а регистры обратного чтения отстают на кадр); теперь драйвер заполняет ручные регистры только при входе в ручной режим и записывает лишь устанавливаемый параметр. (e7a18c0a0)

  • Захват BAYER с PAG7936 и PS5520 на OpenMV N6 завершался ошибкой «Failed to initialize the CSI interface» при любом размере, кроме полного разрешения, поскольку ISP N6 не может масштабировать сырой Bayer. Теперь для BAYER датчики работают в родном режиме, соответствующем запрошенному размеру (PS5520: VGA, HD, SXGA-M, FHD, QHD, WQXGA2; у QVGA нет родного режима, и он не поддерживается). (fe6790055, b7622b245)

Кодирование и сохранение изображений:

  • Программный кодировщик JPEG: переполнение выходного буфера всегда было фатальным, поскольку путь realloc был отключён; теперь он увеличивает буфер (на половину его размера за раз), если владеет им, корректно откатывается при нехватке памяти и обрезает результат. jpeg_write / mjpeg_write больше не записывают буфер после неудачного кодирования. (28e1110be)

  • Аппаратные кодировщики JPEG (STM32): при переполнении возвращалось частично закодированное изображение с размером выделенного буфера, что давало усечённые файлы без маркера EOI (например, снимок 5 МП при качестве 100 с пустой нижней половиной). Теперь они сообщают о переполнении, освобождают буфер при ошибке и обрезают его при успехе. (22ce9619c)

  • Кодировщик VC8000 молча выдавал цветность 4:2:0 для каждого запроса; субдискретизация, отличная от 4:2:0, теперь передаётся аппаратному кодеку, который её поддерживает. (71f2be7f2)

  • image.Image.save() изображения PNG как .jpg записывал до 1 МБ неинициализированной кучи, а изображения JPEG как .png — пустой файл. Теперь оба случая вызывают исключение; изображение, уже находящееся в целевом формате, по-прежнему копируется как есть. (6c1fdf822)

  • png_write теперь проверяет возвращаемое значение компрессора и сжимает данные до создания файла, поэтому при сбое больше не остаётся пустой файл. (557f52d66)

Модуль image:

  • image.Image.get_pixel() с rgbtuple=True на изображениях BAYER и YUV записывал преобразованный пиксель за пределы локальной переменной стека по смещению, контролируемому вызывающей стороной. (13f2a17b6)

  • gif.Gif.add_frame() лишился недостижимой ветки преобразования Bayer/YUV; принимаются только изображения GRAYSCALE и RGB565, как уже требовал API Python. (f20d99d96)

Протокол:

  • Регистрация динамического канала, когда все слоты уже заняты, приводила к записи за пределы массива; теперь идентификатор канала проверяется первым, а зарезервированные идентификаторы каналов статически проверяются на соответствие таблице каналов. (68f635d1f)

  • Объекты динамических каналов переживали мягкий сброс в корневых указателях, поэтому сборщик мусора продолжал сканировать устаревшие блоки кучи от предыдущего запуска; теперь таблица очищается при инициализации. (ef0ebb03b, e23641145)

Порты:

  • i.MX RT: добавлена отсутствовавшая деинициализация CAN и Encoder при мягком сбросе. (7cb9d3dc2)

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

  • OpenMV N6 — теперь включён CAN (machine.CAN). (294f0febd, 91e1c9573)

  • OpenMV AE3 — SPI-драйвер sdcard заморожен в прошивку для разъёма microSD на плате AE3 Battery Shield. (a258f4814)

  • OpenMV RT1062 — lora-sx126x / lora-sync / lora-async заморожены в прошивку (см. «Новые возможности»).

  • FLIR Lepton 3.1R / UW — распознаются драйвером Lepton на всех платах с поддержкой Lepton.

  • PAG7936 — безопасная остановка при выключении, выбор интерфейса во время выполнения, исправление экспозиции/усиления и захват BAYER на N6.

  • PS5520 — захват BAYER на N6 в родных размерах.

  • Симулятор (MPS2_AN500) — сеть.

  • Все платы — модуль совместимости sensor заморожен в манифест каждой платы.

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

v5.0.1 не вносит несовместимых изменений в API csi и image. Скрипты, работавшие на v5.0.0, работают без изменений, со следующими изменениями поведения.

Модуль sensor (behavior)#

Нативный модуль sensor (modules/py_csi.c) удалён и заменён замороженным модулем Python, который реализует тот же API поверх csi. См. sensor.

Коммит: 5e3d40631

  • import sensor выводит в терминал WARNING: The sensor module is deprecated and will be removed in a future release. Please use the csi module instead..

  • Скрытый объект csi.CSI создаётся при импорте, поэтому отсутствие камеры теперь вызывает ошибку при import sensor, а не при sensor.reset().

  • Эти функции теперь вызывают OSError, поскольку в csi нет их эквивалента: get_fb(), alloc_extra_fb(), dealloc_extra_fb(), set_auto_rotation(), get_auto_rotation(), disable_delays(), disable_full_flush(). (Две функции *_extra_fb вызывали исключение уже в v5.0.0.) Для двух последних используйте csi.CSI(delays=False) / csi.CSI(fflush=False).

  • Размеры кадра, которые csi не экспортирует (QQCIF, QQSIF, QQQQVGA, HQQQQVGA, HQQQVGA, HQQVGA, B64X32, B64X64, B128X64, B128X128, B160X160, B320X320, LCD, QQVGA2), теперь являются кортежами (w, h), передаваемыми как пользовательские разрешения. get_framesize() возвращает установленный кортеж, пока камера всё ещё работает с этим размером, поэтому проверки на равенство с константами продолжают работать.

  • ioctl() передаёт не более четырёх аргументов после запроса.

  • sleep() / shutdown() при ошибке, как и раньше, вызывают OSError (исключение csi RuntimeError транслируется).

Переходите на csi — см. таблицу миграции v5.0.0.

Загрузка изображений в буфер кадра (behavior)#

Функции, загружающие изображение в буфер кадра — image.Image с copy_to_fb=True, image.Image.copy() / image.Image.scale() и преобразования to_* с copy_to_fb=True, image.ImageIO.read(), fir.snapshot() и tof.snapshot() с copy_to_fb=True — раньше сразу отправляли новое изображение в предпросмотр IDE, поэтому всё нарисованное на возвращённом изображении никогда не было видно. Теперь они помечают буфер кадра как ожидающий и сбрасывают его, вместе со всем, что на нём нарисовано, непосредственно перед тем, как следующее изображение его перезапишет — то же поведение, что и у csi.CSI.snapshot().

Коммиты: 87b6db5ee, 7b1a35c2f, f773c740d

Циклы, читающие поток изображений, не требуют изменений и теперь показывают нарисованное. Скрипт, который загружает одно изображение и завершается, должен сбросить его явно:

img = image.Image("example.bmp", copy_to_fb=True)
img.flush()          # new: send it to the IDE preview now
time.sleep_ms(1000)

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

Затрагивает только код, который наследует или копирует поставляемые постпроцессоры. YoloV8 теперь транспонирует выход модели после порогового отбора, так что прошедшие отбор обнаружения хранятся по одной строке на рамку (bb[:, 4:]), как в постпроцессорах Darknet и Edge Impulse, а не по одному столбцу на рамку (bb[4:, :]). Публичные результаты ((x, y, w, h), score) не изменились.

Коммиты: c45f99cad, b5c7853f2

Модуль protocol (minor)#

protocol.poll() вернулась. v5.0.0 удалил её, когда задача протокола переехала на таймер; она возвращается как явный способ управлять задачей для собственных транспортов. Больше ничего не изменилось — скрипты, которые её никогда не вызывали, не затронуты.

Коммит: c00c215f9

Сборка / инструментарий (tooling)#

Ничто из этого не затрагивает скрипты MicroPython. py_image.c был разделён: объекты дескрипторов (cascade, keypoints, LBP, keypoint match) переехали в py_image_descriptor.c, а объекты статистики (similarity, statistics, percentile, threshold, histogram) — в py_image_stats.c. API кодировщиков imlib приведён в соответствие с остальной частью imlib: jpeg_compress / png_compress возвращают 0 при успехе и -1 при ошибке, а jpeg_compress лишился аргумента realloc (изменение размера зависит от владения буфером). OMV_PROTOCOL_MAX_CHANNELS стал OMV_PROTOCOL_CHANNEL_MAX в omv_protocol_channel.h, и порты теперь вызывают py_protocol_init0() при инициализации. Определение платы OMV_PAG7936_MIPI_CSI2 удалено (интерфейс выбирается во время выполнения). Дополняют картину обновления зависимостей CI и исправление пустого журнала изменений выпуска. Подробности, важные для форков, см. в истории репозитория прошивки.

Контрольный список миграции#

  • Всё ещё используете import sensor? Он работает, с предупреждением. Переходите на csi (миграция на v5.0.0); замените disable_delays / disable_full_flush аргументами конструктора csi.CSI() и уберите вызовы get_fb / автоповорота.

  • Загружаете одно изображение с copy_to_fb=True и ожидаете его увидеть? Добавьте img.flush() после загрузки.

  • Скопировали постпроцессор YOLOv8? Индексируйте отфильтрованный по порогу выход по строкам (bb[:, 4:]), а не по столбцам.

  • Сравниваете csi0.framesize() после установки кортежа? Теперь он возвращает csi.CUSTOM.

  • Всё остальное: перепрошейте и запускайте.