1

I'm trying to implement a Bayesian Classifier for skin segmentation for a homework but I'm having some trouble with the counting.

The problem is that the paper I'm following says that I need either a RGB Histogram or some sort of map structure of the kind:

map(R,G,B) -> Count of appearances in the image

So far I have tried finding a map structure that meets this requirement or some function or method that can do this count easier (I'm still hoping there is a function somewhere that will save me from iterating through all the image).

I need this to be, ideally, fast, because I need to sum the counts from a bunch of images in a dataset.

Any ideas are welcome.

  • I don't think there is a native 3D histogram function. The highest is [bivariate](https://www.mathworks.com/help/matlab/ref/histcounts2.html). You can map RGB values to 1D and then do histogram on the 1D parameter. Example: [using the "exponentiation trick" to convert RGB to grayscale](https://stackoverflow.com/questions/687261/converting-rgb-to-grayscale-intensity). – Argyll Apr 21 '20 at 05:59
  • Also, while I find your question interesting, I don't think it is a programming question. (Asking how to map RGB to grayscale for example would be a duplicate.) Therefore I don't think it belongs to SO. Maybe the image processing SE site instead. – Argyll Apr 21 '20 at 06:01
  • go with looping: `i = 1:256` val = sum(img(:) == i/256) end` and you have the counts of a particular intensity of a grayscale image. The same applies to RGB images but is one dimension more and thus quires more time. Maybe looping over `unique` colors may speed up the process – max Apr 21 '20 at 06:04
  • @Argyll I want to count appearances of a certain RGB pixel, not map it to grayscale – Sebastian Araneda Apr 21 '20 at 23:18

1 Answers1

1

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:

  1. Mare reversible single value for every present color

  2. Use unique values as a keys in Map object

  3. Count number of appearances for each value

  4. 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 oneenter image description here

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.

Pavel Oganesyan
  • 6,774
  • 4
  • 46
  • 84
  • Thanks a lot! I've reduced the possible pixel values from 0-255 to 0-32, so I'm going to try both approaches on some test images and time them to see which one works best. – Sebastian Araneda Apr 21 '20 at 23:24