Method 1:
{k:np.sum(a==k) for k in set(a.ravel().tolist())}
or a little more readably
count = lambda A, key : np.sum(A==key)
unique_keys = set(A.ravel().tolist())
return {key : count(A,key) for key in unique_keys}
Walking through it:
{...}
dictionary comprehension to generate the mapping
set(a.ravel().tolist())
a.ravel
flattens the image; to list allows it to be cast to a set, which is a container for the unique elements.
np.sum(a==k)
Count how many times the element is in the image. This is not the most efficient way to do this, but puts the histogram into the format you requested
Taken together, if your image is the 3x3
a = np.array([[1,2,3],[1,3,3],[3,3,3]])
then
set(a.ravel().tolist()) # yields set([1, 2, 3])
and the entire expression yields
{1: 2, 2: 1, 3: 6}
Method 2
from PIL.Image import fromarray
b = fromarray(a.astype(np.uint8)) # convert to a PIL image
hist = {idx:count for idx, count in enumerate(b.histogram()) if count}
This works very similarly (using a dictionary comprehension), but makes use of the PIL histogram functionality, and enumerate to fetch the indices. It may have some domain limitations.
"Binning"
If you want to have "bins" of colors, as you indicated, then the remaining work is just defining your bin structure, which an be done many number of ways. For example, in the previous example, we can create fixed size integer bins by
num_bins = 2
b = fromarray(a.astype(np.uint8)//num_bins) # convert to a PIL image, binned
hist = {idx*num_bins:count for idx, count in enumerate(b.histogram()) if count}