C# GDAL 数字图像处理Part8 无人机影像粗校正

        好!

        今天我们来更新“无人机影像粗校正”的部分。

        其实老师刚刚开始布置任务的时候,我一直不明白是什么意思,后来再问了一下才知道,我们到底要干嘛。接下来,细述本次任务的概要与思想:

一、任务概要

        如图所示,我们获得了一幅无人机影像图片(影像来源:SWJTU 地院 曹老师):

        我们打开自己的软件(前提是你已经做了 显示鼠标所在位置地理坐标 的功能,详见:

C# GDAL 数字图像处理Part4 获得鼠标位置的地理坐标_A_RSswjtuer的博客-CSDN博客

        鼠标移动到上边,我们会发现,该影像的地理坐标(如下图示)是有误的,或者说是并未设置的,那么我们的任务,就是求出且设置它的仿射变换六参数,使得它有正确的地理坐标。

 二、解决思路

        首先,我们回想一下之前学过的《摄影测量学基础》,里面有一个共线方程(来源:百度百科):

         我们可以知道,一条直线的共线方程包含以下几个要素:像平面坐标相机(摄站)的地理坐标物体的地理坐标 、内方位元素与方向

        那么在拍照的时候,借助POS系统,我们会知道 相机(摄站)的地理坐标 方向

        内方位元素、像平面坐标可以通过产品信息获得

        所以我们需要根据这四个条件求出像素对应位置的地理坐标

        对于像素位置,我们选用四角的像素位置即可,比较方便。那情况就如下图:

        当我们有了像素坐标(x,y)和对应地理坐标(X,Y),想要解求仿射变换六参数,那问题就变得和Part7(C# GDAL 数字图像处理Part7 仿射变换图像配准_A_RSswjtuer的博客-CSDN博客)的求解仿射变换六参数相同了。本文会用到和Part7一样的最小二乘拟合多元一次多项式的类,如果自己并未实现此类,建议先去看Part7。

        好,这就是我们要做的事情。

三、代码实现

        我们先看四个已知值,像平面坐标、姿态信息、摄站坐标、内方位元素:

3.1 像平面坐标

        像平面坐标怎么求?其实我们只需要知道相机参数的传感器尺寸即可,听起来复杂其实也就是相片的大小。假如一张相片长为36mm,宽为24mm,那它的四角坐标如下图:

         这里是以中心为原点,那么相片的长和宽得让用户输入。

3.2内方位元素

        内方位元素x0、y0以及f 都是商家在生产相机时给出的坐标,让用户输入即可。

3.3姿态信息

        姿态信息也就是相机在α、β、κ方向上的转角,也是用户输入。

3.4摄站坐标

        摄站坐标也就是相机在拍摄时的地理坐标,还是用户输入。

3.5计算公式

        首先我们通过以下公式计算a矩阵:

         代码是这样:

        private double d2h(double d)//度转弧度
        {
            return d / 180.0 * Math.PI;
        }

        private void Compute_paras_a()
        {
            //Paras_a是一个double[3,3]的成员变量
            //Phi、Omega、Kappa是用户输入的值
            this.Paras_a[0, 0] = Math.Cos(d2h(this.Phi)) * Math.Cos(d2h(this.Kappa)) -
                Math.Sin(d2h(this.Phi)) * Math.Sin(d2h(this.Omega)) * Math.Sin(d2h(this.Kappa));

            this.Paras_a[0, 1] = (-Math.Cos(d2h(this.Phi))) * Math.Sin(d2h(this.Kappa)) -
               Math.Sin(d2h(this.Phi)) * Math.Sin(d2h(this.Omega)) * Math.Cos(d2h(this.Kappa));

            this.Paras_a[0, 2] = (-Math.Sin(d2h(this.Phi))) * Math.Cos(d2h(this.Omega));

            this.Paras_a[1, 0] = Math.Cos(d2h(this.Omega)) * Math.Sin(d2h(this.Kappa));

            this.Paras_a[1, 1] = Math.Cos(d2h(this.Omega)) * Math.Cos(d2h(this.Kappa));

            this.Paras_a[1, 2] = (-Math.Sin(d2h(this.Omega)));

            this.Paras_a[2, 0] = Math.Sin(d2h(this.Phi)) * Math.Cos(d2h(this.Kappa)) +
                Math.Cos(d2h(this.Phi)) * Math.Sin(d2h(this.Omega)) * Math.Sin(d2h(this.Kappa));

            this.Paras_a[2, 1] = (-Math.Sin(d2h(this.Phi))) * Math.Sin(d2h(this.Kappa)) +
               Math.Cos(d2h(this.Phi)) * Math.Sin(d2h(this.Omega)) * Math.Sin(d2h(this.Kappa));

            this.Paras_a[2, 2] = Math.Cos(d2h(this.Phi)) * Math.Cos(d2h(this.Omega));
        }

        接下来呢,我们通过以下公式计算四个角点的地理坐标:

         其中 下标为p 是物体地理坐标, 下标为s 是摄站的XYZ坐标。

        我们可以看到这里多了一个 Zp ,课上说可以用 成像区域平均高程 替代,这也是需要用户输入的一部分哈~

        那么,代码如下:

        private void Compute_corners_coor()
        {
            double[,] xy = new double[4, 2];//计算像平面坐标
            xy[0, 0] = -0.5 * this.Camera_W; xy[0, 1] =  0.5 * this.Camera_H;  //LT
            xy[1, 0] =  0.5 * this.Camera_W; xy[1, 1] =  0.5 * this.Camera_H;  //RT
            xy[2, 0] = -0.5 * this.Camera_W; xy[2, 1] = -0.5 * this.Camera_H;  //LB
            xy[3, 0] =  0.5 * this.Camera_W; xy[3, 1] = -0.5 * this.Camera_H;  //RB

            for (int i = 0;i<4;i++)
            {
                //Corners_coor的类型是double[4,2],代表四个角点以及每个角点的地理坐标XY
                //Area_AvH代表区域平均高程
                //Img_H代表的是成像时摄站的高程Z。
                //四角坐标的X
                this.Corners_coor[i, 0] = this.Camera_XY[0] + (this.Area_AvH - this.Img_H) *
                    (this.Paras_a[0, 0] * xy[i, 0] + this.Paras_a[0, 1] * xy[i, 1] - this.Paras_a[0, 2] * this.f)
                    /
                    (this.Paras_a[2, 0] * xy[i, 0] + this.Paras_a[2, 1] * xy[i, 1] - this.Paras_a[2, 2] * this.f);
                //四角坐标的Y
                this.Corners_coor[i, 1] = this.Camera_XY[1] + (this.Area_AvH - this.Img_H) *
                    (this.Paras_a[1, 0] * xy[i, 0] + this.Paras_a[1, 1] * xy[i, 1] - this.Paras_a[1, 2] * this.f)
                    /
                    (this.Paras_a[2, 0] * xy[i, 0] + this.Paras_a[2, 1] * xy[i, 1] - this.Paras_a[2, 2] * this.f);
            }//计算出了四角坐标
        }

        这样,我们就计算出来了四角的地理坐标。

        现在,我们有四组像素坐标(注意,这里变为像素坐标,从(0,0)开始!之前的是像片坐标),四组地理坐标,就可以参照仿射变换的公式,使用之前说到的类进行最小二乘拟合求解最佳参数。(P7有说过类怎么使用,这里就不多赘述)

        最后,我们就求出新的六参数了:{a,b,c,d,e,f}

        但是这还不能设置到图像中。

        在我的Part4:(C# GDAL 数字图像处理Part4 获得鼠标位置的地理坐标_A_RSswjtuer的博客-CSDN博客)中有提到地理坐标的计算公式是:

        GeoX = argout[0] + argout[1] * x + argout[2] * y

        GeoY = argout[3] + argout[4] * x + argout[5] * y

        可以看到,第一项是常数项,第二三项才是乘以xy的参数ab,所以我们应该对原始的六参数顺序进行变换,使得常数项在前:

        {a, b, c, d, e, f} --> {c, a, b, f, d, e}

        好,这样就完成了我们仿射变换六参数的计算!

3.6为Dataset设置仿射变换六参数

        其实很简单,假设我们输出的Dataset名字是“output_dataset",我们使用:

  output_dataset . SetGeoTransform(六参数double数组)

        即可。

        注意,输入的数组一定要是double[6]。

        好,今天的更新就到这里!

        

  • 4
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
c指的是「充分概要」(concise),是指用简练的语言精确地表达出思想或信息。在现代社会,随着信息的快速传播和获取,人们对于信息的处理能力要求越来越高,因此,c的重要性日益凸显。 首先,c有助于有效地沟通。使用简明扼要的语言表达,能使信息更加清晰明了,让读者或听众快速理解和掌握要点,避免产生歧义和误解。对于商务谈判、学术研究或公众演讲等各种场合,c都是至关重要的。 其次,c可以节约时间和精力。在信息爆炸的时代,人们需要面对大量的文字和图像,如何迅速筛选出自己所需要的信息,是一项具有挑战性的任务。使用c的语言,能够让读者快速浏览和理解,从而节约了阅读的时间和精力。 此外,c也能提高工作效率。在商务领域,写作是一项日常的工作。以简洁明了的方式表达出自己的意见和建议,能够让同事或上司更加迅速地理解和接受,提高决策的速度。同样,在团队合作中,c也能使沟通更加高效,减少信息传递上的误解和混乱。 综上所述,c对于现代社会的重要性不言而喻。在信息时代,我们需要以简洁明了的方式表达自己的思想和观点,保证信息的有效传递和理解,从而提高沟通效果、节约时间和精力,并提升工作效率。因此,我们应该注重培养和提高自己的c能力,使自己在各个方面都能够获得更好的表达和沟通效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值