unity中笛卡尔坐标系与无人机倾斜摄影模型GPS对齐

一、几个坐标转换的网站

1.各个坐标系下的转换

https://epsg.io/transform#s_srs=4326&t_srs=32651&x=104.4047181&y=28.6333555Transform coordinates – GPS online converter (epsg.io)

这个网站可以转换各个坐标系下的经纬度

例如xml文件是CGCS2000坐标系——EPGS4544

https://epsg.io/transform#s_srs=4326&t_srs=32651&x=104.4047181&y=28.6333555

经纬度坐标系——EPGS4326

坐标系是51/UTM——EPGS32651

2. 两个经纬度间计算距离

在线经纬度距离计算 (lddgo.net)

 在线工具大全 (lddgo.net)

3. 对于倾斜摄影模型文件中的xml文件坐标系的修改可以用公众号提供的OSGBLab

在这个里面可以修改xml文件中的坐标系,生成需要坐标系的xml文件,还有其他OSGB模型转换功能

 二、关于unity中相机调整部分

1.真实场景相机

由于要模拟真实场景下无人机拍摄,需调整照相机分辨率,广角等参数。这里我们运用的大疆无人机是     大疆精灵4RTK   具体参数如下

精灵 4 RTK – 产品信息 – DJI 大疆创新

 2.unity中相机参数

(1)程序中可调整分辨率

 (2)unity中相机参数设置,可勾选Physical Camera选项

(3) 区分unity中照相机的视野大小,分辨率和输出图片的长宽

Unity中相机的视野大小(Field of View)、分辨率和输出图片的长宽是三个不同的概念,它们分别控制着不同的方面,修改方式也不尽相同。

  1. 视野大小(Field of View):
  • 控制相机捕捉场景的角度范围。
  • 修改方式:选中相机对象,在Inspector面板中修改Field of View属性的值。
  • 影响:较大的视野会捕捉更广阔的场景,较小的视野会缩小捕捉范围。
  1. 分辨率:
  • 控制相机输出图像的像素维度。
  • 修改方式:
    a) 如果渲染到屏幕,分辨率由屏幕决定,可以在Unity Player Settings中修改。
    b) 如果渲染到RenderTexture或截图,分辨率由RenderTexture的构造函数决定,如你的代码中new RenderTexture(width, height, 0)。
  1. 输出图片的长宽:
  • 如果渲染到屏幕,长宽等于分辨率。
  • 如果渲染到RenderTexture或截图,长宽可以通过Rect参数来控制。
  • 在你的代码中,myrect的width和height控制截取矩形区域的尺寸,影响输出图片的长宽。

因此,要分别修改它们:

  • 视野大小: 修改相机的Field of View属性。
  • 分辨率: 如果渲染到屏幕,修改Player Settings;如果渲染到纹理,修改RenderTexture构造函数参数。
  • 输出图片长宽: 修改myrect的width和height值。

需要注意的是,视野大小、分辨率和输出图片长宽虽然相互影响,但它们控制的是不同的方面。合理设置这三个参数,可以获得理想的渲染效果和截图尺寸。

三、代码部分

一下是初步实现无人机图片截取的程序,实现功能为点击拍照按钮截取当前无人机的照片并保存到指定路径对应的txt文件中,若该路径中没有txt文件则自动创建txt文件,qian.txt保存所截取照片中当前照片中心点的unity中的坐标;hou.txt文件保存所截取照片中当前照片中心点转换后的经纬度坐标,便于在谷歌地图上找到unity中对应的照片中心点

参数设置

代码实现 

using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEngine;
using UnityEngine.UI;


public class GPStestconnect : MonoBehaviour
{
    // Start is called before the first frame update
    public Camera myCamera;
    public string filePath;//举例:E:\研学\数字孪生\unity3D\姚雨雯\advance move- UnityOSGB-main\TakePhotos
    public Button m_Button;//绑定相关操作button
    public string qianPath;
    public string houPath;
    public GameObject gpsPoint;
    public GameObject gpsLocationParent;
    public GameObject uavM210;
    private string[] txtGPS;
    private List<string> gpsCoordinates = new List<string>();
    public float projectOffsetX = 24.371f;   //Python最小二乘求解值,投影前纠正:-0.07  30.4  2.54
    public float projectOffsetY = 0;    //投影后纠正:-0.19  30.4  2.86
    public float projectOffsetZ = 255.423f;


