c# 平面四参数转换

来源:http://cruelchen.blog.163.com/blog/static/7869184420105100348910/

c# 平面四参数转换  

关于平面四参数转换和C#中pictureBox的应用实例(附求解四参数的代码和应用的例子)

作者:kiseigo BluePan
四参数的应用非常的广泛,平面上面的图像操作,很多都用到四参数,比如图像的平移,旋转,缩放。这里只讨论四参数中的x轴的缩放系数和y轴的缩放系数相同的情况。
把四参数的变化弄清楚了,就不再害怕平面上面的问题。就好像明白了七参数就不再害怕三维转换的问题一样。

原始坐标系是: Xo-Yo  经过尺度缩放,坐标系旋转,然后再平移,变成了Xt-Yt坐标系。如《控制测量》上的图1:
c 平面四参数转换 - cruelchen - 请重启您的计算........Kiseigo)" alt="平面四参数转换和C#中的应用实例(By Kiseigo)" src="http://static1.photo.sina.com.cn/bmiddle/4c8bb86bg632afb351000" real_src="http://static1.photo.sina.com.cn/bmiddle/4c8bb86bg632afb351000"<
图1中,我们要注意的是:
1. X的方向是向右的,Y是向上的。
2. 旋转角是以顺时针方向为正的
这两点非常重要。如果X是向上的,那么四参数将会不一样;而如果旋转角是逆时针方向为正的,四参数也不一样。X有可能是向左或者向下的甚至是向任意方向的,所以关键是我们一定要能画出图形,并且推导出公式。
如《控制测量》书上的推导图就很典型可以做为参考,如图2:

c 平面四参数转换 - cruelchen - 请重启您的计算........Kiseigo)" alt="平面四参数转换和C#中的应用实例(By Kiseigo)" src="http://static13.photo.sina.com.cn/bmiddle/4c8bb86bg632afc1a61cc" real_src="http://static13.photo.sina.com.cn/bmiddle/4c8bb86bg632afc1a61cc"<
这个图的优点就在于,它的源坐标系旋转后就成为水平和垂直的轴线,非常便于平移理解。

需要注意的是,图2中,源坐标系X向任意方向,Y轴的正方向和X轴的正方向逆时针旋转90度的方向一致,定义旋转角顺时针方向为正时。其实应该有4种情况,图上是下面提到的情况C。

假如源坐标系的X是向上的(其实X轴向哪个方向都没有关系,只要Y轴的正方向和X轴的正方向顺时针旋转90度的方向一致),Y是向右的,定义的旋转角逆时针旋转是正的,平面转换四参数的计算公式如下(公式1):

c 平面四参数转换 - cruelchen - 请重启您的计算........Kiseigo)" alt="平面四参数转换和C#中的应用实例(By Kiseigo)" src="http://static9.photo.sina.com.cn/bmiddle/4c8bb86bg632b0ff94a88" real_src="http://static9.photo.sina.com.cn/bmiddle/4c8bb86bg632b0ff94a88"<

其中 为新坐标, 为两个平移参数,(1+m)为尺度,为旋转角,为原坐标。这就是下面提到的情况A。公式1也可以用在情况C。

令  ,

则四参数公式可以写成:

 c 平面四参数转换 - cruelchen - 请重启您的计算........Kiseigo)" alt="平面四参数转换和C#中的应用实例(By Kiseigo)" src="http://static6.photo.sina.com.cn/bmiddle/4c8bb86bg632b10ed73c5" real_src="http://static6.photo.sina.com.cn/bmiddle/4c8bb86bg632b10ed73c5"<

  (公式2)

为了求解四参数,把所有已知的和未知的矩阵写在一起,构造出:
 的形式,然后再利用 求解。
公式2经过展开,变成下面的形式:


写成矩阵的形式(公式3):
c 平面四参数转换 - cruelchen - 请重启您的计算........Kiseigo)" alt="平面四参数转换和C#中的应用实例(By Kiseigo)" src="http://static1.photo.sina.com.cn/bmiddle/4c8bb86bg632b11983410" real_src="http://static1.photo.sina.com.cn/bmiddle/4c8bb86bg632b11983410"<
这样我们就构造成了 的形式,其中, , 为原坐标系下某点的坐标,  分别为原坐标系到新坐标系的平移量, , ,其中(1+m)是尺度, 为旋转角。
公式三就这样变成了一个单纯的矩阵运算,2个点的话恰好能求出四参数,无法计算残差,如果大于等于3个点,就可以计算出残差,这实际上用了最小二乘法。

现在,我们来根据图1的实际情况假设几个比较接近情况的四参数:


