Maybe this can help:
imdata = double(imread('test.jpg'));
tic
[m,n,~] = size(imdata);
pixels = m*n;
x = imdata(:,:,1)*1000000+imdata(:,:,2)*1000+imdata(:,:,3);
keys = unique(x);
n_keys = length(keys);
map = containers.Map(keys,zeros(n_keys,1));
for i = 1:pixels
map(x(i)) = map(x(i)) +1;
end
toc
%here comes post-processing
tic
b = rem(keys, 1000);
g = floor((rem(keys, 1000000) - b)/1000);
r = floor(keys/1000000);
v = map.values;
result = [r g b [v{:}]'];
toc
I am quite sure that is neither the fastest nor the most elegant solution.
What I tried to do:
Mare reversible single value for every present color
Use unique values as a keys in Map object
Count number of appearances for each value
The last part - optional - convert map to array with first 3 columns for color components and last one for number of appearances.
I checked it on simple image like attached one
You can use it for tests, it is 500x500 and has only 4 colors. It took less than 7 seconds on my PC. And I tried it on real 1080x1920 pixels image - it took 57 seconds. Pretty slow, I guess. So, I tried another approach - i replaced the loop with another one:
for i = 1:n_keys
map(keys(i)) = sum(sum(x==keys(i)));
end
For the small image it worked less than 0.05 seconds (whoa!) - we have few keys in that case, so, we make few iterations.
But for large one - it has 271833 unique colors - it took several minutes, making this approach unacceptable. If we can group close colors in one bin - it will work faster.
So, for I'd stick with the first approach.