private void CreateRib(int x1, int y1, int x2, int y2, byte[,] r, byte[,] g, byte[,] b, Versh[,] v2d, List <Rib> list) { double dist = Math.Sqrt(Math.Pow((x1 - x2), 2) + Math.Pow((y1 - y2), 2) + Math.Pow((r[x1, y1] - r[x2, y2]), 2) + Math.Pow((g[x1, y1] - g[x2, y2]), 2) + Math.Pow((b[x1, y1] - b[x2, y2]), 2)); Rib rib = new Rib(v2d[x1, y1], v2d[x2, y2], dist); ribs.Add(rib); list.Add(rib); }
// очень умная шикарная штука, но она осложнила программу и добавила неточностей( private void MergeSegments() { //теперь объединяем уже существующие сегменты по какой-то хитрой формуле - МАГИЯ double ksegm = 2; for (int k = 0; k < ribs.Count; k++) { Rib r = ribs[k]; //если у них один корень, то они уже в одном сегменте - тогда их не надо соединять снова if (r._firstV.Root == r._secondV.Root) { continue; } //если же они в разных сегментах, то мы должны оценить, должны ли мы соединять сегменты //одинокий пиксель - сегмент из одной вершины //поправка от количества пикселей double t1 = ksegm / r._firstV.VershCount; double t2 = ksegm / r._secondV.VershCount; //перепады внутри сегментов с поправкой от количества пикселей внутри сегмента double m1 = r._firstV.MaxDist + t1; double m2 = r._secondV.MaxDist + t2; //меньшая из больших дистанций внутри сегментов, с поправкой (та которая с количеством пикселей) double minMax = Math.Min(m1, m2); if (r._dist < minMax) { r._firstV.MergeSegment(r._secondV); Versh root = r._firstV.Root; //после объединения ищем новый наибольший перепад //т.к. рёбра упорядочены по возрастанию веса, а мы идём с конца - первое попавшееся ребро из нашего сегмента будет самым большим GetMaxDist(root); } } }
// проходим второй раз либо по всем рёбрам, лбо по маленьким (реализовано два варианта) private void RemoveSmallSegments() { int[,] rebr = { { 0, 1 }, { 1, 0 } }; for (int x = 0, limitX = _height - 1; x < limitX; x++) { for (int y = 0, limitY = _width - 1; y < limitY; y++) { for (int i = 0; i < 2; i++) { int positionX = x + rebr[i, 0]; int positionY = y + rebr[i, 1]; //тут мы знаем, что следующий пиксель существует, потому что границы в цикле ширина-3, высота-3 CreateRib(x, y, positionX, positionY, r, g, b, v2d, smallRibs); } } for (int y = _width - 1; y < _width; y++) { for (int i = 0; i < 2; i++) { int positionX = x + rebr[i, 0]; int positionY = y + rebr[i, 1]; // если следующий пиксел не существует if ((positionX >= _height) || (positionY >= _width)) { continue; } CreateRib(x, y, positionX, positionY, r, g, b, v2d, smallRibs); } } } for (int x = _height - 1; x < _height; x++) { for (int y = 0; y < _width; y++) { for (int i = 0; i < 2; i++) { int positionX = x + rebr[i, 0]; int positionY = y + rebr[i, 1]; // если следующий пиксел не существует if ((positionX >= _height) || (positionY >= _width)) { continue; } CreateRib(x, y, positionX, positionY, r, g, b, v2d, smallRibs); } } } int minSize = (_height + _width) / segmSize; for (int k = 0, ribCount = ribs.Count; k < ribCount; k++) // для всех рёбер // for (int k = 0, ribCount = smallRibs.Count; k < ribCount; k++) // для маленьких рёбер { Rib r = ribs[k]; // для всех рёбер // Rib r = smallRibs[k]; // для маленьких рёбер //если у них один корень, то они уже в одном сегменте - тогда их не надо соединять снова if (r._firstV.Root == r._secondV.Root) { continue; } //если вершины в разных сегментах, и вес ребра меньше лимита - соединяем сегменты if (r._secondV.Root.VershCount < minSize) { r._firstV.MergeSegment(r._secondV); } else if (r._firstV.Root.VershCount < minSize) { r._secondV.MergeSegment(r._firstV); } } }
public Bitmap Segment() { int[,] maxSize = new int[_height * _width, 2]; // соединяем по пикселям for (int k = 0, ribCount = ribs.Count /*так он один раз вычислит и не будет делать это на каждом шаге*/; k < ribCount; k++) { Rib r = ribs[k]; if (r._dist > limit) { break; } //если у них один корень, то они уже в одном сегменте - тогда их не надо соединять снова if (r._firstV.Root == r._secondV.Root) { continue; } //если же они в разных сегментах, то мы должны оценить, должны ли мы соединять сегменты. //Одинокий пиксель - сегмент из одной вершины //если вершины в разных сегментах, и вес ребра меньше лимита - соединяем сегменты if (r._dist < limit) { r._firstV.MergeSegment(r._secondV); } } //для каждого сегмента ищем самое большое ребро внутри него (идём от больших к меньшим, т.к. ищем больший) for (int k = ribs.Count - 1; k >= 0; k--) { if (ribs[k]._firstV.Root == ribs[k]._secondV.Root && ribs[k]._firstV.MaxDist < ribs[k]._dist) { ribs[k]._firstV.MaxDist = ribs[k]._dist; } } // Вторая проверка, уже с образовавшимися сегментами RemoveSmallSegments(); // MergeSegments(); /////////////////////////////////////////////////////////////////////////////// // Красим сегменты в зависимости от цвета корней byte[] mimimi = new byte[_photo.Length]; int index = 0; for (int i = 0; i < _height; i++) { for (int j = 0; j < _width; j++) { mimimi[index++] = v2d[i, j].Root._r; mimimi[index++] = v2d[i, j].Root._g; mimimi[index++] = v2d[i, j].Root._b; } } Bitmap end = Filters.GetBitmap(mimimi, _width, _height); ////////////////////////////////////////////////////////////////////// //end = Filters.GrayImage(end); //Bitmap zyuzyu = Filters.GetBitmap(_foto, _width, _height); //Application.Run(new Form1(zyuzyu, zyu)); return(end); //new Form1(zyuzyu, end).Show(); }