/// <summary> /// Merges spectral values to clusters. /// </summary> private void MergeValuesToClusters() { Int32 minimalIndex = 0; for (Int32 rowIndex = 0; rowIndex < Source.Raster.NumberOfRows; rowIndex++) { for (Int32 columnIndex = 0; columnIndex < Source.Raster.NumberOfColumns; columnIndex++) { switch (Source.Raster.Format) { case RasterFormat.Integer: UInt32[] values = Source.Raster.GetValues(rowIndex, columnIndex); minimalIndex = _clusterCenters.MinIndex(center => _distance.Distance(center, values)); break; case RasterFormat.Floating: Double[] floatValues = Source.Raster.GetFloatValues(rowIndex, columnIndex); minimalIndex = _clusterCenters.MinIndex(center => _distance.Distance(center, floatValues)); break; } if (_clusters[minimalIndex] == null) _clusters[minimalIndex] = ResultSegments.GetSegment(rowIndex, columnIndex); else ResultSegments.MergeSegments(_clusters[minimalIndex], rowIndex, columnIndex); } } }
/// <summary> /// Merges segments to clusters. /// </summary> private void MergeSegmentsToClusters() { Segment[] clusters = new Segment[_numberOfClusters]; Int32 minimalIndex = 0; List <Segment> segments = ResultSegments.GetSegments().ToList(); foreach (Segment segment in segments) { if (!ResultSegments.Contains(segment)) { continue; } minimalIndex = _clusterCenters.MinIndex(center => _distance.Distance(segment, center)); if (clusters[minimalIndex] == null) { clusters[minimalIndex] = segment; } else { clusters[minimalIndex] = ResultSegments.MergeSegments(clusters[minimalIndex], segment); } } }
/// <summary> /// Computes the result of the operation. /// </summary> protected override void ComputeResult() { Boolean hasMerged = true; Double[] distances = new Double[4]; for (Int32 iterationIndex = 0; iterationIndex < _numberOfIterations && hasMerged; iterationIndex++) { hasMerged = false; for (Int32 rowIndex = 0; rowIndex < Source.Raster.NumberOfRows; rowIndex++) { for (Int32 columnIndex = 0; columnIndex < Source.Raster.NumberOfColumns; columnIndex++) { // select best merge direction distances[0] = ComputeDistance(rowIndex, columnIndex, rowIndex, columnIndex - 1); // left distances[1] = ComputeDistance(rowIndex, columnIndex, rowIndex - 1, columnIndex); // up distances[2] = ComputeDistance(rowIndex, columnIndex, rowIndex, columnIndex + 1); // right distances[3] = ComputeDistance(rowIndex, columnIndex, rowIndex + 1, columnIndex); // down Double minDistance = distances.Min(); if (minDistance >= _mergeThreshold) { continue; } // apply merge switch ((SegmentMergeDirection)Array.IndexOf(distances, minDistance)) { case SegmentMergeDirection.Left: ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex, columnIndex - 1); break; case SegmentMergeDirection.Up: ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex - 1, columnIndex); break; case SegmentMergeDirection.Right: ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex, columnIndex + 1); break; case SegmentMergeDirection.Down: ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex + 1, columnIndex); break; } hasMerged = true; } } } }
/// <summary> /// Computes the result of the operation. /// </summary> protected override void ComputeResult() { // source: Felzenszwalb, Huttenlocher: Efficient Graph-Based Image Segmentation List <SimpleGraphEdge> edges = GenerateEdgeList(); _innerDiffences = new Dictionary <Segment, Single>(); // remove the edges and merge segments while (edges.Count > 0) { SimpleGraphEdge edge = edges[edges.Count - 1]; edges.RemoveAt(edges.Count - 1); Segment firstSegment = ResultSegments[edge.Source / Source.Raster.NumberOfColumns, edge.Source % Source.Raster.NumberOfColumns]; Segment secondSegment = ResultSegments[edge.Destination / Source.Raster.NumberOfColumns, edge.Destination % Source.Raster.NumberOfColumns]; // if the two indices are already within the same segment if (firstSegment == secondSegment) { continue; } Double internalDifference = ComputeMaximumInternalDifference(firstSegment, secondSegment); // if the weight of the edge does not influence the internal difference if (internalDifference > edge.Weight) { // the segments should be merged Segment mergedSegment = ResultSegments.MergeSegments(firstSegment, secondSegment); Segment otherSegment = mergedSegment == firstSegment ? firstSegment : secondSegment; // modify internal difference Single weight = edge.Weight; if (_innerDiffences.ContainsKey(otherSegment)) { weight = Math.Max(_innerDiffences[otherSegment], edge.Weight); _innerDiffences.Remove(otherSegment); } if (!_innerDiffences.ContainsKey(mergedSegment)) { _innerDiffences.Add(mergedSegment, (Single)edge.Weight); } else { _innerDiffences[mergedSegment] = Math.Max(_innerDiffences[mergedSegment], weight); } } } }
/// <summary> /// Merges segments to clusters. /// </summary> private void MergeSegmentsToClusters() { Int32 minimalIndex = 0; List<Segment> segments = ResultSegments.GetSegments().ToList(); foreach (Segment segment in segments) { if (!ResultSegments.Contains(segment)) continue; minimalIndex = _clusterCenters.MinIndex(center => _distance.Distance(segment, center)); if (_clusters[minimalIndex] == null) _clusters[minimalIndex] = segment; else _clusters[minimalIndex] = ResultSegments.MergeSegments(_clusters[minimalIndex], segment); } }
/// <summary> /// Merges the clusters. /// </summary> private void MergeClusters() { HashSet <Segment> segmentsToCheck = new HashSet <Segment>(ResultSegments.GetSegments()); do { List <Segment> allSegments = ResultSegments.GetSegments().ToList(); HashSet <Segment> nextSegmentsToCheck = new HashSet <Segment>(); foreach (Segment currentSegment in segmentsToCheck) { for (Int32 index = 0; index < allSegments.Count; index++) { if (allSegments[index] == currentSegment || !ResultSegments.Contains(allSegments[index]) || !ResultSegments.Contains(currentSegment)) { continue; } Double distance = _clusterCenterDistance.Distance(currentSegment, allSegments[index]); if (distance < _clusterDistanceThreshold) { Segment mergedSegment = ResultSegments.MergeSegments(currentSegment, allSegments[index]); if (mergedSegment == currentSegment) { allSegments.RemoveAt(index); } else { allSegments.Remove(currentSegment); } nextSegmentsToCheck.Add(mergedSegment); } } } segmentsToCheck = nextSegmentsToCheck; } while (segmentsToCheck.Count > 0); }
/// <summary> /// Computes the result of the operation. /// </summary> protected override void ComputeResult() { for (Int32 rowIndex = 0; rowIndex < Source.Raster.NumberOfRows; rowIndex += 2) { // initialize the segments of the next rows with 2x2 sized segments for (Int32 columnIndex = 0; columnIndex < Source.Raster.NumberOfColumns; columnIndex += 2) { if (columnIndex < Source.Raster.NumberOfColumns - 1) { ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex, columnIndex + 1); } if (rowIndex < Source.Raster.NumberOfRows - 1) { ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex + 1, columnIndex); if (columnIndex < Source.Raster.NumberOfColumns - 1) { ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex + 1, columnIndex + 1); } } } // connect segments for (Int32 columnIndex = 0; columnIndex < Source.Raster.NumberOfColumns; columnIndex += 2) { SegmentMergeDirection direction = SegmentMergeDirection.None; Double currentDistance = Double.MaxValue; Segment currentSegment = ResultSegments[rowIndex, columnIndex]; // only connect if the cell is homogeneous if (currentSegment.IsHomogeneous(_segmentHomogeneityThreshold)) { // select the best merge direction based on the ANOVA criteria and the euclidean distance // left if (CanMergeSegments(currentSegment, rowIndex, columnIndex - 2)) { currentDistance = _distance.Distance(currentSegment, ResultSegments[rowIndex, columnIndex - 2]); direction = SegmentMergeDirection.Left; } // up if (CanMergeSegments(currentSegment, rowIndex - 2, columnIndex)) { Double distance = _distance.Distance(currentSegment, ResultSegments[rowIndex - 2, columnIndex]); if (distance < currentDistance) { direction = SegmentMergeDirection.Up; } } // right 1 if (CanMergeSegments(rowIndex - 2, columnIndex + 2, rowIndex, columnIndex + 2)) { Segment mergedSegment = ResultSegments.MergeSegments(ResultSegments[rowIndex - 2, columnIndex + 2], ResultSegments[rowIndex, columnIndex + 2]); if (CanMergeSegments(mergedSegment, currentSegment)) { Double distance = _distance.Distance(mergedSegment, currentSegment); if (distance < currentDistance) { direction = SegmentMergeDirection.Right1; } } } // right 2 /*if (direction == SegmentMergeDirection.Right1 && CanMergeSegments(rowIndex - 2, columnIndex + 4, rowIndex, columnIndex + 4)) * { * Segment upperSegment = Result[rowIndex - 2, columnIndex + 4]; * Segment lowerSegment = Result[rowIndex, columnIndex + 4]; * Segment mergedSegment = upperSegment + lowerSegment; * * if (CanMergeSegments(mergedSegment, currentSegment)) * { * Double distance = SpectralDistances.EuclideanDistance(mergedSegment, currentSegment); * if (distance < currentDistance) * direction = SegmentMergeDirection.Right2; * } * }*/ // apply merge switch (direction) { case SegmentMergeDirection.Left: ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex, columnIndex - 2); break; case SegmentMergeDirection.Up: ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex - 2, columnIndex); break; case SegmentMergeDirection.Right1: ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex, columnIndex + 2); ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex - 2, columnIndex + 2); break; case SegmentMergeDirection.Right2: ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex, columnIndex + 2); ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex - 2, columnIndex + 2); ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex, columnIndex + 4); ResultSegments.MergeSegments(rowIndex, columnIndex, rowIndex - 2, columnIndex + 4); break; } } } } // remove original segments that are not homogeneous for (Int32 rowIndex = 0; rowIndex < Source.Raster.NumberOfRows; rowIndex += 2) { for (Int32 columnIndex = 0; columnIndex < Source.Raster.NumberOfColumns; columnIndex += 2) { if (ResultSegments[rowIndex, columnIndex].Count <= 4 && !ResultSegments[rowIndex, columnIndex].IsHomogeneous(_segmentHomogeneityThreshold)) { ResultSegments.SplitSegment(rowIndex, columnIndex); } } } }