2: 1 eşkenar dörtgen panorama'yı küp haritaya dönüştür

Şu anda bir web sitesi için basit bir 3D panorama görüntüleyici üzerinde çalışıyorum. Mobil performans nedeniyle three.js CSS3 kullanıyorum. oluşturucu . Bu, 6 tek görüntüye bölünmüş bir küp haritası gerektirir.

Görüntüleri Google Photosphere uygulamasıyla veya 2: 1 eşkenar dörtgen panoramalar oluşturan benzer uygulamalarla iPhone'da kaydediyorum. Daha sonra bunları yeniden boyutlandırıp bu web sitesiyle bir cubemap'a dönüştürüyorum: http://gonchar.me/panorama/ (Flash)

Tercihen, dönüştürmeyi kendim yapmak , ister mümkünse üç.js kodunda, ister Photoshop'ta. Andrew Hazelden'ın Photoshop eylemlerini buldum ve çok yakın görünüyorlar, ancak doğrudan dönüşüm mümkün değil. Bunları dönüştürmenin matematiksel bir yolu var mı yoksa bunu yapan bir tür komut dosyası var mı? Mümkünse, Blender gibi bir 3D uygulamasından geçmek istemem.

Belki bu uzun bir atış, ama soracağımı düşündüm. Javascript ile iyi bir deneyimim var, ancak three.js konusunda yeniyim. Ayrıca, mobil cihazlarda ya yavaş ya da çocuk arabası gibi göründüğü için WebGL işlevselliğine güvenmekte tereddüt ediyorum. Destek de hala sivilceli.

36
Bunu yapmak için bir python betiği oluşturdum github.com/seiferteric/cubemap
katma yazar Eric Seifert, kaynak
Javascript'te CSS veya kanvas kullanan bu işlemi yapmanın yolları vardır. Ancak three.js ile uyumlu olduğundan emin değilim. stackoverflow.com/questions/8912917 aracılığıyla parçalara ayırma/& hellip;
katma yazar Salix alba, kaynak

11 cevap

Sunucu tarafında yapmak istiyorsanız birçok seçenek var. http://www.imagemagick.org/ , resminizi parçalara ayırabilen birkaç komut satırı aracı içerir . Bunu bir komut dosyasına koyabilir ve her yeni görüntünüz olduğunda onu çalıştırabilirsiniz.

Its hard to tell quite what algorithm is used in the program. We can try and reverse engineer quite what is happening by feeding a square grid into the program. I've used a grid from wikipedia

64 by 64 grid

Bu, öngörülen ızgara ifadesini verir.

Biri enlem ve boylam çizgileri ve onu çevreleyen bir küp ile görüntüleme küresi. Şimdi kürenin ortasındaki noktadan projeksiyon küp üzerinde çarpık bir ızgara üretir.

Mathematically take polar coordinates r, θ, ø, for the sphere r=1, 0 < θ < π, -π/4 < ø < 7π/4

  • x = r sin θ cos ø
  • y = r sin θ sin ø
  • z = r cos θ

centrally project these to the cube. First we divide into four regions by the latitude -π/4 < ø < π/4, π/4 < ø < 3π/4, 3π/4 < ø < 5π/4, 5π/4 < ø < 7π/4. These will either project to one of the four sides the top or the bottom.

Assume we are in the first side -π/4 < ø < π/4. The central projection of (sin θ cos ø, sin θ sin ø, cos θ) will be (a sin θ cos ø, a sin θ sin ø, a cos θ) which hits the x=1 plane when

  • bir günah θ cos ø = 1

yani

  • a = 1/(sin θ cos ø)

ve öngörülen nokta

  • (1, tan ø, karyola θ/cos ø)

If | cot θ/cos ø | < 1 this will be on the front face. Otherwise, it will be projected on the top or bottom and you will need a different projection for that. A better test for the top uses the fact that the minimum value of cos ø will be cos π/4 = 1/√2, yani the projected point is always on the top if cot θ/(1/√2) > 1 or tan θ < 1/√2. This works out as θ < 35º or 0.615 radians.

Bunu python ile bir araya getirin

import sys
from PIL import Image
from math import pi,sin,cos,tan

