namespace ZeroLevel.NN.Clusterization { public class FeatureClusterBulder { public FeatureClusterCollection Build(IEnumerable faces, Func vectorExtractor, Func similarityFunction, float threshold, float clusterThreshold = 0.5f) { var collection = new FeatureClusterCollection(); foreach (var face in faces) { bool isAdded = false; foreach (var cluster in collection.Clusters) { if (cluster.Value.IsNeighbor(face, similarityFunction, threshold, clusterThreshold)) { cluster.Value.Append(face); isAdded = true; break; } } if (false == isAdded) { var cluster = new FeatureCluster(vectorExtractor); cluster.Append(face); collection.Add(cluster); } } MergeClusters(collection, similarityFunction, threshold, clusterThreshold); return collection; } private void MergeClusters(FeatureClusterCollection collection, Func similarityFunction, float threshold, float clusterThreshold = 0.5f) { int lastCount = collection.Clusters.Count; var removed = new Queue(); do { var ids = collection.Clusters.Keys.ToList(); for (var i = 0; i < ids.Count - 1; i++) { for (var j = i + 1; j < ids.Count; j++) { var c1 = collection.Clusters[ids[i]]; var c2 = collection.Clusters[ids[j]]; if (c1.IsNeighborCluster(c2, similarityFunction, threshold, clusterThreshold)) { c1.Merge(c2); removed.Enqueue(ids[j]); ids.RemoveAt(j); j--; } } } while (removed.Count > 0) { collection.Clusters.Remove(removed.Dequeue()); } if (lastCount == collection.Clusters.Count) { break; } lastCount = collection.Clusters.Count; } while (true); } } }