/// <summary>
        /// Returns transformation parameters to coordinatesystem
        /// Return an array with the six affine transformation parameters {a,b,c,d,e,f}
        /// a,b defines vector 1 of coordinate system, d,e vector 2.
        /// c,f defines image center.
        /// Converting from input (X,Y) to output coordinate system (X',Y') is done by:
        /// X' = a*X + b*Y + c, Y' = d*X + e*Y + f
        /// Transformation based on Mikhail "Introduction to Modern Photogrammetry" p. 399-300
        /// Extended to arbitrary number of points by M. Nielsen
        /// </summary>
        /// <returns>Six transformation parameters a,b,c,d,e,f for the affine transformation</returns>
        public AffineTransformationParameters GetTransformation()
        {
            if (_inputs.Count < 3)
            {
                throw new System.Exception(ResourceLoader.GetForCurrentView().GetString("MeasurementsException"));
            }

            int count = _inputs.Count;

            Point[]    outputs = _outputs.ToArray();
            Point[]    inputs  = _inputs.ToArray();
            double[][] N       = CreateMatrix(3, 3);
            //Create normal equation: transpose(B)*B
            //B: matrix of calibrated values. Example of row in B: [x , y , -1]
            for (int i = 0; i < count; i++)
            {
                N[0][0] += Math.Pow(outputs[i].X, 2);
                N[0][1] += outputs[i].X * outputs[i].Y;
                N[0][2] += -outputs[i].X;
                N[1][1] += Math.Pow(outputs[i].Y, 2);
                N[1][2] += -outputs[i].Y;
            }
            N[2][2] = count;

            double[] t1 = new double[3];
            double[] t2 = new double[3];

            for (int i = 0; i < count; i++)
            {
                t1[0] += outputs[i].X * inputs[i].X;
                t1[1] += outputs[i].Y * inputs[i].X;
                t1[2] += -inputs[i].X;

                t2[0] += outputs[i].X * inputs[i].Y;
                t2[1] += outputs[i].Y * inputs[i].Y;
                t2[2] += -inputs[i].Y;
            }

            // Solve equation N = transpose(B)*t1
            var    result = new AffineTransformationParameters();
            double frac   = 1 / (-N[0][0] * N[1][1] * N[2][2] + N[0][0] * Math.Pow(N[1][2], 2) + Math.Pow(N[0][1], 2) * N[2][2] - 2 * N[1][2] * N[0][1] * N[0][2] + N[1][1] * Math.Pow(N[0][2], 2));

            result.A = (-N[0][1] * N[1][2] * t1[2] + N[0][1] * t1[1] * N[2][2] - N[0][2] * N[1][2] * t1[1] + N[0][2] * N[1][1] * t1[2] - t1[0] * N[1][1] * N[2][2] + t1[0] * Math.Pow(N[1][2], 2)) * frac;
            result.B = (-N[0][1] * N[0][2] * t1[2] + N[0][1] * t1[0] * N[2][2] + N[0][0] * N[1][2] * t1[2] - N[0][0] * t1[1] * N[2][2] - N[0][2] * N[1][2] * t1[0] + Math.Pow(N[0][2], 2) * t1[1]) * frac;
            result.C = -(-N[1][2] * N[0][1] * t1[0] + Math.Pow(N[0][1], 2) * t1[2] + N[0][0] * N[1][2] * t1[1] - N[0][0] * N[1][1] * t1[2] - N[0][2] * N[0][1] * t1[1] + N[1][1] * N[0][2] * t1[0]) * frac;
            // Solve equation N = transpose(B)*t2
            result.D = (-N[0][1] * N[1][2] * t2[2] + N[0][1] * t2[1] * N[2][2] - N[0][2] * N[1][2] * t2[1] + N[0][2] * N[1][1] * t2[2] - t2[0] * N[1][1] * N[2][2] + t2[0] * Math.Pow(N[1][2], 2)) * frac;
            result.E = (-N[0][1] * N[0][2] * t2[2] + N[0][1] * t2[0] * N[2][2] + N[0][0] * N[1][2] * t2[2] - N[0][0] * t2[1] * N[2][2] - N[0][2] * N[1][2] * t2[0] + Math.Pow(N[0][2], 2) * t2[1]) * frac;
            result.F = -(-N[1][2] * N[0][1] * t2[0] + Math.Pow(N[0][1], 2) * t2[2] + N[0][0] * N[1][2] * t2[1] - N[0][0] * N[1][1] * t2[2] - N[0][2] * N[0][1] * t2[1] + N[1][1] * N[0][2] * t2[0]) * frac;

            //Calculate s0
            double s0 = 0;

            for (int i = 0; i < this._inputs.Count; i++)
            {
                var tt = result.Transform(_outputs[i]);
                s0 += Math.Pow(tt.X - _inputs[i].X, 2) + Math.Pow(tt.Y - _inputs[i].Y, 2);
            }
            result.S0 = Math.Sqrt(s0) / (this._inputs.Count);
            return(result);
        }
        /// <summary>
        /// Returns transformation parameters to coordinatesystem
        /// Return an array with the six affine transformation parameters {a,b,c,d,e,f}
        /// a,b defines vector 1 of coordinate system, d,e vector 2.
        /// c,f defines image center.
        /// Converting from input (X,Y) to output coordinate system (X',Y') is done by:
        /// X' = a*X + b*Y + c, Y' = d*X + e*Y + f
        /// Transformation based on Mikhail "Introduction to Modern Photogrammetry" p. 399-300
        /// Extended to arbitrary number of points by M. Nielsen
        /// </summary>
        /// <returns>Six transformation parameters a,b,c,d,e,f for the affine transformation</returns>
        public AffineTransformationParameters GetTransformation()
        {
            if (_inputs.Count < 3)
                throw (new System.Exception("At least 3 measurements required to calculate affine transformation"));

            int count = _inputs.Count;
            Point[] outputs = _outputs.ToArray();
            Point[] inputs = _inputs.ToArray();
            double[][] N = CreateMatrix(3, 3);
            //Create normal equation: transpose(B)*B
            //B: matrix of calibrated values. Example of row in B: [x , y , -1]
            for (int i = 0; i < count; i++)
            {
                N[0][0] += Math.Pow(outputs[i].X, 2);
                N[0][1] += outputs[i].X * outputs[i].Y;
                N[0][2] += -outputs[i].X;
                N[1][1] += Math.Pow(outputs[i].Y, 2);
                N[1][2] += -outputs[i].Y;
            }
            N[2][2] = count;

            double[] t1 = new double[3];
            double[] t2 = new double[3];

            for (int i = 0; i < count; i++)
            {
                t1[0] += outputs[i].X * inputs[i].X;
                t1[1] += outputs[i].Y * inputs[i].X;
                t1[2] += -inputs[i].X;

                t2[0] += outputs[i].X * inputs[i].Y;
                t2[1] += outputs[i].Y * inputs[i].Y;
                t2[2] += -inputs[i].Y;
            }

            // Solve equation N = transpose(B)*t1
            var result = new AffineTransformationParameters();
            double frac = 1 / (-N[0][0] * N[1][1] * N[2][2] + N[0][0] * Math.Pow(N[1][2], 2) + Math.Pow(N[0][1], 2) * N[2][2] - 2 * N[1][2] * N[0][1] * N[0][2] + N[1][1] * Math.Pow(N[0][2], 2));
            result.A = (-N[0][1] * N[1][2] * t1[2] + N[0][1] * t1[1] * N[2][2] - N[0][2] * N[1][2] * t1[1] + N[0][2] * N[1][1] * t1[2] - t1[0] * N[1][1] * N[2][2] + t1[0] * Math.Pow(N[1][2], 2)) * frac;
            result.B = (-N[0][1] * N[0][2] * t1[2] + N[0][1] * t1[0] * N[2][2] + N[0][0] * N[1][2] * t1[2] - N[0][0] * t1[1] * N[2][2] - N[0][2] * N[1][2] * t1[0] + Math.Pow(N[0][2], 2) * t1[1]) * frac;
            result.C = -(-N[1][2] * N[0][1] * t1[0] + Math.Pow(N[0][1], 2) * t1[2] + N[0][0] * N[1][2] * t1[1] - N[0][0] * N[1][1] * t1[2] - N[0][2] * N[0][1] * t1[1] + N[1][1] * N[0][2] * t1[0]) * frac;
            // Solve equation N = transpose(B)*t2
            result.D = (-N[0][1] * N[1][2] * t2[2] + N[0][1] * t2[1] * N[2][2] - N[0][2] * N[1][2] * t2[1] + N[0][2] * N[1][1] * t2[2] - t2[0] * N[1][1] * N[2][2] + t2[0] * Math.Pow(N[1][2], 2)) * frac;
            result.E = (-N[0][1] * N[0][2] * t2[2] + N[0][1] * t2[0] * N[2][2] + N[0][0] * N[1][2] * t2[2] - N[0][0] * t2[1] * N[2][2] - N[0][2] * N[1][2] * t2[0] + Math.Pow(N[0][2], 2) * t2[1]) * frac;
            result.F = -(-N[1][2] * N[0][1] * t2[0] + Math.Pow(N[0][1], 2) * t2[2] + N[0][0] * N[1][2] * t2[1] - N[0][0] * N[1][1] * t2[2] - N[0][2] * N[0][1] * t2[1] + N[1][1] * N[0][2] * t2[0]) * frac;

            //Calculate s0
            double s0 = 0;
            for (int i = 0; i < this._inputs.Count; i++)
            {
                var tt = result.Transform(_outputs[i]);
                s0 += Math.Pow(tt.X - _inputs[i].X, 2) + Math.Pow(tt.Y - _inputs[i].Y, 2);
            }
            result.s0 = Math.Sqrt(s0) / (this._inputs.Count);
            return result;
        }