def cot(angle):
    return 1/tan(angle)

# Project polar coordinates onto a surrounding cube
# assume ranges theta is [0,pi] with 0 the north poll, pi yaniuth poll
# phi is in range [0,2pi] 
def projection(theta,phi): 
        if theta<0.615:
            return projectTop(theta,phi)
        elif theta>2.527:
            return projectBottom(theta,phi)
        elif phi <= pi/4 or phi > 7*pi/4:
            return projectLeft(theta,phi)
        elif phi > pi/4 and phi <= 3*pi/4:
            return projectFront(theta,phi)
        elif phi > 3*pi/4 and phi <= 5*pi/4:
            return projectRight(theta,phi)
        elif phi > 5*pi/4 and phi <= 7*pi/4:
            return projectBack(theta,phi)

def projectLeft(theta,phi):
        x = 1
        y = tan(phi)
        z = cot(theta)/cos(phi)
        if z < -1:
            return projectBottom(theta,phi)
        if z > 1:
            return projectTop(theta,phi)
        return ("Left",x,y,z)

def projectFront(theta,phi):
        x = tan(phi-pi/2)
        y = 1
        z = cot(theta)/cos(phi-pi/2)
        if z < -1:
            return projectBottom(theta,phi)
        if z > 1:
            return projectTop(theta,phi)
        return ("Front",x,y,z)

def projectRight(theta,phi):
        x = -1
        y = tan(phi)
        z = -cot(theta)/cos(phi)
        if z < -1:
            return projectBottom(theta,phi)
        if z > 1:
            return projectTop(theta,phi)
        return ("Right",x,-y,z)

def projectBack(theta,phi):
        x = tan(phi-3*pi/2)
        y = -1
        z = cot(theta)/cos(phi-3*pi/2)
        if z < -1:
            return projectBottom(theta,phi)
        if z > 1:
            return projectTop(theta,phi)
        return ("Back",-x,y,z)

def projectTop(theta,phi):
        # (a sin θ cos ø, a sin θ sin ø, a cos θ) = (x,y,1)
        a = 1/cos(theta)
        x = tan(theta) * cos(phi)
        y = tan(theta) * sin(phi)
        z = 1
        return ("Top",x,y,z)

def projectBottom(theta,phi):
        # (a sin θ cos ø, a sin θ sin ø, a cos θ) = (x,y,-1)
        a = -1/cos(theta)
        x = -tan(theta) * cos(phi)
        y = -tan(theta) * sin(phi)
        z = -1
        return ("Bottom",x,y,z)

# Convert coords in cube to image coords 
# coords is a tuple with the side and x,y,z coords
# edge is the length of an edge of the cube in pixels
def cubeToImg(coords,edge):
    if coords[0]=="Left":
        (x,y) = (int(edge*(coords[2]+1)/2), int(edge*(3-coords[3])/2) )
    elif coords[0]=="Front":
        (x,y) = (int(edge*(coords[1]+3)/2), int(edge*(3-coords[3])/2) )
    elif coords[0]=="Right":
        (x,y) = (int(edge*(5-coords[2])/2), int(edge*(3-coords[3])/2) )
    elif coords[0]=="Back":
        (x,y) = (int(edge*(7-coords[1])/2), int(edge*(3-coords[3])/2) )
    elif coords[0]=="Top":
        (x,y) = (int(edge*(3-coords[1])/2), int(edge*(1+coords[2])/2) )
    elif coords[0]=="Bottom":
        (x,y) = (int(edge*(3-coords[1])/2), int(edge*(5-coords[2])/2) )
    return (x,y)

# convert the in image to out image
def convert(imgIn,imgOut):
    inSize = imgIn.size
    outSize = imgOut.size
    inPix = imgIn.load()
    outPix = imgOut.load()
    edge = inSize[0]/4   # the length of each edge in pixels
    for i in xrange(inSize[0]):
        for j in xrange(inSize[1]):
            pixel = inPix[i,j]
            phi = i * 2 * pi/inSize[0]
            theta = j * pi/inSize[1]
            res = projection(theta,phi)
            (x,y) = cubeToImg(res,edge)
            #if i % 100 == 0 and j % 100 == 0:
            #   print i,j,phi,theta,res,x,y
            if x >= outSize[0]:
                #print "x out of range ",x,res
                x=outSize[0]-1
            if y >= outSize[1]:
                #print "y out of range ",y,res
                y=outSize[1]-1
            outPix[x,y] = pixel

