How to draw a histogram of an image in a triangle?

5 views (last 30 days)
I want to get the output image histogram this way
I found the following code from the tutorials of this site after searching, but unfortunately I could not get the output
If possible, please guide me

Accepted Answer

Image Analyst
Image Analyst on 24 Nov 2021
Triangle thresholding has nothing to do with the shape of the histogram, so you don't need the triangle_th() function.
I have a demo for how to get a histogram of any shape you want:
For the demo I made the histogram look like the profile of the woman as shown above. The original image histogram is on the left and the histogram of the modified image is on the right. You could make it a triangle. Basically you need to define the shape you want (a triangle), then cast the image to double, then add a half gray level of noise to the image (to make all pixels have a unique gray level), then sort the gray levels. Then start taking the darkest ones and assigning them to the gray level you're at, then move to the next bin and assign the proper number of pixels a gray level of that bin, and so on all the way across your profile until all pixels have been used up.
The image processing toolbox also has a histmatch() function that you might try.
  1 Comment
jorji
jorji on 25 Nov 2021
Hi
Thank you very much for the answer to my question. I entered the links and downloaded and executed the demo file. It was a really complete and interesting file and had very attractive outputs.
Only I am unfortunately very beginner in MATLAB programming and a lot of code related
shaped_histogram
I did not understand.
The second way you provided me with the MATLAB help commands, I realized that for this I need to have an image as a reference whose histogram is triangular. I searched a lot but could not find an image whose histogram is triangular.
If possible, Mr. Engineer, thank you for giving me a little more guidance on how to use your code so that I can just draw a histogram of a gray image in a triangle.
Or find an image with a triangular histogram
-----------------------------------------------------------------------------------
I wrote this code according to the histmatch command. But I could not find a reference image with a triangular histogram.
A = imread('D:tree.jpeg');
Ref = imread('G:Normal.png');
B = imhistmatch(A,Ref);
subplot(2,2,1)
imshow(A)
title('RGB Image with Color Cast')
subplot(2,2,2)
imshow(Ref)
title('Reference Grayscale Image')
subplot(2,2,3)
imshow(B)
title('Histogram Matched RGB Image')
subplot(2,2,4)
imhist(Ref)

Sign in to comment.

More Answers (2)

Image Analyst
Image Analyst on 25 Nov 2021
Really I think you could do it. I did it in just a few minutes.
Before I give you all the source code tell me if it's your homework, because I don't want you to get into trouble by submitting my code as your own.
Here's a snippet
clc; % Clear the command window.
fprintf('Beginning to run %s.m ...\n', mfilename);
close all; % Close all figures (except those of imtool.)
clearvars;
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 18;
grayImage = imread('cameraman.tif');
[rows, columns, numberOfColorChannels] = size(grayImage);
if numberOfColorChannels == 3
grayImage = rgb2gray(grayImage);
end
subplot(2, 3, 1);
imshow(grayImage);
title('Input Image', 'FontSize', fontSize);
subplot(2, 3, 2);
imhist(grayImage);
grid on;
title('Histogram of Input Image', 'FontSize', fontSize);
% Create noise image.
noiseImage = rand(rows, columns) - 0.5;
% Add noise to gray scale image to make all gray levels unique.
grayImage = double(grayImage) + noiseImage;
% Sort the image from lowest GL to brightest GL.
[sortedGLs, sortOrder] = sort(grayImage(:));
% Create triangle shape
numPixels = rows * columns;
triangle = [linspace(0, 1, 128), linspace(1, 0, 128)];
triangle = round(numPixels * triangle / sum(triangle));
% Sum should now equal the number of pixels.
sum(triangle)
subplot(2, 3, [3, 6]);
plot(triangle, 'b-', 'LineWidth', 2)
grid on;
title('Number of pixels per bin', 'FontSize', fontSize);
gl = 1;
k = 1;
outputImage = grayImage; % Initialize.
while k < numel(sortedGLs)
fprintf('Processing gray level %d\n', gl);
% find out how many pixels we need to put into this gray level.
numInBin = triangle(gl);
% TO DO finish code.
end
% Cast to uint8
outputImage = uint8(outputImage);
subplot(2, 3, 4);
imshow(outputImage, []);
impixelinfo
title('Output Image', 'FontSize', fontSize);
subplot(2, 3, 5);
imhist(outputImage)
grid on;
title('Histogram of Output Image', 'FontSize', fontSize);
  5 Comments
