2011-12-30 19 views
14

मैं बहुत कम ओवरलैप वाली छवियों का उपयोग करके पैनोरमा बनाने की कोशिश कर रहा हूं, लेकिन मुझे कैमरे के कोण को पता है, इसलिए मुझे पता है कि वहां कितना ओवरलैप है और मुझे छवियों का क्रम पता है, इसलिए मुझे पता है कि प्रत्येक व्यक्ति कहां से संबंधित है चित्रमाला। पहले पास के रूप में मैंने बस छवियों को एक साथ संयोजित किया लेकिन परिणाम पर्याप्त नहीं है। क्या ओवरलैप को खत्म करने के लिए टिपपेज़ को ट्राइपोज़ में फसल करने का कोई तरीका है, फिर बिटमैप्स को समेकन से पहले आयतों में वापस खींचें? मुझे पता है कि यह खींचने के दौरान विरूपण पैदा करेगा, और यह कि एक ट्राइपोज़ाइड बिटमैप को वास्तव में कैसे फसल की जरूरत है, इस बारे में एक करीबी अनुमान है, लेकिन मुझे उम्मीद है कि यह काफी अच्छा होगा।बहुत कम ओवरलैप वाली छवियों को कैसे सिलाई करें?

उत्तर

25

तकनीक आप देख रहे हैं कहा जाता है Image Registration एक Affine रूपांतरण का उपयोग कर। यह छवि बी के लिए मैट्रिक्स ट्रांसफॉर्म की गणना करके सॉफ़्टवेयर में हासिल किया जा सकता है जो इसे छवि ए पर मैप करता है। मुझे लगता है कि आप Windows फॉर्म & GDI + का उपयोग कर सॉफ़्टवेयर में ऐसा करने का प्रयास कर रहे हैं? फिर आपके द्वारा उपलब्ध मैट्रिस 3x3 मैट्रिस हैं, स्केल, अनुवाद, घुमाने और स्कू करने में सक्षम हैं। यह अक्सर साधारण छवि पंजीकरण बनाने के लिए पर्याप्त होता है और मैंने इस तकनीक का सफलतापूर्वक व्यावसायिक सॉफ्टवेयर पैकेज (हालांकि WPF था) में उपयोग किया था।

एक Affine रूपांतरण का उपयोग कर छवि पंजीकरण प्राप्त करने के लिए, सबसे पहले आप छवियों की एक जोड़ी में नियंत्रण बिंदुओं का एक संग्रह की जरूरत पंजीकृत होना चाहिए। इससे हम छवियों को पंजीकृत करने के लिए 2 डी परिवर्तन की गणना कर सकते हैं? मैंने इसे WPF में किया है, जिसमें 3x3 मैट्रिक्स को System.Windows.Media का उपयोग करके परिभाषित किया जा सकता है।मैट्रिक्स वर्ग है, जो निम्नलिखित निर्माता है:

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

नोट: GDI + एक मैट्रिक्स वर्ग जिसका निर्माता अलग हो सकता है, लेकिन सिद्धांत एक ही

निर्माता तर्क मैट्रिक्स फार्म इस प्रकार है:

 
M11  M12  0 
M21  M22  0 
OffsetX OffsetY 1 
अब

यदि इनपुट अंक पहला, दूसरा और आउटपुट यू, वी, affine मैट्रिक्स को बदलने, टी कहा जाता है, कि नक्शे पहला, दूसरा यू पर, वी की गणना इस प्रकार किया जा सकता है:

 
U  = X   * T 

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

या

 
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] 

अंग्रेजी में इसका मतलब क्या यह है, कि के अनुरूप अंक एक्स, छवि 1 में वाई की एक सूची दी:

 
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] 

यह भी इस प्रकार सरल किया जा सकता छवि 2, छवि 2 में संबंधित बिंदुओं के मैट्रिक्स द्वारा गुणा किए गए एक्सवाई अंक वाले मैट्रिक्स एक्स के विपरीत आपको छवि 1 से 2

से अपना मैट्रिक्स बदलता है

आउटपुट ट्रांसफॉर्म टी में ए, बी, सी, डी और टीएक्स, टाई है जो 3113 एफ़िन मैट्रिक्स क्लास (उपरोक्त कन्स्ट्रक्टर) में एम 11, एम 12, एम 21, एम 22, ऑफसेटएक्स, ऑफसेटवाई के अनुरूप है। हालांकि, यदि एक्स मैट्रिक्स और यू मैट्रिक्स में 3 से अधिक अंक हैं, तो समाधान अति निर्धारित है और कम से कम वर्ग फिट होना चाहिए। यह X^-1 खोजने के लिए Moores-Penrose Psuedo-Inverse का उपयोग करके प्राप्त किया जाता है।