imgIn = Image.open(sys.argv[1])
inSize = imgIn.size
imgOut = Image.new("RGB",(inSize[0],inSize[0]*3/4),"black")
convert(imgIn,imgOut)
imgOut.show()

projection işlevi, theta ve phi değerlerini alır ve bir küpteki koordinatları her yönden -1 ile 1 arasında döndürür. CubeToImg (x, y, z) kodlayıcılarını alır ve bunları çıktı görüntü kodlarına çevirir.

Yukarıdaki algoritma, buckingham sarayı görüntüsünü kullanarak doğru geometriyi elde ediyor gibi görünüyor. buckingham sarayının küp haritası Bu, kaldırımdaki çizgilerin çoğunu doğru alıyor gibi görünüyor.

We are getting a few image artefacts. This is due to not having a 1 to 1 map of pixels. What we need to do is use a inverse transformation. Rather than loop through each pixel in the yaniurce and find the corresponding pixel in the target we loop through the target images and find the closest corresponding yaniurce pixel.

import sys
from PIL import Image
from math import pi,sin,cos,tan,atan2,hypot,floor
from numpy import clip

# get x,y,z coords from out image pixels coords
# i,j are pixel coords
# face is face number
# edge is edge length
def outImgToXYZ(i,j,face,edge):
    a = 2.0*float(i)/edge
    b = 2.0*float(j)/edge
    if face==0: # back
        (x,y,z) = (-1.0, 1.0-a, 3.0 - b)
    elif face==1: # left
        (x,y,z) = (a-3.0, -1.0, 3.0 - b)
    elif face==2: # front
        (x,y,z) = (1.0, a - 5.0, 3.0 - b)
    elif face==3: # right
        (x,y,z) = (7.0-a, 1.0, 3.0 - b)
    elif face==4: # top
        (x,y,z) = (b-1.0, a -5.0, 1.0)
    elif face==5: # bottom
        (x,y,z) = (5.0-b, a-5.0, -1.0)
    return (x,y,z)

# convert using an inverse transformation
def convertBack(imgIn,imgOut):
    inSize = imgIn.size
    outSize = imgOut.size
    inPix = imgIn.load()
    outPix = imgOut.load()
    edge = inSize[0]/4   # the length of each edge in pixels
    for i in xrange(outSize[0]):
        face = int(i/edge) # 0 - back, 1 - left 2 - front, 3 - right
        if face==2:
            rng = xrange(0,edge*3)
        else:
            rng = xrange(edge,edge*2)

        for j in rng:
            if j=2*edge:
                face2 = 5 # bottom
            else:
                face2 = face

            (x,y,z) = outImgToXYZ(i,j,face2,edge)
            theta = atan2(y,x) # range -pi to pi
            r = hypot(x,y)
            phi = atan2(z,r) # range -pi/2 to pi/2
            # yaniurce img coords
            uf = ( 2.0*edge*(theta + pi)/pi )
            vf = ( 2.0*edge * (pi/2 - phi)/pi)
            # Use bilinear interpolation between the four surrounding pixels
            ui = floor(uf)  # coord of pixel to bottom left
            vi = floor(vf)
            u2 = ui+1       # coords of pixel to top right
            v2 = vi+1
            mu = uf-ui      # fraction of way across pixel
            nu = vf-vi
            # Pixel values of four corners
            A = inPix[ui % inSize[0],clip(vi,0,inSize[1]-1)]
            B = inPix[u2 % inSize[0],clip(vi,0,inSize[1]-1)]
            C = inPix[ui % inSize[0],clip(v2,0,inSize[1]-1)]
            D = inPix[u2 % inSize[0],clip(v2,0,inSize[1]-1)]
            # interpolate
            (r,g,b) = (
              A[0]*(1-mu)*(1-nu) + B[0]*(mu)*(1-nu) + C[0]*(1-mu)*nu+D[0]*mu*nu,
              A[1]*(1-mu)*(1-nu) + B[1]*(mu)*(1-nu) + C[1]*(1-mu)*nu+D[1]*mu*nu,
              A[2]*(1-mu)*(1-nu) + B[2]*(mu)*(1-nu) + C[2]*(1-mu)*nu+D[2]*mu*nu )

            outPix[i,j] = (int(round(r)),int(round(g)),int(round(b)))

