Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 将立方体贴图转换为等矩形全景图_C++_Opencv_Image Processing_Unity3d - Fatal编程技术网

C++ 将立方体贴图转换为等矩形全景图

C++ 将立方体贴图转换为等矩形全景图,c++,opencv,image-processing,unity3d,C++,Opencv,Image Processing,Unity3d,我想将立方体贴图[图1]转换为等矩形全景图[图2] 图1 图2 可以从球形变为立方形(通过以下方式:),但在如何反转它上迷失了方向 图2将使用Unity渲染成球体。假设输入图像采用以下立方体贴图格式: 目标是将图像投影为等矩形格式,如下所示: 转换算法相当简单。 为了计算等矩形图像中每个像素处颜色的最佳估计值,请给出一个具有6个面的立方体贴图: 首先,计算每个像素对应的极坐标 球形图像 其次,利用极坐标形成一个向量,并确定上 立方体贴图的哪个面和该面的哪个像素是向量 谎言;就像来自立方

我想将立方体贴图[图1]转换为等矩形全景图[图2]

图1

图2

可以从球形变为立方形(通过以下方式:),但在如何反转它上迷失了方向


图2将使用Unity渲染成球体。

假设输入图像采用以下立方体贴图格式:

目标是将图像投影为等矩形格式,如下所示:

转换算法相当简单。 为了计算等矩形图像中每个像素处颜色的最佳估计值,请给出一个具有6个面的立方体贴图:

  • 首先,计算每个像素对应的极坐标 球形图像
  • 其次,利用极坐标形成一个向量,并确定上 立方体贴图的哪个面和该面的哪个像素是向量 谎言;就像来自立方体中心的光线投射击中其中一个物体一样 它的侧面和那边的一个特定点
请记住,在给定立方体贴图特定面上的归一化坐标(u,v)的情况下,有多种方法可以估计等矩形图像中像素的颜色。为了简单起见,最基本的方法是将坐标四舍五入到一个特定的像素并使用该像素,这是一种非常原始的近似方法,将在本答案中使用。其他更高级的方法可以计算几个相邻像素的平均值

算法的实现将根据上下文的不同而有所不同。我在Unity3D C#中做了一个快速实现,展示了如何在真实场景中实现该算法。它在CPU上运行,有很大的改进空间,但很容易理解

using UnityEngine;

