E57, объяснение: "PDF облаков точек"
Представьте, что вы фотографируете комнату — но вместо плоского снимка вы фиксируете точное положение миллиона крошечных точек, покрывающих каждую стену, стул и чашку кофе. Если быстро вращать лазер и измерять, как далеко находится всё вокруг, получится облако точек — 3D "фотография" из измеренных точек. Это дружелюбный, без жаргона обзор того, что на самом деле находится внутри файла E57 — и одного удобного приёма, который наше ПО делает с ним.
Зачем вообще нужен специальный формат?
Обычная фотография — это всего лишь сетка цветных пикселей, просто. 3D-скан устроен сложнее. Для каждого из миллионов точек нужно сохранить где она находится в пространстве (три числа: X, Y, Z), какого цвета она, с какой силой лазер отразился обратно (её интенсивность — представьте чёрно-белую "лазерную фотографию") и часто панорамные фотографии, которые сканер сделал одновременно.
Теперь представьте: один человек сканирует с помощью Faro, коллега использует Leica, а клиент открывает результат в ПО Autodesk. Три устройства, три программы — и всем им нужно уметь читать один и тот же файл спустя годы, не выпрашивая у производителя секретный декодер. Именно эту проблему решает E57. Это открытый, нейтральный по отношению к производителю стандарт (опубликованный как ASTM E2807 и основанный на библиотеке с открытым исходным кодом libE57). Его называют "PDF облаков точек": один переносимый файл, который все умеют читать.
Главная идея: текстовая карта с бинарной мощью
По сути, файл E57 — это гибрид двух очень разных вещей, соединённых вместе: небольшого фрагмента XML — обычного, читаемого человеком текста, который служит оглавлением — и больших блоков бинарных данных, хранящих сырые миллионы чисел в компактном виде ради скорости.
Зачем помещать карту в конец? Потому что во время записи файла сканер ещё не знает, какого размера всё получится, поэтому сначала передаёт сырые данные, а уже потом, когда всё готово, записывает аккуратное резюме. Выгода огромна: чтобы извлечь один скан из файла на 20 гигабайт, ПО читает крошечный заголовок, переходит к XML-карте, находит строку "скан #3 находится по байту 4 812 000 000" и сразу прыгает туда.
Незаметная страховка: весь файл разбит на "страницы" по 1024 байта, и каждая страница резервирует последние 4 байта под контрольную сумму — отпечаток, который позволяет ПО заметить, если файл был повреждён.
Всё держится на одном корне
Откройте эту XML-карту, и вы увидите дерево — совсем как папки на компьютере. Есть один root, а две ветви делают основную работу: data3D, нумерованный список сканов, и images2D, нумерованный список фотографий (обычно это панорамы 360°, снятые сканером).
Два способа записать точку
Лазерный сканер на самом деле не мыслит в X, Y, Z. Он стоит в одной точке и вращается, и для каждой точки знает три вещи: дальность (как далеко прошёл луч), азимут (насколько вокруг, влево-вправо) и угол места (насколько вверх или вниз). Это сферические координаты — родной язык сканера. Большинство программ, однако, предпочитает обычные декартовы X, Y, Z. E57 спокойно хранит и то и другое, а перевод между ними — это немного быстрой тригонометрии.
Три вида встроенных фотографий
Фотографии в images2D — это не ссылки на файлы в какой-то папке: настоящий JPEG или PNG спрятан прямо внутри E57. И встроенные фотографии бывают не одного вида. E57 упаковывает каждую в "представление", которое сообщает ПО, насколько можно доверять изображению с геометрической точки зрения. Разница сводится к одному вопросу: насколько полно описана камера?
sphericalRepresentation— полная панорама 360° × 180°, знакомое растянутое эквиректангулярное 2:1 изображение. Поскольку проекция известна, каждый пиксель соответствует точному направлению, поэтому оно идеально совпадает с облаком. Это основной путь в нашем конвейере: мы читаем его, приводим холст к чистому 2:1 и передаём в просмотрщик панорам.pinholeRepresentation— одна обычная фотография с объективом, описанная классической моделью камеры-обскуры (фокусное расстояние, размер сенсора, оптический центр). Этого достаточно, чтобы ПО знало и направление каждого пикселя, только в более узком поле зрения. На практике именно так чаще всего работает Leica: она записывает готовый cubemap — шесть плоских граней куба, смотрящих наружу, — прямо в E57, а наш путь по граням куба точно собирает их в полную панораму. Это один из самых простых случаев, чтобы снова получить чистое изображение 360°.visualReferenceRepresentation— фотография без какой-либо модели камеры, прямо "только для человеческого глаза". С ней нельзя проводить измерения или проецировать её на облако; это лишь референсный снимок. Наш импортёр сохраняет такие изображения как вложенные комментарии, а не размещает их в 3D.
Вот в чём загвоздка. sphericalRepresentation — популярный вариант, но его удивительно легко слегка испортить — именно поэтому один и тот же скан может выглядеть по-разному в разных программах.
- Слепые зоны обрезаются. У каждого сканера есть место, которое он не может видеть — обычно прямо вниз, где стоит его собственный штатив. Некоторые экспортеры просто обрезают панораму там, оставляя разрыв или нестандартную высоту.
- Прямоугольные пиксели. У чистой панорамы пиксели квадратные (
pixelWidth=pixelHeight); в некоторых файлах это не так, поэтому изображение выглядит растянутым, пока его не масштабируют. - Неверное направление — это “forward”. Поворот, сохранённый вместе с панорамой, показывает, какое направление находится в центре изображения, и нет единого соглашения о том, что вообще означает “forward” — одни экспортеры направляют его на север, другие на восток. Малейшая ошибка здесь поворачивает весь вид.
- Инструменты редактирования могут терять данные. Например, при обратной записи E57 через CloudCompare может пропасть позиция съёмки изображений
pinholeRepresentation— фотографии сохраняются, но уже не знают, где были сняты.
Итог такой: в реальности разное ПО часто показывает один и тот же E57 по-разному. Наш импортёр старается сгладить типичные особенности — сделать прямоугольные пиксели квадратными, исправить ориентацию панорамы и привести холст к формату 2:1 — чтобы тур выглядел правильно, независимо от того, какой инструмент записал файл.
Когда панорама встроена прямо в само облако точек
Вот одна из самых элегантных — и наименее оценённых — идей во всём формате. Помимо панорам, хранящихся как отдельные изображения, панорама может скрываться в самом облаке точек. Лазерный сканер не стреляет случайно — он проходит аккуратную сетку углов, строка за строкой, столбец за столбцом, как старый телевизор, рисующий экран. E57 может сохранить этот порядок: каждой точке присваиваются rowIndex и columnIndex, показывающие, из какой ячейки сетки она пришла. Скан, сохранённый таким образом, называется структурированным.
Преимущество в том, что если точки лежат на сетке, облако уже является изображением. Читайте его строка за строкой, и каждая точка попадает в пиксель — панорама возвращается вообще без хитрой перепроекции. Файл даже записывает размер сетки в indexBounds (columnMaximum, rowMaximum), так что программа заранее знает разрешение — наш синтезатор берёт ширину вывода прямо из columnMaximum + 1.
Но сетка должна быть идеальным прямоугольником, а реальный мир — нет. Что делать с направлениями, где луч ушёл в открытое небо и ничего не вернулось? Ответ прагматичен: заполнить эти ячейки фиктивными точками — очень часто с дальностью ровно 0, то есть "луч отправлен, ничего не попало". Они сохраняют целостность прямоугольника, но не являются реальной геометрией, поэтому внимательный читатель должен их отбрасывать. Наш просмотрщик помечает каждую точку с нулевой дальностью, уводит её на фиктивно далёкое расстояние, чтобы математика сетки продолжала работать, и никогда не принимает эти фантомные точки неба за реальные поверхности, когда строит карту глубины или экспортирует облако.
Превратить скан обратно в фотографию, в которую можно войти
Не каждый скан приходит в виде готовой сетки — некоторые представляют собой просто рыхлую, неструктурированную россыпь точек. Хорошая новость: панораму всё ещё можно восстановить, и именно здесь формат встречается с нашей собственной работой. Ведь скан — это по сути "полная сфера точек, измеренных как углы вокруг одной точки", так что его можно развернуть в плоскую панораму.
Зафиксируйте угол каждой точки, пустите слева-направо по ширине изображения и сверху-вниз по его высоте, и каждая точка попадёт в пиксель — знакомую растянутую эквиректангулярную 2:1 панораму. Карта глубины — это магический ингредиент: когда за каждым пикселем есть расстояние, плоская на вид панорама становится измеримой и проходимой — щёлкните две точки на стене, и ПО узнает реальное расстояние, потому что оно никогда не забывает о лежащих под ней 3D-данных.
Так почему же E57 важен?
Потому что это нейтральная точка встречи. Геодезист сканирует мост оборудованием одной марки, инженер открывает его в другом ПО, а архитектор архивирует его на следующие двадцать лет — и E57 это единый файл, на который все трое могут положиться, без какого-либо вендора, держащего ключи. Он хранит цвет, интенсивность, геометрию, панорамы и особенно важные позиции датчика вместе в одном месте, как открытый стандарт, который может реализовать любой.
И ещё один любопытный факт: время съёмки внутри E57 считается в GPS-времени — в секундах с 6 января 1980 года, момента, когда включились часы спутников GPS, — а не от обычной компьютерной эпохи 1970 года. Ошибитесь здесь, и скан, сделанный сегодня, будет выглядеть так, будто он произошёл в 2013 году.
Хотите узнать больше?
- libE57.org — эталонная библиотека с открытым исходным кодом и родной дом формата.
- ASTM E2807 — официальный стандарт.
- libE57Format · Image2D — точные определения сферического, точечного и визуально-справочного представлений.
- Paul Bourke’s E57 notes — краткий технический разбор заголовка и структуры.