imgIn = Image.open(sys.argv[1])
inSize = imgIn.size
imgOut = Image.new("RGB",(inSize[0],inSize[0]*3/4),"black")
convertBack(imgIn,imgOut)
imgOut.save(sys.argv[1].split('.')[0]+"Out2.png")
imgOut.show()

The results of this are Using the inverse transformation

67
katma
Bunları toplayıp github'a atmalısın.
katma yazar freakTheMighty, kaynak
Briliant! Eserleri!
katma yazar Brans Ds, kaynak
@Salixalba Piksel için teta ve phi nasıl elde edilir?
katma yazar Brans Ds, kaynak
@oelna Bunu test ettiniz mi?
katma yazar Brans Ds, kaynak
@Salixalba sadece klip işlevi nedir unlear? Klip (x, lo, hi) ise (x hi) hi döndürür; x döndür;
katma yazar Brans Ds, kaynak
Evet. Bu numpy.clip() işlevi. Alt sınır için çeke ihtiyacınız yok.
katma yazar Salix alba, kaynak
Teta ve phi temel olarak enlem ve boylamdır. θ = 0 kuzey anket, θ = π/2 ekvator ve θ = π güney anket. Bu nedenle, giriş görüntüsünden y koordinatını alın, yüksekliğe bölün ve π ile çarpın. Ø için x-koordinat bölünmesini genişliğe göre alın, 2π ile çarpın ve π/4 ile çıkarın. Çok daha basit bir yöntem, görüntünün ortasından bir şerit almak ve bunu dört eşit parçaya bölmek olacaktır. Bu dört duvar verecek. N = çarpık fakat kabul edilebilir olabilir.
katma yazar Salix alba, kaynak
@BransDs Ne yazık ki hayır. Belirttiğim gibi, şu anda kavrayabileceğimden daha karmaşık. Bence cevap yine de başkalarına yardımcı olabilir. Eğer biri bunu gerçekten kullanıyor ve çalışmasını sağlıyorsa, geri bildirimi duymayı çok isterim.
katma yazar oelna, kaynak
Ayrıntılı cevap için teşekkürler. Kabul etmeliyim ki, bu biraz kafamın üstünde, ama işe yarayacak gibi görünüyor. Bunu biraz düşüneceğim ve çalışmasını sağlarsam, sonuçlarımın ayrıntılarını içeren soruma bir güncelleme göndereceğim. Bu arada cevabınızı kabul edeceğim. Tekrar teşekkürler!
katma yazar oelna, kaynak
Evet, dilimleme gerçekten sorun değil. Zor kısım projeksiyonun eğrilmesi ve eğrilmesidir, böylece görüntü küp haritasına uyar.
katma yazar oelna, kaynak
ÇALIŞIYOR bir cazibe gibi
katma yazar James, kaynak
Bir projede çalışırken, bu algoritmayı bağımsız bir C ++ uygulaması => olarak uyguladım.> /a>
katma yazar Denis Bulichenko, kaynak
Numpy.clip'i saf python ile değiştirdim ve daha iyi oldum (130 saniyeden 50 saniyeye kadar) performans (numpy.clip sayıların bir listesi için). , vi, inSize [1] -1]) [1]]
katma yazar Pooya Mobasher Behrooz, kaynak
Hey millet, bunu bir sürü uyuşuk hileyle yeniden yazdım ve piksel enterpolasyonu için opencv kullandım (gerçekten gerekli değil ..) ve 8000x4000 görüntüde 244'den 7s'ye gitti. Bu yöntemle eşlemeyi bir kez oluşturabilir ve hızlı bir şekilde (cv2 remap ile) birden fazla dosyada kullanabilirsiniz pastebin.com/Eeki92Zv
katma yazar Eric, kaynak