假如原坐标系上有5个点,P1(0, 15) P2(0, 5) P3(3, 0) P4(6, 5) P5(6, 15)
其中P1(0, 15)表示在原坐标系下,点P1的X坐标为0, Y坐标为15。
现在,把原坐标系(整个坐标系:包括原点,X轴,Y轴)的X,Y轴都缩短为原来的1/2,然后把整个坐标系逆时针旋转30度,再把两条坐标轴或者说整个坐标系向X轴的负方向移动(旋转以后的X轴的正方向的反方向)4米(如果是负数,那么应该向旋转后的X轴的正方向移动个单位);同理,向Y轴的负方向移动3米(如果是负数就向正方向),经过这3个步骤,原坐标系变成了新的坐标系,原来的5个点,它们在新坐标系下的坐标分别是:
P1(-11.0, 28.981) P2(-1.0, 11.660) P3(9.196, 6.0) P4(9.392, 17.660) P5(-0.608, 34.981)
注意:P1 P2 P3 P4 P5 并不同原坐标系一起旋转!

我们来看使用四参数的计算过程:
double c = fourP.Scale * Math.Cos(fourP.Rotate);
double d = fourP.Scale * Math.Sin(fourP.Rotate);
公式4:
aPtfNew.X = fourP.Xdelta + (c * aPtfOld.X - d * aPtfOld.Y);
aPtfNew.Y = fourP.Ydelta + (d * aPtfOld.X + c * aPtfOld.Y);
只有同意了这个公式才能讨论下面的问题。


那么,我们求出四参数到底有什么意义呢
假如我们用C#写一个画图的程序,比如在picturebox中画一个某一边是尖头的矩形。我们知道,picturebox的坐标系的原点在它的左上角,X轴是向指向右边的,Y轴是指向下边的。而测量坐标系中,X是指向上边的(北),Y是指向右边的(东),原点在左下角,为了方便用户设计图形,我们就用测量的坐标系来设计。
在船体坐标系中,如下图3(新坐标系,用户定义的坐标系):

c 平面四参数转换 - cruelchen - 请重启您的计算........Kiseigo)" alt="平面四参数转换和C#中的应用实例(By Kiseigo)" src="http://static11.photo.sina.com.cn/bmiddle/4c8bb86bg632afddf234a" real_src="http://static11.photo.sina.com.cn/bmiddle/4c8bb86bg632afddf234a"<
如果我们把图3中的船体坐标系去掉,沿着船的矩形边缘建立一个类似于C#中的Picturebox的坐标系,那么在picturebox中各点坐标如下,如图4(源坐标系,它恰好是下面提到的4种情况的情况A):

c 平面四参数转换 - cruelchen - 请重启您的计算........Kiseigo)" alt="平面四参数转换和C#中的应用实例(By Kiseigo)" src="http://static6.photo.sina.com.cn/bmiddle/4c8bb86bg632afe7754e5" real_src="http://static6.photo.sina.com.cn/bmiddle/4c8bb86bg632afe7754e5"<
这个过程到底是什么转换的呢?或许有些人一眼就看出了是picturebox坐标系先逆时针转90度,然后再下方移动15个单位就变成了船体的坐标系。但是大多数人反应毕竟没有那么快,还是有点晕的。所以现在我们看看可否通过四参数的求解,而不用画图或者凭借空间想象力来探讨坐标系的变换:

我们利用其中的两个点的两套坐标系,求出坐标系的变换参数:
P1(0, 15)    P2(0, 5)   两个点在源的坐标系中的坐标(picturebox坐标系)
P1(0, 0)     P2(10, 0)  两个点在新的坐标系中的坐标(船体坐标系/用户坐标系)

求得的四参数是:(源坐标系的X向右,Y向下,逆时针旋转Rotate为正)
X平移 = 15.0
Y平移 = 0.0
旋转(度) = 90 (逆时针)
尺度 = 1.0
我们用刚才对四参数的解释来理解(按次序):1.不缩放 2.逆时针旋转90度 3.向此刻的坐标系(仅是尺度变化和旋转以后的形成的坐标系)的X方向的反方向移动15个单位。
这里有一个误区,是很容易让人混淆的地方。因为源坐标系和以前定义的不一样了,X,Y的方向分别是向右和向下的,逆时针旋转为正的。

我通过作图,得出的结论是存在4种情况:
情况A.
不管X是向哪个方向的(向上,向下,向左,向右或者任意方向),只要Y轴的正方向和X轴的正方向顺时针旋转90度的方向一致,而且定义旋转角逆时针方向为正,那么用的公式也是公式1。测量上用得最多的情况是X向上,Y向右;也是实例中的picturebox的坐标系的情况。


情况B.
 X向任意方向,Y轴的正方向和X轴的正方向顺时针旋转90度的方向一致,定义旋转角顺时针方向为正(数学坐标系用得比较多),那么公式是:


显然,情况C的四参数计算和求解完全和情况A不同,需要重新推导,如果直接用公式3来求四参数和公司4来计算点在新坐标系下的xy,计算出来的结果和理解的肯定不一样。