Image Analyst
Image Analyst on 25 Nov 2021
OK, here is the complete program:
clc; % Clear the command window.
fprintf('Beginning to run %s.m ...\n', mfilename);
close all; % Close all figures (except those of imtool.)
clearvars;
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 18;
grayImage = imread('cameraman.tif');
[rows, columns, numberOfColorChannels] = size(grayImage);
if numberOfColorChannels == 3
grayImage = rgb2gray(grayImage);
end
subplot(2, 3, 1);
imshow(grayImage);
title('Input Image', 'FontSize', fontSize);
subplot(2, 3, 2);
imhist(grayImage);
grid on;
title('Histogram of Input Image', 'FontSize', fontSize);
% Create noise image.
noiseImage = rand(rows, columns) - 0.5;
% Add noise to gray scale image to make all gray levels unique.
grayImage = double(grayImage) + noiseImage;
% Sort the image from lowest GL to brightest GL.
[sortedGLs, sortOrder] = sort(grayImage(:));
% Create triangle shape
numPixels = rows * columns;
triangle = [linspace(0, 1, 128), linspace(1, 0, 128)];
triangle = round(numPixels * triangle / sum(triangle));
% Sum should now equal the number of pixels.
sum(triangle)
subplot(2, 3, [3, 6]);
plot(triangle, 'b-', 'LineWidth', 2)
grid on;
title('Number of pixels per bin', 'FontSize', fontSize);
gl = 1;
k = 1;
outputImage = grayImage; % Initialize.
while k < numel(sortedGLs)
fprintf('Processing gray level %d\n', gl);
% find out how many pixels we need to put into this gray level.
numInBin = triangle(gl);
% Get location of this gray level in the image. This is a linear index.
k1 = k;
k2 = min([numPixels, (k1 + numInBin - 1)]);
indexes = sortOrder(k1 : k2);
% Assign these indexes the gray level.
fprintf('Assigning %d input pixels with gray level %f to new gray level of %d.\n', ...
length(indexes), mean(outputImage(indexes)), gl)
outputImage(indexes) = gl;
% Move to the next gray level.
gl = gl + 1;
if k2 >= numPixels
break;
else
k = k2 + 1;
end
end
% Cast to uint8
outputImage = uint8(outputImage);
subplot(2, 3, 4);
imshow(outputImage, []);
impixelinfo
title('Output Image', 'FontSize', fontSize);
subplot(2, 3, 5);
imhist(outputImage)
grid on;
title('Histogram of Output Image', 'FontSize', fontSize);
jorji
jorji on 26 Nov 2021
Thank you very much for your kindness and help in learning this.
I hope you always good luck.

Sign in to comment.