Mükemmel kabul görmüş cevaplar göz önüne alındığında, OpenCV 'e dayalı olarak karşılık gelen c ++ uygulamasını eklemek istiyorum.

OpenCV'ye aşina olmayanlar için, Mat 'ı resim olarak düşünün. Öncelikle, eşkenar görüntüden karşılık gelen küp yüzümüze geçen iki harita oluşturduk. Sonra, OpenCV kullanarak ağır kaldırma (yani enterpolasyonla tekrar kapama) yapıyoruz.

Okunabilirlik söz konusu değilse, kod daha kompakt hale getirilebilir.

// Define our six cube faces. 
// 0 - 3 are side faces, clockwise order
// 4 and 5 are top and bottom, respectively
float faceTransform[6][2] = 
{ 
    {0, 0},
    {M_PI/2, 0},
    {M_PI, 0},
    {-M_PI/2, 0},
    {0, -M_PI/2},
    {0, M_PI/2}
};

// Map a part of the equirectangular panorama (in) to a cube face
// (face). The ID of the face is given by faceId. The desired
// width and height are given by width and height. 
inline void createCubeMapFace(const Mat &in, Mat &face, 
        int faceId = 0, const int width = -1, 
        const int height = -1) {

    float inWidth = in.cols;
    float inHeight = in.rows;

   //Allocate map
    Mat mapx(height, width, CV_32F);
    Mat mapy(height, width, CV_32F);

   //Calculate adjacent (ak) and opposite (an) of the
   //triangle that is spanned from the sphere center 
    //to our cube face.
    const float an = sin(M_PI/4);
    const float ak = cos(M_PI/4);

    const float ftu = faceTransform[faceId][0];
    const float ftv = faceTransform[faceId][1];

   //For each point in the target image, 
   //calculate the corresponding source coordinates. 
    for(int y = 0; y < height; y++) {
        for(int x = 0; x < width; x++) {

           //Map face pixel coordinates to [-1, 1] on plane
            float nx = (float)y/(float)height - 0.5f;
            float ny = (float)x/(float)width - 0.5f;

            nx *= 2;
            ny *= 2;

           //Map [-1, 1] plane coords to [-an, an]
           //thats the coordinates in respect to a unit sphere 
           //that contains our box. 
            nx *= an; 
            ny *= an; 

            float u, v;

           //Project from plane to sphere surface.
            if(ftv == 0) {
               //Center faces
                u = atan2(nx, ak);
                v = atan2(ny * cos(u), ak);
                u += ftu; 
            } else if(ftv > 0) { 
               //Bottom face 
                float d = sqrt(nx * nx + ny * ny);
                v = M_PI/2 - atan2(d, ak);
                u = atan2(ny, nx);
            } else {
               //Top face
                float d = sqrt(nx * nx + ny * ny);
                v = -M_PI/2 + atan2(d, ak);
                u = atan2(-ny, nx);
            }

           //Map from angular coordinates to [-1, 1], respectively.
            u = u/(M_PI); 
            v = v/(M_PI/2);

           //Warp around, if our coordinates are out of bounds. 
            while (v < -1) {
                v += 2;
                u += 1;
            } 
            while (v > 1) {
                v -= 2;
                u += 1;
            } 

            while(u < -1) {
                u += 2;
            }
            while(u > 1) {
                u -= 2;
            }

           //Map from [-1, 1] to in texture space
            u = u/2.0f + 0.5f;
            v = v/2.0f + 0.5f;

            u = u * (inWidth - 1);
            v = v * (inHeight - 1);

           //Save the result for this pixel in map
            mapx.at(x, y) = u;
            mapy.at(x, y) = v; 
        }
    }

   //Recreate output image if it has wrong size or type. 
    if(face.cols != width || face.rows != height || 
        face.type() != in.type()) {
        face = Mat(width, height, in.type());
    }

   //Do actual resampling using OpenCV's remap
    remap(in, face, mapx, mapy, 
         CV_INTER_LINEAR, BORDER_CONSTANT, Scalar(0, 0, 0));
}

Aşağıdaki girdi göz önüne alındığında:

