Почему я взялся за эту задачу
В предыдущей статье «Как я собирал ERP-контур из 5 продуктов для строительной компании» я рассказывал об автоматизации учёта и взаимодействия систем. Однако за любыми данными в ERP стоит физический объект: монолит, конструкции, инженерные сети и выполненные работы. Каким образом связать то, что происходит на стройплощадке, с тем, что мы видим в документах и информационных системах ?
Я хотел бы ответить на этот вопрос личной историей, так как связан со строительной отраслью во втором поколении. Мой отец часто задерживался на работе и уезжал в командировки. Я рос, наблюдая, сколько времени и внимания требует строительство. Поэтому мне хочется создавать инструменты, которые сокращают рутинную работу, помогают избежать ошибок и позволяют решать часть вопросов, без очередного выезда на объект.
В конце 2024 года на строительстве аэропорта к саммиту БРИКС мы разговорились с одним из субподрядчиков. Обсуждали, как было бы удобно рассматривать объект по отдельным видам работ: убирать одни данные, показывать другие, изучать конструкции и инженерные системы в общей трёхмерной модели. Хотелось видеть не только то, что запроектировано, но и то, что действительно построено.
Именно в 2024 году я начал разработку. Коллеги с опытом в компьютерном зрении помогли мне выбрать технический стек и направление первых экспериментов. Одной из отправных точек стала статья Fengyu Zhang и соавторов «Automatic generation of architecture drawings from point clouds», опубликованная в 2024 году. По мере погружения выяснилось, что преобразование облаков точек в чертежи и модели, это уже сложившееся направление. И, оказывается уже существуют исследовательские методы, коммерческие решения и инструменты работы с облаками точек в CAD-системах.
Поэтому вопрос для меня постепенно изменился. Какой участок этого процесса я могу автоматизировать так, чтобы результат был полезен инженеру? А что можно восстановить по скану, а где без дополнительных данных и проверки человеком, конкретно не обойтись?
Цель моего проекта, это получать из облаков точек редактируемые чертежи и постепенно развивать на этой основе подготовку исполнительной документации. Дальше я хочу связать полученные данные с контролем выполненных работ и ERP, уже от наблюдаемой геометрии объекта перейти к сведениям, которые инженер может проверять и использовать в рабочем процессе.
До всей этой цепочки ещё предстоит дойти. Сейчас прототип обрабатывает облако точек, выделяет плоские участки и строит черновые отрезки, которые можно экспортировать в DXF. Он уже даёт результат, который можно открыть и исследовать, но вместе с ним возникают ошибки: мебель попадает в сегментацию, поверхности распадаются на фрагменты, а отсутствие точек легко принять за проём.
Таким образом, в этой статье я разберу один из этапов разработки, которой занимаюсь около 2 лет. Покажу реальное облако, последовательность обработки, полученный чертёж и места, где первоначальные ожидания не совпали с результатом.
Это рассказ о текущем исследовательском прототипе и конкретных экспериментах. Я хочу показать, что уже удалось проверить, какие вопросы остаются открытыми и что нужно измерить, прежде чем говорить о точности и практической экономии времени.
Какую систему я хочу получить
Цель проекта: получать из облаков точек редактируемые исполнительные чертежи и развивать на этой основе подготовку исполнительной документации. Затем связывать проверенные сведения с контролем выполненных работ и ERP. В перспективе цепочка выглядит так:
Скан → фактическая геометрия → сопоставление с проектом → проверка инженером → исполнительные материалы → запись в ERP.
Сейчас реализована первая часть: программа загружает PLY, обрабатывает точки, выделяет плоские участки и строит черновые отрезки сечения. Их можно сохранить, восстановить из базы и экспортировать в DXF. Сопоставление с проектом, подготовка полного комплекта исполнительной документации и передача подтверждённых объёмов в ERP пока относятся к дальнейшему развитию.
В статье покажу один реальный проход и подробно разберу построение отрезков. Затем вернусь к ошибкам: что именно мешает превратить полученный результат в инструмент для повседневной работы инженера.
Что происходит в программе ?
Основной путь сейчас такой:
PLY → очистка XYZ → RANSAC-плоскости → горизонтальное сечение → проверка поддержки точками → отрезки → SQLite → DXF.
Рядом существуют диагностические инструменты: развёртка плоскости в 2D, поиск контуров через OpenCV, разбиение плоскости на связные фрагменты, проверка стыков и ручные метки. Они уже полезны для исследования, но было бы неверно нарисовать их одной длинной цепочкой и сказать, что каждый из них улучшает итоговый DXF. В текущем коде это отдельные ветки.
Для основного разбора я взял реальные облака точек, скачал 2 модели на просторах интернета, на которых я и прводил исследования поведение программы. В нём 3 400 000 точек. Все следующие изображения относятся к одному завершённому запуску: одинаковая сегментация используется для плана, развёртки и диагностики стыков. Синтетический пример оставлен отдельно как контрольный опыт.
При проверке обнаружилась важная деталь: в PLY есть RGB. Раньше облако отображалось одноцветным или раскрашенным по сегментам, поэтому возникло впечатление, что цвета во входе нет. Это разные вещи: файл содержит цвет, но нынешний геометрический алгоритм его не использует. На следующем рисунке показаны именно цвета из файла, а не предсказанные классы. Протокол реального запуска

