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(исключениеcsiRuntimeErrorтранслируется).
Переходите на 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) не изменились.
Модуль 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.Всё остальное: перепрошейте и запускайте.