enter image description here

Aşağıdaki yüzler oluşturulur:

enter image description here

Resim, Optonaut izniyle.

11
katma
Merhaba! Programınız doğru, ancak OpenCV’de, x ve y in. mapx.at (y, x) = u; mapy.at (y, x) = v;
katma yazar Raph Schim, kaynak
width = height ise sorun olmaz ama hatalara yol açabilir ... Ama x ile y'yi değiştirirseniz, görüntünüz döndürülür :) Yine de gerçekten iyi çalışıyor, teşekkürler!
katma yazar Raph Schim, kaynak

Oluşturulan cubemap'i tek tek dosyalara kesmek için bir senaryo yazdım (posx.png, negx.png, posy.png, negy.png, posz.png ve negz.png). Ayrıca 6 dosyayı bir .zip dosyasına paketleyecektir.

The source is here: https://github.com/dankex/compv/blob/master/3d-graphics/skybox/cubemap-cut.py

Görüntü dosyalarını ayarlamak için diziyi değiştirebilirsiniz:

name_map = [ \
 ["", "", "posy", ""],
 ["negz", "negx", "posz", "posx"],
 ["", "", "negy", ""]]

Dönüştürülen dosyalar:

enter image description here enter image description here enter image description here enter image description here enter image description here enter image description here

9
katma

İşte Salix Alba'nın kesinlikle fantastik cevabının (saf olarak) değiştirilmiş bir versiyonu. Bir seferde bir yüzü dönüştüren/a>, altı farklı görüntü verir ve orijinal görüntünün dosya türünü korur.

Çoğu kullanım durumunun muhtemelen altı ayrı görüntü beklemesinin yanı sıra, bir defada bir yüzü dönüştürmenin temel avantajı, devasa görüntülerle çalışmayı çok daha az bellek yoğunlaştırmasıdır.

#!/usr/bin/env python
import sys
from PIL import Image
from math import pi, sin, cos, tan, atan2, hypot, floor
from numpy import clip

# get x,y,z coords from out image pixels coords
# i,j are pixel coords
# faceIdx is face number
# faceSize is edge length
def outImgToXYZ(i, j, faceIdx, faceSize):
    a = 2.0 * float(i)/faceSize
    b = 2.0 * float(j)/faceSize

    if faceIdx == 0: # back
        (x,y,z) = (-1.0, 1.0 - a, 1.0 - b)
    elif faceIdx == 1: # left
        (x,y,z) = (a - 1.0, -1.0, 1.0 - b)
    elif faceIdx == 2: # front
        (x,y,z) = (1.0, a - 1.0, 1.0 - b)
    elif faceIdx == 3: # right
        (x,y,z) = (1.0 - a, 1.0, 1.0 - b)
    elif faceIdx == 4: # top
        (x,y,z) = (b - 1.0, a - 1.0, 1.0)
    elif faceIdx == 5: # bottom
        (x,y,z) = (1.0 - b, a - 1.0, -1.0)

    return (x, y, z)

# convert using an inverse transformation
def convertFace(imgIn, imgOut, faceIdx):
    inSize = imgIn.size
    outSize = imgOut.size
    inPix = imgIn.load()
    outPix = imgOut.load()
    faceSize = outSize[0]

    for xOut in xrange(faceSize):
        for yOut in xrange(faceSize):
            (x,y,z) = outImgToXYZ(xOut, yOut, faceIdx, faceSize)
            theta = atan2(y,x) # range -pi to pi
            r = hypot(x,y)
            phi = atan2(z,r) # range -pi/2 to pi/2

            # source img coords
            uf = 0.5 * inSize[0] * (theta + pi)/pi
            vf = 0.5 * inSize[0] * (pi/2 - phi)/pi

            # Use bilinear interpolation between the four surrounding pixels
            ui = floor(uf)  # coord of pixel to bottom left
            vi = floor(vf)
            u2 = ui+1       # coords of pixel to top right
            v2 = vi+1
            mu = uf-ui      # fraction of way across pixel
            nu = vf-vi

            # Pixel values of four corners
            A = inPix[ui % inSize[0], clip(vi, 0, inSize[1]-1)]
            B = inPix[u2 % inSize[0], clip(vi, 0, inSize[1]-1)]
            C = inPix[ui % inSize[0], clip(v2, 0, inSize[1]-1)]
            D = inPix[u2 % inSize[0], clip(v2, 0, inSize[1]-1)]

            # interpolate
            (r,g,b) = (
              A[0]*(1-mu)*(1-nu) + B[0]*(mu)*(1-nu) + C[0]*(1-mu)*nu+D[0]*mu*nu,
              A[1]*(1-mu)*(1-nu) + B[1]*(mu)*(1-nu) + C[1]*(1-mu)*nu+D[1]*mu*nu,
              A[2]*(1-mu)*(1-nu) + B[2]*(mu)*(1-nu) + C[2]*(1-mu)*nu+D[2]*mu*nu )

            outPix[xOut, yOut] = (int(round(r)), int(round(g)), int(round(b)))

