public (TrackingState, int[, ]) LocateFigures(KinectData kinectData, double fieldSize, byte[] canniedBytes, UserDefinedParameters userParameters, TrackingResultData resultData, Bitmap colorBitmap, TrackingState gameTrackingState)
        {
            // Collection of pixel colors for each field on chessboard
            var colorsOfPointsOverIndividualFields = InitializeColorCollection();

            colorsOfPointsOverIndividualFields = FillColorsOverFiledsArrayWithData(colorsOfPointsOverIndividualFields, kinectData, fieldSize, canniedBytes, userParameters);

            var trackingState = DetectPresenceAndColorOfFiguresOnFields(colorsOfPointsOverIndividualFields, gameTrackingState, userParameters);

            resultData.VisualisationBitmap = RenderLabelsToFigures(colorsOfPointsOverIndividualFields, trackingState, resultData.VisualisationBitmap);

            var pointCounts = GetPointsCountsOverIndividualFields(colorsOfPointsOverIndividualFields);

            return(trackingState, pointCounts);
        }
        /// <summary>
        /// Decides which fields contain figure and decides its color
        /// -> if there are more points over field than threshold, the figure is considered as present
        /// -> color is decided by thresholding average fitness of points over field
        /// </summary>
        /// <param name="inputColorsData">Colors of points over individual fields</param>
        /// <param name="userParameters">User defined parameters</param>
        /// <returns>Tracking state of chessboard</returns>
        private TrackingState DetectPresenceAndColorOfFiguresOnFields(List <Point2DWithColor>[,] inputColorsData, TrackingState gameTrackingState, UserDefinedParameters userParameters)
        {
            var figures = new TrackingFieldState[8, 8];

            for (int x = 0; x < 8; x++)
            {
                for (int y = 0; y < 8; y++)
                {
                    int   presenceInfluence = 0;
                    float colorInfluence    = 0;

                    if (gameTrackingState != null)
                    {
                        presenceInfluence =
                            gameTrackingState.Figures[x, y] != TrackingFieldState.None
                                ? userParameters.GameStateInfluenceOnPresence
                                : 0;

                        colorInfluence =
                            (userParameters.GameStateInfluenceOnColor / 100f) *
                            (gameTrackingState.Figures[x, y] == TrackingFieldState.None
                                ? 0
                                : gameTrackingState.Figures[x, y] == TrackingFieldState.White
                                    ? 1
                                    : -1
                            );
                    }


                    if ((inputColorsData[x, y].Count + presenceInfluence) < userParameters.NumberOfPointsIndicatingFigure)
                    {
                        figures[x, y] = TrackingFieldState.None;
                    }
                    else
                    {
                        if (gameTrackingState != null && inputColorsData[x, y].Count == 0)
                        {
                            figures[x, y] = gameTrackingState.Figures[x, y];
                            continue;;
                        }

                        double averageBrightnessInField;

                        if (userParameters.IsFiguresColorMetricExperimental)
                        {
                            averageBrightnessInField =
                                inputColorsData[x, y].Sum(f => 1 - Math.Pow(-2.5f * (Color.FromArgb(f.Color.R, f.Color.G, f.Color.B).CustomBrightness() - 0.5f), 2) + colorInfluence)
                                / inputColorsData[x, y].Count;
                        }
                        else
                        {
                            averageBrightnessInField =
                                inputColorsData[x, y].Sum(f => Color.FromArgb(f.Color.R, f.Color.G, f.Color.B).GetBrightness() + colorInfluence)
                                / inputColorsData[x, y].Count;
                        }


                        figures[x, y] =
                            averageBrightnessInField > 0.5 + userParameters.ColorCalibrationAdditiveConstant
                            ? TrackingFieldState.White
                            : TrackingFieldState.Black;
                    }
                }
            }

            return(new TrackingState(figures));
        }
        /// <summary>
        /// Detects points over individual fields of chessboard satisfying required conditions
        /// </summary>
        private List <Point2DWithColor>[,] FillColorsOverFiledsArrayWithData(List <Point2DWithColor>[,] array, KinectData kinectData, double fieldSize, byte[] canniedBytes, UserDefinedParameters userParameters)
        {
            var csp                    = kinectData.CameraSpacePointsFromDepthData;
            var infraredData           = kinectData.InfraredData;
            var colorFrameData         = kinectData.ColorFrameData;
            var pointsFromDepthToColor = kinectData.PointsFromDepthToColor;

            var chessboardSize = fieldSize * 8;

            for (int i = 0; i < csp.Length; i++)
            {
                var isValid               = !(float.IsInfinity(csp[i].Z) || float.IsNaN(csp[i].Z));
                var lowerBoundOfXIsOk     = csp[i].X > 0;
                var lowerBoundOfYIsOk     = csp[i].Y > 0;
                var upperBoundOfXIsOk     = csp[i].X < chessboardSize;
                var upperBoundOfYIsOk     = csp[i].Y < chessboardSize;
                var infraredThresholdIsOk = infraredData[i] > 1500;
                var aintFlyingPixelAccordingToCannyDetectorOnDepth = canniedBytes[i] != 255;
                var isHighEnought    = csp[i].Z < -(userParameters.MilimetersClippedFromFigure / 1000d);
                var isBelowThreshold = csp[i].Z > -0.5f;

                if (isValid &&
                    lowerBoundOfXIsOk &&
                    lowerBoundOfYIsOk &&
                    upperBoundOfXIsOk &&
                    upperBoundOfYIsOk &&
                    infraredThresholdIsOk &&
                    aintFlyingPixelAccordingToCannyDetectorOnDepth &&
                    isHighEnought &&
                    isBelowThreshold)
                {
                    var reference = pointsFromDepthToColor[i];

                    if (reference.X > 0 && reference.X < 1920 && reference.Y > 0 && reference.Y < 1080)
                    {
                        var r = colorFrameData[((int)reference.X + (int)reference.Y * 1920) * 4 + 0];
                        var g = colorFrameData[((int)reference.X + (int)reference.Y * 1920) * 4 + 1];
                        var b = colorFrameData[((int)reference.X + (int)reference.Y * 1920) * 4 + 2];

                        int x = (int)Math.Floor(csp[i].X / fieldSize);
                        int y = (int)Math.Floor(csp[i].Y / fieldSize);

                        if (x >= 0 && y >= 0 && x < 8 && y < 8)
                        {
                            array[x, y].Add(new Point2DWithColor(Color.FromArgb(r, g, b), (int)reference.X, (int)reference.Y));
                        }
                    }
                }
            }

            return(array);
        }