/// <summary>
        /// Создаёт контур из внешних точек при помощи афинной гистограммы
        /// </summary>
        /// <param name="centerMode">Выбор центра внешнего контура</param>
        /// <param name="histogramScale">Число баров гистограммы 3*histogramScale* (длина стороны матрицы)</param>
        /// <param name="radiusScale">Скалированный радиус от центра</param>
        /// <returns></returns>
        public CvContourInfo ToAraundContour(CenterDrawMode centerMode = CenterDrawMode.BoundingRectCenter, int histogramScale = 1, double radiusScale = 1, MovingPredictType movingType = MovingPredictType.None, int movingRange = 1)
        {
            CvContourInfo araundContour = new CvContourInfo();

            Point center = this.BoundingCenter;

            switch (centerMode)
            {
            case CenterDrawMode.PixelWeightCenter: center = this.WeightCenter; break;

            case CenterDrawMode.HistogramCenter:
                UpdateXYHistogram();
                center = this.HistogramCenter;
                break;
            }

            araundContour.m_points = AraundPoints(center, m_points, histogramScale, radiusScale, movingType, movingRange);

            araundContour.Id              = this.Id;
            araundContour.ParentId        = this.ParentId;
            araundContour.MainColor       = new MCvScalar(this.MainColor.V0, this.MainColor.V1, this.MainColor.V2);
            araundContour.PerimeterColor  = new MCvScalar(this.PerimeterColor.V0, this.PerimeterColor.V1, this.PerimeterColor.V2);
            araundContour.Area            = this.Area;
            araundContour.Perimeter       = this.Perimeter;
            araundContour.BoundingRect    = new Rectangle(this.BoundingRect.X, this.BoundingRect.Y, this.BoundingRect.Width, this.BoundingRect.Height);
            araundContour.BoundingCenter  = new Point(this.BoundingCenter.X, this.BoundingCenter.Y);
            araundContour.WeightCenter    = new Point(this.WeightCenter.X, this.WeightCenter.Y);
            araundContour.HistogramCenter = new Point(this.HistogramCenter.X, this.HistogramCenter.Y);

            return(araundContour);
        }
        public void Update(Mat img, ChainApproxMethod method = ChainApproxMethod.ChainApproxNone)
        {
            m_contours.Clear();

            Mat grayImg = img;

            if (img.NumberOfChannels > 1)
            {
                grayImg = new Mat();
                CvInvoke.CvtColor(img, grayImg, ColorConversion.Bgr2Gray);
            }

            // hierachy[0][i] 0я иерархии для i-ого контура
            // hierachy[0][i][0] - индекс следующего контура на том же уровне
            // hierachy[0][i][1] - индекс предыдущий контура на том же уровне
            // hierachy[0][i][2] - Индекс потомка
            // hierachy[0][i][3] - Индекс родителя
            using (Mat hierachy = new Mat())
                using (VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint())
                {
                    CvInvoke.FindContours(grayImg, contours, hierachy, RetrType.Tree, method);
                    if (contours.Size == 0)
                    {
                        return;
                    }

                    int   sz            = contours.Size * 4;
                    int[] hierachyArray = new int[sz];
                    Marshal.Copy(hierachy.DataPointer, hierachyArray, 0, sz);

                    for (int i = 0; i < contours.Size; i++)
                    {
                        if (contours[i].Size > 2)
                        {
                            int           parentID = hierachyArray[i * 4 + 3];
                            CvContourInfo info     = new CvContourInfo(i, parentID, contours[i]); // пока не понял логику
                            m_contours.Add(info);
                        }
                    }
                }
        }
        public CvContourInfo Clone()
        {
            CvContourInfo info = new CvContourInfo();

            info.m_points = new Point[this.m_points.Length];
            for (int i = 0; i < this.m_points.Length; i++)
            {
                info.m_points[i] = new Point(this.m_points[i].X, this.m_points[i].Y);
            }

            info.Id              = this.Id;
            info.ParentId        = this.ParentId;
            info.MainColor       = new MCvScalar(this.MainColor.V0, this.MainColor.V1, this.MainColor.V2);
            info.PerimeterColor  = new MCvScalar(this.PerimeterColor.V0, this.PerimeterColor.V1, this.PerimeterColor.V2);
            info.Area            = this.Area;
            info.Perimeter       = this.Perimeter;
            info.BoundingRect    = new Rectangle(this.BoundingRect.X, this.BoundingRect.Y, this.BoundingRect.Width, this.BoundingRect.Height);
            info.BoundingCenter  = new Point(this.BoundingCenter.X, this.BoundingCenter.Y);
            info.WeightCenter    = new Point(this.WeightCenter.X, this.WeightCenter.Y);
            info.HistogramCenter = new Point(this.HistogramCenter.X, this.HistogramCenter.Y);
            return(info);
        }
        // По идее ещё нужен алгоритм кластеризации
        //public CvContours[] GetClasters()


        /// <summary>
        /// Сливает все конутра коллекции во внешний контур с единым центром
        /// </summary>
        /// <param name="centerMode"></param>
        /// <param name="histogramScale"></param>
        /// <param name="radiusScale"></param>
        /// <returns></returns>
        public CvContours GetConcatenateAroundContour(CenterDrawMode centerMode = CenterDrawMode.BoundingRectCenter, int histogramScale = 1, double radiusScale = 1)
        {
            CvContours resultContour = new CvContours();

            if (m_contours.Count == 0)
            {
                return(resultContour);
            }

            int totalPoints = 0;

            foreach (var contour in m_contours)
            {
                totalPoints += contour.PointsCnt;
            }

            if (totalPoints == 0)
            {
                return(resultContour);
            }

            double xx = 0;
            double yy = 0;

            int shift = 0;

            Point[] points = new Point[totalPoints];
            foreach (var contour in m_contours)
            {
                contour.CopyPointsTo(points, shift);
                shift += contour.PointsCnt;

                switch (centerMode)
                {
                case CenterDrawMode.BoundingRectCenter:
                    xx += contour.BoundingCenter.X;
                    yy += contour.BoundingCenter.Y;
                    break;

                case CenterDrawMode.PixelWeightCenter:
                    xx += contour.WeightCenter.X;
                    yy += contour.WeightCenter.Y;
                    break;

                case CenterDrawMode.HistogramCenter:
                    contour.UpdateXYHistogram();
                    xx += contour.HistogramCenter.X;
                    yy += contour.HistogramCenter.Y;
                    break;
                }
            }

            Point commonCenterPoint = new Point((int)(xx / m_contours.Count), (int)(yy / m_contours.Count));
            var   aroundPoints      = CvContourInfo.AraundPoints(commonCenterPoint, points, histogramScale, radiusScale);

            CvContourInfo contourInfo = new CvContourInfo(0, -1, aroundPoints);

            resultContour.m_contours.Add(contourInfo);

            return(resultContour);
        }