C#单像空间后方交会计算

空间后方交会 (Space Resection)的定义:利用地面控制点(GCP,Ground Control Point)及其在像片上的像点,确定单幅影像外方位元素的方法。

如果已知每幅影像的6个外方位元素,就能确定被摄物体与航摄影像的关系。因此,如何获取影像的外方位元素,一直是摄影测量工作者所探讨的问题。也可利用影像覆盖范围内一定数量的控制点的空间坐标与影像坐标,根据共线条件方程反求该影像的外方位元素,这种方法称为单幅影像的空间后方交会。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace 单向空间后方交会
{
    public partial class Form1 : Form
    {
        List<ImgData> Img = new List<ImgData>();//像点
        List<GroundData> Ground = new List<GroundData>();//地面点

        Matrix A = new Matrix(8, 6);//误差方程
        Matrix X = new Matrix(6, 1);
        Matrix L = new Matrix(8, 1);

        Matrix AT = new Matrix(6, 8);//A的转置矩阵
        Matrix ATA = new Matrix(6, 6);//A与转置矩阵的乘积
        Matrix inv_ATA = new Matrix(6, 6);//A与其转置的乘积的逆矩阵
        Matrix invATAmAT = new Matrix(6, 8);//A与其转置的乘积的逆矩阵与A转置的乘积

        double f = 153.24 / 1000;
        double m = 40000;
        int k = 0;//迭代次数

        Matrix xy = new Matrix(4, 2);//像点坐标
        Matrix x0y0 = new Matrix(4, 2);//像点坐标计算值(近似)
        Matrix XYZ = new Matrix(4, 3);//地面点坐标

        Matrix XsYsZs = new Matrix(3, 1);//外方位元素直线元素
        Matrix rAngle = new Matrix(3, 1);//外方位元素角元素

        Matrix R = new Matrix(3, 3);//旋转矩阵

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            OpenFileDialog op = new OpenFileDialog();
            op.Filter = "文本文件|*.txt";
            string filepath = null;
            if (op.ShowDialog() == DialogResult.OK)
            {
                filepath = op.FileName;
                imgData(filepath);
            }
        }
        private void button2_Click(object sender, EventArgs e)
        {
            OpenFileDialog op = new OpenFileDialog();
            op.Filter = "文本文件|*.txt";
            string filepath = null;
            if (op.ShowDialog() == DialogResult.OK)
            {
                filepath = op.FileName;
                groundData(filepath);
            }
        }

        private void imgData(string filepath)
        {
            StreamReader sr = new StreamReader(filepath);
            ImgData img;
            while (!sr.EndOfStream)
            {
                string[] info = sr.ReadLine().Trim().Split();
                double x = Convert.ToDouble(info[0]);
                double y = Convert.ToDouble(info[2]);
                img = new ImgData(x, y);
                Img.Add(img);
            }
            //矩阵赋值
            for (int i = 0; i < Img.Count; i++)
            {
                xy.arr[i, 0] = Img[i].X / 1000;
                xy.arr[i, 1] = Img[i].Y / 1000;
            }
            string text = "*****像点坐标*****\n";
            text += "x(mm)\ty(mm)\n";
            for (int i = 0; i < Img.Count; i++)
            {
                text += Img[i].X.ToString() + "\t" + Img[i].Y.ToString() + "\n";
            }
            text += "****************";
            richTextBox1.Text = text;
        }

        private void groundData(string filepath)
        {
            StreamReader sr = new StreamReader(filepath);
            GroundData ground;
            while (!sr.EndOfStream)
            {
                string[] info = sr.ReadLine().Trim().Split();
                double x = Convert.ToDouble(info[0]);
                double y = Convert.ToDouble(info[2]);
                double z = Convert.ToDouble(info[4]);
                ground = new GroundData(x, y, z);
                Ground.Add(ground);
            }
            //矩阵赋值
            for (int i = 0; i < Ground.Count; i++)
            {
                XYZ.arr[i, 0] = Ground[i]._X;
                XYZ.arr[i, 1] = Ground[i]._Y;
                XYZ.arr[i, 2] = Ground[i]._Z;
            }
            string text = "**************地面点坐标**************\n";
            text += "X(m)\t\tY(m)\t\tZ(m)\n";
            for (int i = 0; i < Ground.Count; i++)
            {
                text += Ground[i]._X.ToString() + "\t" + Ground[i]._Y.ToString() + "\t" + Ground[i]._Z.ToString() + "\n";
            }
            text += "**************************************";
            richTextBox2.Text = text;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            for (int i = 0; i < 3; i++)
                rAngle.arr[i, 0] = 0;//角元素初始值为0

            for (int i = 0; i < 6; i++)
            {
                X.arr[i, 0] = 0;
            }

            double sumX = 0, sumY = 0, sumZ = 0;
            for (int i = 0; i < 4; i++)
            {
                sumX += XYZ.arr[i, 0];
                sumY += XYZ.arr[i, 1];
                sumZ += XYZ.arr[i, 2];
            }
            XsYsZs.arr[0, 0] = sumX / 4;
            XsYsZs.arr[1, 0] = sumY / 4;
            XsYsZs.arr[2, 0] = sumZ / 4 + f * m;

            Algo algo = new Algo();
            //系数矩阵A
            A = algo.Cal_A(A, m, f, xy);
            //计算A的转置
            AT = algo.Cal_AT(AT, A);
            //计算ATA
            ATA = algo.Cal_MmN(AT, A, ATA);
            //计算ATA逆阵
            inv_ATA = algo.Cal_invATA(ATA, inv_ATA);
            //计算ATA逆阵与AT乘积
            invATAmAT = algo.Cal_MmN(inv_ATA, AT, invATAmAT);

            //迭代计算
            do
            {
                XsYsZs.arr[0, 0] += X.arr[0, 0];
                XsYsZs.arr[1, 0] += X.arr[1, 0];
                XsYsZs.arr[2, 0] += X.arr[2, 0];

                rAngle.arr[0, 0] += X.arr[3, 0];
                rAngle.arr[1, 0] += X.arr[4, 0];
                rAngle.arr[2, 0] += X.arr[5, 0];

                //计算旋转矩阵
                R = algo.Cal_R(R, rAngle);

                //计算(x)(y)
                x0y0 = algo.Cal_x0y0(x0y0, R, f, XYZ, XsYsZs);

                //计算L
                L = algo.Cal_L(L, xy, x0y0);

                //计算X
                X = algo.Cal_MmN(invATAmAT, L, X);

                k++;//迭代跳出
   /*                 if (k > 5)
                    break;*/

            } while (Math.Abs(X.arr[4, 0]) > 0.0000001);
            richTextBox3.AppendText(" 直线元素          角元素\n");
            richTextBox3.AppendText("--------------------------------\n");
            richTextBox3.AppendText("Xs  " + XsYsZs.arr[0, 0].ToString("0.00").PadRight(12, ' ') + "ψ   " + rAngle.arr[0, 0].ToString("0.00000") + "\n");
            richTextBox3.AppendText("Ys  " + XsYsZs.arr[1, 0].ToString("0.00").PadRight(12, ' ') + "ω   " + rAngle.arr[1, 0].ToString("0.00000") + "\n");
            richTextBox3.AppendText("Zs  " + XsYsZs.arr[2, 0].ToString("0.00").PadRight(12, ' ') + "κ   " + rAngle.arr[2, 0].ToString("0.00000") + "\n\n");

            richTextBox3.AppendText("迭代次数:   " + k.ToString() + "\n");
            richTextBox3.AppendText("比例尺:   " + (m).ToString("0.000000") + "\n");

        }

    }
}

