Пример #1
0
        /// <summary>
        /// Выполняет эффективную сегментацию изображения.
        /// </summary>
        /// <param name="inputBitmap">Изображение, которое будет сегментировано.</param>
        /// <param name="outputFolder">Путь к папке, в которую нужно сохранить изображение.</param>
        /// <param name="segmentOut">Массив представителей для каждого пикселя.</param>
        /// <returns>Сегментированное изображение.</returns>
        public Bitmap ExecuteEfficientSegmentation(Bitmap inputBitmap, string outputFolder, out int[] segmentOut)
        {
            Bitmap outputBitmap = new Bitmap(inputBitmap.Width, inputBitmap.Height);

            using (Graphics graphics = Graphics.FromImage(outputBitmap))                      //рисует на поверхности smoothedImage
            {
                graphics.DrawImage(inputBitmap, 0, 0, inputBitmap.Width, inputBitmap.Height); //рисует на поверхности изображение inputBitmap
            }

            //обернуть изображение в lockBitmap и далее пользоваться им
            LockBitmap lockBitmap = new LockBitmap(outputBitmap);

            lockBitmap = new GaussianBlur(Sigma).SmoothImage(lockBitmap);

            int edgesCount; //число ребер в графе

            Edge[]      edges       = BuildGraph(lockBitmap, out edgesCount);
            DisjointSet disjointSet = SegmentGraph(edges, edgesCount, lockBitmap.Width * lockBitmap.Height);

            JointSmallSegments(disjointSet, edges, edgesCount);

            segmentOut = Colorize(lockBitmap, disjointSet);

            return(lockBitmap.Source);
        }
Пример #2
0
        /// <summary>
        /// Рассчитывает разницу между пикселями.
        /// </summary>
        /// <returns>Разница между пикселями.</returns>
        private double Difference(LockBitmap lockBitmap, int x1, int y1, int x2, int y2)
        {
            double diffR = Math.Pow((int)lockBitmap.GetPixel(x1, y1).R - lockBitmap.GetPixel(x2, y2).R, 2);
            double diffG = Math.Pow((int)lockBitmap.GetPixel(x1, y1).G - lockBitmap.GetPixel(x2, y2).G, 2);
            double diffB = Math.Pow((int)lockBitmap.GetPixel(x1, y1).B - lockBitmap.GetPixel(x2, y2).B, 2);

            return(Math.Sqrt(diffR + diffG + diffB));
        }
Пример #3
0
        /// <summary>
        /// Осуществляет размытие данного изображения.
        /// </summary>
        /// <param name="inputImage">Изображение, которое будет размыто.</param>
        /// <returns>Размытое изображение.</returns>
        public LockBitmap SmoothImage(LockBitmap inputImage)
        {
            double[] mask = CreateConvolutionVector();
            NormalizeVector(mask);
            //дважды применяем маску, чтобы осуществить размытие как по горизонтали, так и по вертикали
            LockBitmap smoothedImage = ApplyMask(inputImage, mask);

            smoothedImage = ApplyMask(smoothedImage, mask);

            return(smoothedImage);
        }
Пример #4
0
        /// <summary>
        /// Строит граф, в котором ребра соединяют все соседние пиксели (в том числе и по диагонали).
        /// </summary>
        /// <param name="lockBitmap">Изображение, для которого строится граф.</param>
        /// <param name="count">Число ребер в выходном массиве ребер.</param>
        /// <returns>Массив ребер графа.</returns>
        private Edge[] BuildGraph(LockBitmap lockBitmap, out int count)
        {
            lockBitmap.LockBits();

            int width  = lockBitmap.Width - 1;
            int height = lockBitmap.Height - 1;

            //от каждого пикселя строится 4 ребра: вправо, вниз, вправо-вниз, вправо-вверх.
            Edge[] edges = new Edge[width * height * 4];
            count = 0;

            for (int y = 0; y < height; y++)
            {
                int YtimesWidth = y * width; //вершины нумеруются построчно
                for (int x = 0; x < width; x++)
                {
                    if (x < width - 1)
                    {
                        edges[count].A = YtimesWidth + x;
                        edges[count].B = YtimesWidth + (x + 1);
                        edges[count].W = Difference(lockBitmap, x, y, x + 1, y);
                        count++;
                    }

                    if (y < width - 1)
                    {
                        edges[count].A = YtimesWidth + x;
                        edges[count].B = YtimesWidth + width + x;
                        edges[count].W = Difference(lockBitmap, x, y, x, y + 1);
                        count++;
                    }

                    if (x < width - 1 && y < height - 1)
                    {
                        edges[count].A = YtimesWidth + x;
                        edges[count].B = YtimesWidth + width + (x + 1);
                        edges[count].W = Difference(lockBitmap, x, y, x + 1, y + 1);
                        count++;
                    }

                    if (x < width - 1 && y > 0)
                    {
                        edges[count].A = YtimesWidth + x;
                        edges[count].B = YtimesWidth - width + x + 1;
                        edges[count].W = Difference(lockBitmap, x, y, x + 1, y - 1);
                        count++;
                    }
                }
            }

            lockBitmap.UnlockBits();

            return(edges);
        }
