.. NodaLogic documentation master file, created by sphinx-quickstart on Wed Nov 5 07:29:33 2025. You can adapt this file completely to your liking, but it should at least contain the root `toctree` directive. Компьютерное зрение и дополненная реальность ActiveCV ======================================================== .. image:: _static/2025_cv_1.png :scale: 75% :align: center ActiveCV – это технология автоматизации бизнес-процесса, когда все необходимые данные бизнес-процесса выводятся не на экран, а сразу в видеопоток, при этом с камерой работают различные детекторы: штрихкодов, OCR, лиц и т.д. Также смысл сего действия в беспрерывной работе оператора без необходимости каких то переключений. Например, запустил ActiveCV – отсканировал код помещения, не прерываясь и ничего не нажимая переключился на сканирование инвентарных кодов оборудования, VIN-ов, далее серии фото этого оборудования и все это, не переключаясь на обычные экраны с кнопками. И пошел дальше к другим объектам. Важным свойством технологии является подсветка объектов разными цветами – цветовая маркировка. Примеры цветовой маркировки: * объект находится там, где надо — зеленый цвет, там, где не надо — красный. * объект проинвентаризирован — зеленый цвет, не проинвентаризирован — желтый. * заказ просрочен по дедлайну — красный, подходит срок — желтый, не просрочен — зеленый .. image:: _static/2025_cv_3.png :scale: 75% :align: center .. note:: Конфигурация с BARCODE/OCR лежит в https://github.com/dvdocumentation/nodalogic/tree/main/Samples Примеры (лучше смотреть видео или GIFы) по технологии собраны в этих статьях (на платформе было 2 генерации ActiveCV: первая, в виде самостоятельно процесса - устарела, в виде элмента экрана - актуальная): * https://habr.com/ru/articles/874560/ Обзор механизмов работы. ----------------------------- Размещение визуального элемента. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Само окно камеры(предпросмотра) можно разместить на экране. Размещение на экране ничем не отличается от других элементов разметки и имеет те же свойства - ширину, высоту, вес. Сам визуальный элемент называется ActiveCV. Можно разместить на часть экрана, весь экран. И также с помощью команды RunCV можно запустить полноэкранный режим в отдельном окне, чтобы не размещать на экране. Разрешение ~~~~~~~~~~~~ Можно задавать разрешение для детектора **CameraSetResolutionAnalysis** и для фото **CameraSetResolutionImage**. Разрешение предпросмотра меняться не будет – оно подстраивается автоматически. Также заданное разренеие может не поддерживаться (особенно для детектора) – будет выставлено максимально возможное Возможные разрешения: ``"4K"(4096*2160))``, ``"2K"(2048*1080)``, ``"1080"(1920*1080)``, ``"720"(1280*720)``, ``"640"(640*480)``, ``"360"(360*240)``, ``"200"(200*200)``, ``"100"(100*100)`` Соответственно, чем меньше разрешение (особенно детектора) тем быстрее и плавнее работает визуальная составляющая. Цикл работы детекторов. Общее. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Детектор включается/переключается командой **CameraSetDetector**, где параметром указывается тип или типы детекторов. Сейчас доступны ``BARCODE``, ``OCR``, ``FACE`` и ``PHOTO``. Если нужно совместить несколько – то через нижнее подчеркивание. Например, ``BARCODE_PHOTO``, ``BARCODE_OCR`` Когда появляется новый объект в кадре, который еще не был распознан срабатывает событие (listener) **new_text_detected** или **new_barcodes_detected** в зависимости от детектора. В _data доступен JSON-массив объектов кадра - **detected_values**. Наполнение распознанных элементов зависит от детектора. В обработчике этого события возможно задать внешний вид распознанных объектов. Отображение объектов ~~~~~~~~~~~~~~~~~~~~~~~~ Можно переопределять заголовки распознанных объектов и задавать цвет рамки над ними. Это все хранится в одном списке **SetObjectsView** в виде JSON-массива объектов с полями id, color (HEX-формат) и caption. Id – это соответственно штрихкод или текст. Для медленных устройств отображение упрощенное. Для быстрых доступна HTML-строки в заголовках объектов с помощью команды **CameraSetPrettyView**. Т.е. можно например написать в caption ``"Товар такой то, остаток такой то "``. Также в PrettyView секции заголовка выстраивается по размеру объекта, а не текста, т.е. происходят переносы. Для такого отображения дополнительно с SetObjectsView нужно добавить команду CameraSetPrettyView Ручное управление списком детектированных объектов. ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ По умолчанию на новые объекты вызывается обработчик **new_..._detected** (**new_barcodes_detected***, **new_text_detected**) и после этого они уже перестают считаться «новыми», на них события не вызываются. Но можно управлять этим вручную с помощью флага **CameraSetOCRDetectedListManual**, пустой параметр, затем ручная регистрация с помощью **CameraOCRAddDetected**, параметр – список ID. Также доступно **CameraClearDetected**, пустой параметр для того, чтобы просто сбросить список всех детектированных объектов. Подключение валидатора ~~~~~~~~~~~~~~~~~~~~~~~~~~ Валидатор можно подключить для того, чтобы при считывании происходил поиск по индексам узлов или датасетов и в обработчик в new_text_detected/new_barcodes_detected попадали не все объекты (отобранные по маске, формату и другой предобработке), а только те, которые есть в базе данных, т.е. только известные объекты. Это делается в основном для ускорения. Функционально, получить значения в обработчик и обработать там - тоже самое, но чуть менее производительно. Это не всегда применимо, иногда нужно разбирать варианты в обработчике. Пример валидатора для штрихкодов по индексу узлов: .. code-block:: Python self._data["CameraSetBarcodeValidator"] = { "node_index": { "class": "Goods", "name": "barcode" } } также можно через глобальный индекс: .. code-block:: Python { "global_index": "goods_barcode" } по индексу датасетов: .. code-block:: Python { "dataset": "goods", "keys": ["barcode"] } Для OCR: .. code-block:: Python self._data["CameraSetOCRValidator"] = { "node_index": { "class": "Goods", "name": "name" }, "min_chars": 3, "max_chars": 40 } Смена фронтальной и тыловой камеры ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **CameraSetSelector**,<режим> - если режим="front" то камера-фронтальная, если "back"-обычная Задание рамки ~~~~~~~~~~~~~~~~~~~~~~ На экране можно вывести рамку, тогда значения будут считываться только из нее, игнорируя пространство вне рамки **CameraSetFrame**,<строка параметров> - задает рамку в процентах от размера элемента ActiveCV в формате <процент_x1>_<процент_y1>_<процент_x2>_<процент_y2> Например: .. code-block:: Python self._data["CameraSetFrame"] = "20_45_80_55" Зум ~~~~~ **CameraSetZoom**, <параметр> – число требуемого приближения (стек перменных строковый, поэтому и числа и другие параметры в виде строки). Остановка видеопотока. ~~~~~~~~~~~~~~~~~~~~~~~~ **CameraStopDetectorOnNewObjects** - включение режима, когда предпросмотр камеры встает на паузу автоматически при обнаружении объекта. Альтернатива – использование из кода обработчика команды **CameraStop**. Возобновляется – обновлением экрана. Фонарик ~~~~~~~~~ **CameraTorchTurnOn** – включает подсветку камеры (если есть аппаратная возможность) Запуск в отдельном экране с возвратом значения ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **RunCV, ** - запускает из экрана ActiveCV на весь экран до считывания первого результата, после чего закрывает камеру и генерирует событие с указанным в параметре именем события. Эта возможность для ситуаций, когда что-то нужно быстро считать, а размещать на экране элемент ActiveCV не хочется или нет возможности (экран маленький). При этом в onStart вызывающего экрана нужно указать все опции как и для объекта camera (CameraSetResolutionAnalysis, CameraSetDetector и так далее). В указанный в команде параметр (listener) при этом возвращаются detected_values и в целом работа с обработкой результата аналогична, с той только разницей, что раскраска и подписи объектов SetObjectsView не имеют смысла. В примере в этой статье(вариант для ТСД) https://infostart.ru/1c/tools/2364633/ я использую чисто для распознавания OCR на новом движке ActiveCV2 для ТСД-варианта. На ТСД не нужен сканер через камеру (свой есть), а вот OCR нужен, но размещать на экране ActiveCV негде (экран маленький). Особенности детектора штрихкодов (BARCODE) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ **CameraSetSupportedBarcodes** задает список доступных штрихкодов через нижнее подчеркивание. Например: ``self._data["CameraSetSupportedBarcodes"] ="QR_EAN13"`` Если не задано, либо задано ALL то сканируются все. Список доступных форматов: ``QR``, ``EAN13``, ``AZTEC``, ``CODABAR``, ``CODE_93``, ``CODE_39``, ``CODE_128``, ``DATA_MATRIX``, ``EAN_8``, ``ITF``, ``UPC_A``, ``UPC_E`` **CameraSetCurrentBarcodeDetector** задает список текущих форматов штрихкодов при динамическом переключении. Формат аналогичен CameraSetSupportedBarcodes. При этом CameraSetSupportedBarcodes задает форматы которые камера вообще способна считывать. Это так сказать – для ускорения работы и отсечки возможных ошибок. А CameraSetCurrentBarcodeDetector для переключения между форматами в процессе работы. Массив штрихкодов в **detected_values** включает в себя объекты с полями: **value** – штрихкод как есть (со спецсимволами если они есть), **display_value** – отображаемое значение, **format** – формат штрихкода. Ну и **result** ,если используется валидатор, с непосредственно записью датасета. Особенности детектора лиц (FACE) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ При детектировании лиц, результаты возвращаются в событии new_faces_detected в переменную detected_values в виде массива объектов с ключами id(номер объекта) и value(Base64 упакованное изображение лица) .. code-block:: Python values = self._data.get("detected_values") faces_list = [] for value_item in values: faces_list.append({"_id":value_item["id"],"picture":value_item["value"]}) Особенности OCR (распознавание текста) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Цикл обработки блоков текста включает в себя несколько этапов. Все они происходят очень быстро так как выполняются платформой. Поэтому крайне рекомендую не отдавать в обработчики сырой текст, пропущенный через слабые фильтры и обрабатывать его как есть там – это будет гораздо более тормозящий вариант чем использование масок, валидаторов и предобработки. .. note:: Важно! OCR работает **только** если опредена маска. Без маски, не будет запускаться! Можно конечно задать очень широкую маску, но лучше - такую как надо по условиям задачи. Пример запуска OCR в отдельном окне в NodaScript (в python аналогично): .. code-block:: JavaScript _data.CameraSetDetector="OCR"; _data.CameraSetOCRMask=["([a-zA-Z0-9-.]{3,15})"]; RunCV("my_cv") Обработка текста в ActiveCV ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Итак, текст может быть подвергнут предобработке, после чего к нему применяются Regex-маски, после чего могут выполниться еще процедуры предобработки (часть настроек работает до масок- часть после), после чего он либо попадает на валидатор либо отдается в обработчик new_text_detected как есть. Если задача к примеру выделить все даты в кадре то валидатор не нужен, а если сверить инвентарные номера - то подключаем валидатор. Команда **CameraSetOCRFormatOptions** задает опции предобработки текста. Она может включать в себя несколько действий через нижнее подчеркивание: * CLEARSPACES – убирает различные пробелы * LOWER -преобразует к нижнему регистру * UPPER – преобразует к верхнему регистру * TOZERO – преобразует букву О в ноль И часть опций, которая выполняется уже после отбора Regex: * DATE, INT, FLOAT – нативная проверка текста на соответствующий тип Команда **CameraSetOCRMask** – задает JSON массив строк-масок. Каждая маска представляет из себя Regex-выражение. Например, "([a-zA-Z0-9-.]{5,10})" - это маска, для поиска подстрок включающих в себя символы латинского алфавита и цифры общей длиной от 5 до 10 символов. Удобно проверять маски через редакторы regex-выражений, например https://regex101.com/ Каждая маска последовательно применяется, приоритет имеет та, которая стоит раньше в массиве. **CameraOCRListOnly** флаг чтобы выводились не только текст после валидатора, если он есть. **detected_values** в OCR содержат в себе поля: * value - текст после всех преобразований * confidence - точность определения * result - запись валидатора Примеры обработчика new__detected + SetObjectsView: .. code-block:: Python values = self._data.get("detected_values", []) #Получаем объекты в кадре objects = self._data.get("SetObjectsView", []) #массив раскраски if values: barcode = values[0].get("value", "") self._data["last_barcode"] = barcode beep() # Обновляем только текстовое поле, ActiveCV не трогаем, не перерисовываем экран self.UpdateView("last_barcode", None) #ищем объект по индексу res = getByIndex("SKU", "barcode", barcode) #CameraSetObjectView(barcode, "#f0e224", name) #можно менять так, по одному. Ниже - более общий способ name = "Not found" if res is not None: name = res._data.get("name", "") cv = { "id": barcode, "color": "#f0e224", "caption": name } item = next((x for x in objects if x.get("id") == barcode), None) if item is None: objects.append(cv) else: item["color"] = cv["color"] item["caption"] = cv["caption"] CameraSetObjectsView(objects) Команды (python/NodaScript) ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Часть опций ActiveCV задаются как опции при размещении объекта, но в процессе работы управлять опциями через _data не очень удобно, т.к. в таком случае объект надо будет перерисовать, а это очень тяжелый объект и он пересоздается около 1-2 секунды. Поэтому часть функций выделены в команды, которые влияют на объект без перерисовки. Например SetObjectView позволяет перекрашивать объекты в кадре на лету. **CameraSetObjectView(, , <заголовок>) - перехрашивает/устанавливает загодовок на 1 объект. ``CameraSetObjectView(barcode, "#f0e224", "my caption")`` **CameraSetObjectsView(objects)** заменяет массив раскраски новым (для всех объектов). Идентичен ключу CameraSetObjectsView, но работает динамически **CameraSetZoom** динамически меняет зум ``CameraSetZoom(0.5)`` **CameraStop** останавливает камеру **CameraSetSupportedBarcodes** меняет список поддерживаемых штрихкодов динамически **CameraSetSelector** меняет камеру динамически