Algo.cs
namespace 单向空间后方交会
{
    internal class Algo
    {
        public Matrix Cal_A(Matrix A, double m, double f, Matrix xy)
        {
            for (int i = 0; i < 4; i++)
            {
                A.arr[i * 2, 0] = -1 / m;
                A.arr[i * 2, 1] = 0;
                A.arr[i * 2, 2] = -xy.arr[i, 0] / (f * m);
                A.arr[i * 2, 3] = -f * (1 + Math.Pow(xy.arr[i, 0], 2) / (f * f));
                A.arr[i * 2, 4] = -xy.arr[i, 0] * xy.arr[i, 1] / f;
                A.arr[i * 2, 5] = xy.arr[i, 1];

                A.arr[i * 2 + 1, 0] = 0;
                A.arr[i * 2 + 1, 1] = -1 / m;
                A.arr[i * 2 + 1, 2] = -xy.arr[i, 1] / (f * m);
                A.arr[i * 2 + 1, 3] = -xy.arr[i, 0] * xy.arr[i, 1] / f;
                A.arr[i * 2 + 1, 4] = -f * (1 + Math.Pow(xy.arr[i, 1], 2) / (f * f));
                A.arr[i * 2 + 1, 5] = -xy.arr[i, 0];
            }
            return A;
        }

