/// <summary>
/// Fit an ellipse to the points collection
/// </summary>
/// <param name="points">The points to be fitted</param>
/// <returns>An ellipse</returns>
public static Ellipse EllipseLeastSquareFitting(PointF[] points)
{
IntPtr seq = Marshal.AllocHGlobal(StructSize.MCvSeq);
IntPtr block = Marshal.AllocHGlobal(StructSize.MCvSeqBlock);
GCHandle handle = GCHandle.Alloc(points, GCHandleType.Pinned);
CvInvoke.cvMakeSeqHeaderForArray(
CvInvoke.CV_MAKETYPE((int)CvEnum.MAT_DEPTH.CV_32F, 2),
StructSize.MCvSeq,
StructSize.PointF,
handle.AddrOfPinnedObject(),
points.Length,
seq,
block);
Ellipse e = new Ellipse(CvInvoke.cvFitEllipse2(seq));
//The angle returned by cvFitEllipse2 has the wrong sign.
//Returned angle is clock wise rotation, what we need for the definition of MCvBox is the counter clockwise rotation.
//For this, we needs to change the sign of the angle
MCvBox2D b = e.MCvBox2D;
b.angle = -b.angle;
if (b.angle < 0)
{
b.angle += 360;
}
e.MCvBox2D = b;
handle.Free();
Marshal.FreeHGlobal(seq);
Marshal.FreeHGlobal(block);
return(e);
}