Высокоскоростной конвейер компьютерного зрения для универсальной сортировочной машины LEGO

Последние несколько лет я конструировал и конструировал машину, которая может распознавать и сортировать кубики LEGO. Ключевой частью машины является Блок захвата - это небольшая закрытая камера, в которой есть ремень, свет и камера.

Камера делает снимки деталей LEGO, движущихся по ленте, а затем отправляет изображения деталей по беспроводной сети на сервер, который запускает алгоритм искусственного интеллекта, чтобы идентифицировать деталь из тысяч возможных элементов LEGO. Я расскажу больше о самом алгоритме ИИ в будущих статьях, но эта статья будет посвящена обработке, которая происходит между необработанным видеовыходом камеры и входом в нейронную сеть.

Основная проблема, которую мне нужно решить, - это преобразование видеопотока ремня в реальном времени в отдельные изображения частей, которые может использовать нейронная сеть.

Это отличный пример проблемы, которая на первый взгляд кажется простой, но на самом деле представляет собой множество уникальных и интересных препятствий, многие из которых уникальны для платформ компьютерного зрения.

Такое извлечение соответствующих частей изображения часто называют «обнаружением объекта». Это именно то, что мне нужно сделать: обнаруживать присутствие объектов, их расположение и размер, чтобы я мог создавать ограничивающие рамки для каждой части в каждом кадре.

Я рассмотрю три аспекта решения:

  • Настроить себя на успех, исключив посторонние переменные
  • Построение конвейера из простых операций CV
  • Поддержание хорошей производительности на ограниченной платформе Raspberry Pi

Устранение посторонних переменных

Для подобных проблем лучше всего устранить как можно больше переменных, прежде чем пытаться применить методы компьютерного зрения. Я не хочу беспокоиться об условиях окружающей среды, разных положениях камеры или потере информации, например, из-за окклюзии. Возможно (если это очень сложно) при необходимости адресовать все эти переменные в программном обеспечении, но, к счастью для меня, я проектирую эту машину с нуля - я могу настроить себя на успех, удалив такие переменные еще до того, как какой-либо код станет ровным. написано.

Первый шаг - установить фиксированное положение камеры, угол и фокус. Это просто, установка фиксирует камеру над ремнем. Мне тоже не нужно беспокоиться об окклюзиях; нежелательные объекты вряд ли начнут блуждать в блок захвата. Немного сложнее, но очень важно обеспечить постоянные условия освещения. Я не хочу, чтобы мой детектор объектов ошибочно интерпретировал тень прохожего как физический объект. Для многих приложений компьютерного зрения принудительное освещение очень сложно или невозможно. К счастью, блок захвата очень маленький (все поле обзора камеры меньше буханки хлеба!), Поэтому у меня больше, чем обычно, контроль над окружающей средой.

Один из вариантов - сделать коробку полностью закрытой, чтобы внутрь не проникал свет из окружающей среды. Я попробовал это, используя светодиодные ленты в качестве источника света. К сожалению, это очень хитроумно - одна крошечная дырочка в корпусе, и свет может проникать внутрь, не позволяя обнаруживать любые объекты.
В конце концов, лучшим решением было «вытеснить» другие источники света, полностью взорвав крошечную камеру. света. Оказывается, такие лампы, которые могут осветить всю комнату, очень дешевы и просты в использовании.

Направленный в крошечную камеру, свет сильно подавляет любые потенциальные помехи. В качестве приятного побочного эффекта такое обилие света означает, что камера может использовать очень короткую выдержку, делая совершенно четкие изображения деталей, даже когда они бегут по ленте.

Детектор объекта

Итак, как мне взять это красивое, постоянно освещенное видео и превратить его в полезные ограничивающие рамки? Если вы специалист в области искусственного интеллекта, вы можете предложить реализовать нейронную сеть для обнаружения объектов, такую ​​как YOLO или Faster R-CNN. Эти нейронные сети легко достигли цели. К сожалению, я запускаю код обнаружения объектов на Raspberry pi. Даже высокопроизводительный компьютер будет изо всех сил пытаться запустить эти сверточные нейронные сети с необходимой мне частотой кадров ~ 90 кадров в секунду. Невозможно, чтобы Raspberry pi, лишенный какого-либо аппаратного обеспечения графического процессора, совместимого с AI, мог запускать даже очень урезанную версию одного из этих алгоритмов AI. Я мог бы транслировать видео с Pi на другой компьютер, но потоковое видео в реальном времени очень сложно, с ограничениями как задержки, так и полосы пропускания, вызывающих серьезные проблемы, особенно при требуемых высоких скоростях передачи данных.

К счастью, я могу избежать сложного решения искусственного интеллекта, обратившись к методам компьютерного зрения «старой школы». Первый - это вычитание фона, при котором делается попытка выделить любую изменяющуюся часть изображения. В моем случае камера видит только движущиеся части LEGO. (Конечно, ремень движется, но, поскольку он имеет однородный цвет, кажется, что он не движется в камеру). Отделите эти детали LEGO от фона, и я на полпути.

