6
votes

Algorithme de projection cubique à Equirectangulaire

J'ai une texture de carte cube qui définit un environnement environnant, mais je dois la transmettre à un programme qui fonctionne uniquement avec des cartes de latitude / longitude. Je suis vraiment perdu ici sur la façon de faire la traduction. Toute aide ici?

En d'autres termes, je dois venir d'ici:

Entrez la description de l'image ici

à ceci (je pense que l'image a une rotation ADITIONNEL -90 ° sur l'axe X):

Entrez la description de l'image ici

Mise à jour: J'ai reçu les noms officiels des projections. À propos, j'ai trouvé la projection opposée ici


0 commentaires

5 Réponses :


8
votes

Procédure générale pour la projection d'images raster comme celle-ci est la suivante:

x = cos(lat)*cos(lon)
y = cos(lat)*sin(lon)
z = sin(lat)


0 commentaires

1
votes

Alors, j'ai trouvé une solution mélangeant Cet article sur des coordonnées sphériques de Wikipedia et de la Section 3.8.10 de la spécification OpenGL 4.1 (plus des hacks pour le faire fonctionner). Ainsi, en supposant que l'image cubique ait une hauteur h_o et largeur w_o , l'équivérectangulaire aura une hauteur h = w_o / 3 et une largeur w = 2 * h . Maintenant pour chaque pixel (x, y) 0 <= x <= w, 0 <= y <= h dans la saillie équilangulaire, nous voulons trouver le pixel correspondant dans la projection cubique, je résolve Il utilise le code suivant dans Python (j'espère que je n'ai pas fait des erreurs tout en le traduisant de c) xxx

à la fin, nous venons d'appeler wind_correspondant_pixel pour chaque pixel dans la saillie équivéchange


0 commentaires

2
votes

Projet a changé de nom sur libcube2cyl . Même bonté, meilleurs exemples de travail à la fois en C et C ++.


Maintenant également disponible en c.


Je suis arrivé à résoudre le même problème que vous avez décrit.

J'ai écrit ce minuscule C ++ Lib appelé " cube2cyl ", vous pouvez trouver l'explication détaillée de l'algorithme Ici: cube2cyl

Veuillez trouver le code source de github: cube2cyle

Il est publié sous licence MIT, utilisez-le gratuitement!


1 commentaires

Belle bibliothèque, mais je n'ai pas pu le construire sur Macos, ou peut-être que je ne comprends pas cela, ça marche comme cet autre CLI? Github.com/perthcpe23/cube-a-Equirectangulaire



2
votes

J'aimerais partager ma mise en œuvre de malab de cette conversion. J'ai également emprunté à la spécification OpenGL 4.1, chapitre 3.8.10 ( trouvé ici ), ainsi que le site Web de Paul Bourke ( trouvé ici ). Assurez-vous de regarder sous la sous-position: Conversion de 6 cartes de l'environnement cubique et une carte sphérique em>.

