[转]C#中的矩阵转换,应用.net GDI+
说明:
在.NET中,利用System.Drawing.Drawing2D
命名空间下的Matrix类,可以使对二维图像坐标转换的处理大大简化,在这篇文章中,我将向读者分享如何利用Matrix类进行二维图像的坐标转换。
背景知识:
Matrix
类中描述了3行2列的六个项,举个例子,对Matrix使用默认的构造方法进行构造时,默认构造方法的参数为( 1,0,0,1,0,0 ),矩阵描述如下
这是下面这个矩阵的简化
最后一列始终为
因此,一个X轴方向移动3,Y轴方向移动2的的平移变换可以被表示成如下形式:
需要说明一点,变换矩阵是对图像矢量做右乘.举一个例子,我们现在有这样一个图形,包含4个点:(1,1) ( 2,3) (5,0) (6 7),这个图形向量可以被表示成一个4行2列的矩阵:
当我们将变换矩阵应用到这个图像矩阵时,变换矩阵是对图像矩阵的右乘
结果矩阵的最后一列是被忽略的,因此变换结果为四个新点(4,3) (5,5) (8,2) (9,9)
一个复合变换由两个以上的矩阵组成,我们看一个例子,一个X轴分量为2,Y轴分量为3的缩放矩阵如下图所示:
当我们进行一个先平移再缩放的复合变换时,缩放矩阵应该右乘平移矩阵,
同样,如果我们进行一个先缩放再平移的坐标变换时平移矩阵应该右乘缩放矩阵.
右乘也叫做追加矩阵,左乘叫做前置矩阵,左边的矩阵总是先被应用的.
矩阵转换:
这篇文章中,只针对以下四种变换:
(1)旋转
(2)平移
(3)缩放
(4)翻转
如何实例化一个Matrix类:
//这会创建一个单位矩阵(1,0,0,1,0,0) Matrix m=new Matrix();
也可以在实例化时设置初始值
//这会创建一个矩阵(1,2,3,4,5,6) Matrix m=new Matrix(1,2,3,4,5,6);
Matrix类实现了多种方法
Rotate
Translate
Scale
Multiply
要创建一个复合矩阵,先要创建一个单位矩阵,然后用以上的方法来追加或者前置(append/prepend)变换
Matrix m=new Matrix(); //从初始点移动至200,200 m.Translate(200,200); //顺时针旋转90度 m.Rotate(90,MatrixOrder.Prepend);
在上面的代码中,因为旋转矩阵是前置矩阵,所以旋转操作会首先被应用
在矩阵变换中,变换的先后顺序是非常重要的,先平移后旋转还是先旋转后平移,结果会有很大不同(旋转时根据原点的).如下图所示
应用Matrix对象
下面的三个GDI+对象应用了Matrix对象
Graphics
Pen
GraphicsPath
以上每个对象都包含了Transform属性,这个属性是Matrix类型的,默认的Transform属性是一个单位矩阵,所有的绘制操作都会遵循各自的Transform属性
因此举个简单的例子,如果将顺时针旋转45度的变换矩阵赋给了Graphics对象的Transform属性,然后画一条水平线,这条线会被呈现为倾斜45度.
矩阵变换应用在GraphicsPath对象上时特别有意思,当Transform属性属性被赋值时,GraphicsPath对象中的PathPoints会立即被更改以反映此次变换.
利用这一行为我们可以在GraphicsPath对象上进行变换,并用DrawImage方法来呈现这次变换
Graphics g=Graphics.FromImage(pictureBox1.Image); //.. GraphicsPath gp=new GraphicsPath(); Image imgpic=(Image)pictureBoxBase.Image.Clone(); //多边形的坐标必须为 //point 1 = 左上角 //point 2 = 右上角 //point 3 = 右下角 if(cbFlipY.CheckState ==CheckState.Checked) gp.AddPolygon(new Point[]{new Point(0,imgpic.Height), new Point(imgpic.Width,imgpic.Height), new Point(0,0)}); else gp.AddPolygon(new Point[]{new Point(0,0), new Point(imgpic.Width,0), new Point(0,imgpic.Height)}); //apply the transformation matrix on the graphical path gp.Transform(mm1); //get the resulting path points PointF[] pts=gp.PathPoints; //draw on the picturebox content of imgpic using the local transformation //using the resulting parralleogram described by pts g.DrawImage(imgpic,pts);
翻转:
很遗憾,Matrix类型中没有关于翻转的方法,但是翻转矩阵大家都知道,对于沿X轴翻转,矩阵为(1,0,0,-1,0,0),沿Y轴旋转,矩阵为
(-1,0,0,1,0,0)
仿射变换:
矩阵变换不仅是简单的点到点的变换
举个例子,有一个矩形,顶点为(0,0) (0,1) (1,1) (1,0),如果单位是像素,那么组成这个矩阵的就是这四个点,如果我们对这个矩阵进行X轴Y轴分量都为2,相对于(0,0)进行缩放,那么结果矩形的四个顶点为(0,0) (0,2) (2,2) (2,0),它还包含四个顶点之间的其他点,为什么四个点的图形被转换成了多于四个点的图形呢?
答案就是,变换操作利用插值来产生哪些不能直接映射的点(未知像素的值使用已知像素的值来估计)