/// <summary>
        /// Объединяет сегментированные изображения в одно сегментированное с подавлением шума
        /// </summary>
        /// <param name="points">Ключевые точки фона</param>
        /// <param name="lim">Разброс цвета подложки по поверхности чипа</param>
        /// <param name="images">Массив несегментированных изображений</param>
        /// <returns>Объединенное (усредненное) сегментированное изображение с подавлением шума</returns>
        public static Bitmap UnionOfImages(List<Point> points, int lim, List<Bitmap> images)
        {
            int width = images.First().Width;
            int height = images.First().Height;

            int[,] res = new int[height, width];

            Segmentation segmentation = new Segmentation(points, lim);
            foreach (Bitmap image in images)
            {
                byte[,,] currMas = segmentation.GetSegmentedMass(image);

                for (int i = 0; i < height; i++)
                    for (int j = 0; j < width; j++)
                        if (currMas[i, j, 0] != 0)
                            res[i, j]++;
            }

            byte[,,] outputPicture = new byte[height, width, 3];
            for (int i = 0; i < height; i++)
                for (int j = 0; j < width; j++)
                    ProColors.SetColor(outputPicture, i, j, res[i, j] > 2 ? ProColors.NoWafer : ProColors.Wafer);

            var noiseSuppression = new NoiseSuppression(outputPicture);
            outputPicture = noiseSuppression.GetNoiseSuppressedMas();

            return ByteToBitmapRgb(outputPicture);
        }
        private void обрезатьToolStripMenuItem_Click(object sender, EventArgs e)
        {
            if (CurrResume != Resume.Cutting)
                return;

            // сохраняем отступ по которому будет обрезание изображения
            _offset.X += trbLeftPosition.Value;
            _offset.Y += trbUpPosition.Value;

            // определяем позицию текущего изображения на форме
            int pos = _images.IndexOf(_currImage);

            // обрезаем изображение на форме
            _images[pos] = CutBitmapImage(_images[pos], trbLeftPosition.Value, trbRightPosition.Value, trbUpPosition.Value, trbDownPosition.Value);

            Segmentation segmentationOrigin = new Segmentation(GetCorrectedPoints(), trbToleranceLimit.Value);
            byte[,,] originMas = segmentationOrigin.GetSegmentedMass(_images[pos]);

            SuperImposition superImposition = new SuperImposition(originMas);
            Segmentation segmentation = new Segmentation(_keyPoints, trbToleranceLimit.Value);
            for (int i = 0; i < _images.Count; i++)
            {
                if (i == pos)
                    continue;

                byte[, ,] currMas = segmentation.GetSegmentedMass(_images[i]);
                Point offset = superImposition.FindBestImposition(currMas, new Point(trbLeftPosition.Value, trbUpPosition.Value));
                _images[i] = CutBitmapImage(_images[i], offset, _images[pos].Width, _images[pos].Height);
            }

            _currImage = _images[pos];
            pbGoodChipImage.Image = _currImage;

            // сбрасываем показания контролов
            trbRightPosition.Value = 0;
            trbLeftPosition.Value = 0;
            trbUpPosition.Value = 0;
            trbDownPosition.Value = 0;
            RefreshCuttingLabels();
            SetDimensionsOfPositionTrackBars(_currImage);
        }
        /// <summary>
        /// Проверка очередного изображения чипа
        /// </summary>
        /// <param name="pathToChipFile">Путь к файлу с изображением чипа</param>
        /// <returns>Возвращает изображение в формате Bitmap с пометкой подозрительных областей</returns>
        public void CheckNextChip(string pathToChipFile)
        {
            // сегментируем очередной чип, который нужно проверить
            Bitmap bmp = new Bitmap(pathToChipFile);
            Segmentation segm = new Segmentation(_cullingProject.KeyPoints, _cullingProject.Lim)
            {
                RadiusOfStartFilling = SegmentationRadiusOfStartFilling
            };
            byte[,,] segmentedMass = segm.GetSegmentedMass(bmp);

            // сохраняем изображение очередного чипа
            _currChipForTest = bmp;

            // находим наилучшее совмещение
            _offset = _superImposition.FindBestImposition(segmentedMass, _cullingProject.OriginOffset);

            CurrMarkIsland = 0;
            CurrMarkDust = 0;
            CountOfDamages = 0;
            // сравниваем хороший чип и очередной тестируемый
            CheckChipForDamage(segmentedMass);

            CurrVerdict = CurrMarkIsland < _sumIslandLimit ? Verdict.Good.Name : Verdict.Bad.Name;
        }