Чтобы вычитание фона работало, объекты переднего плана должны существенно отличаться от фона, чтобы их можно было поднять. Детали LEGO бывают самых разных цветов, поэтому мне нужно выбирать цвет фона очень конкретно, чтобы он был как можно более не-LEGO. Вот почему пояс под камерой сделан из бумаги - он не только должен быть очень однородным, но и не может быть сделан из LEGO, иначе он будет того же цвета, что и некоторые кирпичи, которые необходимо распознать! Я выбрал бледно-розовый, но подойдет любой другой пастельный цвет, не похожий на обычный цвет LEGO.

В замечательной библиотеке OpenCV есть несколько встроенных алгоритмов вычитания фона. Вычитатель фона MOG2 является наиболее сложным и работает невероятно быстро даже на Raspberry Pi. Однако подача видеокадров напрямую в MOG2 не совсем работает. Светло-серые и белые кусочки слишком похожи по яркости на бледный фон и теряются. Мне нужен был способ более четко отличить пояс от того, что на нем, путем указания вычитателю фона более внимательно смотреть на * цвет *, чем на * яркость *. Все, что мне нужно сделать, это увеличить насыщенность изображения перед тем, как передать его фоновому вычитателю. Результаты были существенно улучшены.

После вычитания фона мне нужно использовать морфологические операции, чтобы устранить как можно больше шума. Функциональность OpenCV findContours () может использоваться для поиска контуров белых областей. После применения эвристики для удаления контуров, содержащих шум, на основе площади контура, можно с помощью простого процесса преобразовать эти контуры в окончательные ограничивающие рамки.

Представление

Нейронная сеть - голодный зверь. Для получения наилучших результатов классификации требуются изображения с максимальным разрешением и как можно больше. Это означает, что мне нужно снимать с очень высокой частотой кадров, сохраняя при этом высокое качество изображения и разрешение. Я буду доводить камеру и графический процессор Raspberry PI до абсолютного предела.
Великолепно исчерпывающая документация picamera показывает, что чип камеры V2 может выводить изображения с разрешением 1280x720 пикселей с максимальной частотой 90 кадров в секунду. Это невероятный объем данных, и даже если камера может их генерировать, это не означает, что компьютер может с ними справиться. Если бы я обрабатывал необработанные 24-битные изображения RGB, это было бы ~ 237 МБ / с пропускной способности, слишком много для графического процессора или SDRAM бедного Pi. Даже при использовании сжатия JPEG с ускорением на GPU невозможно достичь 90 кадров в секунду.
Камера raspberry pi может выводить необработанное нефильтрованное изображение YUV. Несмотря на то, что с ним труднее работать, чем с RGB, на самом деле YUV обладает множеством хороших свойств. Что наиболее важно, у него всего 12 бит на пиксель (против 24 для RGB).

Это означает, что я могу обрабатывать вдвое больше кадров YUV, чем кадры RGB, даже не учитывая дополнительное время, сэкономленное графическому процессору, который в противном случае пришлось бы потратить на кодирование изображения RGB.
Вышеупомянутые места довольно уникальны. ограничения на фактический конвейер обработки. Большинство операций с полноразмерным кадром видео будут чрезвычайно интенсивно потреблять память и процессор. Даже декодирование полноразмерного кадра YUV невозможно в мои жесткие временные рамки.

К счастью, мне не нужно обрабатывать весь кадр! Обнаружение объектов не требует точных ограничивающих рамок, только достаточно близко, поэтому весь конвейер обнаружения объектов может быть выполнен на гораздо меньшем кадре с измененным размером. Операция уменьшения масштаба не требует учета всех пикселей в полноразмерном кадре, поэтому при осторожности размер кадра можно изменить очень быстро и дешево. Полученные ограничивающие рамки затем снова масштабируются и используются для удаления обрезков из полноразмерного кадра YUV. Таким образом, мне никогда не нужно декодировать или иным образом обрабатывать весь кадр с высоким разрешением.

К счастью, из-за того, как хранится этот формат YUV (см. Выше), на самом деле очень легко реализовать операции быстрого кадрирования и уменьшения масштаба, которые работают напрямую с форматом YUV. Наконец, весь конвейер можно без особых проблем реализовать в многопоточном режиме через 4 ядра Pi (вам действительно нужна блокировка на этапе вычитания фона). Однако я обнаружил, что не все ядра используются в полной мере, что указывает на то, что узким местом по-прежнему является пропускная способность памяти. Тем не менее, на практике я могу достичь 70–80 кадров в секунду. Более глубокий анализ использования памяти, вероятно, может еще больше ускорить его.

Если вы хотите узнать больше об этом проекте, ознакомьтесь с моей предыдущей статьей Как я создал более 100 000 изображений для обучения LEGO.

Вы можете подписаться на меня в Twitter: @JustASquid