Преобразование карты глубины angular в трехмерное облако точек - PullRequest
1 голос
/ 09 апреля 2020

У меня есть двухмерная экваториальная карта глубины angular, представляющая собой массив с плавающей точкой 1024 x 512, каждый в диапазоне от 0 до 1. Вот пример (усеченный до оттенков серого):

img

Я хочу преобразовать его в набор трехмерных точек, но у меня возникают проблемы с поиском правильной формулы для этого - это своего рода близкий - псевдокод здесь (с использованием библиотеки vec3 ()):

for(var y = 0; y < array_height; ++y) {

    var lat = (y / array_height) * 180.0 - 90.0;

    var rho = Math.cos(lat * Math.PI / 180.0);

    for(var x = 0; x < array_width; ++x) {

        var lng = (x / array_width) * 360.0 - 180.0;

        var pos = new vec3();
        pos.x = (r * Math.cos(lng * Math.PI / 180.0));
        pos.y = (Math.sin(lat * Math.PI / 180.0));
        pos.z = (r * Math.sin(lng * Math.PI / 180.0));
        pos.norm();

        var depth = parseFloat(depth[(y * array_width) + x] / 255);

        pos.multiply(depth);

        // at this point I can plot pos as an X, Y, Z point
    }
}

То, что я получаю, не совсем правильно, и я не могу сказать, почему нет. Я уверен, что данные верны. Может кто-нибудь подсказать, что я делаю не так.

Спасибо.

Молли.

1 Ответ

0 голосов
/ 11 апреля 2020

Хорошо выглядит, как текстура полусферы в сферических координатах:

  • x ось - это угол долготы a <0,180> [deg]
  • y ось - это угол широты b <-45,+45> [deg]
  • интенсивность - это радиус r <0,1> [-]

Таким образом, для каждого пикселя просто:

  1. , линейное преобразование x,y в a,b

    в градусах:

    a =         x*180 / (width -1)
    b = -45 + ( y* 90 / (height-1) )
    

    или в радианах:

    a =                    x*M_PI / (width -1)
    b = -0.25*M_PI + ( 0.5*y*M_PI / (height-1) )
    
  2. применяется сферическое преобразование в декартовое

    x=r*cos(a)*cos(b);
    y=r*sin(a)*cos(b);
    z=r*       sin(b);
    

    Похоже, вы неверно закодировали это преобразование , поскольку угол широты должен быть во всех x,y,z, а не только y !!! Также вам следует не нормализовать результирующую позицию, которая бы испортила форму !!!

  3. сохранить точку в облаке точек.

Когда я собираю все вместе в VCL / C ++ (извините, не кодируйте в javascript):

List<double> pnt;                   // 3D point list x0,y0,z0,x1,y1,z1,...
void compute()
    {
    int x,y,xs,ys;      // texture positiona and size
    double a,b,r,da,db; // spherical positiona and angle steps
    double xx,yy,zz;    // 3D point
    DWORD *p;           // texture pixel access
    // load and prepare BMP texture
    Graphics::TBitmap *bmp=new Graphics::TBitmap;
    bmp->LoadFromFile("map.bmp");
    bmp->HandleType=bmDIB;
    bmp->PixelFormat=pf32bit;
    xs=bmp->Width;
    ys=bmp->Height;
/*
    // 360x180 deg
    da=2.0*M_PI/double(xs-1);
    db=1.0*M_PI/double(ys-1);
    b=-0.5*M_PI;
*/
    // 180x90 deg
    da=1.0*M_PI/double(xs-1);
    db=0.5*M_PI/double(ys-1);
    b=-0.25*M_PI;

    // proces all its pixels
    pnt.num=0;
    for (                                 y=0; y<ys; y++,b+=db)
     for (p=(DWORD*)bmp->ScanLine[y],a=0.0,x=0; x<xs; x++,a+=da)
        {
        // pixel access
        r=DWORD(p[x]&255);  // obtain intensity from texture <0..255>
        r/=255.0;           // normalize to <0..1>
        // convert to 3D
        xx=r*cos(a)*cos(b);
        yy=r*sin(a)*cos(b);
        zz=r*       sin(b);
        // store to pointcloud
        pnt.add(xx);
        pnt.add(yy);
        pnt.add(zz);
        }
    // clean up
    delete bmp;
    }

Вот предварительный просмотр для 180x90 градусов:

180x90

и предварительный просмотр для 360x180 град .:

360x180

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

В случае, если второй вариант просто использует разные числа (удвоенные) для интерполяции в маркере # 1

Также, если вы хотите удалить фон, просто игнорируйте r==1 пикселей:

no background

, просто проверяя интенсивность до максимальное значение (до нормализации) в моем случае, добавив эту строку:

if (r==255) continue;

после этой

r=DWORD(p[x]&255);

В вашем случае (у вас уже есть <0..1>) вы должны проверить r>=0.9999 о Вместо этого что-то подобное.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...