zoukankan      html  css  js  c++  java
  • C#中的矩阵转换,应用.net GDI+

    下载示例(因为你看到的有可能是导入后的文章,示例文件如果不能下载请登录www.lizhecome.com)
    Transformation.7z (46.65 kb)

    transnew

    说明:

    在.NET中,利用System.Drawing.Drawing2D命名空间下的Matrix类,可以使对二维图像坐标转换的处理大大简化,在这篇文章中,我将向读者分享如何利用Matrix类进行二维图像的坐标转换。

    背景知识:

    Matrix类中描述了3行2列的六个项,举个例子,对Matrix使用默认的构造方法进行构造时,默认构造方法的参数为( 1,0,0,1,0,0 ),矩阵描述如下

    image002

    这是下面这个矩阵的简化

    image004

    最后一列始终为

    image006

    因此,一个X轴方向移动3,Y轴方向移动2的的平移变换可以被表示成如下形式:

    111 但实际上内部的表示为image010

    需要说明一点,变换矩阵是对图像矢量做右乘.举一个例子,我们现在有这样一个图形,包含4个点:(1,1) ( 2,3) (5,0) (6 7),这个图形向量可以被表示成一个4行2列的矩阵:

    image012 但实际上内部的表示为image014

    当我们将变换矩阵应用到这个图像矩阵时,变换矩阵是对图像矩阵的右乘

    image018

    结果矩阵的最后一列是被忽略的,因此变换结果为四个新点(4,3) (5,5) (8,2) (9,9)

    一个复合变换由两个以上的矩阵组成,我们看一个例子,一个X轴分量为2,Y轴分量为3的缩放矩阵如下图所示:

    2 但实际上内部的表示为image022

    当我们进行一个先平移再缩放的复合变换时,缩放矩阵应该右乘平移矩阵,

    image024

    同样,如果我们进行一个先缩放再平移的坐标变换时平移矩阵应该右乘缩放矩阵.

    右乘也叫做追加矩阵,左乘叫做前置矩阵,左边的矩阵总是先被应用的.

    矩阵转换:

    这篇文章中,只针对以下四种变换:

    (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);
    在上面的代码中,因为旋转矩阵是前置矩阵,所以旋转操作会首先被应用
    在矩阵变换中,变换的先后顺序是非常重要的,先平移后旋转还是先旋转后平移,结果会有很大不同(旋转时根据原点的).如下图所示
    trans1 

    应用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),它还包含四个顶点之间的其他点,为什么四个点的图形被转换成了多于四个点的图形呢?
    答案就是,变换操作利用插值来产生哪些不能直接映射的点(未知像素的值使用已知像素的值来估计)
    肩负责任,永不退缩
  • 相关阅读:
    CF1051F The Shortest Statement 题解
    CF819B Mister B and PR Shifts 题解
    HDU3686 Traffic Real Time Query System 题解
    HDU 5969 最大的位或 题解
    P3295 萌萌哒 题解
    BZOJ1854 连续攻击游戏 题解
    使用Python编写的对拍程序
    CF796C Bank Hacking 题解
    BZOJ2200 道路与航线 题解
    USACO07NOV Cow Relays G 题解
  • 原文地址:https://www.cnblogs.com/ATP/p/1736955.html
Copyright © 2011-2022 走看看