public static class CubemapConverter
{
    public static byte[] ConvertToEquirectangular(Texture2D sourceTexture, int outputWidth, int outputHeight)
    {
        Texture2D equiTexture = new Texture2D(outputWidth, outputHeight, TextureFormat.ARGB32, false);
        float u, v; //Normalised texture coordinates, from 0 to 1, starting at lower left corner
        float phi, theta; //Polar coordinates
        int cubeFaceWidth, cubeFaceHeight;

        cubeFaceWidth = sourceTexture.width / 4; //4 horizontal faces
        cubeFaceHeight = sourceTexture.height / 3; //3 vertical faces


        for (int j = 0; j < equiTexture.height; j++)
        {
            //Rows start from the bottom
            v = 1 - ((float)j / equiTexture.height);
            theta = v * Mathf.PI;

            for (int i = 0; i < equiTexture.width; i++)
            {
                //Columns start from the left
                u = ((float)i / equiTexture.width);
                phi = u * 2 * Mathf.PI;

                float x, y, z; //Unit vector
                x = Mathf.Sin(phi) * Mathf.Sin(theta) * -1;
                y = Mathf.Cos(theta);
                z = Mathf.Cos(phi) * Mathf.Sin(theta) * -1;

                float xa, ya, za;
                float a;

                a = Mathf.Max(new float[3] { Mathf.Abs(x), Mathf.Abs(y), Mathf.Abs(z) });

                //Vector Parallel to the unit vector that lies on one of the cube faces
                xa = x / a;
                ya = y / a;
                za = z / a;

                Color color;
                int xPixel, yPixel;
                int xOffset, yOffset;

                if (xa == 1)
                {
                    //Right
                    xPixel = (int)((((za + 1f) / 2f) - 1f) * cubeFaceWidth);
                    xOffset = 2 * cubeFaceWidth; //Offset
                    yPixel = (int)((((ya + 1f) / 2f)) * cubeFaceHeight);
                    yOffset = cubeFaceHeight; //Offset
                }
                else if (xa == -1)
                {
                    //Left
                    xPixel = (int)((((za + 1f) / 2f)) * cubeFaceWidth);
                    xOffset = 0;
                    yPixel = (int)((((ya + 1f) / 2f)) * cubeFaceHeight);
                    yOffset = cubeFaceHeight;
                }
                else if (ya == 1)
                {
                    //Up
                    xPixel = (int)((((xa + 1f) / 2f)) * cubeFaceWidth);
                    xOffset = cubeFaceWidth;
                    yPixel = (int)((((za + 1f) / 2f) - 1f) * cubeFaceHeight);
                    yOffset = 2 * cubeFaceHeight;
                }
                else if (ya == -1)
                {
                    //Down
                    xPixel = (int)((((xa + 1f) / 2f)) * cubeFaceWidth);
                    xOffset = cubeFaceWidth;
                    yPixel = (int)((((za + 1f) / 2f)) * cubeFaceHeight);
                    yOffset = 0;
                }
                else if (za == 1)
                {
                    //Front
                    xPixel = (int)((((xa + 1f) / 2f)) * cubeFaceWidth);
                    xOffset = cubeFaceWidth;
                    yPixel = (int)((((ya + 1f) / 2f)) * cubeFaceHeight);
                    yOffset = cubeFaceHeight;
                }
                else if (za == -1)
                {
                    //Back
                    xPixel = (int)((((xa + 1f) / 2f) - 1f) * cubeFaceWidth);
                    xOffset = 3 * cubeFaceWidth;
                    yPixel = (int)((((ya + 1f) / 2f)) * cubeFaceHeight);
                    yOffset = cubeFaceHeight;
                }
                else
                {
                    Debug.LogWarning("Unknown face, something went wrong");
                    xPixel = 0;
                    yPixel = 0;
                    xOffset = 0;
                    yOffset = 0;
                }

                xPixel = Mathf.Abs(xPixel);
                yPixel = Mathf.Abs(yPixel);

                xPixel += xOffset;
                yPixel += yOffset;

                color = sourceTexture.GetPixel(xPixel, yPixel);
                equiTexture.SetPixel(i, j, color);
            }
        }

        equiTexture.Apply();
        var bytes = equiTexture.EncodeToPNG();
        Object.DestroyImmediate(equiTexture);

        return bytes;
    }
}
通过在转换过程中采用更复杂的方法来估计像素的颜色,或者通过对结果图像进行后处理(或者实际上两者兼而有之),可以极大地提高结果图像的质量。例如,可以生成较大尺寸的图像以应用模糊过滤器,然后将其向下采样到所需的尺寸

我用两个编辑器向导创建了一个简单的Unity项目,展示了如何正确使用C代码或上面显示的着色器。在这里获取:

请记住在Unity中为输入图像设置正确的导入设置:

  • 点滤波
  • 真彩色格式
  • 禁用mipmap
  • 非2次幂:无(仅适用于2D纹理)
  • 启用读/写(仅适用于2D纹理)
使整个过程自动化。例如:

$ cube2sphere front.jpg back.jpg right.jpg left.jpg top.jpg bottom.jpg -r 2048 1024 -fTGA -ostitched

如果我想在将它映射到球面上(然后映射到2D面上),我会怎么做?@ BARTZZ——我已经把这个代码转换成C++ OpenCV,我在这行中有问题:代码> A= Mthf。马克斯(新浮点[3 ] {Mathf.ABS(x),Mthf.ABS(y),Mthf.abs(z)});代码>-因为当x、y、z值低于1时,a返回为0,这使得xa、xy和xz未定义,由于被零除的问题,我是否遗漏了什么?我的C++行看起来是这样的:<代码> a=最大值(ABS(x),ABS(y),ABS(z));<代码>(我已经添加了我自己的最大功能)。嗨!我分析你的代码已经有一段时间了。你有没有关于6个以上面的解决方案的想法?在这种情况下,有6个面,每个面对应1个轴(x,y,z,-x,-y,-z)。如果有多个面/图像,每个图像都有自己的“面”,也有自己的“轴”。这是我的想法,因为我不能从这里继续下去。你能帮我吗?这是一个很好的答案谢谢!如果要使用6个单独的纹理生成spheremap,每个纹理代表一个边,该怎么办?
$ cube2sphere front.jpg back.jpg right.jpg left.jpg top.jpg bottom.jpg -r 2048 1024 -fTGA -ostitched