private Pixel[] kMeans() {
        int k = numberOfColours;
        
        // Randomly initialize k clusters from dataset
        Pixel[] clusters = ColourReducer.kRandomPixels(pixels, k);
        
        // Each cluster gets assigned a list of indices from the pixel array
        ArrayList<ArrayList<Integer>> assignments = new ArrayList<ArrayList<Integer>>(k);
        for (int i = 0; i < clusters.length; i++) {
            ArrayList<Integer> singleClusterAssignments = new ArrayList<Integer>();
            assignments.add(i, singleClusterAssignments);
        }
        
        // Move clusters
        for(int i = 0; i < ITERATIONS; i ++) {
            
            // Assign points to clusters
            for (int p = 0; p < pixels.length; p++) {
                int closestIndex = pixels[p].findClosestIndex(clusters);
                assignments.get(closestIndex).add(p);
            }
            
            // Move every cluster to mean of assigned points
            for (int c = 0; c < clusters.length; c++) {
                int length = assignments.get(c).size();
                Pixel[] pix = new Pixel[length];    // pix contains the pixels assigned to cluster c
                for(int q = 0; q < length; q++) {
                    pix[q] = pixels[assignments.get(c).get(q)];
                }
                Pixel mean = ColourReducer.mean(pix);
                
                // Reinitialize cluster if mean is invalid (no points assigned)
                if(mean.red < 0) mean = ColourReducer.kRandomPixels(pixels, 1)[0];
                
                clusters[c] = new Pixel(mean);
            }
            
            // Print feedback
            System.out.println("Iteration " + i);
            for(int z = 0; z < clusters.length; z++) {
                System.out.println(clusters[z]);
            }
            System.out.println("--------------------------");
            System.out.println();
        }
        
        return clusters;
    }