Как это выглядит в программе
Сначала нажимаю «Загрузить PLY файл», затем «Предобработка». Программа сохраняет путь и после шумоподавления и статистической очистки остаётся 32 443 точки. Фильтр высоты в этом запуске не применяю: обрезанная сцена могла бы исказить размеры участков.

Шумоподавление уменьшает объём данных, но может убрать тонкие детали. Поэтому сокращение числа точек само по себе не говорит об улучшении точности. Для данного эксперимента фильтр высоты перед сегментацией не применялся.
Вход предполагается в метрах, ось Z: вертикальной. Автоматического определения масштаба и исправления наклона сцены сейчас нет. Эти условия необходимо проверить до расчёта: единицы в заголовке DXF не исправят ошибку масштаба исходных координат.
Выделение плоскостей
Для геометрии используются Open3D и NumPy, для интерфейса — Tkinter и Matplotlib. Плоскости выделяются последовательно методом RANSAC: проверяются кандидаты по случайным тройкам точек, выбираются согласованные с плоскостью наблюдения, затем поиск продолжается на остатке облака.
Настройки запуска: максимум 15 плоскостей, минимум 100 точек, порог расстояния 0.02 м и 1500 итераций на поиск плоскости. В сценарии воспроизведения задан Open3D seed=42. Отдельного поля seed в интерфейсе пока нет. Все последующие результаты используют одну сохранённую сегментацию.

Каждый участок описывается уравнением плоскости:
Полученные уравнения позволяют вычислять расстояния и пересечения. Однако RANSAC выделяет плоскую геометрию, а назначение объекта нужно определять отдельно. Именно эта граница позже стала одной из основных проблем проекта.
Как плоскость превращается в конечный отрезок
Разберу основной этап подробнее. Пусть выбрана высота
В текущих настройках h по умолчанию равна 1.2 м. После подстановки высоты уравнение плоскости становится уравнением прямой на плане:
Для почти вертикальной плоскости положим n=(a,b). Тогда одну точку на прямой можно выбрать как
а единичное направление вдоль неё
Горизонтальные плоскости здесь отбрасываются, поэтому вырожденный случай a=b=0 не используется. Для каждой точки из полосы около сечения вычисляется скалярная координата
Теперь трёхмерная задача сведена к распределению наблюдений вдоль одной прямой. Именно это делает build_plan в cad_plan.py.
Можно было бы просто взять минимальное и максимальное s и провести один отрезок. Где косяк? Между крайними точками может быть дверь, большой провал сканирования или несколько раздельных объектов. Один длинный отрезок соединит их без оснований.
Поэтому текущая версия проверяет локальную плотность. В полосе ±10 см относительно выбранной высоты проекции разбиваются на ячейки длиной 10 см. Ячейка считается поддержанной, если содержит хотя бы три различных XYZ-наблюдения. После сортировки последовательность разделяется при пропуске ячейки либо расстоянии между соседними проекциями больше 20 см. Сохраняются достаточно длинные группы: минимум 25 см и минимум пять опорных записей.
Это не непрерывное доказательство существования стены. Внутри разрешения сетки всё равно остаются предположения. Но теперь программа хотя бы не обязана соединять весь участок между двумя крайними точками.
Для каждого принятого интервала концы восстанавливаются как o+s_min t и o+s_max t. Сохраняются номер исходной плоскости, поддержка и RMSE расстояний её точек до плоскости. Низкий RMSE означает хорошее согласие с этой математической плоскостью. Он не означает, что найден правильный край физической стены.
Дополнительно программа сравнивает поддержку отрезка на нескольких высотах. Этот признак помогает увидеть, что участок наблюдается не только в одном срезе. Пока он не является классификатором: высокая мебель тоже может поддерживаться на нескольких уровнях.
От сечения к редактируемому DXF
Во вкладке «Чертёж» для этого запуска оставлена пустой отметка пола (аналог нулевой точки в ПСД). В таком режиме программа использует минимальную Z очищенного облака: 1.120608 м. При высоте сечения 1.2 м абсолютная отметка получается 2.320608 м. Это запасной способ задания уровня, а не распознавание пола.
После «Построить и сохранить» получены 11 отрезков. У восьми есть поддержка на нескольких высотах. Для каждого сохранены исходная плоскость, координаты концов, число опорных записей и RMSE подгонки.