कोड में इसका क्या अर्थ है? खैर मैंने रूपांतरण को संभालने के लिए अपने स्वयं के मैट्रिक्स 3x3, मैट्रिक्स 3x2 कक्षाओं और नियंत्रण बिंदु (एक्स, वाई बिंदु) को कोड किया, फिर इसे किसी तत्व पर एक WPF MatrixTransform पर लागू किया। जीडीआई में + आप ग्राफिक्स को कॉल करने से पहले ग्राफिक्स पाइपलाइन पर मैट्रिक्स को लागू करके भी ऐसा कर सकते हैं। DrawImage। चलो देखते हैं कि हम रूपांतरण मैट्रिक्स की गणना कैसे कर सकते हैं।

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 
} 

और एक 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 
} 

इन से हम है कि दो छवियों के अनुरूप बिंदुओं की एक सूची के साथ छवि पंजीकरण कर सकते हैं:

प्रथम श्रेणी हम जरूरत Matrix3x3 वर्ग है । इसका अर्थ यह स्पष्ट करने के लिए, कहें कि आपके पैनोरामा शॉट्स में कुछ विशेष विशेषताएं हैं जो समान हैं। दोनों में कैथेड्रल स्पायर होता है, दोनों में पेड़ होता है। छवियों को पंजीकृत करने वाले अंक ए से बी एक्स के साथ प्रत्येक छवि में एक्स, वाई स्थान होंगे, यानी: दोनों छवियों में स्पिर का एक्सवाई स्थान बिंदुओं की एक जोड़ी होगी।

अंकों की इस सूची के साथ अब

हम गणना कर सकता है हमारे परिणत:

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; 
} 

अंत में, इसके बाद के संस्करण कहा जा सकता है इस प्रकार है:

// जहां xy1, xy2, xy3 पहले में नियंत्रण अंक हैं छवि, और यूवी 1, यूवी 2, यूवी 3 // दूसरी छवि मैट्रिक्स 3x2 परिणाम = कंप्यूटफॉरवर्ड ट्रान्सफॉर्म (नया [] {xy1, xy2, xy3}। नया [] {uv1, uv2, uv3});

वैसे भी, मुझे आशा है कि यह आपके लिए सहायक होगा।मुझे इसका एहसास नहीं है कि यह जीडीआई + विशिष्ट है लेकिन चर्चा करता है कि 3x3 ट्रांसफॉर्म का उपयोग करके छवियों को कैसे पंजीकृत किया जाए, जिसका उपयोग जीडीआई + और डब्ल्यूपीएफ दोनों में किया जा सकता है। मेरे पास वास्तव में मेरे हार्ड ड्राइव पर गहराई से एक कोड उदाहरण है और यदि आपको ऊपर दिए गए स्पष्टीकरण की आवश्यकता है तो अधिक बात करने में खुशी होगी।

नीचे: डेमो दिखा stiched छवियों Image registration - choosing control points

Image registration result - panoramas have been stiched

+0

+1 मुझे यह पसंद है! कोड के लिए तत्पर हैं। :) – rfmodulator

+0

वहां जा रहा है! लॉल –

+0

ठीक है, यह मैट्रिक्स कोड है। तुम क्या सोचते हो? मैं अपने एचडीडी पर एक टेस्ट ऐप की तलाश में हूं, यह देखने के लिए कि क्या मैं इस विधि का उपयोग करके पैनोरमास के साथ एक साथ स्क्रीनशॉट रख सकता हूं .. –

6

जो आप चाहते हैं उसे मैट्रिक्स परिवर्तन के रूप में जाना जाता है।

Here सी #/GDI + में कुछ सरल उदाहरण हैं।

MSDN कुछ अधिक गहराई से वर्णन है।

मुझे विश्वास है कि अंत में आप "परिप्रेक्ष्य परिवर्तन" की तलाश करेंगे, here इस बारे में एक ऐसा प्रश्न है जो आपको सही रास्ते पर ले जा सकता है।

मैं इनाम के बारे में चिंतित नहीं हूँ, यह एक जटिल (और मजेदार) विषय है और मैं समय एक समाधान बाहर काम करने की जरूरत नहीं है, मैं सिर्फ उम्मीद है कि इस जानकारी उपयोगी है। :)

+0

कृपया इसे वोट न दें। इसके बजाए एंड्रयू वोट दें। – rfmodulator

+0

यह आपके आरएफ का बहुत ही खेल है, मैं सिर्फ अपरिवर्तित हूं और यह आपके द्वारा 10pts काट दिया है। मुझे डर है कि मैं भी एक स्पोर्टिंग चैप हूं इसलिए फिर से ऊपर हट जाएगा। गलतफहमी के लिए खेद है! lol –

+0

लॉल, मुझे लगता है ... लेकिन यह बिल्कुल जवाब नहीं है, यह एक टिप्पणी के लिए बहुत बड़ा है। :) हालांकि धन्यवाद। – rfmodulator

संबंधित मुद्दे