Image Analyst
Image Analyst on 2 Jan 2022
OK, since your homework is over, I'll post a full demo. I also expanded it so that you can choose either a triangle output histogram or one in the shape of a parabola, sine wave, or perfectly flat (like histogram equalized). (NOTE: Students should consider whether it's ethical to turn in my code as their own work if they have an assignment to do this, lest they get into trouble.)
% Demo to transform a gray scale image so that its histogram is of a prescribed shape, such as triangle, parabola, flat, since wave.
% Initialization steps.
clc; % Clear the command window.
close all; % Close all figures (except those of imtool.)
clear; % Erase all existing variables. Or clearvars if you want.
workspace; % Make sure the workspace panel is showing.
format long g;
format compact;
fontSize = 15;
fprintf('Beginning to run %s.m ...\n', mfilename);
%----------------------------------------------------------------------------
% Read in original image and display its histogram.
grayImage = imread('cameraman.tif');
[rows, columns, numberOfColorChannels] = size(grayImage);
if numberOfColorChannels == 3
grayImage = rgb2gray(grayImage);
end
numPixels = rows * columns;
subplot(2, 3, 1);
imshow(grayImage);
title('Input Image', 'FontSize', fontSize);
subplot(2, 3, 2);
imhist(grayImage);
grid on;
title('Histogram of Input Image', 'FontSize', fontSize);
%----------------------------------------------------------------------------
% Create noise image.
noiseImage = rand(rows, columns) - 0.5;
% Add noise to gray scale image to make all gray levels unique.
grayImage = double(grayImage) + noiseImage;
% Sort the image from lowest GL to brightest GL.
[sortedGLs, sortOrder] = sort(grayImage(:));
%-------------------------------------------------------------------------------------------------------------
% Create desired shape of output histogram, for example a triangle shape or parabola or flat.
% First example: create a triangle.
triangle = [linspace(0, 1, 128), linspace(1, 0, 128)];
% Second example shape: a parabola.
g = 0:255;
parabola = -((g - 128).^2/150) + 100;
% Third example: perfectly flat, like for histogram equalization.
flat = ones(1, 256);
% Fourth example: sine wave
sineWave = 1 + sin(2 * pi * g / 256);
%-------------------------------------------------------------------------------------------------------------
% We need to pick only one example shape to use, either triangle, parabola, flat, or sine wave.
histShape = triangle;
% histShape = parabola;
% histShape = flat;
% histShape = sineWave;
% Make sure the function has no negative values.
histShape = max(histShape, 0);
% Make sure it sums to the number of pixels in the entire image.
histShape = round(numPixels * histShape / sum(histShape));
% Sum should now equal the number of pixels.
shapeSum = sum(histShape) % Not really needed - it's just to double check that it sums to the number of pixels.
%-------------------------------------------------------------------------------------------------------------
subplot(2, 3, [3, 6]);
plot(histShape, 'b-', 'LineWidth', 2)
grid on;
title('Number of pixels per bin', 'FontSize', fontSize);
%-------------------------------------------------------------------------------------------------------------
% Process the vector that we'll use for the output
gl = 1;
k = 1; % k can be thought of as "the next pixel index".
outputImage = sortedGLs(:); % Initialize.
while k < numel(sortedGLs)
fprintf('Processing gray level %d.', gl);
% find out how many pixels we need to put into this gray level.
numInBin = histShape(gl);
fprintf(' Making %d pixels have gray level %d.\n', numInBin, gl);
% Make sure index doesn't go past end of vector..
lastIndex = min(k + numInBin - 1, numel(outputImage));
% Assign all those elements to the current gray level.
outputImage(k : lastIndex) = gl;
% Increment the gray level, and the pixel index that we'll be changing next.
gl = gl + 1;
k = k + numInBin; % Increment the next pixel index.
end
%-------------------------------------------------------------------------------------------------------------
% Unscramble the image. Put pixels back where they came from.
outputImage2(sortOrder) = outputImage; % Unsort/unscramble.
% Convert from 1-D vector into 2-D image.
outputImage = reshape(outputImage2, [rows, columns]);
% Cast to uint8
outputImage = uint8(outputImage);
%-------------------------------------------------------------------------------------------------------------
% Display processed image and display its histogram.
subplot(2, 3, 4);
imshow(outputImage, []);
impixelinfo
title('Output Image', 'FontSize', fontSize);
subplot(2, 3, 5);
imhist(outputImage)
grid on;
title('Histogram of Output Image', 'FontSize', fontSize);
% Maximize window
hFig = gcf;
hFig.WindowState = 'maximized';
Here is what it looks like if you tell it to use the other shapes. Sine wave shape below:
Flat shape below, like histogram equalized -- perfect equalization, not like the usual functions that do it.
Parabola shape below:

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!