        public Matrix Cal_AT(Matrix AT, Matrix A)
        {
            //计算A的转置
            AT = A.Transpose(A);
            return AT;
        }

        public Matrix Cal_MmN(Matrix M, Matrix N, Matrix MmN)
        {
            //计算ATA
            MmN = M * N;
            return MmN;
        }

        public Matrix Cal_invATA(Matrix ATA, Matrix inv_ATA)
        {
            //计算ATA逆矩阵
            inv_ATA = ATA.Inverse(ATA);
            return inv_ATA;
        }


        public Matrix Cal_R(Matrix R, Matrix rAngle)
        {
            R.arr[0, 0] = Math.Cos(rAngle.arr[0, 0]) * Math.Cos(rAngle.arr[2, 0]) - Math.Sin(rAngle.arr[0, 0]) * Math.Sin(rAngle.arr[1, 0]) * Math.Sin(rAngle.arr[2, 0]);
            R.arr[0, 1] = -(Math.Cos(rAngle.arr[0, 0]) * Math.Sin(rAngle.arr[2, 0])) - Math.Sin(rAngle.arr[0, 0]) * Math.Sin(rAngle.arr[1, 0]) * Math.Cos(rAngle.arr[2, 0]);
            R.arr[0, 2] = -(Math.Sin(rAngle.arr[0, 0]) * Math.Cos(rAngle.arr[1, 0]));

            R.arr[1, 0] = Math.Cos(rAngle.arr[1, 0]) * Math.Sin(rAngle.arr[2, 0]);
            R.arr[1, 1] = Math.Cos(rAngle.arr[1, 0]) * Math.Cos(rAngle.arr[2, 0]);
            R.arr[1, 2] = -(Math.Sin(rAngle.arr[1, 0]));

            R.arr[2, 0] = Math.Sin(rAngle.arr[0, 0]) * Math.Cos(rAngle.arr[2, 0]) + Math.Cos(rAngle.arr[0, 0]) * Math.Sin(rAngle.arr[1, 0]) * Math.Sin(rAngle.arr[2, 0]);
            R.arr[2, 1] = -(Math.Sin(rAngle.arr[0, 0]) * Math.Sin(rAngle.arr[2, 0])) + Math.Cos(rAngle.arr[0, 0]) * Math.Sin(rAngle.arr[1, 0]) * Math.Cos(rAngle.arr[2, 0]);
            R.arr[2, 2] = Math.Cos(rAngle.arr[0, 0]) * Math.Cos(rAngle.arr[1, 0]);
            return R;
        }

