List of all colors in an image using opencv and python
Asked Answered
C

2

6

Python beginner here. I'm using python 3.6 and opencv and I'm trying to create a list of rgb values of all colors present in an image. I can read the rgb values of one pixel using cv2.imread followed by image[px,px]. The result is a numpy array. What I want is list of rgb tuples of unique colors present in an image and am not sure how to do that. Any help is appreciated. TIA

Coterminous answered 6/8, 2018 at 10:8 Comment(3)
Have you tried the naive aproach of just looping over the whole image and collecting every unique color (i.e. keep a list/dict/whatever with every color seen so far)Heron
I wasn't sure how to convert from array to tuple and I just searched and apparantly tuple(a) where a is array gives tuple lol (forgive me, I just started learning python). So, I'm trying the looping approach now. Meanwhile, it'd be great if someone could share a better approach since I have to loop it over 3000 images and it may take a long time.Coterminous
Be aware that for most real world images this is going to be a very very long list. You might have memory issues.Chelate
S
12

Check out numpy's numpy.unique() function:

import numpy as np

test = np.array([[255,233,200], [23,66,122], [0,0,123], [233,200,255], [23,66,122]])
print(np.unique(test, axis=0, return_counts = True))

>>> (array([[  0,   0, 123],
       [ 23,  66, 122],
       [233, 200, 255],
       [255, 233, 200]]), array([1, 2, 1, 1]))

You can collect the RGB numpy arrays in a 2D numpy array and then use the numpy.unique() funtion with the axis=0 parameter to traverse the arrays within. Optional parameter return_counts=True will also give you the number of occurences.

Sixpenny answered 6/8, 2018 at 10:19 Comment(2)
Thanks! This worked. I still had to loop over whole image and over many images to get the arrays and then used np.unique.Coterminous
@KalyanM That should not be necessary. I have not validated it but the following should work as the cv2.imread() function already returns a numpy ndarray: img = cv2.imread(path_to_img) to get the 3D ndarray of per pixel rbgs. all_rgb_codes = img.reshape(-1, img.shape[-1]) to flatten the 3D array by one dimension to a 2D array we need. unique_rgbs = np.unique(all_rgb_codes, axis=0) to get the unique colors as per my answer above. Please test and evaluate this tho before using it in production. Happy coding :)Sixpenny
B
0

I tried to add this as a comment but realised that it was unreadable. I henceforth add this as an answer but all upvotes can go to iRoNic's post. Here 'cropped' is the image we are interested in and we want to extract prominent colors (instead of all colors) which is usually the use-case:

all_rgb_codes = cropped.reshape(-1, cropped.shape[-1])
unique_rgbs = np.unique(all_rgb_codes, axis=0, return_counts=True)
prominent_2_colors = np.argsort(unique_rgbs[1])[-2:]
foreground_idx, background_idx = prominent_2_colors[-2], prominent_2_colors[-1]
foreground_color, background_color = unique_rgbs[0][foreground_idx], unique_rgbs[0][background_idx]
print('foreground color:', foreground_color, 'background color:', background_color)

Here I am extracting the prominent 2 colors but similar logic can be extended further to get more colors

Bucolic answered 26/6 at 13:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.