Implementing image histogram with Matlab

I am using tyring to implement (I know there is a custom function to achieve it) a histogram of a grayscale image in Matlab, so far I've tried:

function h = histogram_matlab(imageSource)
openImage = rgb2gray(imread(imageSource));
[rows,cols] =  size(openImage);

histogram_values = [0:255];

for i = 1:rows
  for j = 1:cols
    p = openImage(i,j);
    histogram_values(p) = histogram_values(p) + 1;

  end
end
histogram(histogram_values)

      

However, when I call a function like: histogram_matlab('Harris.png')

I am getting some graph like:

enter image description here

which is obviously not what I expect, the x-axis should go from 0 to 255 and the y-axis from 0 to whatever maximum value is stored in histogram_values

.

I need to get something like what suggests imhist

:

enter image description here

How do I set it up? Am I doing a bad implementation?

Edit

I changed my code to the improvements and fixes suggested by @rayryeng:

function h = histogram_matlab(imageSource)
openImage = rgb2gray(imread(imageSource));
[rows,cols] =  size(openImage);

histogram_values = zeros(256,1)

for i = 1:rows
  for j = 1:cols
    p = double(openImage(i,j)) +1;
    histogram_values(p) = histogram_values(p) + 1;

  end
end
histogram(histogram_values, 0:255)

      

However, the histogram plot is not as expected:

enter image description here

It is noticeable here that there is some problem or error on the y-axis as it has definitely reached MORE than 2.

+3


source to share


2 answers


In terms of histogram computation, the frequency-to-intensity computation is correct, although there is a slight error ... more on that later. Also, I would personally avoid using loops here. See my little note at the end of this post.

However, there are three problems with your code:

Problem # 1 - Histogram is not initialized correctly

histogram_values

should contain your histogram, but you are initializing the histogram with a vector 0:255

. Each intensity value must start at 0 , so you really need to do this:

histogram_values = zeros(256,1);

      

Problem # 2 - A small error in the loop for

Your intensity ranges from 0 to 255, but MATLAB starts indexing at 1. If you ever get intensities equal to 0, you will get an out-of-bounds error. So the right thing to do is to take p

and add it at 1 to start indexing at 1. However, one complication I have to point out is that if you have a use case uint8

, adding 1 to intensity 255 will just saturate the value up to 255. It won't go to 256 .... so it's also reasonable that you roll something like this double

to ensure you reach 256.

Thus:

histogram_values = zeros(256,1);
for i = 1:rows
  for j = 1:cols
    p = double(openImage(i,j)) + 1;
    histogram_values(p) = histogram_values(p) + 1;

  end
end

      

Problem # 3 - Not Calling histogram

Right

You have to override the behavior histogram

and include the edges. Basically, do the following:

histogram(histogram_values, 0:255);

      

The second vector indicates where we should place the columns on the axis x

.

Small note



You can perform a complete histogram calculation without any loops for

. You can try this with a combination of bsxfun

, permute

, reshape

and two sum

:

mat = bsxfun(@eq, permute(0:255, [1 3 2]), im);
h = reshape(sum(sum(mat, 2), 1), 256, 1);

      


If you want a more detailed explanation of how this code works under the hood, see this conversation between kkuilla and me: http://chat.stackoverflow.com/rooms/81987/conversation/explanation-of-computing-an-images -histogram-vectorized

However, the gist of it is as shown below.


The first line of code creates a 1 column 3-D vector that ranges from 0 to 255 by permute

, and then using bsxfun

with the eq

(equal) function , we broadcast to get us a 3D matrix where each slice is the same size as and a grayscale image, and gives us locations that are equal to the intensity of interest. Specifically, the first snippet tells you where the elements are 0, the second slice tells you where the elements are 1 until the last snippet where it tells you where the elements are 255.

For the second line of code, once we have calculated this 3D matrix, we will calculate the two sums - first by summing each row independently, and then by summing each column of that intermediate result. We then get the total per slice, which tells us how many values ​​there were for each intensity. It is therefore a 3D vector and so we reshape

will go back to a single 1D vector to complete the calculation.


To display a histogram I would use bar

with a flag histc

. Here's a reproducible example if we use an image cameraman.tif

:

%// Read in grayscale image
openImage = imread('cameraman.tif');
[rows,cols] = size(openImage); 

%// Your code corrected
histogram_values = zeros(256,1);
for i = 1:rows
  for j = 1:cols
    p = double(openImage(i,j)) + 1;
    histogram_values(p) = histogram_values(p) + 1;    
  end
end

%// Show histogram
bar(0:255, histogram_values, 'histc');

      

We get the following:

enter image description here

+8


source


Your code looks correct. The problem is calling the histogram. You need to specify the number of bins in the call to the histogram, otherwise they will be calculated automatically.

Try this simple modification, which calls stem to get the correct graph, instead of relying on the histogram

function h = histogram_matlab(imageSource)
openImage = rgb2gray(imread(imageSource));
[rows,cols] =  size(openImage);

histogram_values = [0:255];

for i = 1:rows
  for j = 1:cols
    p = openImage(i,j);
    histogram_values(p) = histogram_values(p) + 1;

  end
end
stem(histogram_values); axis tight;

      



EDIT: After some code review, you have error 0/1. If you have zero pixel then histogram_value(p)

will give you an index error

Try this instead. No need for vectorization for this simple case:

function hv = histogram_matlab_vec(I)

  assert(isa(I,'uint8')); % for now we assume uint8 with range [0, 255]

  hv = zeros(1,256);
  for i = 1 : numel(I)
    p = I(i);
    hv(p + 1) = hv(p + 1) + 1;
  end

  stem(hv); axis tight;
end

      

+3


source







All Articles