2011-12-30 35 views
14

Tôi đang cố gắng tạo ảnh toàn cảnh bằng cách sử dụng hình ảnh với rất ít chồng chéo nhưng tôi biết góc của máy ảnh để tôi biết chính xác có bao nhiêu chồng chéo và tôi biết thứ tự của hình ảnh để tôi biết vị trí của từng ảnh toàn cảnh. Là lần đầu tiên tôi chỉ đơn giản là cocantenated các hình ảnh với nhau nhưng kết quả là không đủ tốt. Có cách nào để cắt các ảnh bitmap thành hình thang để loại bỏ (phần lớn) chồng lên nhau, sau đó kéo dài các ảnh bitmap trở lại hình chữ nhật trước khi kết nối không? Tôi biết điều này sẽ tạo ra sự biến dạng trong quá trình kéo dài, và hình thang chỉ gần đúng với cách Bitmap thực sự cần được cắt, nhưng tôi hy vọng điều này sẽ đủ tốt.Làm cách nào để ghép hình ảnh với chồng chéo rất ít?

Trả lời

25

Kỹ thuật bạn đang tìm kiếm được gọi là Image Registration bằng cách sử dụng Biến đổi affine. Điều này có thể đạt được trong phần mềm bằng cách tính toán biến đổi ma trận cho hình ảnh B ánh xạ nó lên hình A. Tôi cho rằng bạn đang cố gắng làm điều này trong phần mềm bằng cách sử dụng Windows Forms & GDI +? Sau đó, các ma trận bạn có sẵn là các ma trận 3x3, có khả năng Scale, dịch, Rotate và Skew. Điều này thường đủ để tạo đăng ký hình ảnh đơn giản và tôi đã sử dụng kỹ thuật này thành công trong gói phần mềm thương mại (tuy nhiên là WPF).

Để đạt được đăng ký hình ảnh bằng cách sử dụng Biến đổi affine, trước hết bạn cần một bộ sưu tập các điểm kiểm soát trong một cặp hình ảnh sẽ được đăng ký. Từ đây chúng ta có thể tính toán chuyển đổi 2D để đăng ký hình ảnh? Tôi đã làm điều này trong WPF, trong đó có một ma trận 3x3 có thể được xác định bằng cách sử dụng System.Windows.Media.lớp ma trận, trong đó có các nhà xây dựng sau đây:

Matrix(double m11, double m12, double m21, double m22, 
     double offsetX, double offsetY) 

Lưu ý: GDI + có một lớp Matrix có nhà xây dựng có thể khác nhau nhưng nguyên tắc là như nhau

Những lập luận constructor tạo ma trận như sau:

 
M11  M12  0 
M21  M22  0 
OffsetX OffsetY 1 

Bây giờ nếu các điểm đầu vào được gọi là X, Y và đầu ra U, V, ma trận affine biến đổi, T, mà bản đồ X, Y vào U, V có thể được tính như sau:

 
U  = X   * T 

[U1 V1 1] = [X1 Y1 1] [A B 0] 
[U2 V2 1] = [X2 Y2 1] * [C D 0] 
[U3 V3 1] = [X3 Y3 1] [Tx Ty 1] 

này cũng có thể được đơn giản hóa như sau:

 
U  = X   * T 

[U1 V1] = [X1 Y1 1] [A B ] 
[U2 V2] = [X2 Y2 1] * [C D ] 
[U3 V3] = [X3 Y3 1] [Tx Ty] 

hoặc

 
X^-1   * U  = T 
[X1 Y1 1]^-1 [U1 V1] [A B ] 
[X2 Y2 1] * [U2 V2] = [C D ] 
[X3 Y3 1]  [U3 V3] [Tx Ty] 

Trong tiếng Anh điều này có nghĩa là, được đưa ra một danh sách các điểm X, Y theo hình ảnh của 1 tương ứng với hình ảnh 2, nghịch đảo của ma trận X chứa các điểm XY nhân với ma trận của các điểm tương ứng trong hình ảnh 2 cho phép biến đổi ma trận của bạn từ Hình 1 đến 2

