private IBagOfWords <Bitmap> CreateBow() { var binarySplit = new BinarySplit(10); var surfBow = BagOfVisualWords.Create(10); return(surfBow.Learn(Images.ToArray())); }
private static void CreateBoW() { var numberOfWords = 36; foreach (var file in Directory.EnumerateFiles(@"C:\Temp\TLLCamerasTestData\37_Training", "*.jpg")) { var trainingImage = (Bitmap)Bitmap.FromFile(file); trainingImages.Add(file, trainingImage); } foreach (var file in Directory.EnumerateFiles(@"C:\Temp\TLLCamerasTestData\37_Testing", "*.jpg")) { var testImage = (Bitmap)Bitmap.FromFile(file); testingImages.Add(file, testImage); } // We will use SURF, so we can use a standard clustering // algorithm that is based on Euclidean distances. A good // algorithm for clustering codewords is the Binary Split // variant of the K-Means algorithm. // Create a Binary-Split clustering algorithm BinarySplit binarySplit = new BinarySplit(numberOfWords); // Create bag-of-words (BoW) with the given algorithm BagOfVisualWords surfBow = new BagOfVisualWords(binarySplit); // Compute the BoW codebook using training images only IBagOfWords <Bitmap> bow = surfBow.Learn(trainingImages.Values.ToArray()); // now that we've created the bow we need to use it to create a representation of each training and test image foreach (var trainingImage in trainingImages.Keys) { var asBitmap = trainingImages[trainingImage] as Bitmap; var featureVector = (bow as ITransform <Bitmap, double[]>).Transform(asBitmap); var featureString = featureVector.ToString(DefaultArrayFormatProvider.InvariantCulture); trainingFeatures.Add(trainingImage, featureVector); } foreach (var testingImage in testingImages.Keys) { var asBitmap = testingImages[testingImage] as Bitmap; var featureVector = (bow as ITransform <Bitmap, double[]>).Transform(asBitmap); var featureString = featureVector.ToString(DefaultArrayFormatProvider.InvariantCulture); testingFeatures.Add(testingImage, featureVector); } }
public void BinarySplitConstructorTest3() { // Create a new algorithm BinarySplit binarySplit = new BinarySplit(3); Assert.IsNotNull(binarySplit.Clusters); Assert.IsNotNull(binarySplit.Distance); Assert.IsNotNull(binarySplit.Clusters.Centroids); Assert.IsNotNull(binarySplit.Clusters.Count); Assert.IsNotNull(binarySplit.Clusters.Covariances); Assert.IsNotNull(binarySplit.Clusters.Proportions); }
public void BinarySplitConstructorTest() { Accord.Math.Random.Generator.Seed = 0; // Declare some observations double[][] observations = { new double[] { -5, -2, -1 }, new double[] { -5, -5, -6 }, new double[] { 2, 1, 1 }, new double[] { 1, 1, 2 }, new double[] { 1, 2, 2 }, new double[] { 3, 1, 2 }, new double[] { 11, 5, 4 }, new double[] { 15, 5, 6 }, new double[] { 10, 5, 6 }, }; double[][] orig = observations.MemberwiseClone(); // Create a new binary split with 3 clusters BinarySplit binarySplit = new BinarySplit(3); // Compute the algorithm, retrieving an integer array // containing the labels for each of the observations int[] labels = binarySplit.Compute(observations); // As a result, the first two observations should belong to the // same cluster (thus having the same label). The same should // happen to the next four observations and to the last three. Assert.AreEqual(labels[0], labels[1]); Assert.AreEqual(labels[2], labels[3]); Assert.AreEqual(labels[2], labels[4]); Assert.AreEqual(labels[2], labels[5]); Assert.AreEqual(labels[6], labels[7]); Assert.AreEqual(labels[6], labels[8]); Assert.AreNotEqual(labels[0], labels[2]); Assert.AreNotEqual(labels[2], labels[6]); Assert.AreNotEqual(labels[0], labels[6]); int[] labels2 = binarySplit.Clusters.Nearest(observations); Assert.IsTrue(labels.IsEqual(labels2)); // the data must not have changed! Assert.IsTrue(orig.IsEqual(observations)); }
/// <summary> /// This methods computes the Bag-of-Visual-Words with the training images. /// </summary> /// private void btnBagOfWords_Click(object sender, EventArgs e) { int numberOfWords = (int)numWords.Value; // Create a Binary-Split clustering algorithm BinarySplit binarySplit = new BinarySplit(numberOfWords); // Create bag-of-words (BoW) with the given algorithm BagOfVisualWords bow = new BagOfVisualWords(binarySplit); if (cbExtended.Checked) { bow.Detector.ComputeDescriptors = SpeededUpRobustFeatureDescriptorType.Extended; } Stopwatch sw1 = Stopwatch.StartNew(); // Compute the BoW codebook using training images only var points = bow.Compute(originalTrainImages.Values.ToArray()); sw1.Stop(); Stopwatch sw2 = Stopwatch.StartNew(); // Extract features for all images foreach (ListViewItem item in listView1.Items) { // Get item image Bitmap image = originalImages[item.ImageKey] as Bitmap; // Process image double[] featureVector = bow.GetFeatureVector(image); string featureString = featureVector.ToString(DefaultArrayFormatProvider.InvariantCulture); if (item.SubItems.Count == 2) { item.SubItems[1].Text = featureString; } else { item.SubItems.Add(featureString); } int classLabel = (item.Tag as Tuple <double[], int>).Item2; item.Tag = Tuple.Create(featureVector, classLabel); } sw2.Stop(); lbStatus.Text = "BoW constructed in " + sw1.Elapsed + "s. Features extracted in " + sw2.Elapsed + "s."; btnSampleRunAnalysis.Enabled = true; }
public void binary_split_new_method() { #region doc_sample1 // Use a fixed seed for reproducibility Accord.Math.Random.Generator.Seed = 0; // Declare some data to be clustered double[][] input = { new double[] { -5, -2, -1 }, new double[] { -5, -5, -6 }, new double[] { 2, 1, 1 }, new double[] { 1, 1, 2 }, new double[] { 1, 2, 2 }, new double[] { 3, 1, 2 }, new double[] { 11, 5, 4 }, new double[] { 15, 5, 6 }, new double[] { 10, 5, 6 }, }; // Create a new binary split with 3 clusters BinarySplit binarySplit = new BinarySplit(3); // Learn a data partitioning using the Binary Split algorithm KMeansClusterCollection clustering = binarySplit.Learn(input); // Predict group labels for each point int[] output = clustering.Decide(input); // As a result, the first two observations should belong to the // same cluster (thus having the same label). The same should // happen to the next four observations and to the last three. #endregion Assert.AreEqual(output[0], output[1]); Assert.AreEqual(output[2], output[3]); Assert.AreEqual(output[2], output[4]); Assert.AreEqual(output[2], output[5]); Assert.AreEqual(output[6], output[7]); Assert.AreEqual(output[6], output[8]); Assert.AreNotEqual(output[0], output[2]); Assert.AreNotEqual(output[2], output[6]); Assert.AreNotEqual(output[0], output[6]); int[] labels2 = binarySplit.Clusters.Nearest(input); Assert.IsTrue(output.IsEqual(labels2)); }
static void ImageFeatures() { Dictionary <string, Bitmap> testImages = new Dictionary <string, Bitmap>(); testImages.Add("img_acropolis", (Bitmap)Bitmap.FromFile("test_imgs/acropolis_athens.jpg")); testImages.Add("img_cathedral", (Bitmap)Bitmap.FromFile("test_imgs/amiens_cathedral.jpg")); testImages.Add("img_bigben", (Bitmap)Bitmap.FromFile("test_imgs/big_ben.jpg")); int numberOfWords = 6; // number of cluster centers: typically >>100 // Create a Binary-Split clustering algorithm BinarySplit binarySplit = new BinarySplit(numberOfWords); IBagOfWords <Bitmap> bow; // Create bag-of-words ( BoW ) with the given algorithm BagOfVisualWords surfBow = new BagOfVisualWords(binarySplit); // Compute the BoW codebook using training images only Bitmap[] bmps = new Bitmap[testImages.Count]; testImages.Values.CopyTo(bmps, 0); surfBow.Compute(bmps); bow = surfBow; // this model needs to be saved once it is calculated: only compute it once to calculate features // from the collection as well as for new queries. // THE SAME TRAINED MODEL MUST BE USED TO GET THE SAME FEATURES!!! Dictionary <string, double[]> testImageFeatures = new Dictionary <string, double[]>(); // Extract features for all images foreach (string imagename in testImages.Keys) { double[] featureVector = bow.GetFeatureVector(testImages[imagename]); testImageFeatures.Add(imagename, featureVector); Console.Out.WriteLine(imagename + " features: " + featureVector.ToString(DefaultArrayFormatProvider.InvariantCulture)); } // Calculate Image Similarities string[] imagenames = new string[testImageFeatures.Keys.Count]; testImageFeatures.Keys.CopyTo(imagenames, 0); for (int i = 0; i < imagenames.Length; i++) { for (int j = i + 1; j < imagenames.Length; j++) { double dist = Distance.Cosine(testImageFeatures[imagenames[i]], testImageFeatures[imagenames[j]]); Console.Out.WriteLine(imagenames[i] + " <-> " + imagenames[j] + " distance: " + dist.ToString()); } } }
public void LargeTest() { // Requires data from the National Data Science bowl // https://github.com/accord-net/framework/issues/58 var trainingDirectory = @"C:\Users\CésarRoberto\Downloads\train\train\"; var images = LabeledImages.FromDirectory(trainingDirectory).ToArray(); var binarySplit = new BinarySplit(32); var bow = new BagOfVisualWords(binarySplit); bow.Compute(images.Select(i => i.Item).Take(50).ToArray()); }
private void setBinaryCluster(System.IO.StreamReader sr) { BinarySplit bSplit = new BinarySplit(k); KMeansClusterCollection kmeansColl = bSplit.Clusters; for (int i = 0; i < k; i++) { double[] mns = (from s in (sr.ReadLine().Split(new char[] { ',' })) select System.Convert.ToDouble(s)).ToArray(); sr.ReadLine(); double p = System.Convert.ToDouble(sr.ReadLine()); KMeansCluster kc = new KMeansCluster(kmeansColl, i); kc.Mean = mns; kc.Proportion = p; } clusterCollection = kmeansColl; model = bSplit; }
private static void binarySplit(double[][] inputs) { // Create a binary-split algorithm var binarySplit = new BinarySplit(k: 3) { Distance = new SquareEuclidean(), MaxIterations = 1000 }; // Use it to learn a data model var model = binarySplit.Learn(inputs); // Use the model to group new instances int[] prediction = model.Decide(inputs); // Plot the results ScatterplotBox.Show("Binary Split's answer", inputs, prediction).Hold(); }
public void buildModel() { if (inputMatrix == null) { getMatrix(); } switch (cType) { case clusterType.KMEANS: KMeans kmeans = new KMeans(k); kmeans.Compute(inputMatrix, precision); clusterCollection = kmeans.Clusters; model = kmeans; break; case clusterType.BINARY: BinarySplit bSplit = new BinarySplit(k); bSplit.Compute(inputMatrix, precision); clusterCollection = bSplit.Clusters; model = bSplit; //Console.WriteLine("BinarySplit"); break; case clusterType.GAUSSIANMIXTURE: GaussianMixtureModel gModel = new GaussianMixtureModel(k); gModel.Compute(inputMatrix, precision); clusterCollection = gModel.Gaussians; model = gModel; break; default: break; } lbl = new List <string>(); for (int i = 0; i < k; i++) { lbl.Add(i.ToString()); } }
/// <summary> /// This methods computes the Bag-of-Visual-Words with the training images. /// </summary> /// private void btnBagOfWords_Click(object sender, EventArgs e) { int numberOfWords = (int)numWords.Value; // Create a Binary-Split clustering algorithm BinarySplit binarySplit = new BinarySplit(numberOfWords); Stopwatch sw1 = Stopwatch.StartNew(); IBagOfWords <Bitmap> bow; if (rbSurf.Checked) { // Create bag-of-words (BoW) with the given algorithm var surfBow = new BagOfVisualWords(binarySplit); // Compute the BoW codebook using training images only surfBow.Compute(originalTrainImages.Values.ToArray()); bow = surfBow; } else { // Alternative creation using the FREAK detector // Create a Binary-Split clustering algorithm var kmodes = new KModes <byte>(numberOfWords, new Hamming()); var detector = new FastRetinaKeypointDetector(); // Create bag-of-words (BoW) with the given algorithm var freakBow = new BagOfVisualWords <FastRetinaKeypoint, byte[]>(detector, kmodes); // Compute the BoW codebook using training images only freakBow.Compute(originalTrainImages.Values.ToArray()); bow = freakBow; } sw1.Stop(); Stopwatch sw2 = Stopwatch.StartNew(); // Extract features for all images foreach (ListViewItem item in listView1.Items) { // Get item image Bitmap image = originalImages[item.ImageKey] as Bitmap; // Process image double[] featureVector = bow.GetFeatureVector(image); string featureString = featureVector.ToString(DefaultArrayFormatProvider.InvariantCulture); if (item.SubItems.Count == 2) { item.SubItems[1].Text = featureString; } else { item.SubItems.Add(featureString); } int classLabel = (item.Tag as Tuple <double[], int>).Item2; item.Tag = Tuple.Create(featureVector, classLabel); } sw2.Stop(); lbStatus.Text = "BoW constructed in " + sw1.Elapsed + "s. Features extracted in " + sw2.Elapsed + "s."; btnSampleRunAnalysis.Enabled = true; }
/// <summary> /// This methods computes the Bag-of-Visual-Words with the training images. /// </summary> /// private void btnBagOfWords_Click(object sender, EventArgs e) { int numberOfWords = (int)numWords.Value; Stopwatch sw1 = Stopwatch.StartNew(); IBagOfWords <Bitmap> bow; // Check if we will use SURF or FREAK as the feature detector if (rbSurf.Checked) { // We will use SURF, so we can use a standard clustering // algorithm that is based on Euclidean distances. A good // algorithm for clustering codewords is the Binary Split // variant of the K-Means algorithm. // Create a Binary-Split clustering algorithm BinarySplit binarySplit = new BinarySplit(numberOfWords); // Create bag-of-words (BoW) with the given algorithm BagOfVisualWords surfBow = new BagOfVisualWords(binarySplit); // Compute the BoW codebook using training images only bow = surfBow.Learn(originalTrainImages.Values.ToArray()); } else if (rbFreak.Checked) { // We will use the FREAK detector. The features generated by FREAK // are represented as bytes. While it is possible to transform those // to standard double vectors, we will demonstrate how to use a non- // Euclidean distance based algorithm to generate codewords for it. // Note: Using Binary-Split with normalized FREAK features would // possibly work better than the k-modes. This is just an example. // Create a k-Modes clustering algorithm var kmodes = new KModes <byte>(numberOfWords, new Hamming()); // Create a FREAK detector explicitly (if no detector was passed, // the BagOfVisualWords would be using a SURF detector by default). var freak = new FastRetinaKeypointDetector(); // Create bag-of-words (BoW) with the k-modes clustering and FREAK detector var freakBow = new BagOfVisualWords <FastRetinaKeypoint, byte[]>(freak, kmodes); // Compute the BoW codebook using training images only bow = freakBow.Learn(originalTrainImages.Values.ToArray()); } else { // We will use HOG, so we can use a standard clustering // algorithm that is based on Euclidean distances. A good // algorithm for clustering codewords is the Binary Split // variant of the K-Means algorithm. // Create a Binary-Split clustering algorithm BinarySplit binarySplit = new BinarySplit(numberOfWords); // Create a HOG detector explicitly (if no detector was passed, // the BagOfVisualWords would be using a SURF detector by default). var hog = new HistogramsOfOrientedGradients(); // Create bag-of-words (BoW) with the given algorithm var hogBow = BagOfVisualWords.Create(hog, binarySplit); // Compute the BoW codebook using training images only bow = hogBow.Learn(originalTrainImages.Values.ToArray()); } sw1.Stop(); // Now that we have already created and computed the BoW model, we // will use it to extract representations for each of the images in // both training and testing sets. Stopwatch sw2 = Stopwatch.StartNew(); // Extract features for all images foreach (ListViewItem item in listView1.Items) { // Get item image Bitmap image = originalImages[item.ImageKey] as Bitmap; // Get a feature vector representing this image double[] featureVector = (bow as ITransform <Bitmap, double[]>).Transform(image); // Represent it as a string so we can show it onscreen string featureString = featureVector.ToString(DefaultArrayFormatProvider.InvariantCulture); // Show it in the visual grid if (item.SubItems.Count == 2) { item.SubItems[1].Text = featureString; } else { item.SubItems.Add(featureString); } // Retrieve the class labels, that we had stored in the Tag int classLabel = (item.Tag as Tuple <double[], int>).Item2; // Now, use the Tag to store the feature vector too item.Tag = Tuple.Create(featureVector, classLabel); } sw2.Stop(); lbStatus.Text = "BoW constructed in " + sw1.Elapsed + "s. Features extracted in " + sw2.Elapsed + "s."; btnSampleRunAnalysis.Enabled = true; }
public void custom_clustering_test() { #region doc_clustering // Ensure results are reproducible Accord.Math.Random.Generator.Seed = 0; // The Bag-of-Visual-Words model converts images of arbitrary // size into fixed-length feature vectors. In this example, we // will be setting the codebook size to 10. This means all feature // vectors that will be generated will have the same length of 10. // By default, the BoW object will use the sparse SURF as the // feature extractor and K-means as the clustering algorithm. // In this example, we will use the Binary-Split clustering // algorithm instead. // Create a new Bag-of-Visual-Words (BoW) model var bow = BagOfVisualWords.Create(new BinarySplit(10)); // Since we are using generics, we can setup properties // of the binary split clustering algorithm directly: bow.Clustering.ComputeProportions = true; bow.Clustering.ComputeCovariances = false; // Get some training images Bitmap[] images = GetImages(); // Compute the model bow.Learn(images); // After this point, we will be able to translate // images into double[] feature vectors using double[][] features = bow.Transform(images); #endregion Assert.AreEqual(-1, bow.NumberOfInputs); Assert.AreEqual(10, bow.NumberOfOutputs); Assert.AreEqual(10, bow.NumberOfWords); Assert.AreEqual(64, bow.Clustering.Clusters.NumberOfInputs); Assert.AreEqual(10, bow.Clustering.Clusters.NumberOfOutputs); Assert.AreEqual(10, bow.Clustering.Clusters.NumberOfClasses); BinarySplit binarySplit = bow.Clustering; string str = binarySplit.Clusters.Proportions.ToCSharp(); double[] expectedProportions = new double[] { 0.158034849951597, 0.11810261374637, 0.0871248789932236, 0.116408518877057, 0.103581800580833, 0.192642787996128, 0.0365440464666021, 0.0716360116166505, 0.0575992255566312, 0.058325266214908 }; Assert.IsTrue(binarySplit.Clusters.Proportions.IsEqual(expectedProportions, 1e-10)); Assert.IsTrue(binarySplit.Clusters.Covariances.All(x => x == null)); Assert.AreEqual(features.GetLength(), new[] { 6, 10 }); str = features.ToCSharp(); double[][] expected = new double[][] { new double[] { 73, 36, 41, 50, 7, 106, 23, 22, 22, 29 }, new double[] { 76, 93, 25, 128, 86, 114, 20, 91, 22, 72 }, new double[] { 106, 47, 67, 57, 37, 131, 33, 31, 22, 21 }, new double[] { 84, 41, 49, 59, 33, 73, 32, 50, 6, 33 }, new double[] { 169, 105, 92, 47, 95, 67, 16, 25, 83, 20 }, new double[] { 145, 166, 86, 140, 170, 305, 27, 77, 83, 66 } }; for (int i = 0; i < features.Length; i++) { for (int j = 0; j < features[i].Length; j++) { Assert.IsTrue(expected[i].Contains(features[i][j])); } } #region doc_classification_clustering // Now, the features can be used to train any classification // algorithm as if they were the images themselves. For example, // let's assume the first three images belong to a class and // the second three to another class. We can train an SVM using int[] labels = { -1, -1, -1, +1, +1, +1 }; // Create the SMO algorithm to learn a Linear kernel SVM var teacher = new SequentialMinimalOptimization <Linear>() { Complexity = 10000 // make a hard margin SVM }; // Obtain a learned machine var svm = teacher.Learn(features, labels); // Use the machine to classify the features bool[] output = svm.Decide(features); // Compute the error between the expected and predicted labels double error = new ZeroOneLoss(labels).Loss(output); // should be 0 #endregion Assert.AreEqual(error, 0); }
private void button4_Click(object sender, EventArgs e) { var path = new DirectoryInfo(dataPath + "BoW"); //var path = new DirectoryInfo(@"C:\tmp\Accord\Resources"); Dictionary <string, Bitmap> train = new Dictionary <string, Bitmap>(); Dictionary <string, Bitmap> test = new Dictionary <string, Bitmap>(); Dictionary <string, Bitmap> all = new Dictionary <string, Bitmap>(); Dictionary <string, int> labelIndex = new Dictionary <string, int>(); int labelCount = 0; foreach (DirectoryInfo classFolder in path.EnumerateDirectories()) { string name = classFolder.Name; labelIndex[name] = ++labelCount; logDebug(name + " " + labelIndex[name]); FileInfo[] files = Utils.GetFilesByExtensions(classFolder, ".jpg", ".png").ToArray(); Vector.Shuffle(files); for (int i = 0; i < files.Length; i++) { FileInfo file = files[i]; Bitmap image = (Bitmap)Bitmap.FromFile(file.FullName); if ((i / (double)files.Length) < 0.7) { // Put the first 70% in training set train.Add(file.FullName, image); } else { // Put the restant 30% in test set test.Add(file.FullName, image); } all.Add(file.FullName, image); logDebug(file.FullName); } } int numberOfWords = 36; IBagOfWords <Bitmap> bow; BinarySplit binarySplit = new BinarySplit(numberOfWords); // Create bag-of-words (BoW) with the given algorithm BagOfVisualWords surfBow = new BagOfVisualWords(binarySplit); // Compute the BoW codebook using training images only bow = surfBow.Learn(train.Values.ToArray()); logDebug("BOW Done"); List <double[]> lstInput = new List <double[]>(); List <int> lstOutput = new List <int>(); // Extract Feature in bother training and testing foreach (String fileName in train.Keys) { double[] featureVector = (bow as ITransform <Bitmap, double[]>).Transform(train[fileName]); //string featureString = featureVector.ToString(DefaultArrayFormatProvider.InvariantCulture); //logDebug(featureString); lstInput.Add(featureVector); //FileInfo fin = new FileInfo(fileName); String labelString = Path.GetFileName(Path.GetDirectoryName(fileName)); lstOutput.Add(labelIndex[labelString]); } //this.ksvm = teacher.Learn(inputs, outputs); double[][] inputs = lstInput.ToArray(); int[] outputs = lstOutput.ToArray(); IKernel kernel = new ChiSquare(); MulticlassSupportVectorLearning <IKernel> teacher = new MulticlassSupportVectorLearning <IKernel>() { Kernel = kernel, Learner = (param) => { return(new SequentialMinimalOptimization <IKernel>() { Kernel = kernel, Complexity = 1.0, Tolerance = 0.01, CacheSize = 500, Strategy = SelectionStrategy.Sequential, }); } }; var ksvm = teacher.Learn(inputs, outputs); logDebug("ksvm Done"); double error = new ZeroOneLoss(outputs).Loss(ksvm.Decide(inputs)); logDebug("error=" + error); int trainingHit = 0; int trainintMiss = 0; // For each image group (i.e. flowers, dolphins) Dictionary <string, Bitmap> data = train; foreach (String fileName in data.Keys) { double[] input = (bow as ITransform <Bitmap, double[]>).Transform(data[fileName]); String labelString = Path.GetFileName(Path.GetDirectoryName(fileName)); int label = labelIndex[labelString]; int actual = ksvm.Decide(input); if (label == actual) { trainingHit++; } else { trainintMiss++; logDebug(labelString + " " + String.Format("{0} {1}", label, actual)); } } logDebug(String.Format("Result {0}/{1}", trainingHit, data.Count)); }
public void binary_split_information_test() { // Use a fixed seed for reproducibility Accord.Math.Random.Generator.Seed = 0; // Declare some data to be clustered double[][] input = { new double[] { -5, -2, -1 }, new double[] { -5, -5, -6 }, new double[] { 2, 1, 1 }, new double[] { 1, 1, 2 }, new double[] { 1, 2, 2 }, new double[] { 3, 1, 2 }, new double[] { 11, 5, 4 }, new double[] { 15, 5, 6 }, new double[] { 10, 5, 6 }, }; // Create a new binary split with 3 clusters BinarySplit binarySplit = new BinarySplit(3) { ComputeProportions = true, ComputeCovariances = true, ComputeError = true, }; // Learn a data partitioning using the Binary Split algorithm KMeansClusterCollection clustering = binarySplit.Learn(input); string str = clustering.Proportions.ToCSharp(); double[] expectedProportions = new double[] { 0.333333333333333, 0.444444444444444, 0.222222222222222 }; Assert.IsTrue(expectedProportions.IsEqual(clustering.Proportions, 1e-10)); var strs = clustering.Covariances.Apply(x => x.ToCSharp()); double[][][] expectedCovar = { new double[][] { new double[] { 7, 0, 1 }, new double[] { 0, 0, 0 }, new double[] { 1, 0, 1.33333333333333 } }, new double[][] { new double[] { 0.916666666666667, -0.25, -0.0833333333333333 }, new double[] { -0.25, 0.25, 0.0833333333333333 }, new double[] { -0.0833333333333333, 0.0833333333333333, 0.25 } }, new double[][] { new double[] { 0, 0, 0 }, new double[] { 0, 4.5, 7.5 }, new double[] { 0, 7.5, 12.5 } } }; Assert.IsTrue(expectedCovar.IsEqual(clustering.Covariances, 1e-10)); }