        public Matrix Cal_x0y0(Matrix x0y0, Matrix R, double f, Matrix XYZ, Matrix XsYsZs)
        {
            for (int i = 0; i < 4; i++)
            {
                x0y0.arr[i, 0] = f * (R.arr[0, 0] * (XYZ.arr[i, 0] - XsYsZs.arr[0, 0]) + R.arr[1, 0] * (XYZ.arr[i, 1] - XsYsZs.arr[1, 0]) + R.arr[2, 0] * (XYZ.arr[i, 2] - XsYsZs.arr[2, 0])) / (R.arr[0, 2] * (XYZ.arr[i, 0] - XsYsZs.arr[0, 0]) + R.arr[1, 2] * (XYZ.arr[i, 1] - XsYsZs.arr[1, 0]) + R.arr[2, 2] * (XYZ.arr[i, 2] - XsYsZs.arr[2, 0]));
                x0y0.arr[i, 1] = f * (R.arr[0, 1] * (XYZ.arr[i, 0] - XsYsZs.arr[0, 0]) + R.arr[1, 1] * (XYZ.arr[i, 1] - XsYsZs.arr[1, 0]) + R.arr[2, 1] * (XYZ.arr[i, 2] - XsYsZs.arr[2, 0])) / (R.arr[0, 2] * (XYZ.arr[i, 0] - XsYsZs.arr[0, 0]) + R.arr[1, 2] * (XYZ.arr[i, 1] - XsYsZs.arr[1, 0]) + R.arr[2, 2] * (XYZ.arr[i, 2] - XsYsZs.arr[2, 0]));
            }
            return x0y0;
        }