imgIn = Image.open(sys.argv[1])
inSize = imgIn.size
faceSize = inSize[0]/4
components = sys.argv[1].rsplit('.', 2)

FACE_NAMES = {
  0: 'back',
  1: 'left',
  2: 'front',
  3: 'right',
  4: 'top',
  5: 'bottom'
}

for face in xrange(6):
  imgOut = Image.new("RGB", (faceSize, faceSize), "black")
  convertFace(imgIn, imgOut, face)
  imgOut.save(components[0] + "_" + FACE_NAMES[face] + "." + components[1])

7
katma

Bu soruyu buldum ve cevaplar iyi olsa da, hala ortaya çıkmış bir miktar zemin olduğunu düşünüyorum, işte benim iki kuruşum.

İlk olarak: görüntüleri gerçekten kendiniz dönüştürmek zorunda olmadığınız sürece (yani, belirli bir yazılım gereksinimi nedeniyle), yapma .

Bunun nedeni, eşzamanlı projeksiyon ve kübik projeksiyon arasında çok basit bir eşleme olmasına rağmen, alanlar arasındaki eşleme basit değildir : hedef görüntünüzün belirli bir noktası arasında bir yazışma kurduğunuzda ve kaynağında temel bir hesaplamaya sahip bir nokta, her iki noktayı da pikselleri dönüştürdüğünüzde yuvarlayarak çok ham bir yaklaşımda bulunuyorsunuz pikseller ve görüntünün kalitesi düşüktür.

İkincisi: Dönüştürmeyi çalışma zamanında yapmanız gerekse bile, dönüşümü hiç yapmanız gerektiğine emin misiniz? Çok sıkı bir performans sorunu olmadığı sürece, sadece bir gökyüzü kutusuna ihtiyacınız varsa, çok büyük bir küre yaratın, üzerine dörtgen dokuyu dikin ve gidin. Üç JS, küreyi zaten hatırlıyorum;

Üçüncüsü: NASA akla gelebilecek tüm projeksiyonlar arasında dönüşüm yapmak için bir araç sunmaktadır (yeni öğrendim, test ettim ve cazibe gibi çalışıyorum). Burada bulabilirsiniz:

G.Projector - Küresel Harita Projektörü

ve erkeklerin ne yaptıklarını bildiklerini düşünmek için makul buluyorum ;-)

Bu yardımcı olur umarım

UPDATE: it turns out that the "guys" know what they do up to some point: the generated cubemap has an hideous border which makes the conversion not that easy...

UPDATE 2: found the definitive tool for equirectangular to cubemap conversion, and it's called erect2cubic.

Bu şekilde, sarılmak için beslenecek bir senaryo oluşturan küçük bir yardımcı programdır:

$ erect2cubic --erect=input.png --ptofile=cube.pto
$ nona -o cube_prefix cube.pto 

