1

I need to compute the Cumulative Distribution Function of an image. I normalized the values using the following code:

im = imread('cameraman.tif');
im_hist = imhist(im);
tf = cumsum(im_hist); %transformation function
tf_norm = tf / max(tf);
plot(tf_norm), axis tight

Also, when the CDF function is plotted, does the plot have to be somewhat a straight line which ideally should be a straight line to represent equal representation for pixel intensities?

David Norman
  • 301
  • 2
  • 10
  • 18
  • I'm rather confused. `cumsum` **is** the CDF of the image. You answered your own question? – rayryeng Aug 09 '14 at 05:52
  • @rayryeng, I am confused too. I know cumsum is the CDF but my lecturer said this is not the answer? WAATT – David Norman Aug 09 '14 at 05:53
  • OK. You need to normalize by `sum(tf)`, not `max`. `sum(tf)` is essentially the dimensions of your image (`prod(size(im);`). I see why it is not (entirely) correct. You almost have it right. You just didn't normalize properly. Remember, when you sum up all of the probabilities, the total must be equal to 1. That's why you need to divide by the total summation. Good code though! – rayryeng Aug 09 '14 at 05:54
  • @rayryeng, you are referring to numel(tf) right? But max(tf) returns the same value as numel(tf) – David Norman Aug 09 '14 at 05:59
  • Oh yes, my bad. In that case.... this code should be correct. Your lecturer is cracked. This should achieve the right answer. – rayryeng Aug 09 '14 at 06:02
  • @rayryeng, how would I apply this to my image to check its quality? When I map it to my image all I get is a black image (all pixels are at 0) – David Norman Aug 09 '14 at 06:04
  • If you run the above code, you get the same code that @citz gets..... again, your lecturer is cracked. – rayryeng Aug 09 '14 at 06:04
  • What you are essentially doing is a **histogram equalization**. This `cumsum` is basically a LUT. Recall our post earlier. You would simply do: `out = uint8(255*tf_norm(im+1));`. This should contrast stretch your image. Try doing this on the famous `pout` image: `im = imread('pout.tif');` – rayryeng Aug 09 '14 at 06:07
  • DavidNorman - Take a look at my post on histogram equalization. If you're applying this to your image, then you are essentially doing this. http://stackoverflow.com/questions/24094649/explanation-of-the-histogram-equalization-function-in-matlab/24094955#24094955 – rayryeng Aug 09 '14 at 06:12
  • @rayryeng, OH MAN, I am not multiplying it by 255 so I have all zeros as uint8. How can I be so stupid. What I noticed is that the image becomes brighter and so the dark bits are more noticeable, but the bright bits are over saturated is that correct? – David Norman Aug 09 '14 at 06:14
  • Yes. Darker pixels get pushed to be more darker while lighter pixels get pushed to be more brighter... that is the **ideal** situation. Depending on the spread of your pixels, histogram equalization may give you poor results. Use hist. eq. with a grain of salt. It doesn't work all the time. Also, glad I helped! – rayryeng Aug 09 '14 at 06:16
  • @rayryeng, in this case the whole image has become bright so the dark bits are bight (which is good) and the bright bits are almost white (which is not so good) – David Norman Aug 09 '14 at 06:20
  • That's because you have chosen an image **that does not need** contrast enhancement. This only works on something with very bad contrast. Use it on the `pout` image... then again, it doesn't work all of the time. If you're getting a pretty bad output, then there's nothing you can do about it! – rayryeng Aug 09 '14 at 06:21
  • 1
    @rayryeng, beautiful, just tried it on pout image and it works great, more details emerge that couldn't be seen before. you're great help thanks – David Norman Aug 09 '14 at 06:26
  • My pleasure David. Feel free to ask more questions. Image processing is my livelihood. I do this stuff for a living! – rayryeng Aug 09 '14 at 06:27
  • @rayryeng I'm not familiar with hist eq, but, as an amateur photographer, I guess what you are doing is essentially "pushing" the histogram to a more evenly spread shape? I saw the "peaks" get spread wider, while their height are maintained. This is equivalent to the "curve" tool in Photoshop, except that you are always using a special mapping curve - CDF. That's why "it doens't work all of the time"; histogram is done by computer which looks at the whole picture without noticing the content; by "details" a human means the particular parts that _they need_. – Yvon Aug 09 '14 at 08:09
  • @Yvon - That is very very correct. Histogram equalization tries to flatten and spread the histogram so that the contrast is represented as best as possible. The computer looks at the entire image, while we tend to only focus on sub-regions of the image instead. Very nice observation :) – rayryeng Aug 09 '14 at 08:18
  • Aha there's another technique that's usually used in exposure measurement. You can calculate the "weighted sum" of the picture, not just putting them to bins (each pixel means +1). Start with designing a 2D weighting function (usually a Gaussian) that covers the entire image. Move its peak to the region you are interested. Include the function into your calculation. Then hopefully you can get a more satisfying result. For OP if the interesting region is fixed or predictable, just generate the weighting function with Matlab! – Yvon Aug 09 '14 at 08:26
  • @rayryeng, http://stackoverflow.com/questions/25278491/video-processing-inter-frame-prediction – David Norman Aug 13 '14 at 05:12
  • @DavidNorman - I have answered your question. Good luck! – rayryeng Aug 13 '14 at 05:38

