/// <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); }
/// <summary> /// Строит на основе графа лес минимальных остовных деревьев, каждое из которых представляет сегмент изображения. /// </summary> /// <param name="edges">Набор ребер, представляющих исходный граф.</param> /// <param name="edgesCount">Число ребер в графе.</param> /// <param name="numVerticies">Число вершин в графе.</param> /// <returns>Система непересекающихся множеств, каждое из которых представляет собой сегмент изображения.</returns> private DisjointSet SegmentGraph(Edge[] edges, int edgesCount, int numVerticies) { QuickSort(edges, 0, edgesCount - 1); DisjointSet disjointSet = new DisjointSet(numVerticies); //значение пороговой функции изначально дано для каждой вершины double[] thresholdValues = new double[numVerticies]; for (int i = 0; i < numVerticies; i++) { thresholdValues[i] = ThresholdFunction(1); } for (int i = 0; i < edgesCount; i++) { //найти представителей сегментов, которые соединяются этим ребром int a = disjointSet.Find(edges[i].A); int b = disjointSet.Find(edges[i].B); if (a != b) { if (edges[i].W <= thresholdValues[a] && edges[i].W <= thresholdValues[b]) { disjointSet.Joint(a, b); a = disjointSet.Find(a); thresholdValues[a] = edges[i].W + ThresholdFunction(disjointSet.Size(a)); } } } return(disjointSet); }
/// <summary> /// Объединяет маленькие сегменты. /// </summary> /// <param name="disjointSet">Система непересекающихся множеств, представляющая сегменты.</param> /// <param name="edges">Массив всех ребер изображения.</param> /// <param name="count">Число всех ребер изображения.</param> private void JointSmallSegments(DisjointSet disjointSet, Edge[] edges, int edgesCount) { for (int i = 0; i < edgesCount; i++) { int a = disjointSet.Find(edges[i].A); int b = disjointSet.Find(edges[i].B); if (a != b && (disjointSet.Size(a) < MinSize || disjointSet.Size(b) < MinSize)) { disjointSet.Joint(a, b); } } }
/// <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); }