Пример #5
0
        /// <summary>
        /// Применяет вектор скручивания к исходному изображению и на его основе формирует новое изображение.
        /// </summary>
        /// <param name="inputBitmap">Исходное изображение.</param>
        /// <param name="mask">Вектор скручивания.</param>
        /// <returns>Новое повернутое изображение, созданное на основе исходного с примененим вектора скручивания.</returns>
        private LockBitmap ApplyMask(LockBitmap inputBitmap, double[] mask)
        {
            inputBitmap.LockBits();

            Bitmap     outputBitmap = new Bitmap(inputBitmap.Height, inputBitmap.Width);
            LockBitmap lockBitmap   = new LockBitmap(outputBitmap);

            lockBitmap.LockBits();

            //проходим строчку за строчкой, для каждого элемента вычисляя определенную сумму
            for (int y = 0; y < inputBitmap.Height; y++)
            {
                for (int x = 0; x < inputBitmap.Width; x++)
                {
                    Color  color = inputBitmap.GetPixel(x, y);
                    double sumR  = mask[0] * color.R;
                    double sumG  = mask[0] * color.G;
                    double sumB  = mask[0] * color.B;

                    for (int i = 1; i < mask.Length; i++)
                    {
                        //просмотр соседних пикселей на расстоянии i от заданного координатам (x,y)
                        Color leftColor  = inputBitmap.GetPixel(Math.Max(x - i, 0), y);
                        Color rightColor = inputBitmap.GetPixel(Math.Min(x + i, inputBitmap.Width - 1), y);
                        sumR += mask[i] * (leftColor.R + rightColor.R);
                        sumG += mask[i] * (leftColor.G + rightColor.G);
                        sumB += mask[i] * (leftColor.B + rightColor.B);
                    }
                    lockBitmap.SetPixel(y, x, Color.FromArgb((int)sumR, (int)sumG, (int)sumB));
                }
            }

            lockBitmap.UnlockBits();
            inputBitmap.UnlockBits();

            return(lockBitmap);
        }
Пример #6
0
        /// <summary>
        /// Раскрашивает изображение.
        /// </summary>
        /// <param name="lockBitmap">Изображение, которое будет раскрашено.</param>
        /// <param name="disjointSet">Система непересекающихся множеств, описывающая сегменты.</param>
        /// <returns>Массив, в котором каждому пикселю поставлен в соответствие представитель множества, которому он принадлежит.</returns>
        private int[] Colorize(LockBitmap lockBitmap, DisjointSet disjointSet)
        {
            lockBitmap.LockBits();
            int width  = lockBitmap.Width;
            int height = lockBitmap.Height;

            int[] segmentOut = new int[width * height]; //массив представителей для каждого пикселя (обход - построчно)


            //создадим массив случайных цветов для каждого пикселя
            //но на практике понадобятся не все цвета, а только цвет представителя каждого сегмента
            Random random = new Random();

            Color[] colors = new Color[width * height];
            for (int i = 0; i < colors.Length; i++)
            {
                colors[i] = Color.FromArgb(random.Next(0, 256), random.Next(0, 256), random.Next(0, 256));
            }

            int temp;

            for (int y = 0; y < height - 1; y++)
            {
                int YtimesWidth = y * (width - 1);
                temp = y;
                for (int x = 0; x < width - 1; x++)
                {
                    int parent = disjointSet.Find(YtimesWidth + x);
                    lockBitmap.SetPixel(x, y, colors[parent]);
                    segmentOut[temp] = parent;
                    temp            += height;
                }
            }

            lockBitmap.UnlockBits();
            return(segmentOut);
        }