Эпизод 1: Введение в проблему

Эпизод 2: Подготовка данных

Мы сделали несколько важных вещей в предыдущих эпизодах.

  • Сформулировал проблему.
  • Скачал базовый набор данных (ModelNet10), с которым мы будем работать.
  • Осталось всего 7 классов из первоначальных 10.
  • Сделали датасет более сбалансированным, создав конвертер .skp -> .off и конвертируя модели из 3d-склада.

Теперь пришло время погрузиться в предварительную обработку данных.

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

Прежде всего, нам нужен способ чтения 3D-сетки в память. Это можно сделать с помощью замечательной библиотеки trimesh. Он предоставляет не только функции чтения/записи, но и множество полезных вещей, таких как преобразование сетки, трассировка лучей и т. д.

Второй шаг заключается в вычислении цилиндрической проекции. Что это такое? Представьте, что у вас есть куб с центром в плоскости XoY и вертикальной осью в начале координат.

Примечание: если главная ось тела не вертикальна, то перед задачей распознавания необходимо применить алгоритм выравнивания ориентации. Это совершенно другая тема, поэтому в данной публикации она не рассматривается.

Теперь представьте минимальный цилиндр, ограничивающий куб.

Теперь разбейте боковую поверхность цилиндра на сетку размером M на N.

Теперь спроецируйте ортогонально каждый узел сетки на главную ось и получите набор точек проекции. Множество точек проекции обозначается буквой P. Множество сегментов проекций обозначается буквой S.

Теперь пересекаем каждый сегмент из S с телом сетки — кубом. Вы получите одну точку пересечения из каждого сегмента. Назначьте эту точку соответствующему узлу сетки.

На самом деле это частный случай. В общем случае один отрезок из S может давать несколько точек пересечения. Или вообще без перекрестков. Вот пример.

Таким образом, обычно результатом этого процесса является матрица размеров MxN с массивом точек пересечения (возможно, пустым) в каждой ячейке. Для куба каждая ячейка будет содержать массив с одним элементом.

Следующим шагом является перенос самой удаленной точки из каждого массива ячеек в соответствующую точку из M и запись расстояния между ними в результирующую MxN матрицу R. Матрица (или изображение) R называется панорамным видом.

Почему мы должны брать самую дальнюю точку? Фокусируемся на внешней поверхности тела, выбирая наиболее удаленную точку. Модуль распознавания будет работать с внешней поверхностью тела в виде панорамы. Конечно, можно возразить: «Тор и цилиндр одинаковой высоты дадут точно такой же панорамный вид» или «куб со сферическим отверстием в центре и куб без отверстия дадут точно такой же панорамный вид», и он будет быть правильным. Трехмерное представление тела в панорамном виде не идеально, воксельный подход не имеет такого ограничения. К счастью, тела реального мира, такие как стулья, кровати, автомобили или самолеты, редко имеют такой же панорамный вид из-за их сложности.

Последний шаг — нормализовать матрицу R, масштабируя ее значения, чтобы они соответствовали интервалу [0, 1]. Если для ячейки не было пересечения, присвойте этой ячейке нулевое значение.

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

Что именно мы сделали до сих пор? Подведем итоги.

  • Теперь у нас есть способ представить трехмерное тело сетки в виде изображения в градациях серого.
  • 3D-тела должны быть правильно выровнены. Если это не так, нам нужно сначала использовать алгоритм выравнивания ориентации.
  • Существует вероятность того, что два разных тела будут иметь один и тот же панорамный вид, но она пренебрежимо мала.

Теперь мы готовы создать свёрточную нейронную сеть и решить задачу распознавания.

Увидимся в следующий раз!