    public string shuchu;


    Rect myrect;
    void Start()
    {
        myrect = new Rect();
        //myrect.width = 963;
        //myrect.height = 722;
        myrect.width = 8000;
        myrect.height = 8000;
        //myCamera = Camera.main;
        m_Button.onClick.AddListener(onclickbutton);//button触发的监听,触发onclickbutton函数
                                                    //saveXYZ();
                                                    //saveGPS();
                                                    //*************************************************
                                                    //txtGPS = File.ReadAllLines("C:\\Users\\ZehaiZou\\Desktop\\毕业论文\\测试数据结果\\rtkCampusOriginal.txt");
                                                    //txtGPS = File.ReadAllLines(qianPath);//转换前的UTM坐标文件
                                                    // 在 Start 方法中初始化 gpsCoordinates 列表

    }

    public void onclickbutton()
    {

        CaptureCamera(myCamera, myrect);
        saveXYZ();
        calculateGPS();
        saveGPS();
    }
    Texture2D CaptureCamera(Camera camera, Rect rect)
    {
        // 创建一个RenderTexture对象  
        RenderTexture renderTexture = new RenderTexture((int)rect.width, (int)rect.height, 0);
        // 临时设置相关相机的targetTexture为rt, 并手动渲染相关相机  
        camera.targetTexture = renderTexture;
        print(camera.targetTexture.name);
        camera.Render();
        //如果这样加上第二个相机,可以实现只截图某几个指定的相机一起看到的图像。  
        // camera2.targetTexture = rt;  
        // camera2.Render();  
        //-------------------------------------------------------------------  
        // 激活这个rt, 并从中中读取像素。  
        RenderTexture.active = renderTexture;
        Texture2D screenShot = new Texture2D((int)rect.width, (int)rect.height, TextureFormat.RGB24, false);
        screenShot.ReadPixels(rect, 0, 0);// 注:这个时候,它是从RenderTexture.active中读取像素  
        screenShot.Apply();
        // 重置相关参数,以使用camera继续在屏幕上显示  
        camera.targetTexture = null;
        //ps: camera2.targetTexture = null;  
        RenderTexture.active = null; // JC: added to avoid errors  
        GameObject.Destroy(renderTexture);
        // 最后将这些纹理数据,成一个png图片文件  
        byte[] bytes = screenShot.EncodeToPNG();
        //string filename = Application.dataPath + "/Screenshot.png";//string filename = Application.dataPath + "文件名.png"//在项目文件夹下保存,且只刷新同一张截图
        //string filename = filePath + "/" + $"{System.DateTime.Now:yyyy-MM-dd_HH-mm-ss}" + ".png";
        string filename = filePath + "/" + $"{System.DateTime.Now:HH-mm-ss}" + $"{transform.position}" + ".JPG";
        System.IO.File.WriteAllBytes(filename, bytes);
        Debug.Log(string.Format("截屏了一张照片: {0}", filename));
        return screenShot;
    }

    private void saveXYZ()
    {
        //string qianPath = "your_file_path"; // 替换为实际的文件路径

        // 获取 transform.position 的字符串表示形式
        string positionString = transform.position.ToString();
        //去掉括号
        positionString = positionString.Replace("(", "").Replace(")", "");

        // 检查文件是否存在
        if (!File.Exists(qianPath))
        {
            // 如果文件不存在,则创建文件
            File.Create(qianPath).Dispose();
        }

        using (StreamWriter writer = new StreamWriter(qianPath, true))
        {
            writer.WriteLine(positionString);
        }
    }