情况C.
X向任意方向,Y轴的正方向和X轴的正方向逆时针旋转90度的方向一致,定义旋转角顺时针方向为正时,得出的也是公式1。如前面的图2显示,公式同情况A是:


情况A和情况C都可以用公式3来求四参数,用公式4来计算点在新坐标系下的XY坐标。
情况D.
 如果,X向任意方向,Y轴的正方向和X轴的正方向逆时针旋转90度的方向一致,定义旋转角逆时针方向为正,那么公式同情况B是:


显然,情况D的四参数计算和求解完全和情况A不同,需要重新推导,否则计算出来的结果和理解的肯定是错的。

回到刚才讨论的应用的例子(船体坐标系和picturebox的转换)这和视觉上看起来是一样的,比较容易理解。这就恰恰是四参数的用武之地。

而在C#的picturebox中,我们是如何利用四参数来为我们服务的呢?
我们的想法是:重新定义picturebox的坐标系,让它变成船体坐标系,然后直接在picturebox上面画出5个船体坐标点的连线:P1(0, 0) P2(10, 0) P3(15, 3) P4(10, 6) P5(0, 6)

这其实有3个步骤(这要求我们把源坐标系和新坐标系颠倒过来看,就是说把picturebox坐标系当做源坐标系,这样四参数就反过来了。而当源坐标系的X向右,Y向下,逆时针旋转时,四参数的计算公式和源坐标X向):
1. 先在picShip的paint事件中利用ScaleTransform把比例尺调整成我们需要的坐标范围,它本来是用象素做单位的,写入e.Graphics.ScaleTransform(picShip.Width / 6, picShip.Height / 15)
把它的水平轴范围调整成[0,6],垂直的范围调整成[0, 15]

2. e.Graphics.RotateTransform(-90.0F); // 此句运行之后picShip的X坐标向上了,Y向右了。可视区域的范围是x[-6, 0] y[0, 15]

3. e.Graphics.TranslateTransform(-15, 0); // 把旋转之后的坐标系再向下移动15个单位

这些我花了将近一两个星期的时间,始终不能理解,现在回头过来探讨1年前弄不清楚半知半解的东西——有点或然开朗的感觉。

这些都不太好理解,挺恶心,但是为了以后不再恐惧,我们不如多花点时间把它彻底弄清楚,增强我们的信心和实力。试验分析如下:
假如picturebox的长为400象素,高为300象素。
1. ScaleTransform(10, 10)的作用是,把picturebox的水平轴X轴拉长10倍,垂直轴也拉长10倍。那么picturebox现在能显示的范围就变成了:水平[0, 40] 垂直[0, 30]。 而如果e.Graphics.ScaleTransform(0.1F, 0.1F)之后,picturebox可显示的范围放大了10倍将变成:水平[0, 4000] 垂直[0,3000]
// ScaleTransform的作用是对坐标轴X轴和Y轴进行缩放

// pic能表达的范围缩小了10倍

e.Graphics.ScaleTransform(10, 10);

e.Graphics.DrawLine(Pens.Blue, new PointF(0, 0), new PointF(39, 29));

2.
// 作用把当前的坐标系改变,新坐标系的原点在源坐标系的[100, 10]位置

// 也就是说现在picturebox的左上角的坐标是[-100, -10]

// pic现在能表达的范围是: 水平[-100, 300] 垂直[-10, 290]

// 所以画出的两个点故意缩进了一下,这样就能看到整条线的面貌。

e.Graphics.TranslateTransform(100, 10);

e.Graphics.DrawLine(Pens.Blue, new PointF(-95, -5), new PointF(295, 285));

3.
// RotateTransform的作用是对坐标系进行顺时针的旋转

// 这个比较复杂,而且不好理解

// 假如是顺时针旋转30度后形成新的坐标系,

// 那么当前pic的右上角的点在新坐标系下的坐标是(346.4, -200)

// pic的左下角点在新坐标系中的坐标是[150, 259.8]

// pic的右下角点在新坐标系中的坐标是[496.4, 59.8]

e.Graphics.RotateTransform(30.0F);
// 连接到pic的右上角的点

e.Graphics.DrawLine(Pens.Blue, new PointF(5, 5), new PointF(340, -190));
// 连接到pic的左下角的点

e.Graphics.DrawLine(Pens.Blue, new PointF(5, 5), new PointF(155, 250));
// 连接到pic的右下角的点

e.Graphics.DrawLine(Pens.Blue, new PointF(5, 5), new PointF(485, 51));

最后,我们要注意的是:使用或者求解四参数之前,应该弄明白源坐标是如何定义的,X轴是向哪个方向,Y轴和X轴呈什么关系,旋转角是逆时针转为正还是正时针转为正,得自己推导一下公式。如果情况A和情况C,就可以用上面的公式3求解四参数,用公式4来计算xy,否则会出错的。所以会推导公式才是最重要的,千万不要乱用,乱猜,或者知之而不能言而乱言。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值