private static void drawContour(IList <PointF> controlPoints, Image <Bgr, byte> image)
        {
            const float CONTOUR_TENSION = 0;

            /********************  contour and control points *********************/
            var pointIndices = CardinalSpline.GetEqualyDistributedPointIndices(controlPoints, CONTOUR_TENSION, 500);
            var points       = CardinalSpline.InterpolateAt(controlPoints, CONTOUR_TENSION, pointIndices);

            var normals       = new List <LineSegment2DF>();
            var normalIndices = CardinalSpline.GetEqualyDistributedPointIndices(controlPoints, CONTOUR_TENSION, 100);

            foreach (var idx in normalIndices)
            {
                var pt = CardinalSpline.InterpolateAt(controlPoints, CONTOUR_TENSION, idx);
                var normalDirection = CardinalSpline.NormalAt(controlPoints, CONTOUR_TENSION, idx);
                var orientation     = (int)Angle.ToDegrees(System.Math.Atan2(normalDirection.Y, normalDirection.X));
                var normal          = getLine(orientation, pt, 20);
                normals.Add(normal);
            }
            /********************  contour and control points *********************/

            image.Draw(points.ToArray(),
                       Bgr8.Blue,
                       3);

            image.Draw(controlPoints.Select(x => new CircleF(x, 3)), Bgr8.Red, 3);

            image.Draw(normals, Bgr8.Green, 3, false);
        }
        private static ITemplate create(IEnumerable <PointF> normalizedPoints,
                                        int scale,
                                        int rotation,
                                        string label = "")
        {
            var pointTransform = Transforms2D.Combine
                                 (
                Transforms2D.Scale(scale, scale),
                Transforms2D.Rotation((float)Angle.ToRadians(rotation))
                                 );

            var transformedPts = normalizedPoints.Transform(pointTransform).ToList();

            var boundingRect = transformedPts.BoundingRect();
            var offset       = boundingRect.Location;

            transformedPts = transformedPts.Transform(Transforms2D.Translation(-offset.X, -offset.Y)).ToList();

            var template = new OpenHandTemplate();

            var features = new List <Feature>();

            //var validIdxRange = CardinalSpline.ValidIndicesRange(transformedPts.Count);
            //for (int i = validIdxRange.Min; i <= validIdxRange.Max; i++)
            for (int i = CardinalSpline.MIN_INDEX; i < (transformedPts.Count - 1 - CardinalSpline.MAX_INDEX_OFFSET); i++)
            {
                var intPt = transformedPts[i].Round();

                var direction = CardinalSpline.NormalAt(transformedPts, CONTOUR_TENSION, i);
                var orientDeg = (int)Angle.ToDegrees(Math.Atan2(direction.Y, direction.X));
                orientDeg = (int)Angle.NormalizeDegrees(orientDeg + 180);

                var feature = createFeature(intPt.X, intPt.Y, orientDeg);
                features.Add(feature);
            }

            template.Features   = features.ToArray();
            template.Size       = Size.Round(boundingRect.Size);
            template.ClassLabel = label;

            return(template);
        }