Экспорт через ezdxf создаёт DXF R2010: 11 объектов LINE, 11 DIMENSION и служебное примечание. Единицы — метры. Перед окончательной записью файл читается обратно и проходит проверку структуры. Для следующего изображения линии извлечены именно из сохранённого DXF и наложены на исходные точки.

На этом шаге есть редактируемая геометрия, с которой можно продолжать работу. Автоматическое создание толщины и осей стен, замыкание помещений и подтверждённые блоки проёмов в этот путь пока не входят.
Где ожидания разошлись с результатом
Расхождение №1 смысл найденной плоскости.
На ранних изображениях интерфейс называл сегменты стенами, хотя часть точек относилась к мебели. При совместном разборе сцены небольшие прямоугольники на боковых стенах были определены как картины, а большое окно оказалось закрыто жалюзи. Назначение этих объектов установил человек; RANSAC его не определял.
Это важно и для чтения метрик. Небольшой RMSE показывает, что выбранные точки близки к подогнанной плоскости. Но поверхность шкафа может быть подогнана хорошо и всё равно оказаться лишней в архитектурном плане.
Расхождение №2 проёмы. Размерная эвристика в текущем проходе дала 8 гипотез стен, 0 дверей и 0 окон, хотя человек видит двери и окно в исходной сцене. Проверки ширины, высоты и положения целой плоскости относительно пола здесь оказались недостаточными. DBSCAN сам по себе тоже не присваивает кластеру смысл «дверь».
Расхождение №3 разрывы Локальная поддержка не позволяет безусловно провести линию между крайними точками, но вместе с реальными промежутками сохраняются пропуски наблюдений. В DXF остаются короткие отрезки и незамкнутые участки. Чтобы понять причину, приходится возвращаться к трёхмерной сцене.
Отдельная проверка пересечений выявила похожую неоднозначность: в сохранённом синтетическом опыте поверхности с зазором 5 см дали ложный кандидат стыка. В другом опыте настоящий угол был пропущен из-за отсутствия точек рядом с ним. Уменьшение допуска подавляет одни ошибки и может увеличивать другие.
Наконец, при пакетном проходе проявилась техническая проблема интерфейса: очистка объектов Tkinter из фонового потока сопровождалась ошибками и тайм-аутом. Завершённый демонстрационный запуск использовал временное отключение циклической сборки мусора в сценарии; при выходе осталось предупреждение Tkinter. Ещё необходимо исправление управления объектами интерфейса.
Как OpenCV и фрагменты помогают исследовать ошибки
Для выбранной плоскости программа строит локальную развёртку UV. По ней формируется карта наблюдений, а OpenCV выделяет связные области и контуры через connectedComponentsWithStats и findContours.
В этом запуске выбрана плоскость №2 и ячейка 0.1 м. Получены одна связная область и два контура, один из них внутренний.

Что это даёт? Можно исследовать, где заканчиваются наблюдения выбранной поверхности. Но прямоугольный пробел может возникнуть и там, где висит картина, точки которой выделились в другую плоскость. Вырез, выходящий к внешней границе, также отличается от замкнутого внутреннего контура. Для интерпретации нужны сопоставление с облаком и дополнительные признаки.
В исходной научной статье рассматривается упрощение контуров через approxPolyDP. В текущем основном пути моего приложения отрезки DXF строятся через сечения плоскостей. Развёртка OpenCV существует как отдельный диагностический инструмент.
Ещё один инструмент — DBSCAN внутри каждой найденной плоскости. При радиусе 0.12 м сохранены 43 фрагмента; 91 малая компонента исключена из последующей проверки стыков. Так становятся видны пространственно раздельные наблюдения, которые RANSAC объединил одной плоскостью.