    private void calculateGPS()
    {
        gpsCoordinates = new List<string>();
        //txtGPS = transform.position;//转换前的UTM坐标文件
        //txtGPS = File.ReadAllLines(qianPath);
        //print("txtGPS.Length"+ txtGPS.Length);
        GPSEncoder.SetGPSInUnityOrigin(new Vector2(0, 0));   //除以100  2472.94f, 33574.17f   (-0.067694f, 2.539496f)
        Quaternion rotationPoint = Quaternion.Euler(-90f, 0f, 0f);
        //for (int i = 0; i < txtGPS.Length; i++)
        //{
        //    string[] gps;
        //    gps = txtGPS[i].Split(',');
            string[] gps = new string[3];
            gps[0] = transform.position.x.ToString();
            gps[2] = transform.position.y.ToString();
            gps[1] = transform.position.z.ToString();

            double[] gps2utm = UTMAndWGS84.LatLonToUTMXY(double.Parse(gps[1]), double.Parse(gps[0]));///
            
            //double[] utm2gps = UTMAndWGS84.UTMXYToLatLon(double.Parse(gps[0]) + 247294 - projectOffsetX, double.Parse(gps[1]) + 3357417 - projectOffsetZ, 51, false);
            double[] utm2gps = UTMAndWGS84.UTMXYToLatLon(double.Parse(gps[0]) + -1334326.438 - projectOffsetX, double.Parse(gps[1]) + 3313015.016 - projectOffsetZ, 51, false);
            float h = 140 - projectOffsetY;//h是UTM里面的Y轴值
            Debug.Log("LLH" + ":  " + utm2gps[0] + ",  " + utm2gps[1] + ",  " + h);
            //double[] utm2gps = UTMAndWGS84.UTMXYToLatLon((float)gps2utm[0], (float)gps2utm[1], 51, false);
            //print(utm2gps[0]);
            //sw.WriteLine("N" + utm2gps[0] + " " + "E" + utm2gps[1]);
            //sw.WriteLine(utm2gps[1] + "," + utm2gps[0] + "," + gps[2]);
            //Vector3 gps2ucs = GPSEncoder.GPSToUCS(double.Parse(gps[1]), double.Parse(gps[0]));  //GPS坐标转换为Unity坐标
            //Vector2 usc2gps = GPSEncoder.USCToGPS(gps2ucs);  //Unity坐标转换为GPS坐标


            Debug.Log("sdasd");
            Debug.Log(utm2gps[0]);
            print("utm2gps[0]");
            print(utm2gps[0]);
            print("utm2gps[1]");
            print(utm2gps[1]);

            Debug.Log("gps2utm length: " + gps2utm.Length);
            Debug.Log("gps2utm[0]: " + gps2utm[0]);
            Debug.Log("gps2utm[1]: " + gps2utm[1]);
        // GameObject point = Instantiate(gpsPoint, new Vector3(((float)gps2utm[0] - 385543 - 0.2f), float.Parse(gps[2]) + 30.4f, ((float)gps2utm[1]) - 3163008 + 2.84f), rotationPoint);
        //GameObject point = Instantiate(gpsPoint, new Vector3((float)gps2utm[0] - -1334326.438f - - 24.371f, float.Parse(gps[2]) + 30.4f, (float)gps2utm[1] - 3313015.016f + 255.423f), rotationPoint);
        //point.transform.parent = gpsLocationParent.transform;   //设置父对象

            //shuchu = "N" + utm2gps[0] + " " + "E" + utm2gps[1];

            // 将计算得到的 GPS 坐标添加到列表中
            string gpsCoordinate = "N" + utm2gps[0] + " " + "E" + utm2gps[1];
            gpsCoordinates.Add(gpsCoordinate);


    }

    private void saveGPS()
    {
        // 检查文件是否存在
        if (!File.Exists(houPath))
        {
            // 如果文件不存在,则创建文件
            File.Create(houPath).Dispose();
        }

        using (StreamWriter writer = new StreamWriter(houPath, true))
        {
            foreach (string gpsCoordinate in gpsCoordinates)
            {
                writer.WriteLine(gpsCoordinate);
            }
        }
    }


}

版权声明:本文为博主作者:今天可以不摆摊吗原创文章,版权归属原作者,如果侵权,请联系我们删除!

原文链接:https://blog.csdn.net/weixin_45486395/article/details/137781287

共计人评分,平均

到目前为止还没有投票!成为第一位评论此文章。

(0)
社会演员多的头像社会演员多普通用户
上一篇 2024年5月6日
下一篇 2024年5月6日

相关推荐