AaronDT
AaronDT

Reputation: 4060

K-Means for color classification with filter for mask: ValueError: cannot reshape array of size 13498 into shape (3)

I am trying to classify the color of an object in an image using KMeans. First, I have used a mask in order to subtract the background of the image in order to separate the object from the background. Hence, I am working with an image that has a pure black background i.e. rgb(0,0,0) with the object sitting isolated within that black space. Now I would like to perform KMeans on the colors of the object in the image without feeding the background to the algorithm, as I don't want the background to be included within the clusters.

I am trying to filter out the black pixels and then reshape the array in order to feed it to the classifier.

 # reshape the image to be a list of pixels
    image = image[image != 0]
    image = np.reshape(image, (-1,3))

    # cluster the pixel intensities
    clt = KMeans(n_clusters = 3, n_jobs=1,random_state=42)
    clt.fit(image)

While this works for some images well, I get an error message for some of my other images, like so:

ValueError: cannot reshape array of size 13498 into shape (3)

Is there any way to dynamically adjust the size of the array after filtering in order for it to fit into shape 3?

I am using Python v3 and the images are loaded using OpenCV2

Upvotes: 1

Views: 508

Answers (1)

api55
api55

Reputation: 11420

Your problem is that you are looking first for ALL non zero values, but not for non black pixels... which I guess is your final goal. To put a simple example of your problem let's say we get 3 pixels with non-zero values, that would be 9 values right:

import numpy as np

a = np.array([1,2,3,4,5,6,7,8,9])
a = np.reshape(a, (-1,3))

This may not give you an error, but what happens if, for a pixel, the value of one of the channels is actually 0 ? then you will have one value less. As an example, let's say it is only for one value, then you will get 8 values only:

import numpy as np

a = np.array([1,2,3,4,5,6,7,8])
a = np.reshape(a, (-1,3)) #Error

It does not have enough values to do the reshaping... The problem may get even worst if you have more pixels with this 0 value in one of the channels of different pixels... if it is in quantities multiple of 3 then the function will not give you error, but the pixels colors will be all wrong :(

You can always try the numbers in the error it gave you as well: 13498 / 3 = 4499.333 this means at least one value was 0 (actually at least 2).

I am not the best with numpy, but a working solution for your problem could be this:

# create the indices that have at least one channel of the pixel different than 0
indToSelect = np.any(image != 0, keepdims=True, axis=2)[:,:,0] # used [:,:,0] because numpy returns an array of shape (rows, cols, 1)
# get the 3 channel values of the selected values above
forKmeans = image[indToSelect, :]

This already gives a BGR pixel array with a shape of (points, 3) so no need to reshape. I hope this helps you.

Upvotes: 2

Related Questions