Biến đổi đầu ra T chứa A, B, C, D và Tx, Ty tương ứng với M11, M12, M21, M22, OffsetX, Bù đắp trong lớp ma trận affin 3x3 (hàm tạo bên trên). Tuy nhiên, nếu ma trận X và ma trận U có nhiều hơn 3 điểm, thì giải pháp được xác định trước và phải tìm ra một hình vuông nhỏ nhất. Điều này được thực hiện bằng cách sử dụng nghịch đảo Paseo của Moores-Penrose để tìm X^-1.

Điều này có nghĩa là gì trong mã? Tôi cũng mã hóa các lớp Matrix3x3, Matrix3x2 và Điểm điều khiển (x, y point) của riêng mình để xử lý phép biến đổi rồi áp dụng điều này cho một MatrixFansform WPF trên một phần tử. Trong GDI +, bạn có thể làm tương tự bằng cách áp dụng Ma trận vào đường ống đồ họa trước khi gọi Graphics.DrawImage. Hãy xem cách chúng ta có thể tính toán ma trận chuyển đổi.

Lớp đầu tiên chúng ta cần là lớp Matrix3x3:

public class Matrix3x3 : ICloneable 
{ 
    #region Local Variables 

    private double [] coeffs; 

    private const int _M11 = 0; 
    private const int _M12 = 1; 
    private const int _M13 = 2; 
    private const int _M21 = 3; 
    private const int _M22 = 4; 
    private const int _M23 = 5; 
    private const int _M31 = 6; 
    private const int _M32 = 7; 
    private const int _M33 = 8; 

    #endregion 

    #region Construction 

