2

I have an RGB image -ndarray- and I want to count the occurrence of some colors like [255,0,0] or [0,0,255] in this image.

example of image data

np.ones((3, 3, 3)) * 255

array([[[255., 255., 255.],
        [255., 255., 255.],
        [255., 255., 255.]],
       [[255., 255., 255.],
        [255., 255., 255.],
        [255., 255., 255.]],
       [[255., 255., 255.],
        [255., 255., 255.],
        [255., 255., 255.]]])

So as result I want something like this

{
'[255,255,255]' : 9,
}
yatu
  • 86,083
  • 12
  • 84
  • 139
zaki
  • 127
  • 1
  • 10
  • I added an example. so in general the dimension of RGB image is (width, height, 3) – zaki Jul 03 '19 at 08:43
  • 1
    np.unique can be used in the linked dupe @MatteoPeluso being a 1d array. However with a 2darray its a little more tricky :) – yatu Jul 03 '19 at 09:36

3 Answers3

4

One solution could be the Counter function:

from collections import Counter
import numpy as np

# Generate some data
data = np.ones((10, 20, 3)) * 255

# Convert to tuple list
data_tuple = [ tuple(x) for x in data.reshape(-1,3)]
Counter(data_tuple)

Returns:

Counter({(255.0, 255.0, 255.0): 200})
Nakor
  • 1,484
  • 2
  • 13
  • 23
3

Whereas its possible to use Counter or opencv histogram function to compute frequency of every single pixel , for specific pixels, its more efficient to use this:

import numpy as np

ar = np.ones([3,3,3]) *255
ar[1,1,:] = [0, 0, 200]

pixels = dict()
pixels['[255, 255, 255]'] =  np.sum(np.all(ar == [255,255, 255], axis = 2))
pixels['[0, 0, 200]'] =  np.sum(np.all(ar == [0, 0, 200], axis = 2)) 

result : {'[255, 255, 255]': 8, '[0, 0, 200]': 1}

Masoud
  • 1,270
  • 7
  • 12
1

Here's an approach using NumPy. Being values in the range 0-255, we could view the rows as tuples with three elements of type f8, and use np.unique to count the occurrences of the actual rows in the original ndarray. Using nakor's array:

a = np.ones((10, 20, 3)) * 255

We could then do:

vals, counts = np.unique(a.view('f8,f8,f8'), return_counts=True)

Where:

print(vals)
array([(255., 255., 255.)],
      dtype=[('f0', '<f8'), ('f1', '<f8'), ('f2', '<f8')])

print(counts)
array([200])
yatu
  • 86,083
  • 12
  • 84
  • 139
  • I tried with a real picture and I had this error `ValueError: When changing to a larger dtype, its size must be a divisor of the total size in bytes of the last axis of the array.` – zaki Jul 03 '19 at 13:21