# I have 32k black and white images. Want to do clustering on them

As the title says I'm trying to do clustering on a set of black and white images. These images are all 200x200 with black dots on a white canvas Example pics here (These are not actual photos from the data set. Just a general idea of what they look like). The idea is to hopefully find an underlying pattern when it comes to general shape of these images and hopefully cluster by that.

What I've done so far is turned each of my 200 x 200 image in a numpy array of size 40,000. Then put all the images together into a singly numpy array of 32k x 40k.

I'm kind of not sure where to go from there. What I did next was use scikit learn's TruncateSVD on my data set and set the paramater 'n_componenets=100' and fitted and transformed it, so now my data set of images are 32k x 100.

From here on out I don't know what's the best plan of action. Should I just start using k_means algos on my data set? and how would I visualize it?

Sorry if this is a lot. Any help/tips would be much appreciated it.

• Please stop reposting the same question again and again in different sites... As said before, you need to do proper feature extraction and preprocessing. Commented Jul 23, 2019 at 23:04
• Commented Jul 24, 2019 at 5:36

As the dimension of your data is very high (40000), you can try using Spherical K-Means on your raw data. It uses the cosine similarity to compute the distance between 2 points. Indeed, euclidian distance is not so much informative in high dimensional vector spaces, because of the curse of dimensionality. see https://stats.stackexchange.com/questions/99171/why-is-euclidean-distance-not-a-good-metric-in-high-dimensions

Or you can apply a dimension reduction strategy like truncated SVD or ACP like you did, and then apply the classical k-means algorithm. So yeah you should try to apply k-means on your 100-dimensions data. Maybe try with k = 30 or something similar as 100 may already be too high.

• What should I do if I am not sure how many clusters there should be in my data set, or should I just try out random k values and see how it works. Last question would be how would I validate how accurate my program is? Would I be able to feed it an image and have it tell me what cluster it should be in? Sorry if these questions seem very basic Commented Jul 23, 2019 at 15:04
• It is hard to determine the optimised number of clusters. You can maybe have an intuition by looking qualitatively the images, or if it is not possible you should empirically try several values. There exist several metrics to evaluate a given clustering result : en.wikipedia.org/wiki/Cluster_analysis#Internal_evaluation These are often based on the inter-distance between clusters (which you want to maximize) and intra-distance between points in a given cluster (which you want to minimize). Commented Jul 23, 2019 at 15:24

For image clustering, I don't suggest you to start with clustering techniques immediately. First, run some dimensionality reduction model.

The most powerful dimensionality reduction technique is represented by Autoencoders. If you are familiar with Deep learning, use Autoencoders to generate compressed, dense representations of the images. Alternatively, you can use "lighter" models, such as PCA, kernel-PCA, or some manifold learning technique.

This first step has the advantage of reducing noise, multicollinearity, and sparsity in your data. Most importantly, it can save you from the curse of dimensionality.

Once you have compressed the original data, then I suggest you to run k-Means clustering (or another technique if you prefer). Its results will be much more meaningful and easy to interepret.

Using a pretrained model (e.g. VGG16) and extracting features, it is possible to do some image clustering. Also see this post on SO.

# Imports
from keras.preprocessing import image
from keras.applications.vgg16 import VGG16
from keras.applications.vgg16 import preprocess_input
import numpy as np
from sklearn.cluster import KMeans
import os, shutil, glob, os.path
from PIL import Image as pil_image
model = VGG16(weights='imagenet', include_top=False)

# Variables
imdir = 'C:/indir/' # DIR containing images
targetdir = "C:/outdir/" # DIR to copy clustered images to
number_clusters = 10

# Loop over files and get features
filelist = glob.glob(os.path.join(imdir, '*.jpg'))
filelist.sort()
featurelist = []
for i, imagepath in enumerate(filelist):
try:
print("    Status: %s / %s" %(i, len(filelist)), end="\r")
img_data = image.img_to_array(img)
img_data = np.expand_dims(img_data, axis=0)
img_data = preprocess_input(img_data)
features = np.array(model.predict(img_data))
featurelist.append(features.flatten())
except:
continue

# Clustering
kmeans = KMeans(n_clusters=number_clusters, random_state=0).fit(np.array(featurelist))

# Copy images renamed by cluster
# Check if target dir exists
try:
os.makedirs(targetdir)
except OSError:
pass
# Copy with cluster name
print("\n")
for i, m in enumerate(kmeans.labels_):
try:
print("    Copy: %s / %s" %(i, len(kmeans.labels_)), end="\r")
shutil.copy(filelist[i], targetdir + str(m) + "_" + str(i) + ".jpg")
except:
continue