    /// <summary> 
    /// Initializes a new instance of the <see cref="Matrix3x3"/> class. 
    /// </summary> 
    public Matrix3x3() 
    { 
     coeffs = new double[9]; 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="Matrix3x3"/> class. 
    /// </summary> 
    /// <param name="coefficients">The coefficients to initialise. The number of elements of the array should 
    /// be equal to 9, else an exception will be thrown</param> 
    public Matrix3x3(double[] coefficients) 
    { 
     if (coefficients.GetLength(0) != 9) 
      throw new Exception("Matrix3x3.Matrix3x3()", "The number of coefficients passed in to the constructor must be 9"); 

     coeffs = coefficients; 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="Matrix3x3"/> class. 
    /// </summary> 
    /// <param name="m11">The M11 coefficient</param> 
    /// <param name="m12">The M12 coefficien</param> 
    /// <param name="m13">The M13 coefficien</param> 
    /// <param name="m21">The M21 coefficien</param> 
    /// <param name="m22">The M22 coefficien</param> 
    /// <param name="m23">The M23 coefficien</param> 
    /// <param name="m31">The M31 coefficien</param> 
    /// <param name="m32">The M32 coefficien</param> 
    /// <param name="m33">The M33 coefficien</param> 
    public Matrix3x3(double m11, double m12, double m13, double m21, double m22, double m23, double m31, double m32, double m33) 
    { 
     // The 3x3 matrix is constructed as follows 
     // 
     // | M11 M12 M13 | 
     // | M21 M22 M23 | 
     // | M31 M32 M33 | 

     coeffs = new double[] { m11, m12, m13, m21, m22, m23, m31, m32, m33 }; 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="Matrix3x3"/> class. The IAffineTransformCoefficients 
    /// passed in is used to populate coefficients M11, M12, M21, M22, M31, M32. The remaining column (M13, M23, M33) 
    /// is populated with homogenous values 0 0 1. 
    /// </summary> 
    /// <param name="affineMatrix">The IAffineTransformCoefficients used to populate M11, M12, M21, M22, M31, M32</param> 
    public Matrix3x3(IAffineTransformCoefficients affineTransform) 
    { 
     coeffs = new double[] { affineTransform.M11, affineTransform.M12, 0, 
           affineTransform.M21, affineTransform.M22, 0, 
           affineTransform.OffsetX, affineTransform.OffsetY, 1}; 
    } 

    #endregion 

    #region Public Properties 

    /// <summary> 
    /// Gets or sets the M11 coefficient 
    /// </summary> 
    /// <value>The M11</value> 
    public double M11 
    { 
     get 
     { 
      return coeffs[_M11]; 
     } 
     set 
     { 
      coeffs[_M11] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the M12 coefficient 
    /// </summary> 
    /// <value>The M12</value> 
    public double M12 
    { 
     get 
     { 
      return coeffs[_M12]; 
     } 
     set 
     { 
      coeffs[_M12] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the M13 coefficient 
    /// </summary> 
    /// <value>The M13</value> 
    public double M13 
    { 
     get 
     { 
      return coeffs[_M13]; 
     } 
     set 
     { 
      coeffs[_M13] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the M21 coefficient 
    /// </summary> 
    /// <value>The M21</value> 
    public double M21 
    { 
     get 
     { 
      return coeffs[_M21]; 
     } 
     set 
     { 
      coeffs[_M21] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the M22 coefficient 
    /// </summary> 
    /// <value>The M22</value> 
    public double M22 
    { 
     get 
     { 
      return coeffs[_M22]; 
     } 
     set 
     { 
      coeffs[_M22] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the M23 coefficient 
    /// </summary> 
    /// <value>The M23</value> 
    public double M23 
    { 
     get 
     { 
      return coeffs[_M23]; 
     } 
     set 
     { 
      coeffs[_M23] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the M31 coefficient 
    /// </summary> 
    /// <value>The M31</value> 
    public double M31 
    { 
     get 
     { 
      return coeffs[_M31]; 
     } 
     set 
     { 
      coeffs[_M31] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the M32 coefficient 
    /// </summary> 
    /// <value>The M32</value> 
    public double M32 
    { 
     get 
     { 
      return coeffs[_M32]; 
     } 
     set 
     { 
      coeffs[_M32] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the M33 coefficient 
    /// </summary> 
    /// <value>The M33</value> 
    public double M33 
    { 
     get 
     { 
      return coeffs[_M33]; 
     } 
     set 
     { 
      coeffs[_M33] = value; 
     } 
    } 

    /// <summary> 
    /// Gets the determinant of the matrix 
    /// </summary> 
    /// <value>The determinant</value> 
    public double Determinant 
    { 
     get 
     { 
      //        |a b c| 
      // In general, for a 3X3 matrix |d e f| 
      //        |g h i| 
      // 
      // The determinant can be found as follows: 
      // a(ei-fh) - b(di-fg) + c(dh-eg) 

      // Get coeffs 
      double a = coeffs[_M11]; 
      double b = coeffs[_M12]; 
      double c = coeffs[_M13]; 
      double d = coeffs[_M21]; 
      double e = coeffs[_M22]; 
      double f = coeffs[_M23]; 
      double g = coeffs[_M31]; 
      double h = coeffs[_M32]; 
      double i = coeffs[_M33]; 
      double ei = e * i; 
      double fh = f * h; 
      double di = d * i; 
      double fg = f * g; 
      double dh = d * h; 
      double eg = e * g; 

      // Compute the determinant 
      return (a * (ei - fh)) - (b * (di - fg)) + (c * (dh - eg)); 
     } 
    } 

    /// <summary> 
    /// Gets a value indicating whether this matrix is singular. If it is singular, it cannot be inverted 
    /// </summary> 
    /// <value> 
    ///  <c>true</c> if this instance is singular; otherwise, <c>false</c>. 
    /// </value> 
    public bool IsSingular 
    { 
     get 
     { 
      return Determinant == 0; 
     } 
    } 

    /// <summary> 
    /// Gets the inverse of this matrix. If the matrix is singular, this method will throw an exception 
    /// </summary> 
    /// <value>The inverse</value> 
    public Matrix3x3 Inverse 
    { 
     get 
     { 
      // Taken from http://everything2.com/index.pl?node_id=1271704 
      //             a b c 
      //In general, the inverse matrix of a 3X3 matrix d e f 
      //             g h i 

      //is 

      //  1        (ei-fh) (bi-ch) (bf-ce) 
      // ----------------------------- x  (fg-di) (ai-cg) (cd-af) 
      // a(ei-fh) - b(di-fg) + c(dh-eg)  (dh-eg) (bg-ah) (ae-bd) 

      // Get coeffs 
      double a = coeffs[_M11]; 
      double b = coeffs[_M12]; 
      double c = coeffs[_M13]; 
      double d = coeffs[_M21]; 
      double e = coeffs[_M22]; 
      double f = coeffs[_M23]; 
      double g = coeffs[_M31]; 
      double h = coeffs[_M32]; 
      double i = coeffs[_M33]; 

      //// Compute often used components 
      double ei = e * i; 
      double fh = f * h; 
      double di = d * i; 
      double fg = f * g; 
      double dh = d * h; 
      double eg = e * g; 
      double bi = b * i; 
      double ch = c * h; 
      double ai = a * i; 
      double cg = c * g; 
      double cd = c * d; 
      double bg = b * g; 
      double ah = a * h; 
      double ae = a * e; 
      double bd = b * d; 
      double bf = b * f; 
      double ce = c * e; 
      double cf = c * d; 
      double af = a * f; 

      // Construct the matrix using these components 
      Matrix3x3 tempMat = new Matrix3x3(ei - fh, ch - bi, bf - ce, fg - di, ai - cg, cd - af, dh - eg, bg - ah, ae - bd); 

      // Compute the determinant 
      double det = Determinant; 

      if (det == 0.0) 
      { 
       throw new Exception("Matrix3x3.Inverse", "Unable to invert the matrix as it is singular"); 
      } 

      // Scale the matrix by 1/determinant 
      tempMat.Scale(1.0/det); 

      return tempMat; 
     } 
    } 

    /// <summary> 
    /// Gets a value indicating whether this matrix is affine. This will be true if the right column 
    /// (M13, M23, M33) is 0 0 1 
    /// </summary> 
    /// <value><c>true</c> if this instance is affine; otherwise, <c>false</c>.</value> 
    public bool IsAffine 
    { 
     get 
     { 
      return (coeffs[_M13] == 0 && coeffs[_M23] == 0 && coeffs[_M33] == 1); 
     } 
    } 

    #endregion 

    #region Public Methods 

    /// <summary> 
    /// Multiplies the current matrix by the 3x3 matrix passed in 
    /// </summary> 
    /// <param name="rhs"></param> 
    public void Multiply(Matrix3x3 rhs) 
    { 
     // Get coeffs 
     double a = coeffs[_M11]; 
     double b = coeffs[_M12]; 
     double c = coeffs[_M13]; 
     double d = coeffs[_M21]; 
     double e = coeffs[_M22]; 
     double f = coeffs[_M23]; 
     double g = coeffs[_M31]; 
     double h = coeffs[_M32]; 
     double i = coeffs[_M33]; 

     double j = rhs.M11; 
     double k = rhs.M12; 
     double l = rhs.M13; 
     double m = rhs.M21; 
     double n = rhs.M22; 
     double o = rhs.M23; 
     double p = rhs.M31; 
     double q = rhs.M32; 
     double r = rhs.M33; 

     // Perform multiplication. Formula taken from 
     // http://www.maths.surrey.ac.uk/explore/emmaspages/option1.html 

     coeffs[_M11] = a * j + b * m + c * p; 
     coeffs[_M12] = a * k + b * n + c * q; 
     coeffs[_M13] = a * l + b * o + c * r; 
     coeffs[_M21] = d * j + e * m + f * p; 
     coeffs[_M22] = d * k + e * n + f * q; 
     coeffs[_M23] = d * l + e * o + f * r; 
     coeffs[_M31] = g * j + h * m + i * p; 
     coeffs[_M32] = g * k + h * n + i * q; 
     coeffs[_M33] = g * l + h * o + i * r; 
    } 

    /// <summary> 
    /// Scales the matrix by the specified scalar value 
    /// </summary> 
    /// <param name="scalar">The scalar.</param> 
    public void Scale(double scalar) 
    { 
     coeffs[0] *= scalar; 
     coeffs[1] *= scalar; 
     coeffs[2] *= scalar; 
     coeffs[3] *= scalar; 
     coeffs[4] *= scalar; 
     coeffs[5] *= scalar; 
     coeffs[6] *= scalar; 
     coeffs[7] *= scalar; 
     coeffs[8] *= scalar; 
    } 

    /// <summary> 
    /// Makes the matrix an affine matrix by setting the right column (M13, M23, M33) to 0 0 1 
    /// </summary> 
    public void MakeAffine() 
    { 
     coeffs[_M13] = 0; 
     coeffs[_M23] = 0; 
     coeffs[_M33] = 1; 
    } 

    #endregion 

    #region ICloneable Members 

    /// <summary> 
    /// Creates a new object that is a copy of the current instance. 
    /// </summary> 
    /// <returns> 
    /// A new object that is a copy of this instance. 
    /// </returns> 
    public object Clone() 
    { 
     double[] coeffCopy = (double[])coeffs.Clone(); 
     return new Matrix3x3(coeffCopy); 
    } 

    #endregion 

    #region IAffineTransformCoefficients Members 

    // 
    // NB: M11, M12, M21, M22 members of IAffineTransformCoefficients are implemented within the 
    // #region Public Properties directive 
    // 

    /// <summary> 
    /// Gets or sets the Translation Offset in the X Direction 
    /// </summary> 
    /// <value>The M31</value> 
    public double OffsetX 
    { 
     get 
     { 
      return coeffs[_M31]; 
     } 
     set 
     { 
      coeffs[_M31] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the Translation Offset in the Y Direction 
    /// </summary> 
    /// <value>The M32</value> 
    public double OffsetY 
    { 
     get 
     { 
      return coeffs[_M32]; 
     } 
     set 
     { 
      coeffs[_M32] = value; 
     } 
    } 

    #endregion 
} 

Và một lớp Matrix3x2

public class Matrix3x2 : ICloneable 
{ 
    #region Local Variables 

    private double[] coeffs; 

    private const int _M11 = 0; 
    private const int _M12 = 1; 
    private const int _M21 = 2; 
    private const int _M22 = 3; 
    private const int _M31 = 4; 
    private const int _M32 = 5; 

    #endregion 

    #region Construction 

    /// <summary> 
    /// Initializes a new instance of the <see cref="Matrix3x2"/> class. 
    /// </summary> 
    public Matrix3x2() 
    { 
     coeffs = new double[6]; 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="Matrix3x2"/> class. 
    /// </summary> 
    /// <param name="coefficients">The coefficients to initialise. The number of elements of the array should 
    /// be equal to 6, else an exception will be thrown</param> 
    public Matrix3x2(double[] coefficients) 
    { 
     if (coefficients.GetLength(0) != 6) 
      throw new Exception("Matrix3x2.Matrix3x2()", 
       "The number of coefficients passed in to the constructor must be 6"); 

     coeffs = coefficients; 
    } 

    public Matrix3x2(double m11, double m12, double m21, double m22, double m31, double m32) 
    { 
     coeffs = new double[] { m11, m12, m21, m22, m31, m32 }; 
    } 

    /// <summary> 
    /// Initializes a new instance of the <see cref="Matrix3x2"/> class. The IAffineTransformCoefficients 
    /// passed in is used to populate coefficients M11, M12, M21, M22, M31, M32. 
    /// </summary> 
    /// <param name="affineMatrix">The IAffineTransformCoefficients used to populate M11, M12, M21, M22, M31, M32</param> 
    public Matrix3x2(IAffineTransformCoefficients affineTransform) 
    { 
     coeffs = new double[] { affineTransform.M11, affineTransform.M12, 
           affineTransform.M21, affineTransform.M22, 
           affineTransform.OffsetX, affineTransform.OffsetY}; 
    } 

    #endregion 

    #region Public Properties 

    /// <summary> 
    /// Gets or sets the M11 coefficient 
    /// </summary> 
    /// <value>The M11</value> 
    public double M11 
    { 
     get 
     { 
      return coeffs[_M11]; 
     } 
     set 
     { 
      coeffs[_M11] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the M12 coefficient 
    /// </summary> 
    /// <value>The M12</value> 
    public double M12 
    { 
     get 
     { 
      return coeffs[_M12]; 
     } 
     set 
     { 
      coeffs[_M12] = value; 
     } 
    } 


    /// <summary> 
    /// Gets or sets the M21 coefficient 
    /// </summary> 
    /// <value>The M21</value> 
    public double M21 
    { 
     get 
     { 
      return coeffs[_M21]; 
     } 
     set 
     { 
      coeffs[_M21] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the M22 coefficient 
    /// </summary> 
    /// <value>The M22</value> 
    public double M22 
    { 
     get 
     { 
      return coeffs[_M22]; 
     } 
     set 
     { 
      coeffs[_M22] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the M31 coefficient 
    /// </summary> 
    /// <value>The M31</value> 
    public double M31 
    { 
     get 
     { 
      return coeffs[_M31]; 
     } 
     set 
     { 
      coeffs[_M31] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the M32 coefficient 
    /// </summary> 
    /// <value>The M32</value> 
    public double M32 
    { 
     get 
     { 
      return coeffs[_M32]; 
     } 
     set 
     { 
      coeffs[_M32] = value; 
     } 
    } 

    #endregion 

    #region Public Methods 

    /// <summary> 
    /// Transforms the the ILocation passed in and returns the result in a new ILocation 
    /// </summary> 
    /// <param name="location">The location to transform</param> 
    /// <returns>The transformed location</returns> 
    public ILocation Transform(ILocation location) 
    { 
     // Perform the following equation: 
     // 
     // | x y 1 | | M11 M12 | |(xM11 + yM21 + M31) (xM12 + yM22 + M32)| 
     //   * | M21 M22 | = 
     //    | M31 M32 | 

     double x = location.X * coeffs[_M11] + location.Y * coeffs[_M21] + coeffs[_M31]; 
     double y = location.X * coeffs[_M12] + location.Y * coeffs[_M22] + coeffs[_M32]; 

     return new Location(x, y); 
    } 

    /// <summary> 
    /// Multiplies the 3x3 matrix passed in with the current 3x2 matrix 
    /// </summary> 
    /// <param name="x">The 3x3 Matrix X</param> 
    public void Multiply(Matrix3x3 lhs) 
    { 
     // Multiply the 3x3 matrix with the 3x2 matrix and store inside the current 2x3 matrix 
     // 
     // [a b c] [j k] [(aj + bl + cn) (ak + bm + co)] 
     // [d e f] * [l m] = [(dj + el + fn) (dk + em + fo)] 
     // [g h i] [n o] [(gj + hl + in) (gk + hm + io)] 

     // Get coeffs 
     double a = lhs.M11; 
     double b = lhs.M12; 
     double c = lhs.M13; 
     double d = lhs.M21; 
     double e = lhs.M22; 
     double f = lhs.M23; 
     double g = lhs.M31; 
     double h = lhs.M32; 
     double i = lhs.M33; 

     double j = coeffs[_M11]; 
     double k = coeffs[_M12]; 
     double l = coeffs[_M21]; 
     double m = coeffs[_M22]; 
     double n = coeffs[_M31]; 
     double o = coeffs[_M32]; 

     coeffs[_M11] = a * j + b * l + c * n; 
     coeffs[_M12] = a * k + b * m + c * o; 
     coeffs[_M21] = d * j + e * l + f * n; 
     coeffs[_M22] = d * k + e * m + f * o; 
     coeffs[_M31] = g * j + h * l + i * n; 
     coeffs[_M32] = g * k + h * m + i * o; 
    } 

    #endregion 

    #region ICloneable Members 

    /// <summary> 
    /// Creates a new object that is a copy of the current instance. 
    /// </summary> 
    /// <returns> 
    /// A new object that is a copy of this instance. 
    /// </returns> 
    public object Clone() 
    { 
     double[] coeffCopy = (double[])coeffs.Clone(); 
     return new Matrix3x2(coeffCopy); 
    } 

    #endregion 

    #region IAffineTransformCoefficients Members 

    // 
    // NB: M11, M12, M21, M22 members of IAffineTransformCoefficients are implemented within the 
    // #region Public Properties directive 
    // 

    /// <summary> 
    /// Gets or sets the Translation Offset in the X Direction 
    /// </summary> 
    /// <value>The M31</value> 
    public double OffsetX 
    { 
     get 
     { 
      return coeffs[_M31]; 
     } 
     set 
     { 
      coeffs[_M31] = value; 
     } 
    } 

    /// <summary> 
    /// Gets or sets the Translation Offset in the Y Direction 
    /// </summary> 
    /// <value>The M32</value> 
    public double OffsetY 
    { 
     get 
     { 
      return coeffs[_M32]; 
     } 
     set 
     { 
      coeffs[_M32] = value; 
     } 
    } 

    #endregion 
} 

Từ những chúng ta có thể thực hiện đăng ký hình ảnh với một danh sách các điểm tương ứng với hai hình ảnh . Để làm rõ điều này có nghĩa là gì, hãy nói rằng ảnh toàn cảnh của bạn có các tính năng nhất định giống nhau. Cả hai đều có một ngọn tháp nhà thờ, cả hai đều có một cái cây. Các điểm đăng ký ảnh A đến B sẽ là vị trí X, Y trong mỗi ảnh tương ứng, ví dụ: vị trí XY của ngọn tháp trong cả hai hình ảnh sẽ là một cặp điểm.

Bây giờ với danh sách các điểm chúng ta có thể tính toán của chúng tôi thay đổi:

public Matrix3x2 ComputeForwardTransform(IList<Point> baselineLocations, IList<Point> registerLocations) 
{ 
    if (baselineLocations.Count < 3 || registerLocations.Count < 3) 
    { 
     throw new Exception("ComputeForwardTransform()", 
      "Unable to compute the forward transform. A minimum of 3 control point pairs are required"); 
    } 

    if (baselineLocations.Count != registerLocations.Count) 
    { 
     throw new Exception("ComputeForwardTransform()", 
      "Unable to compute the forward transform. The number of control point pairs in baseline and registration results must be equal"); 
    } 

    // To compute 
    // Transform = ((X^T * X)^-1 * X^T)U = (X^T * X)^-1 (X^T * U) 

    // X^T * X = 
    // [ Sum(x_i^2) Sum(x_i*y_i) Sum(x_i) ] 
    // [ Sum(x_i*y_i) Sum(y_i^2) Sum(y_i) ] 
    // [ Sum(x_i)  Sum(y_i)  Sum(1)=n ] 

    // X^T * U = 
    // [ Sum(x_i*u_i) Sum(x_i*v_i) ] 
    // [ Sum(y_i*u_i) Sum(y_i*v_i) ] 
    // [ Sum(u_i)  Sum(v_i) ] 

    IList<Point> xy = baselineLocations; 
    IList<Point> uv = registerLocations; 

    double a = 0, b = 0, c = 0, d = 0, e = 0, f = 0, g = 0, h = 0, n = xy.Count; 
    double p = 0, q = 0, r = 0, s = 0, t = 0, u = 0; 

    for (int i = 0; i < n; i++) 
    { 
     // Compute sum of squares for X^T * X 
     a += xy[i].X * xy[i].X; 
     b += xy[i].X * xy[i].Y; 
     c += xy[i].X; 
     d += xy[i].X * xy[i].Y; 
     e += xy[i].Y * xy[i].Y; 
     f += xy[i].Y; 
     g += xy[i].X; 
     h += xy[i].Y; 

     // Compute sum of squares for X^T * U 
     p += xy[i].X * uv[i].X; 
     q += xy[i].X * uv[i].Y; 
     r += xy[i].Y * uv[i].X; 
     s += xy[i].Y * uv[i].Y; 
     t += uv[i].X; 
     u += uv[i].Y; 
    } 

    // Create matrices from the coefficients 
    Matrix3x2 uMat = new Matrix3x2(p, q, r, s, t, u); 
    Matrix3x3 xMat = new Matrix3x3(a, b, c, d, e, f, g, h, n); 

    // Invert X 
    Matrix3x3 xInv = xMat.Inverse; 

    // Perform the multiplication to get the transform 
    uMat.Multiply(xInv); 

    // Matrix uMat now holds the image registration transform to go from the current result to baseline 
    return uMat; 
} 

Cuối cùng, trên có thể được gọi như sau:

// nơi xy1, xy2, xy3 là điểm kiểm soát ở đầu tiên hình ảnh, và uv1, uv2, uv3 là // cặp tương ứng trong hình ảnh thứ hai Kết quả Matrix3x2 = ComputeForwardTransform (mới [] {xy1, xy2, xy3}. new [] {uv1, uv2, uv3});

Dù sao, tôi hy vọng điều này hữu ích cho bạn.Tôi nhận ra nó không phải là GDI + cụ thể nhưng không thảo luận làm thế nào để đăng ký hình ảnh bằng cách sử dụng biến đổi 3x3 chi tiết, có thể được sử dụng cả trong GDI + và WPF. Tôi thực sự có một ví dụ mã sâu xuống một nơi nào đó trên ổ cứng của tôi và sẽ rất vui khi được nói nhiều hơn nếu bạn cần làm rõ ở trên.

Dưới đây: Demo cho thấy hình ảnh stiched Image registration - choosing control points

Image registration result - panoramas have been stiched

+0

+1 Tôi thích nó! Mong mã. :) – rfmodulator

+0

Đến đó! Lol –

+0

Được rồi, đó là mã ma trận. Bạn nghĩ sao? Tôi đang tìm một ứng dụng thử nghiệm mà tôi đã viết trên ổ cứng của mình để xem liệu tôi có thể đặt một ảnh chụp màn hình lên các ảnh toàn cảnh với nhau bằng cách sử dụng phương pháp này hay không .. –

6

Điều bạn muốn được gọi là chuyển đổi ma trận.

Here là một số ví dụ đơn giản trong C#/GDI +.

MSDN có một số mô tả chi tiết hơn.

Tôi tin rằng cuối cùng bạn sẽ tìm kiếm một "Chuyển đổi quan điểm", here là một câu hỏi SO về điều đó có thể dẫn bạn xuống con đường bên phải.

Tôi không lo lắng về tiền thưởng, đây là một chủ đề phức tạp (và thú vị) và tôi không có thời gian để tìm ra giải pháp, tôi chỉ hy vọng thông tin này hữu ích. :)

+0

Vui lòng không bỏ phiếu này. Lên bầu chọn Andrew. – rfmodulator

+0

Đó là rất thể thao của bạn rf, tôi chỉ un-upvoted và nó khấu trừ 10pts từ bạn. Tôi e rằng tôi cũng là một đội thể thao nên sẽ tái xuất hiện. Xin lỗi vì sự nhầm lẫn! lol –

+0

Lol, tôi cho rằng ... nhưng điều này không có nghĩa là một câu trả lời nào cả, nó quá lớn để nhận xét. :) Cảm ơn mặc dù. – rfmodulator

Các vấn đề liên quan