3D Scanner собственными руками
3D Scanner собственными руками
Высшее назначение математики состоит в том, чтобы находить скрытый порядок в хаосе, который нас окружает
Норберт Винер
Здравствуйте!
Этот материал про то, как собственными руками создать 3d Scanner. Я постараюсь на пальцах объяснить логику его работы.
Вдохновившись вот этим:
http://en.wikipedia.org/wiki/3d_scanner
захотелось тоже сделать себе такую штуковину. Точнее это один вариант решения этой задачи из бесчисленного множества. Это, конечно же, не будет сверхточным прибором, но я надеюсь, что вам будет интересно.
Что необходимо для того чтобы завести сканер:
1. Web-камера.
2. Лампа.
3. Два квадратных листа перпендикулярных друг другу.
Web-камеры сейчас стоят очень дешево: обошлась мне в 600 р. (D-Link DSB C320). Разумеется, что чем лучше камера, тем лучше результаты.
Я с гордостью представляю вам свой девайс:
Картонка для отбрасывания тени (должна быть плоской и отбрасывать тень в одной плоскости). Это будет имитировать работу лазера, который светит в плоскости, который вы тоже можете использовать, если он у вас есть (вы его можете заказать в интернете, он стоит около 20 у.е.). Естественно, лазер лучше лампы.
Теперь о принципе работы. Давайте посмотрим на эту картинку:
Мы видим, как падает тень. Линия тени должна быть чётко видна как на квадратных плоскостях, так и на сканируемом объекте. Угол ABC (как вы уже должны были догадаться) - прямой.
Давайте взглянем на то, что нам из этого нужно поближе:
Обратите внимание на линию пересечения с квадратными плоскостями и линию сканирования. Все точки на этих линиях лежат в одной плоскости. Если вы внимательно посмотрите на линию пересечения с плоскостями, то обнаружите, что они образуют три точки (A,B,C) пересечения с плоскостями. Значит, нам известны три точки из плоскости, в которой лежит линия сканирования (и линия пересечения). Три точки это всё что необходимо для построения уравнения плоскости.
Зная координату камеры, можем испустить луч из камеры на линию сканирования. Пересечение с плоскостью тени и будут будущим 3d объектом.
Рассчитать координату камеры имея точки 0,1,2,3,4,5 очень трудно. Однако мы можем калибровать камеру вручную в 3д редакторе.
Я предпочитаю Maya и буду делать в ней и описывать всё на языке MEL.
Если вдуматься, то всё очень просто. Я даже полагаю, что человеческий мозг руководствуется теми же принципами, когда оценивает расстояние одним глазом. Если мы посчитаем картинку без тени, то предметы будут «висеть в воздухе», т.е. глазомер не может определить месторасположение объекта. Его координату можно вычислить только если объект движется … однако я загнался.
И так. Если вы не понимаете, что такое уравнение плоскости, то я постараюсь рассказать, как это понимаю я.
Несмотря на неоценимую мощь, плоскость описывается просто:
Ax + By + Cz + D = 0 (где A,B,C и D - постоянные, причём A,B и C одновременно не равны нулю)
Это общее уравнение плоскости. В прочем, в интернете вы можете много чего найти про плоскость.
В справочниках очень сложно-звучащие определения. Лично я представляю себе плоскость в виде нормали и расстояния до плоскости от центра координат. Нормаль – это единичный вектор, а расстояние – это скаляр.
Представьте себе нормаль: она описывает плоскость, проходящую через центр координат, а потом подвиньте эту плоскость в направлении нормали на известное расстояние. Получается, что плоскость – это четыре скаляра или один вектор и скаляр.
На языке MEL плоскость можно описать так:
float $plane[4];
Это просто четыре числа. Получить их можно из трёх точек (три точки – это три вектора). Пример решения на MEL:
Выглядит громоздко, потому что я очень стараюсь комментировать подробно, но если вам что-то непонятно, то это простые действия над векторами. Обратитесь к любому справочнику (или даже к руководству Maya). Ничего сверхсложного здесь нет.
Как находить плоскость уже догадываемся. Теперь жизненно необходима позиция камеры. Чтобы рассчитать луч из камеры до линии сканирования.
Калибровка камеры является очень сложной математической задачей. И я не решился мучить себя и (не дай бог) Вас этим занятием. Я подумал, что проще всего в ручную настроить камеру и снимать с неё координату.
Для этого создал сцену, в которой создал персональную камеру и каркас для подгона будущих точек, которые тоже будут назначаться вручную.
Да… это не очень уж быстро, нудно, но нет никаких ограничений по материалу санируемого объекта и его окружению. Так что плюсов в этом способе предостаточно (лучшим плюсом является, пожалуй, - простота реализации).
Калибровку камеры удобно совершать, когда картинка подгоняется к Resolution Gate.
Появилась позиция камеры. Теперь необходимо научиться рассчитывать пересечение луча с плоскостью. Для этого надо понимать, что такое луч. Луч – это два вектора. Один вектор - это координата старта луча (в нашем случае это камера), другой - это его направление. Направление, как и нормаль, - это единичный вектор (нормализованный вектор).
Можно долго на словах объяснять, как рассчитывать пересечение:
Как видите, решение весьма изящное:
Ну вот математика и кончилась.
Непосредственно сам процесс сканирования выглядит так:
Функция ( createScannerPoint ) создает точки (сферы) будущего объекта и помещает их в специальную группу (final_group), которую удобно проявлять и убирать из виду с помощью дополнительных кнопок на интерфейсе:
Если это можно назвать интерфейсом. А что тут собственно ещё такого придумаешь. Мне кажется, что код сложных интерфейсов крайне неудобно читать (даже если ты сам его написал), а это всё-таки ещё и урок.
Ресурсы:
1) Проект Maya 8.5 (ma)
2) Script
Запускаем проект майя и скрипт (source "3dScanner.mel";).
Смотрим, как всё устроено: дёргаем локаторы. Теперь снимаем видео с web-камеры:
Подгоняем main_camera вместе с подключённым Image Plane (с включённым проигрыванием секвенции кадров из avi). Как я уже говорил подгонять удобно по Resolution Gate:
Чтобы повысить точность сначала воспользуйтесь alt и мышью, а потом Move Tool, Rotate Tool и чуть угол обзора подкрутить, если нужно. После подгона сделайте камере Lock ( в дополнительных инструментах окошка это делается одной кнопкой ).
У меня моя горе-цифромыльница умеет снимать максимум 640*480 и делает это ужасно. В принципе, можно использовать цифровой фотоаппарат или видеокамеру подключённые к компьютеру. Раз 640*480, то и в настройках Image Size должны быть эти числа.
Теперь, не нервничая, вручную двигаем прицел (target) по линии сканирования, не забывая перемещать локаторы, образующие плоскость тени (p1,p2,p3). Удобно также проставить на хот кей команду createScannerPoint или использовать кнопку G, после запуска команды из Script Editor.
В итоге получаем набор из точек в трёх координатах. Чем точнее были ваши движения и техника, тем с меньшим шумом выглядит финальный результат.
На этом всё.
На самом деле меня очень сильно расстроило качество моей техники: мыленная и очень маленькая картинка, кадров в секунду катастрофически мало и монитор маловат у меня для точной работы. Самый облом – это лампа. Она даёт рассеянную тень в любом случае. Необходим специальный лазер (хоть он и стоит дёшево, но мой опыт общения с нашей почтой отбил желание его заказывать).
Вы можете из каждой сканированной линии делать NURBS кривую и по ним в итоге запустить loft поверхность. Или же написать скрипт, который строит сетку по полученным точкам, координаты которых вы можете снимать со сфер.
Урок построен так, что без понимания принципа работы отсканировать было бы трудновато. Не знаю, даже, хорошо это или плохо, но я подумал, что принцип тут интереснее реализации и на этом делал акцент урока (или статьи?). Короче говоря, сам не знаю, что я написал.
Надеюсь, что вам было интересно и спасибо за внимание.