// Вычисление параметров объекта, которые будут // использованы для последующей его класстеризации. private ObjectParameters сalculateParameters(BitmapIntMatrix ba, List <Point> objectPoints) { ObjectParameters parameters = new ObjectParameters(); parameters.Square = objectPoints.Count; int blackColor = unchecked ((int)(0xFF000000)); foreach (Point objectPoint in objectPoints) { int x = objectPoint.X, y = objectPoint.Y; int top = ba[x, y + 1], bottom = ba[x, y - 1], right = ba[x + 1, y], left = ba[x - 1, y]; // Если есть чёрный сосед-4 if (top == blackColor || bottom == blackColor || right == blackColor || left == blackColor) { parameters.Perimeter++; } parameters.Xmas += x; parameters.Ymas += y; } parameters.Xmas /= parameters.Square; parameters.Ymas /= parameters.Square; foreach (Point objectPoint in objectPoints) { int x = objectPoint.X, y = objectPoint.Y; parameters.m02 += Math.Pow((y - parameters.Ymas), 2); parameters.m20 += Math.Pow((x - parameters.Xmas), 2); parameters.m11 += (x - parameters.Xmas) * (y - parameters.Ymas); } parameters.Compactness = Math.Pow((parameters.Perimeter), 2) / parameters.Square; double a1 = parameters.m20 + parameters.m02; double a2 = Math.Sqrt( Math.Pow((parameters.m20 - parameters.m02), 2) + 4 * Math.Pow(parameters.m11, 2) ); if ((a1 - a2) != 0) { parameters.Elongation = (a1 + a2) / (a1 - a2); } else { parameters.Elongation = 1; } return(parameters); }
// Int32 min-фильтр, анализирующий 32-разрядное значение содержания пикселя public static Image MinFilterInt(Image img, byte coreRank) { if (coreRank < 3 || coreRank % 2 == 0) { MessageBox.Show("Недопустимое значение размерности ядра фильтра: значение не может быть меньше 3, или чётным числом."); return(img); } BitmapIntMatrix bimOriginal = new BitmapIntMatrix(img); BitmapIntMatrix bimResult = new BitmapIntMatrix(img.Width, img.Height); for (int x = 0; x < img.Width; ++x) { int start_x_area = x - coreRank / 2, end_x_area = x + coreRank / 2; if (start_x_area < 0) { start_x_area = 0; } if (end_x_area >= img.Width) { end_x_area = img.Width; } for (int y = 0; y < img.Height; ++y) { int start_y_area = y - coreRank / 2, end_y_area = y + coreRank / 2; if (start_y_area < 0) { start_y_area = 0; } if (end_y_area >= img.Height) { end_y_area = img.Height; } int[] area = new int[(end_x_area - start_x_area + 1) * (end_y_area - start_y_area + 1)]; int counter = 0; // Сбор значений из области, покрываемой ядром for (int x_m = start_x_area; x_m < end_x_area; ++x_m) { for (int y_m = start_y_area; y_m < end_y_area; ++y_m) { area[counter] = bimOriginal[x_m, y_m]; ++counter; } } // Выбор наименьшего из найденных значений int min = int.MaxValue; for (int i = 0; i < area.Length; ++i) { if (area[i] < min) { min = area[i]; } } bimResult[x, y] = min; } } return(bimResult.getImage()); }
// Разметка отдельных доменов уникальными численными значениями и // формирование массивов, состоящих из непересекающихся множеств пикселей. private BitmapIntMatrix differentiationOfConnectedDomains(Image img) { this.domainsMap = new BitmapIntMatrix(img); int blackColor = unchecked ((int)(0xFF000000)); int whiteColor = unchecked ((int)(0xFFFFFFFF)); for (int i = 0; i < domainsMap.Width; ++i) { domainsMap[i, 0] = blackColor; domainsMap[i, domainsMap.Height - 1] = blackColor; } for (int j = 0; j < domainsMap.Height; ++j) { domainsMap[0, j] = blackColor; domainsMap[domainsMap.Width - 1, j] = blackColor; } // Переменная отметки сплошной залитой области (объекта) int domainMarkCounter = 0; // Списки групп объектов, состоящих в соседстве-4 List <List <int> > groupsNeighbors = new List <List <int> >(); // Построчный проход заливки слева направо, сверху вниз for (int y = 1; y < domainsMap.Height; ++y) { for (int x = 1; x < domainsMap.Width; ++x) { int target = domainsMap[x, y], top = domainsMap[x, y - 1], left = domainsMap[x - 1, y]; if (target != blackColor) { if (left != blackColor) { domainsMap[x, y] = left; if (!domainsPixelTable.ContainsKey(left)) { domainsPixelTable[left] = new List <Point>(); } domainsPixelTable[left].Add(new Point(x, y)); // Если верхний и левый отличны от чёрного и не равны if ((top != left) && (top != blackColor)) { int leftGroupIndex = -1; int topGroupIndex = -1; // Поиск групп, которым принадлежат объекты for (int i = 0; i < groupsNeighbors.Count; ++i) { if (groupsNeighbors[i].Contains(left)) { leftGroupIndex = i; } if (groupsNeighbors[i].Contains(top)) { topGroupIndex = i; } // Если обе группы найдены if ((leftGroupIndex != -1) && (topGroupIndex != -1)) { break; } } // Если таких групп нет, то нужно создать новую группу if ((leftGroupIndex == -1) && (topGroupIndex == -1)) { groupsNeighbors.Add(new List <int> { left, top }); } // Если они в одной группе else if (leftGroupIndex == topGroupIndex) { continue; } // Если нет группы левого объекта, то добавить его в группу верхнего else if (leftGroupIndex == -1) { groupsNeighbors[topGroupIndex].Add(left); } // Если нет группы верхнего объекта, то добавить его в группу левого else if (topGroupIndex == -1) { groupsNeighbors[leftGroupIndex].Add(top); } // Если если они принадлежат двум разным группам, то необходимо объединить их else { groupsNeighbors[topGroupIndex].AddRange(groupsNeighbors[leftGroupIndex]); groupsNeighbors.RemoveAt(leftGroupIndex); } } } else if (top != blackColor) { domainsMap[x, y] = top; if (!domainsPixelTable.ContainsKey(top)) { domainsPixelTable[top] = new List <Point>(); } domainsPixelTable[top].Add(new Point(x, y)); } else if (target == whiteColor) { if (++domainMarkCounter == blackColor) { ++domainMarkCounter; } domainsMap[x, y] = domainMarkCounter; domainsPixelTable[domainMarkCounter] = new List <Point>(); domainsPixelTable[domainMarkCounter].Add(new Point(x, y)); // Если предворительный счётчик объектов достиг предельного значения UInt32 if (domainMarkCounter == int.MaxValue) { throw new Exception("Переполнение счётчика числа объектов на изображении."); } } } } } // Если есть группы объектов, состоящих в соседстве-4, // то необходимо произвести их слияние if (groupsNeighbors.Count > 0) { foreach (List <int> groupNeighbors in groupsNeighbors) { do { int lastNeighbor = groupNeighbors.Last(); domainsPixelTable[groupNeighbors[0]].AddRange(domainsPixelTable[lastNeighbor]); domainsPixelTable.Remove(lastNeighbor); groupNeighbors.Remove(lastNeighbor); }while (groupNeighbors.Count > 1); // Перекрашивание карты объектов foreach (Point pixel in domainsPixelTable[groupNeighbors[0]]) { domainsMap[pixel.X, pixel.Y] = groupNeighbors[0]; } groupNeighbors.Clear(); } } MessageBox.Show(domainsPixelTable.Count.ToString()); return(domainsMap); }