Below is an example of a (randomly generated) **gray-scale image** (a). The image is displayed from a matrix of random numbers between 1 and 26 (number of letters in the English alphabet). Underneath it (d) is displayed the same matrix but each number is replaced by a letter (at the position determined by the original number).

Bar plots (b) and (c) show **histograms** computed from the image/letter matrix (they are, of course, the same; the only difference is that in one case, occurrences of intensity values are counted and in the other case, occurrences of letters are counted). Note that the original numbers are generated from a normal distribution (mean is 13) and this can be seen on the histograms as well. Since the normal distribution has relatively small sigma, certain 'edge' values/letters do not occur in the image/letter matrix (which can again be seen on the histogram).

Finally, plots (e) and (f) show the **cumulative distribution functions** (CDFs) of the image/letter matrix (or technically, of their histograms). Again, they are the same for the numbers and letters, since the underlying distributions are the same. Note the 'S' shape of the CDFs - this is caused by the fact that normal distribution was used to generate the values. If the values were generated uniformly, the CDFs would approximately look like the function `f(x)=x/y`

.

Code to reproduce the figure above (not exactly, since the image is random):

% Creates random alphabetic matrix and displays it as an image. % The later the letter appears in the alphabet, the higher the intensity % it represents (e.g., A = black, Z = white). % Histogram and CDF of the alphabetic (and numeric but it's the same) image % are shown. % The "count(value)" in CDF plot x-axis labels represents a method that counts % the occurrences of the value 'value'. Values of for example 'A to D' means % it counts the occurrences of all A, B, C, D and sums the occurrences up, % that is: % count(A to D) = sum([count(A), count(B), count(C), count(D)]) % some parameters to play with: random_mode = 'normal'; % 'normal' or 'uniform' random number generation pseudo_sigma = 3; % if normal distribution, use this parameter to scale the Gaussian. image_size = [7 7]; % size of the generated image (not fool-proof, use sensible values only) %% Below is the code to generate and show the images, histograms and CDFs % create a figure window fig = figure('Name', sprintf('Random gray-scale image with intensities drawn from a %s distribution.', random_mode)); % create an array of the capital letters letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; num_letters = length(letters); % number of letters % create a 10 by 10 matrix of random integers from 1 to 26 (i.e. the length of the alphabet) switch random_mode % we need to identify the requested random number generation method and act accordingly case 'normal' % normal random generator numMat = ceil(randn(image_size) * pseudo_sigma + num_letters / 2); % normally distributed random numbers numMat(numMat > num_letters) = num_letters; numMat(numMat < 1) = num_letters; case 'uniform' % uniform random generator numMat = randi(num_letters, image_size); % uniformly distributed random numbers otherwise % unknown method request (perhaps a typo), throw error error('Invalid random number generation mode: %s', random_mode); end ax = subplot(2, 3, 1); % create a subplot in the main figure - this is used to show multiple plots and images in the same figure % this can be thought of as a gray-scale image, let's plot it as such intensity_image = numMat ./ num_letters; % theoretically we can also plot the "raw" numbers and adjust the intensity scale instead imagesc(intensity_image, 'Parent', ax); axis(ax, 'image', 'off'); % no need for axis to show for images colormap(ax, gray); % sets the color map to "gray-scale" (better to see the intensity) title('(a) Gray-scale image from the numeric matrix', 'FontSize', 18) % compute histogram of the values contained in the matrix numHist = hist(numMat(:), 1:num_letters); subplot(2, 3, 2); % numHist variable holds the individual counts or occurrences of the values in the matrix bar(numHist); % bar plot to show the histogram title('(b) Histogram of the numeric matrix', 'FontSize', 18); xlim([1 length(letters)]); ax = gca; ax.XTick = 1:length(letters); % let's create a matrix of letters from the numeric matrix, by substituting the integers with letters letterMat = letters(numMat); % manually count the occurrences of the individual letters letterHist = zeros(1, length(letters)); for l = letters lpos = find(letters == l); letterHist(lpos) = sum(sum(l == letterMat)); end subplot(2, 3, 3); % variable letterHist holds the counts of the individual letters in the alphabetic matrix bar(letterHist); title('(c) Histogram of the alphabetic matrix', 'FontSize', 18); xlim([1 length(letters)]); ax = gca; ax.XTick = 1:length(letters); ax.XTickLabel = letters'; % next, we need to compute and plot the CDFs subplot(2, 3, 5); % CDF can be computed from a histogram by calculating the cumulative sum of the histogram plot(cumsum(numHist)); title('(e) CDF of the numeric matrix', 'FontSize', 18); xlim([1 length(letters)]); ax = gca; ax.XTick = 1:num_letters; ax.XTickLabelRotation = -90; xlabels = ['count(1) '; [repmat('count(1 to ', num_letters-1, 1) cell2mat(splitlines(sprintf('%2d\n', 2:num_letters))) repmat(')', num_letters-1, 1)]]; ax.XTickLabel = xlabels; subplot(2, 3, 6); % the same procedure as before, just with the alphabetic histogram plot(cumsum(letterHist)); title('(f) CDF of the alphabetic matrix', 'FontSize', 18); xlim([1 length(letters)]); ax = gca; ax.XTick = 1:num_letters; ax.XTickLabelRotation = -90; letters_vec = cell2mat(split(letters, '')); xlabels = ['count(A) '; [repmat('count(A to ', num_letters-1, 1) letters_vec(2:end) repmat(')', num_letters-1, 1)]]; ax.XTickLabel = xlabels; % display the letter matrix e_letterMat = char(zeros(image_size .* [1 2])); % insert horizontal spaces between letters e_letterMat(:, 1:2:end) = letterMat; tstring = evalc('disp(e_letterMat)'); % convert the matrix into a contiguous string ax = subplot(2, 3, 4); pos = get(ax, 'position'); annotation(gcf,'Textbox', pos, 'String',tstring,'Interpreter','Tex', 'FontName', 'FixedWidth','Units','Normalized',... 'EdgeColor', 'none', 'FaceAlpha', 0,... 'FontWeight', 'bold', 'FontSize', floor(32 / (max(image_size) / 10))); % display the stirng as an annotation axis(ax, 'image', 'off'); title('(d) Original letter matrix', 'FontSize', 18);

Uniform gradient of all possible values (histogram with 16 bins):

Four discrete values 0, 1/3, 2/3 and 1 (histogram with 16 bins):

For an RGB image you would use the same histogram and CDF computation function, just run them individually on each of the color channels: Image of Tower ravens - Colin / Wikimedia Commons / CC BY-SA 4.0

courses/b4m33dzo/labs/1_monadic_functions/histogram_cdf_example.txt · Last modified: 2023/10/02 18:25 by panekvo1