J'ai également utilisé la poste de Sambatyon ci-dessus comme source d'inspiration. Il a commencé comme port de Python sur Matlab, mais j'ai fait le code de sorte qu'il soit complètement vectorisé (c'est-à-dire non pour code> boucles). Je prends aussi l'image cubique et divisez-la en 6 images séparées, car l'application que je consomme a l'image cubique dans ce format. De plus, il n'y a pas de vérification erronée avec le code et cela suppose que toutes les images cubes sont de la même taille ( n x n code>). Cela suppose également que les images sont au format RVB. Si vous souhaitez le faire pour une image monochromatique, commencez simplement ces lignes de code nécessitant un accès à plusieurs canaux. Ici, nous allons! P>

function [out] = cubic2equi(top, bottom, left, right, front, back)

% Height and width of equirectangular image
height = size(top, 1);
width = 2*height;

% Flags to denote what side of the cube we are facing
% Z-axis is coming out towards you
% X-axis is going out to the right
% Y-axis is going upwards
% Assuming that the front of the cube is towards the
% negative X-axis
FACE_Z_POS = 1; % Left
FACE_Z_NEG = 2; % Right
FACE_Y_POS = 3; % Top
FACE_Y_NEG = 4; % Bottom
FACE_X_NEG = 5; % Front 
FACE_X_POS = 6; % Back

% Place in a cell array
stackedImages{FACE_Z_POS} = left;
stackedImages{FACE_Z_NEG} = right;
stackedImages{FACE_Y_POS} = top;
stackedImages{FACE_Y_NEG} = bottom;
stackedImages{FACE_X_NEG} = front;
stackedImages{FACE_X_POS} = back;

% Place in 3 3D matrices - Each matrix corresponds to a colour channel
imagesRed = uint8(zeros(height, height, 6));
imagesGreen = uint8(zeros(height, height, 6));
imagesBlue = uint8(zeros(height, height, 6));

% Place each channel into their corresponding matrices
for i = 1 : 6
    im = stackedImages{i};
    imagesRed(:,:,i) = im(:,:,1);
    imagesGreen(:,:,i) = im(:,:,2);
    imagesBlue(:,:,i) = im(:,:,3);
end

% For each co-ordinate in the normalized image...
[X, Y] = meshgrid(1:width, 1:height);

% Obtain the spherical co-ordinates
Y = 2*Y/height - 1;
X = 2*X/width - 1;
sphereTheta = X*pi;
spherePhi = (pi/2)*Y;

texX = cos(spherePhi).*cos(sphereTheta);
texY = sin(spherePhi);
texZ = cos(spherePhi).*sin(sphereTheta);

% Figure out which face we are facing for each co-ordinate
% First figure out the greatest absolute magnitude for each point
comp = cat(3, texX, texY, texZ);
[~,ind] = max(abs(comp), [], 3);
maxVal = zeros(size(ind));
% Copy those values - signs and all
maxVal(ind == 1) = texX(ind == 1);
maxVal(ind == 2) = texY(ind == 2);
maxVal(ind == 3) = texZ(ind == 3);

% Set each location in our equirectangular image, figure out which
% side we are facing
getFace = -1*ones(size(maxVal));

% Back
ind = abs(maxVal - texX) < 0.00001 & texX < 0;
getFace(ind) = FACE_X_POS;

% Front
ind = abs(maxVal - texX) < 0.00001 & texX >= 0;
getFace(ind) = FACE_X_NEG;

% Top
ind = abs(maxVal - texY) < 0.00001 & texY < 0;
getFace(ind) = FACE_Y_POS;

% Bottom
ind = abs(maxVal - texY) < 0.00001 & texY >= 0;
getFace(ind) = FACE_Y_NEG;

% Left
ind = abs(maxVal - texZ) < 0.00001 & texZ < 0;
getFace(ind) = FACE_Z_POS;

% Right
ind = abs(maxVal - texZ) < 0.00001 & texZ >= 0;
getFace(ind) = FACE_Z_NEG;

% Determine the co-ordinates along which image to sample
% based on which side we are facing
rawX = -1*ones(size(maxVal));
rawY = rawX;
rawZ = rawX;

% Back
ind = getFace == FACE_X_POS;
rawX(ind) = -texZ(ind);
rawY(ind) = texY(ind);
rawZ(ind) = texX(ind);

% Front
ind = getFace == FACE_X_NEG;
rawX(ind) = texZ(ind);
rawY(ind) = texY(ind);
rawZ(ind) = texX(ind);

% Top
ind = getFace == FACE_Y_POS;
rawX(ind) = texZ(ind);
rawY(ind) = texX(ind);
rawZ(ind) = texY(ind);

% Bottom
ind = getFace == FACE_Y_NEG;
rawX(ind) = texZ(ind);
rawY(ind) = -texX(ind);
rawZ(ind) = texY(ind);

% Left
ind = getFace == FACE_Z_POS;
rawX(ind) = texX(ind);
rawY(ind) = texY(ind);
rawZ(ind) = texZ(ind);

% Right
ind = getFace == FACE_Z_NEG;
rawX(ind) = -texX(ind);
rawY(ind) = texY(ind);
rawZ(ind) = texZ(ind);

% Concatenate all for later
rawCoords = cat(3, rawX, rawY, rawZ);

% Finally determine co-ordinates (normalized)
cubeCoordsX = ((rawCoords(:,:,1) ./ abs(rawCoords(:,:,3))) + 1) / 2;
cubeCoordsY = ((rawCoords(:,:,2) ./ abs(rawCoords(:,:,3))) + 1) / 2;
cubeCoords = cat(3, cubeCoordsX, cubeCoordsY);

% Now obtain where we need to sample the image
normalizedX = round(cubeCoords(:,:,1) * height);
normalizedY = round(cubeCoords(:,:,2) * height);

% Just in case.... cap between [1, height] to ensure
% no out of bounds behaviour
normalizedX(normalizedX < 1) = 1;
normalizedX(normalizedX > height) = height;
normalizedY(normalizedY < 1) = 1;
normalizedY(normalizedY > height) = height;

% Place into a stacked matrix
normalizedCoords = cat(3, normalizedX, normalizedY);

% Output image allocation
out = uint8(zeros([size(maxVal) 3]));

% Obtain column-major indices on where to sample from the
% input images
% getFace will contain which image we need to sample from
% based on the co-ordinates within the equirectangular image
ind = sub2ind([height height 6], normalizedCoords(:,:,2), ...
    normalizedCoords(:,:,1), getFace);

% Do this for each channel
out(:,:,1) = imagesRed(ind);
out(:,:,2) = imagesGreen(ind);
out(:,:,3) = imagesBlue(ind);


0 commentaires

0
votes

Je pense de votre algorithme dans Python, vous aurez peut-être inversé X et Y dans le calcul de Theta et Phi. XXX

du site Web de Paul Bourke ici

theta = x pi Phi = y pi / 2

et dans votre code, vous utilisez y dans le calcul THETA et x dans le calcul du PHI.

corrigez-moi si je me trompe.


1 commentaires

Et si vous pouviez m'aider à comprendre pourquoi la formule à trouver (x, y, z) si différente de votre code (qui utilise la page Wikipedia) et la formule de Paul Bourke? Lequel est réellement correct?