尝试渲染等距柱状全景图

发布于 2024-11-03 11:11:41 字数 3221 浏览 2 评论 0原文

我有一个等距柱状全景源图像,经度为 360 度,纬度为 120 度。

我想编写一个函数,可以在给定视口的宽度和高度以及经度旋转的情况下渲染它。我想调整我的输出图像,使其高度为 120 度。

有人有任何指示吗?我无法理解如何从目标坐标转换回源坐标的数学问题。

感谢

这是我到目前为止的代码:-(创建 ac# 2.0 控制台应用程序,添加对 system.drawing 的引用)

static void Main(string[] args)
    {

        Bitmap src = new Bitmap(@"C:\Users\jon\slippyr4\pt\grid2.jpg");

        // constant stuff
        double view_width_angle = d2r(150);
        double view_height_angle = d2r(120);
        double rads_per_pixel = 2.0 * Math.PI / src.Width;

        // scale everything off the height
        int output_image_height = src.Width;

        // compute radius (from chord trig - my output image forms a chord of a circle with angle view_height_angle)
        double radius = output_image_height / (2.0 * Math.Sin(view_height_angle / 2.0));

        // work out the image width with that radius.
        int output_image_width = (int)(radius * 2.0 * Math.Sin(view_width_angle / 2.0));

        // source centres for later
        int source_centre_x = src.Width / 2;
        int source_centre_y = src.Height / 2;

        // work out adjacent length
        double adj = radius * Math.Cos(view_width_angle / 2.0);

        // create output bmp
        Bitmap dst = new Bitmap(output_image_width, output_image_height);

        // x & y are output pixels offset from output centre
        for (int x = output_image_width / -2; x < output_image_width / 2; x++)
        {
            // map this x to an angle & then a pixel
            double x_angle = Math.Atan(x / adj);
            double src_x = (x_angle / rads_per_pixel) + source_centre_x;

            // work out the hypotenuse of that triangle
            double x_hyp = adj / Math.Cos(x_angle);

            for (int y = output_image_height / -2; y < output_image_height / 2; y++)
            {
                // compute the y angle and then it's pixel
                double y_angle = Math.Atan(y / x_hyp);
                double src_y = (y_angle / rads_per_pixel) + source_centre_y;

                Color c = Color.Magenta;
                // this handles out of range source pixels. these will end up magenta in the target
                if (src_x >= 0 && src_x < src.Width && src_y >= 0 && src_y < src.Height)
                {
                    c = src.GetPixel((int)src_x, (int)src_y);
                }


                dst.SetPixel(x + (output_image_width / 2), y + (output_image_height / 2), c);
            }
        }

        dst.Save(@"C:\Users\slippyr4\Desktop\pana.jpg");

    }

    static double d2r(double degrees)
    {
        return degrees * Math.PI / 180.0;
    }

使用此代码,当我将目标图像宽度设置为 120 度时,我得到了预期的结果。我看到水平线等的右曲率,如下所示,当我尝试使用现实生活中的等距柱状全景图时,它看起来像商业观众渲染的。 正确输出 120 度 x 120 度

但是,当我使输出图像更宽时,一切都会出错。您开始在中心的抛物线顶部和底部看到无效像素,如下所示,图像宽 150 度,高 120 度:-

在此处输入图像描述

商业观众似乎所做的就是放大 - 因此,在中心,图像高度为 120 度,因此在两侧,更多内容被剪掉。因此,不存在洋红色(即,不存在无效源像素)。

但我无法理解如何在数学中做到这一点。

这不是家庭作业,这是一个爱好项目。因此,为什么我对正在发生的事情缺乏了解!另外,请原谅代码的严重低效,当我让它正常工作时我会优化它。

再次感谢

I have an equirectangular panorama source image which is 360 degrees of longitude and 120 degrees of latitude.

I want to write a function which can render this, given width and height of the viewport and a rotation in longitude. I want to can my output image so that it's the full 120 degrees in height.

has anyone got any pointers? I can't get my head around the maths on how to transform from target coordinates back to source.

thanks

slip

Here is my code so far:- (create a c# 2.0 console app, add a ref to system.drawing)

static void Main(string[] args)
    {

        Bitmap src = new Bitmap(@"C:\Users\jon\slippyr4\pt\grid2.jpg");

        // constant stuff
        double view_width_angle = d2r(150);
        double view_height_angle = d2r(120);
        double rads_per_pixel = 2.0 * Math.PI / src.Width;

        // scale everything off the height
        int output_image_height = src.Width;

        // compute radius (from chord trig - my output image forms a chord of a circle with angle view_height_angle)
        double radius = output_image_height / (2.0 * Math.Sin(view_height_angle / 2.0));

        // work out the image width with that radius.
        int output_image_width = (int)(radius * 2.0 * Math.Sin(view_width_angle / 2.0));

        // source centres for later
        int source_centre_x = src.Width / 2;
        int source_centre_y = src.Height / 2;

        // work out adjacent length
        double adj = radius * Math.Cos(view_width_angle / 2.0);

        // create output bmp
        Bitmap dst = new Bitmap(output_image_width, output_image_height);

        // x & y are output pixels offset from output centre
        for (int x = output_image_width / -2; x < output_image_width / 2; x++)
        {
            // map this x to an angle & then a pixel
            double x_angle = Math.Atan(x / adj);
            double src_x = (x_angle / rads_per_pixel) + source_centre_x;

            // work out the hypotenuse of that triangle
            double x_hyp = adj / Math.Cos(x_angle);

            for (int y = output_image_height / -2; y < output_image_height / 2; y++)
            {
                // compute the y angle and then it's pixel
                double y_angle = Math.Atan(y / x_hyp);
                double src_y = (y_angle / rads_per_pixel) + source_centre_y;

                Color c = Color.Magenta;
                // this handles out of range source pixels. these will end up magenta in the target
                if (src_x >= 0 && src_x < src.Width && src_y >= 0 && src_y < src.Height)
                {
                    c = src.GetPixel((int)src_x, (int)src_y);
                }


                dst.SetPixel(x + (output_image_width / 2), y + (output_image_height / 2), c);
            }
        }

        dst.Save(@"C:\Users\slippyr4\Desktop\pana.jpg");

    }

    static double d2r(double degrees)
    {
        return degrees * Math.PI / 180.0;
    }

source image i am using

With this code, i get the results i expect when i set my target image width to 120 degrees. I see the right curvature of horizontal lines etc, as below, and when i try it with a real-life equirectangular panorama, it looks like commercial viewers render.
correct output at 120 degrees by 120 degrees

But, when i make the output image wider, it all goes wrong. You start to see the invalid pixels in a parabola top and bottom at the centre, as shown here with the image 150 degrees wide by 120 degrees high:-

enter image description here

What commericial viewers seem to do is sort of zoom in - so the in the centre, the image is 120 degrees high and therefore at the sides, more is clipped. and therfore, there is no magenta (ie, no invalid source pixels).

But i can't get my head around how to do that in the maths.

This isn't homework, it's a hobby project. hence why i am lacking the understanding of what is going on!. Also, please forgive the severe inefficeincy of the code, i will optimise it when i have it working propertly.

thanks again

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文