(bilgi Vinay's Hacks sayfasından sifonlandı)

ve 6 küp haritası yüzünü de oluşturur. Projem için kullanıyorum ve cazibe gibi çalışıyor !

Bu yaklaşımın tek dezavantajı, erect2cubit betiğinin standart Ubuntu dağıtımında (kullanıyorum ne) olduğu ve bu bağlantıdaki talimatlara uymak zorunda olduğum.

erect2cubic

nasıl kurulacağını öğrenmek için.

Tamamen buna değer!

6
katma

cmft Studio supports conversion/filtering of various HDR/LDR projections to cubemaps.

https://github.com/dariomanesku/cmftStudio

1
katma

Perhaps I am missing something here. But it seems that most if not all the presented transformation code may be somewhat incorrect. They take a spherical panorama (equirectangular --- 360 deg horizontally and 180 deg vertically) and seem to convert to the cube faces using a cartesian <-> cylindrical transformation. Should they not be using a cartesian <-> spherical transformation. See http://mathworld.wolfram.com/SphericalCoordinates.html

Sanırım küp yüzlerinden panoramaya gitmek için hesaplamayı tersine çevirdikleri sürece, çalışması gerekir. Ancak küresel dönüşüm kullanılırken küp yüzlerinin görüntüleri biraz farklı olabilir.

Eğer bu eşitli dikdörtgen (küresel panorama) ile başlarsam:

enter image description here

Sonra eğer silindirik bir dönüşüm kullanırsam (ki şu anda% 100 doğru olmadığından emin değilim), şu sonucu alıyorum:

enter image description here

Fakat küresel bir dönüşüm kullanırsam, bu sonucu alıyorum:

enter image description here

Onlar aynı değil. Ancak küresel dönüşüm sonucum Danke Xie'nin sonucuyla eşleşiyor gibi gözüküyor, ancak bağlantısı en iyi okuyabildiğim kadar kullandığı dönüşümü göstermiyor.

Peki, bu konuya katkıda bulunanların birçoğu tarafından kullanılan kodu yanlış mı anlıyorum?

0
katma

İşte Benjamn Dobell'in kodunun bir JavaScript versiyonu. convertFace iki ìmageData nesnesi ve bir yüz kimliğinin (0-6) iletilmesi gerekir.

Sağlanan kod, herhangi bir bağımlılığı bulunmadığından web çalışanlarında güvenle kullanılabilir.

       //convert using an inverse transformation
        function convertFace(imgIn, imgOut, faceIdx) {
            var inPix = shimImgData(imgIn),
                        outPix = shimImgData(imgOut),
                        faceSize = imgOut.width,
                        pi = Math.PI,
                        pi_2 = pi/2;

            for(var xOut=0;xOutmax?max:val));
        }

        function shimImgData(imgData) {
            var w=imgData.width*4,
                    d=imgData.data;

            return({
                getPx:function(x,y) {
                    x=x*4+y*w;
                    return([ d[x], d[x+1], d[x+2] ]);
                },
                setPx:function(x,y,rgb) {
                    x=x*4+y*w;
                    d[x]=rgb.r;
                    d[x+1]=rgb.g;
                    d[x+2]=rgb.b;
                    d[x+3]=255;//alpha
                }
            });
        }//function shimImgData(imgData) {...}
0
katma

A very simple C++ app which converts an equirectangular panorama to cube map based on the answer by Salix Alba => https://github.com/denivip/panorama

0
katma

Çevre haritalarının çeşitli sunumları vardır. İşte güzel bir bakış.

Genel Bakış - Panoramik Görüntüler

Photosphere (veya bu konuda herhangi bir panorama uygulaması) kullanıyorsanız, büyük olasılıkla yatay bir enlem/boylam gösterimi. Daha sonra dokulu bir üç.js çizebilirsiniz. SphereGeometry . İşte dünyayı nasıl oluşturacağınızla ilgili bir öğretici.

Öğretici - Nasıl Dünya Olur WebGL?

İyi şanslar :).

0
katma

OpenGL kullanarak bu problem için bir çözüm yarattım ve çevresinde bir komut satırı aracı yaptım. Hem görüntüler hem de videolar ile çalışır ve orada bulduğum en hızlı araçtır.

Convert360 - Project on GitHub.

OpenGL Shader - The fragment shader used for the re-projection.

Kullanımı kadar basittir:

$ pip install convert360
$ convert360 -i ~/Pictures/Barcelona/sagrada-familia.jpg -o example.png -s 300 300

Böyle bir şey almak için:

enter image description here

0
katma