2 Answers2

3

You can obtain a CDF very easily by:

A = imread('cameraman.tif');    
[histIM, bins] = imhist(A);
cdf = cumsum(counts) / sum(counts);
plot(cdf); % If you want to be more precise on the X axis plot it against bins

For the famous cameraman.tif it results in:

enter image description here

As for your second question. When the histogram is perfectly equalized (i.e. when at each intensity correspond roughly the same number of pixels) your CDF will look like a straight 45° line.

EDIT: Strictly speaking cumsum alone is not a proper CDF as a CDF describe a probability, hence it must obey probability axioms. In particular the first axiom of probability tell us that a probability value should lie in the range [0 ... 1] and cumsum alone does not guarantee that.

cifz
  • 1,078
  • 7
  • 24
  • Thanks for your answer, how do I apply this to the image to check its quality? – David Norman Aug 09 '14 at 05:57
  • @DavidNorman A is your Image :) Let me edit the code in a more verbose way – cifz Aug 09 '14 at 05:58
  • @citz - This doesn't work out of the box for me. I had to cast the image to `double` before running this. Also, for a digital image, the bins should be between `[0,255]`, yet I am seeing uneven bins. Suggest you use `imhist` instead to compute your histogram. – rayryeng Aug 09 '14 at 06:01
  • @cifz, what is 'bins' I see this everywhere but I have no clue what it is? is it similar to 'linspace'? – David Norman Aug 09 '14 at 06:02
  • @DavidNorman - Bins are those locations on the `x` axis where the intensities were gathered. Using `imhist`, the bins are between `[0,255]`. – rayryeng Aug 09 '14 at 06:03
  • @rayryeng my fault, I was usign imhist on my end (as can be noticed in the plot) but copying without c&p I ended up writing hist. Correcting that straight-away. Thanks for pointing it out – cifz Aug 09 '14 at 06:04
0
function icdf = imgcdf(img)
% Author: Javier Montoya (jmontoyaz@gmail.com).
%         http://www.lis.ic.unicamp.br/~jmontoya
%
% IMGCDF calculates the Cumulative Distribution Function of image I.
% Input parameters:
%    img: image I (passed as a bidimensional matrix).
% Ouput parameters:
%    icdf: cumulative distribution function.
%
% See also: IMGHIST
%
% Usage:
%    I    = imread('tire.tif');
%    icdf = imgcdf(I);
%    figure; stem(icdf); title('Cumulative Distribution Function (CDF)');

   if exist('img', 'var') == 0
      error('Error: Specify an input image.');
   end

   icdf    = [];
   ihist   = imghist(img);
   maxgval = 255;
   icdf    = zeros(1,maxgval);

   icdf(1)= ihist(1);
   for i=2:1:maxgval+1
      icdf(i) = ihist(i) + icdf(i-1);
   end
end

Its not my code but it works for me! Also check the cdf function in the statistics toolbox

Juan David
  • 2,676
  • 4
  • 32
  • 42