как раскрасить облако точек из пикселей изображения?

Я использую планшет google tango для получения данных облака точек и изображений с камеры RGB. Я хочу создать 3D-скан комнаты. Для этого мне нужно сопоставить пиксели 2D-изображения с точкой облака точек. Я буду делать это с множеством облаков точек и соответствующих изображений. Таким образом, мне нужно написать сценарий кода, который имеет два входа: 1. облако точек и 2. изображение, полученное из одной и той же точки в том же направлении, и сценарий должен выводить цветные точки. облако. Как мне подойти к этому и какие платформы будут очень простыми в использовании?


person david    schedule 04.06.2015    source источник


Ответы (2)


Вот математика для сопоставления трехмерной точки v с пространством 2D пикселей в изображении камеры (при условии, что v уже включает внешнее положение и ориентацию камеры, см. Примечание внизу *):

// Project to tangent space.
vec2 imageCoords = v.xy/v.z;

// Apply radial distortion.
float r2 = dot(imageCoords, imageCoords);
float r4 = r2*r2;
float r6 = r2*r4;
imageCoords *= 1.0 + k1*r2 + k2*r4 + k3*r6;

// Map to pixel space.
vec3 pixelCoords = cameraTransform*vec3(imageCoords, 1);

Где cameraTransform - матрица 3x3:

[ fx   0  cx ]
[  0  fy  cy ]
[  0   0   1 ]

с fx, fy, cx, cy, k1, k2, k3 из _13 _ .

pixelCoords объявлен vec3, но на самом деле он 2D в однородных координатах. Третья координата всегда равна 1, поэтому для практических целей ею можно пренебречь.

Обратите внимание: если вам нужны координаты текстуры вместо координат пикселей, это просто еще одно линейное преобразование, которое можно предварительно умножить на cameraTransform (как и любая адресация строк развертки сверху вниз или снизу вверх).

Что касается того, какая «платформа» (которую я в общих чертах интерпретирую как «язык») является самой простой, то собственный API кажется наиболее простым способом заполучить пиксели камеры, хотя, похоже, людям также удалось использовать Unity и Java.


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

person rhashimoto    schedule 04.06.2015

Этот ответ не является оригинальным, он просто предназначен для удобства пользователей Unity, которые хотели бы, чтобы правильный ответ, предоставленный @rhashimoto, был разработан для них. Мой вклад (надеюсь) заключается в предоставлении кода, который уменьшает обычные 16 умножений и 12 сложений (учитывая, что Unity делает только матрицы 4x4) до 2 умножений и 2 сложений, отбрасывая все нулевые результаты. Я прогнал тест чуть меньше миллиона точек, проверяя каждый раз, что мои расчеты согласуются с расчетами базовой матрицы - определяемой как абсолютная разница между двумя результатами меньше, чем машинный эпсилон - мне это нравится настолько, насколько я могу знать, что @rhashimoto может появиться и проткнуть в нем гигантскую дыру :-)

Если вы хотите переключаться вперед и назад, помните, что это C #, поэтому определение USEMATRIXMATH должно появиться в начале файла.

Учитывая, что сейчас есть только одно устройство Tango, и я предполагаю, что встроенные функции постоянны для всех устройств, я просто выгружал их как константы, так что

fx = 1042.73999023438
fy = 1042.96997070313
cx = 637.273986816406
cy = 352.928985595703
k1 = 0.228532999753952
k2 = -0.663019001483917
k3 = 0.642908990383148

Да, их можно использовать как константы, что сделает вещи более читабельными, и C #, вероятно, достаточно умен, чтобы оптимизировать его - однако я провел слишком большую часть своей жизни в материалах Агнера Фогга и всегда буду параноиком.

Закомментированный код внизу предназначен для проверки разницы, если хотите. Вам придется раскомментировать некоторые другие вещи и закомментировать результаты, если вы хотите проверить результаты.

Еще раз спасибо @rhashimoto, это намного лучше, чем то, что у меня было

Я остался верен его логике, помните, что это координаты пикселей, а не координаты UV - он прав, вы можете предварительно умножить преобразование, чтобы получить нормализованные значения UV, но, поскольку он уже научил меня этому однажды, я буду придерживаться именно математики он представил, прежде чем я слишком много возился :-)

static public Vector2 PictureUV(Vector3 tangoDepthPoint)
    {
        Vector2 imageCoords = new Vector2(tangoDepthPoint.x / tangoDepthPoint.z, tangoDepthPoint.y / tangoDepthPoint.z);
        float r2 = Vector2.Dot(imageCoords, imageCoords);
        float r4 = r2*r2;
        float r6 = r2*r4;
        imageCoords *= 1.0f + 0.228532999753952f*r2 + -0.663019001483917f*r4 + 0.642908990383148f*r6;
        Vector3 ic3 = new Vector3(imageCoords.x,imageCoords.y,1);

#if USEMATRIXMATH
        Matrix4x4 cameraTransform  = new Matrix4x4();
        cameraTransform.SetRow(0,new Vector4(1042.73999023438f,0,637.273986816406f,0));
        cameraTransform.SetRow(1, new Vector4(0, 1042.96997070313f, 352.928985595703f, 0));
        cameraTransform.SetRow(2, new Vector4(0, 0, 1, 0));
        cameraTransform.SetRow(3, new Vector4(0, 0, 0, 1));
        Vector3 pixelCoords = cameraTransform * ic3;
        return new Vector2(pixelCoords.x, pixelCoords.y);
#else
        //float v1 = 1042.73999023438f * imageCoords.x + 637.273986816406f;
        //float v2 = 1042.96997070313f * imageCoords.y + 352.928985595703f;
        //float v3 = 1;
        return new Vector2(1042.73999023438f * imageCoords.x + 637.273986816406f,1042.96997070313f * imageCoords.y + 352.928985595703);
#endif

        //float dx = Math.Abs(v1 - pixelCoords.x);
        //float dy = Math.Abs(v2 - pixelCoords.y);
        //float dz = Math.Abs(v3 - pixelCoords.z);
        //if (dx > float.Epsilon || dy > float.Epsilon || dz > float.Epsilon)
        //    UnityEngine.Debug.Log("Well, that didn't work");
        //return new Vector2(v1, v2);
    }

И последнее замечание: обратите внимание, что предоставленный им код - это GLSL - если вы используете его только для красивых картинок, используйте его - это для тех, кому действительно нужна дополнительная обработка.

person Mark Mullin    schedule 05.06.2015