        public Matrix Cal_L(Matrix L, Matrix xy, Matrix x0y0)
        {
            for (int i = 0; i < 4; i++)
            {
                L.arr[i * 2, 0] = xy.arr[i, 0] + x0y0.arr[i, 0];
                L.arr[i * 2 + 1, 0] = xy.arr[i, 1] + x0y0.arr[i, 1];
            }
            return L;
        }
    }
}
Matrix.cs
namespace 单向空间后方交会
{
    internal class Matrix
    {
        public int r;//行数
        public int c;//列数
        public double[,] arr;//矩阵元素
        /// <summary>
        /// 无参构造函数
        /// </summary>
        public Matrix()
        {
            r = 0;
            c = 0;
            arr = new double[r, c];
        }
        /// <summary>
        /// 拷贝构造函数
        /// </summary>
        /// <param name="m">矩阵</param>
        public Matrix(Matrix m)
        {
            r = m.r;
            c = m.c;
            //arr = m.arr;
            for (int i = 0; i < r; i++)
            {
                for (int j = 0; j < c; j++)
                {
                    arr[i, j] = m.arr[i, j];
                }
            }
        }
        /// <summary>
        /// 有参构造函数
        /// </summary>
        /// <param name="rr">行数</param>
        /// <param name="cc">列数</param>
        /// <param name="arr1">矩阵元素</param>
        public Matrix(int rr, int cc, double[,] arr1)
        {
            r = rr;
            c = cc;
            for (int i = 0; i < r; i++)
            {
                for (int j = 0; j < c; j++)
                {
                    arr[i, j] = arr1[i, j];
                }
            }
        }
        /// <summary>
        /// 有参构造函数
        /// </summary>
        /// <param name="rr">行数</param>
        /// <param name="cc">列数</param>
        public Matrix(int rr, int cc)
        {
            r = rr;
            c = cc;
            arr = new double[r, c];
        }
        /// <summary>
        /// 单位矩阵
        /// </summary>
        /// <param name="rr">行数</param>
        /// <param name="cc">列数</param>
        /// <returns></returns>
        public Matrix eye(int rr, int cc)
        {
            Matrix matrix = new Matrix(rr, cc);
            for (int i = 0; i < rr; i++)
            {
                for (int j = 0; j < cc; j++)
                {
                    arr[i, j] = 1;
                }
            }
            return matrix;
        }
        /// <summary>
        /// 创建零矩阵
        /// </summary>
        /// <param name="rr">行数</param>
        /// <param name="cc">列数</param>
        /// <returns></returns>
        public Matrix zeros(int rr, int cc)
        {
            Matrix matrix = new Matrix(rr, cc);
            for (int i = 0; i < rr; i++)
            {
                for (int j = 0; j < cc; j++)
                {
                    arr[i, j] = 0;
                }
            }
            return matrix;
        }
        /// <summary>
        /// 加法
        /// </summary>
        /// <param name="A">矩阵A</param>
        /// <param name="B">矩阵B</param>
        /// <returns></returns>
        static public Matrix operator +(Matrix A, Matrix B)
        {
            Matrix C = new Matrix(A.r, B.c);
            if (A.r != B.r || A.c != B.c || A.r != C.r || A.c != C.c)
                MessageBox.Show("矩阵维数不同");
            for (int i = 0; i < C.r; i++)
            {
                for (int j = 0; j < C.c; j++)
                {
                    C.arr[i, j] = A.arr[i, j] + B.arr[i, j];
                }
            }
            return C;
        }
        /// <summary>
        /// 减法
        /// </summary>
        /// <param name="A">矩阵A</param>
        /// <param name="B">矩阵B</param>
        /// <returns></returns>
        static public Matrix operator -(Matrix A, Matrix B)
        {
            Matrix C = new Matrix(A.r, B.c);
            if (A.r != B.r || A.c != B.c || A.r != C.r || A.c != C.c)
                MessageBox.Show("矩阵维数不同");
            for (int i = 0; i < C.r; i++)
            {
                for (int j = 0; j < C.c; j++)
                {
                    C.arr[i, j] = A.arr[i, j] - B.arr[i, j];
                }
            }
            return C;
        }
        /// <summary>
        /// 矩阵乘法
        /// </summary>
        /// <param name="A">矩阵A</param>
        /// <param name="B">矩阵B</param>
        /// <returns></returns>
        static public Matrix operator *(Matrix A, Matrix B)
        {
            double temp = 0;
            Matrix C = new Matrix(A.r, B.c);
            if (A.r != C.r || B.c != C.c || A.c != B.r)
                MessageBox.Show("矩阵乘法错误");
            for (int i = 0; i < C.r; i++)
            {
                for (int j = 0; j < C.c; j++)
                {
                    temp = 0;
                    for (int k = 0; k < A.c; k++)
                    {
                        temp += A.arr[i, k] * B.arr[k, j];
                    }
                    C.arr[i, j] = temp;
                }
            }
            return C;
        }
        /// <summary>
        /// 矩阵转置
        /// </summary>
        /// <param name="A">待装置矩阵A</param>
        /// <returns></returns>
        public Matrix Transpose(Matrix A)
        {
            Matrix matrix = new Matrix(A.c, A.r);
            for (int i = 0; i < matrix.r; i++)
            {
                for (int j = 0; j < matrix.c; j++)
                {
                    matrix.arr[i, j] = A.arr[j, i];
                }
            }
            return matrix;
        }
        public double[,] inverseMatrix(double[,] matrix)
        {
            int n = matrix.GetLength(0);
            double[,] result = new double[n, n];
            double[,] temp = new double[n, 2 * n];

            //将矩阵和单位矩阵拼接成一个2n*n的矩阵
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    temp[i, j] = matrix[i, j];
                    temp[i, j + n] = i == j ? 1 : 0;
                }
            }
            //高斯-约旦消元法
            for (int i = 0; i < n; i++)
            {
                double tempValue = temp[i, i];
                for (int j = i; j < 2 * n; j++)
                {
                    temp[i, j] /= tempValue;
                }
                for (int j = 0; j < n; j++)
                {
                    if (j != i)
                    {
                        tempValue = temp[j, i];
                        for (int k = i; k < 2 * n; k++)
                        {
                            temp[j, k] -= tempValue * temp[i, k];
                        }
                    }
                }
            }
            //取出逆矩阵
            for (int i = 0; i < n; i++)
            {
                for (int j = 0; j < n; j++)
                {
                    result[i, j] = temp[i, j + n];
                }
            }

            return result;
        }
        /// <summary>
        /// 矩阵求逆
        /// </summary>
        /// <param name="A"></param>
        /// <returns></returns>
        public Matrix Inverse(Matrix A)
        {
            Matrix result = new Matrix(A.r, A.c);
            result.arr = inverseMatrix(A.arr);
            return result;
        }
    }
}

  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

湫秋刀鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值