4

I am trying to count the number of unique colours in an image. I have some code that I think should work however when I run it on an image its saying a I have 252 different colours out of a possible 16,777,216‬. That seems wrong given the image is BGR so shouldn't their be much more different colours (thousands not hundreds?)?

def count_colours(src):
    unique, counts = np.unique(src, return_counts=True)
    print(counts.size)
    return counts.size

src = cv2.imread('../../images/di8.jpg')
src = imutils.resize(src, height=300)
count_colours(src) # outputs 252 different colours!? only?

Is that value correct? And if not how can I fix my function count_colours()?

Source image: enter image description here

Edit: is this correct?

def count_colours(src):
    unique, counts = np.unique(src.reshape(-1, src.shape[-1]), axis=0, return_counts=True)
    return counts.size
sazr
  • 24,984
  • 66
  • 194
  • 362
  • You might be only counting 1 layer of the RGB spectrum. You should convert the image into each of the three layers in numpy arrays and then find each of the unique combinations at index [i][j][k]. [More Reading Here](https://stackoverflow.com/questions/41500637/how-to-extract-r-g-b-values-with-numpy-into-seperate-arrays) and [here](https://docs.opencv.org/2.4/doc/tutorials/imgproc/histograms/histogram_calculation/histogram_calculation.html) – Edeki Okoh Jun 15 '19 at 00:19

3 Answers3

6

If you look at the uniques you are getting back, I'm pretty sure you'll find they are scalars. You need to use the axis keyword:

>>> import numpy as np
>>> from scipy.misc import face
>>> 
>>> img = face()
>>> np.unique(img.reshape(-1, img.shape[-1]), axis=0, return_counts=True)
(array([[  0,   0,   5],
       [  0,   0,   7],
       [  0,   0,   9],
       ...,
       [255, 248, 255],
       [255, 249, 255],
       [255, 252, 255]], dtype=uint8), array([1, 2, 2, ..., 1, 1, 1]))
stateMachine
  • 5,227
  • 4
  • 13
  • 29
Paul Panzer
  • 51,835
  • 3
  • 54
  • 99
  • thanks for your answer. I have editted my question with a solution. Do you think the math is adding up now? – sazr Jun 15 '19 at 00:49
  • 3
    @sazr Can't see anything wrong with it. Btw. if all you want is the number of distinct colors, then you do not need to `return_counts`. Just use `uniques = np.unique(src.reshape(-1, src.shape[-1]), axis=0)` and then `len(uniques)` or `uniques.shape[0]` – Paul Panzer Jun 15 '19 at 00:54
  • 1
    That is definitely a cleaner solution! I tested it and it returns the same value as my method. – Julian Jun 15 '19 at 01:03
4

The comment by @ Edeki Okoh is correct. You need to find a way to take the color channels into account. There is probably a much cleaner solution but a hacky way to do this would be something like this. Each color channels has values from 0 to 255 so we add 1 in order to make sure that it gets multiplied. Blue will represent the last the digits, green the middle three ones and red the first three. Now every value is representing a unique color.

b,g,r = cv2.split(src)
shiftet_im = b + 1000 * (g + 1)  + 1000 * 1000 * (r + 1)

The resulting image should have one channel with each value representing a unique color combination.

Julian
  • 909
  • 8
  • 21
1

I think you only counted for a single channel e.g R-value out of full RGB channel. that's why you have only 252 discrete values.

In theory R G B each can have 256 discrete states.

256*256*256 =16777216

means in total you can have 16777216 possibilities of colors.

My suggestion is to convert RGB uchar CV_8UC3 into a single 32bit data structure like CV_32FC1

Let Given image as input

enter image description here # my test small sie text image. which I can count the number of the state by hand

import cv2
import numpy as np
image=cv2.imread('/home/usr/naneDownloads/vuQ9y.png' )# change here
b,g,r = cv2.split(image)
out_in_32U_2D =  np.int32(b) << 16 + np.int32(g) << 8 + np.int32(r)  #bit wise shift 8 for each channel. 
out_in_32U_1D= out_in_32U_2D.reshape(-1) #convert to 1D
np.unique(out_in_32U_1D)
array([-2147483648, -2080374784, -1073741824, -1006632960,           0,
             14336,       22528,       30720,       58368,       91136,
            123904,      237568,      368640,      499712,      966656,
           1490944,     2015232,     3932160,     6029312,     8126464,
          15990784,    24379392,    32768000,    65011712,    67108864,
          98566144,   132120576,   264241152,   398458880,   532676608,
         536870912,   805306368,  1073741824,  1140850688,  1342177280,
        1610612736,  1879048192], dtype=int32)
len(np.unique(out_in_32U_1D))
37 # correct for my test wirting paper when compare when my manual counting

The code here should be able to provide you with what you needed

Dr Yuan Shenghai
  • 1,849
  • 1
  • 6
  • 19