Проверка стыков сравнила 903 пары фрагментов: 436 почти параллельны, 414 пространственно разделены, у 48 недостаточно поддержки. Пять оставшихся пар дали шесть интервалов. Программа хранит основания этих решений и не соединяет поверхности автоматически.
Это помогает разбирать поведение метода, однако в сохранённом сравнении до и после фрагментации геометрия шести интервалов не изменилась. Поэтому пока я могу говорить о более подробном представлении данных, но не об измеренном росте точности.
SQL: откуда взялась линия и кто подтвердил результат
Идея базы данных пришла из опыта работы с финансовым ядром. Там важно иметь возможность проследить происхождение значения. Здесь возник похожий вопрос: по каким данным, с какими параметрами и почему появился конкретный отрезок?
В SQLite уже сохраняются запуски, описание источника, параметры обработки, коэффициенты плоскостей, отрезки и история экспорта. Для обычной загрузки из GUI фиксируется хеш исходного PLY. Из истории можно восстановить чертёж без повторной обработки облака. В демонстрационном проходе параметры и координаты всех 11 отрезков после чтения из базы совпали с сохранёнными.
Добавлены и ручные метки фрагментов с автором, датой и причиной. Эта часть ещё требует доработки: метки пока не меняют DXF, повторное назначение может оставлять несколько действующих записей, а перенос опирается на хеш локальных индексов. Одинаковые номера в разных массивах не гарантируют один и тот же физический участок.
Следующее развитие этой модели данных я вижу так:
Элемент чертежа → исходные наблюдения и параметры → решение инженера → связанная работа в ERP.
Первую часть этой связи уже можно исследовать в архиве запусков. Проверенное решение инженера и привязку к работе в ERP предстоит реализовать. Для этого нужны устойчивые идентификаторы, версия проекта, единицы измерения, история исправлений и понятный статус каждого результата.
Например, видимость поверхности на скане ещё не означает, что работа по ней принята. Для будущей интеграции я хочу различать состояния «наблюдается», «сопоставлено с проектом», «проверено» и «принято». Тогда запись в учёте будет связана с конкретным решением и его основанием. Автоматический расчёт смет или сумм к оплате текущий прототип не выполняет.
Что проверено и какой эксперимент будет следующим
На проверенном 2 октября состоянии проекта прошли 83 теста. Они покрывают свойства геометрии, разрывы, хранение и восстановление данных, структуру DXF и другие программные сценарии. В реальном проходе проверены экспорт 11 линий и 11 размеров, восстановление из SQLite и целостность базы. Графики интерфейса получены вызовом его обработчиков в сценарии воспроизведения.
Для моего облака точек пока нет независимого эталонного обмерного плана. Поэтому я не указываю процент правильных стен или гарантированную ошибку в миллиметрах. Время до готового результата с ручными исправлениями тоже ещё не измерено.
Сравнение с другим открытым решением, Cloud2BIM, показало необходимость учитывать требования к исходным данным. Полученные там оси стен нельзя напрямую оценивать по количеству относительно наших отрезков поверхностей. Такой опыт полезен для поиска ограничений, но не доказывает превосходство метода.

Следующий эксперимент хочу ограничить одним участком и одной задачей, подготовкой редактируемого плана наблюдаемых перегородок. Для него нужны скан, проектный план и независимая проверка инженером. Условия применения и критерии оценки должны быть определены до сравнения результатов.
Сначала нужно измерить смещение линий, пропуски, лишние элементы и полное время доведения DXF до пригодного чертежа. Сравнивать следует обычную работу специалиста и работу с прототипом, учитывая исправления и проверку. Затем можно проверять сопоставление с проектом и передачу подтверждённых сведений в ERP.
Для меня ценность следующей версии будет в том, что инженер сможет быстрее получить пригодный результат и проследить происхождение его элементов. Именно такой эксперимент должен показать, насколько путь от скана к исполнительным материалам и учёту работает за пределами демонстрации.

Сафиуллин Нияз Шамилевич
Инженер по автоматизации и внедрению ИИ · ERP, компьютерное зрение, Scan-to-CAD