Histograms too different compared to how they should be - matlab

I have a black/white image I0 (512 x 512) to which I have to remove the first k pixel and calculate the histogram of the resulting image.
Let me explain: I have to build the histogram of the image I0 without considering the first k pixels.
This is my code:
k = 8;
% compute the histogram of the entire image I0
[vecComp, histComp] = histKtoEnd(I0, 0, k);
% compute the histogram of the image I0 without the first k pixel
[vecWithoutKPixel, histWithoutKPixel] = histKtoEnd(I0, k, k);
where:
function [vecWithoutKPixel, hist] = histKtoEnd(image, k, colorDepth)
% image to row vector
imageVec = reshape(image.', [], 1);
l = length(imageVec);
% I "delete" the first k pixel
vecWithoutKPixel = imageVec((k+1) : l-1);
vecWithoutKPixel(end+1) = imageVec(l);
% inizialization
hist = zeros(1, 2^colorDepth);
% create the vector of occurrences
for i = 0 : (2^colorDepth - 1)
grayI = (vecWithoutKPixel == i);
hist(1, i+1) = sum(grayI(:));
end
end
To display the two histograms do:
subplot(1, 2, 1);
bar(0:2^k-1, histComp, 'r');
title('Histogram of the entire image');
axis([minColor, maxColor, 0, numberOfPixels]);
subplot(1, 2, 2);
bar(0:2^k-1, histWithoutKPixel, 'r');
title('Histogram of the image without the first k pixels');
axis([minColor, maxColor, 0, numberOfPixels]);
and I get:
As you can see, the histograms are very different, yet should differ very little since the difference is only 8 pixels.
Where am I wrong?
Also in warkspace the newly created variables have these dimensions:
vecComp -> 262144 x 1 uint8
histComp -> 1 x 256 double
vecWithoutKPixel -> 65528 x 1 uint8
histWithoutKPixel -> 1 x 256 double
This is very strange. I should have:
vecComp -> 262144 x 1
vecWithoutKPixel -> 262136 x 1
Could someone help me?
Thank you
I'm working with DICOM images and the command info = dicominfo(filename) get
size = info.FileSize; % 262582;
colorType = info.ColorType; % grayscale
So I don't think that the problem is the image.
If I put a brakpoint on line vecWithoutKPixel(end+1) = imageVec(l); I get that imageVec is 262144 x 1 uint8, and:
function [vecWithoutKPixel, hist] = histKtoEnd(image, k, colorDepth)
% image to row vector
imageVec = reshape(image.', [], 1);
l = length(imageVec);
size(imageVec) % 262144 x 1
% I "delete" the first k pixel
vecWithoutKPixel = imageVec((k+1) : l-1);
vecWithoutKPixel(end+1) = imageVec(l);
% inizialization
hist = zeros(1, 2^colorDepth);
% create the vector of occurrences
for i = 0 : (2^colorDepth - 1)
grayI = (vecWithoutKPixel == i);
hist(1, i+1) = sum(grayI(:));
end
end
If I change the commands vecWithoutKPixel = imageVec((k+1) : l-1);
vecWithoutKPixel(end+1) = imageVec(l); with vecWithoutKPixel = imageVec((k+1) : l); I get that vecWithoutKPixel = [].

Creating a 'random-image' using I0=randi(255,100,100) and then running your code will produce a plot like this:
I guees this plot looks exactly like it should and the dimensions of the variables are correct as well:
vecComp 10000x1 double
vecWithoutKPixel 9992x1 double
Thus our problem is not actually your code, but your image. Your image is not really gray level valued which has been mentioned by others before. But instead of casting some variables to uint8 like #Richard suggested, you should cast your image to double. If your image is rgb valued use I0=double(rgb2gray(I0)); or if it is just uint8 for some other reason use I0=double(I0) and then pass it to the function. Hope this helps.

I believe the problem is that the image data is originally in uint8 format and gets converted to double at some point. Therefore, the line
grayI = (vecWithoutKPixel == i);
in histKtoEnd probably only works with the uint8 data ( since you compare the data with an integer).
Try adding the line
vecWithoutKPixel = uint8(vecWithoutKPixel);
to the histKtoEnd function:
function [vecWithoutKPixel, hist] = histKtoEnd(image, k, colorDepth)
% image to row vector
imageVec = reshape(image.', [], 1);
l = length(imageVec);
% I "delete" the first k pixel
vecWithoutKPixel = imageVec((k+1) : l-1);
vecWithoutKPixel(end+1) = imageVec(l);
% inizialization
hist = zeros(1, 2^colorDepth);
% create the vector of occurrences
for i = 0 : (2^colorDepth - 1)
vecWithoutKPixel = uint8(vecWithoutKPixel); % Cast to integer
grayI = (vecWithoutKPixel == i);
hist(1, i+1) = sum(grayI(:));
end
end

Related

Histogram of an image

I need to take histogram of each splited image and i want to calculate mean and variance of the splited image. here i am getting an error while i calculating the mean value..... please guide me
[h w c] = size(x);
numSplits = 3; %
sw = floor(w/numSplits); %
widths = repmat(sw, 1, numSplits-1);
widths(numSplits) = w - sum(widths);
splits = mat2cell(x, h, widths, c);
% show the splits
for ii=1:numSplits
subplot(1,numSplits,ii);
imshow(splits{ii});
g(ii)=(splits{ii});
figure, imhist(g(ii));
end
%mean
im1=g(ii);
su=mean2(im1);
mean=ceil(su);
disp('mean Value');
disp(mean)
%variance
sv=double(im1);
v = var(sv);
disp(v)
i need to get the histograms of each seperate images and i need to calculate the mean for that splitted images
I assume that x is the image you want to split and analyze and that it is the image you have linked:
First, I load the image (you have already done this, I guess, so you do not need to copy this):
x = imread('https://i.stack.imgur.com/4PAaI.png');
The following code solves your coding errors:
[h, w, c] = size(x);
numSplits = 3; %
sw = floor(w/numSplits); %
widths = repmat(sw, 1, numSplits-1);
widths(numSplits) = w - sum(widths);
splits = mat2cell(x, h, widths, c);
results = repmat(struct('mean',[], 'variance',[]),numSplits, 1);
% show and analyze the splits
for ii=1:numSplits
subplot(2,numSplits,ii);
imshow(splits{ii});
subplot(2,numSplits, ii+numSplits);
imhist(splits{ii});
results(ii).mean = mean2(splits{ii});
results(ii).variance = (std2(splits{ii})).^2;
end
The mean and variance are stored in results:
>> results(1)
ans =
struct with fields:
mean: 118.0233
variance: 1.3693e+03
>> results(2)
ans =
struct with fields:
mean: 126.1719
variance: 1.9608e+03
>> results(3)
ans =
struct with fields:
mean: 121.9004
variance: 958.3740
However, please double check that you really want to compute the stats for the combined color channels of the images and not only for, for eample, the red one.

Precompute weights for multidimensional linear interpolation

I have a non-uniform rectangular grid along D dimensions, a matrix of logical values V on the grid, and a matrix of query data points X. The number of grid points differs across dimensions.
I run the interpolation multiple times for the same grid G and query X, but for different values V.
The goal is to precompute the indexes and weights for the interpolation and to reuse them, because they are always the same.
Here is an example in 2 dimensions, in which I have to compute indexes and values every time within the loop, but I want to compute them only once before the loop. I keep the data types from my application (mostly single and logical gpuArrays).
% Define grid
G{1} = single([0; 1; 3; 5; 10]);
G{2} = single([15; 17; 18; 20]);
% Steps and edges are reduntant but help make interpolation a bit faster
S{1} = G{1}(2:end)-G{1}(1:end-1);
S{2} = G{2}(2:end)-G{2}(1:end-1);
gpuInf = 1e10;
% It's my workaround for a bug in GPU version of discretize in Matlab R2017a.
% It throws an error if edges contain Inf, realmin, or realmax. Seems fixed in R2017b prerelease.
E{1} = [-gpuInf; G{1}(2:end-1); gpuInf];
E{2} = [-gpuInf; G{2}(2:end-1); gpuInf];
% Generate query points
n = 50; X = gpuArray(single([rand(n,1)*14-2, 14+rand(n,1)*7]));
[G1, G2] = ndgrid(G{1},G{2});
for i = 1 : 4
% Generate values on grid
foo = #(x1,x2) (sin(x1+rand) + cos(x2*rand))>0;
V = gpuArray(foo(G1,G2));
% Interpolate
V_interp = interpV(X, V, G, E, S);
% Plot results
subplot(2,2,i);
contourf(G1, G2, V); hold on;
scatter(X(:,1), X(:,2),50,[ones(n,1), 1-V_interp, 1-V_interp],'filled', 'MarkerEdgeColor','black'); hold off;
end
function y = interpV(X, V, G, E, S)
y = min(1, max(0, interpV_helper(X, 1, 1, 0, [], V, G, E, S) ));
end
function y = interpV_helper(X, dim, weight, curr_y, index, V, G, E, S)
if dim == ndims(V)+1
M = [1,cumprod(size(V),2)];
idx = 1 + (index-1)*M(1:end-1)';
y = curr_y + weight .* single(V(idx));
else
x = X(:,dim); grid = G{dim}; edges = E{dim}; steps = S{dim};
iL = single(discretize(x, edges));
weightL = weight .* (grid(iL+1) - x) ./ steps(iL);
weightH = weight .* (x - grid(iL)) ./ steps(iL);
y = interpV_helper(X, dim+1, weightL, curr_y, [index, iL ], V, G, E, S) +...
interpV_helper(X, dim+1, weightH, curr_y, [index, iL+1], V, G, E, S);
end
end
I found a way to do this and posting it here because (as of now) two more people are interested. It takes only a slight modification to my original code (see below).
% Define grid
G{1} = single([0; 1; 3; 5; 10]);
G{2} = single([15; 17; 18; 20]);
% Steps and edges are reduntant but help make interpolation a bit faster
S{1} = G{1}(2:end)-G{1}(1:end-1);
S{2} = G{2}(2:end)-G{2}(1:end-1);
gpuInf = 1e10;
% It's my workaround for a bug in GPU version of discretize in Matlab R2017a.
% It throws an error if edges contain Inf, realmin, or realmax. Seems fixed in R2017b prerelease.
E{1} = [-gpuInf; G{1}(2:end-1); gpuInf];
E{2} = [-gpuInf; G{2}(2:end-1); gpuInf];
% Generate query points
n = 50; X = gpuArray(single([rand(n,1)*14-2, 14+rand(n,1)*7]));
[G1, G2] = ndgrid(G{1},G{2});
[W, I] = interpIW(X, G, E, S); % Precompute weights W and indexes I
for i = 1 : 4
% Generate values on grid
foo = #(x1,x2) (sin(x1+rand) + cos(x2*rand))>0;
V = gpuArray(foo(G1,G2));
% Interpolate
V_interp = sum(W .* single(V(I)), 2);
% Plot results
subplot(2,2,i);
contourf(G1, G2, V); hold on;
scatter(X(:,1), X(:,2), 50,[ones(n,1), 1-V_interp, 1-V_interp],'filled', 'MarkerEdgeColor','black'); hold off;
end
function [W, I] = interpIW(X, G, E, S)
global Weights Indexes
Weights=[]; Indexes=[];
interpIW_helper(X, 1, 1, [], G, E, S, []);
W = Weights; I = Indexes;
end
function [] = interpIW_helper(X, dim, weight, index, G, E, S, sizeV)
global Weights Indexes
if dim == size(X,2)+1
M = [1,cumprod(sizeV,2)];
Weights = [Weights, weight];
Indexes = [Indexes, 1 + (index-1)*M(1:end-1)'];
else
x = X(:,dim); grid = G{dim}; edges = E{dim}; steps = S{dim};
iL = single(discretize(x, edges));
weightL = weight .* (grid(iL+1) - x) ./ steps(iL);
weightH = weight .* (x - grid(iL)) ./ steps(iL);
interpIW_helper(X, dim+1, weightL, [index, iL ], G, E, S, [sizeV, size(grid,1)]);
interpIW_helper(X, dim+1, weightH, [index, iL+1], G, E, S, [sizeV, size(grid,1)]);
end
end
To do the task the whole process of interpolation ,except computing the interpolated values, should be done. Here is a solution translated from the Octave c++ source. Format of the input is the same as the frst signature of the interpn function except that there is no need to the v array. Also Xs should be vectors and should not be of the ndgrid format. Both the outputs W (weights) and I (positions) have the size (a ,b) that a is the number of neighbors of a points on the grid and b is the number of requested points to be interpolated.
function [W , I] = lininterpnw(varargin)
% [W I] = lininterpnw(X1,X2,...,Xn,Xq1,Xq2,...,Xqn)
n = numel(varargin)/2;
x = varargin(1:n);
y = varargin(n+1:end);
sz = cellfun(#numel,x);
scale = [1 cumprod(sz(1:end-1))];
Ni = numel(y{1});
index = zeros(n,Ni);
x_before = zeros(n,Ni);
x_after = zeros(n,Ni);
for ii = 1:n
jj = interp1(x{ii},1:sz(ii),y{ii},'previous');
index(ii,:) = jj-1;
x_before(ii,:) = x{ii}(jj);
x_after(ii,:) = x{ii}(jj+1);
end
coef(2:2:2*n,1:Ni) = (vertcat(y{:}) - x_before) ./ (x_after - x_before);
coef(1:2:end,:) = 1 - coef(2:2:2*n,:);
bit = permute(dec2bin(0:2^n-1)=='1', [2,3,1]);
%I = reshape(1+scale*bsxfun(#plus,index,bit), Ni, []).'; %Octave
I = reshape(1+sum(bsxfun(#times,scale(:),bsxfun(#plus,index,bit))), Ni, []).';
W = squeeze(prod(reshape(coef(bsxfun(#plus,(1:2:2*n).',bit),:).',Ni,n,[]),2)).';
end
Testing:
x={[1 3 8 9],[2 12 13 17 25]};
v = rand(4,5);
y={[1.5 1.6 1.3 3.5,8.1,8.3],[8.4,13.5,14.4,23,23.9,24.2]};
[W I]=lininterpnw(x{:},y{:});
sum(W.*v(I))
interpn(x{:},v,y{:})
Thanks to #SardarUsama for testing and his useful comments.

From image to vector and vice versa, rotated image

I read a DICOM image and for a variety of reasons, I had to turn the image matrix in a row vector.
After performing various operations on the bits of the vector, I need to reprocess the vector in a DICOM image of the same size as the original.
I've done all these steps but when I go to display the resulting image, this is rotated.
This is what I get:
That's part of the code:
function [I0, Iw] = watIns(filename, w)
I0 = dicomread(filename);
figure(1);
imshow(I0, []);
title('(1) I0 originale');
info = dicominfo(filename);
width = info.Width;
height = info.Height;
size = info.FileSize;
k = info.BitDepth;
% I extract the first k pixels and memorize their LBS in a variable S.
x = 1 : k;
y = 1;
firstKPixel = I0(x, y);
% convert in binary
firstKPixel2 = 0*firstKPixel;
for i = 1 : length(firstKPixel)
if firstKPixel(i) == 0
firstKPixel2(i) = 0;
else
firstKPixel2(i) = dec2bin(firstKPixel(i), 'left-msb');
end
end
% I take the LSB of each element in firstKPixel2 and concatenate in the string S
S = '';
for i = 1 : k
c = firstKPixel2(i, :);
s = num2str(c(end));
S = strcat(S, s);
end
% I compute the vector corresponding to I0 but without the first 0 pixels and the corresponding histogram
[vecComp, histComp] = histKtoEnd(I0, 0, k);
% I compute the vector corresponding to I0 but without the first k pixels and the corresponding histogram
[vecWithoutKPixel, histWithoutKPixel] = histKtoEnd(I0, k, k);
L = ...; % is a vector of values
% I save l_0 in the LSB of the first k pixels.
% prendo l_0, ovvero il primo elemento di L
l_0 = L(1);
l_02 = fliplr(bitget(l_0, 1:k));
% I take the LSB of each element in firstKPixel2 and I sret it to the i-th element of l0_2
for i = 1 : k
c = firstKPixel2(i, :);
c(end) = l_02(i);
firstKPixel2(i, :) = c;
end
% convert to decimal each element of firstKPixel2
for i = 1 : length(firstKPixel2)
str = int2str(firstKPixel2(i));
firstKPixel2_lsb10(i) = bin2dec(str);
end
% I set first k pixels in the image to those just modified
vecComp(1 : k) = firstKPixel2_lsb10(1 : k);
% Transform the vector image
mat = reshape(vecComp, [width, height]);
dicomwrite(mat, './I1.dcm', 'CompressionMode', 'None');
I1 = dicomread('./I1.dcm');
figure(7);
imshow(I1, []); % ROTATE IMAGE!!!
% ...
end
histKtoEnd function is:
function [vecWithoutKPixel, hist] = histKtoEnd(image, k, colorDepth)
imageVec = reshape(image.', [], 1);
l = length(imageVec);
vecWithoutKPixel = imageVec((k+1) : l-1);
vecWithoutKPixel(end+1) = imageVec(l);
hist = zeros(1, 2^colorDepth);
for i = 0 : (2^colorDepth - 1)
grayI = (vecWithoutKPixel == i);
hist(1, i+1) = sum(grayI(:));
end
end
I read here that Matlab shows images like a matrix with the first coordinates (rows) going top-down and the second (columns) left-right.
I couldn't solve, can anyone help me?
Thank you!
Somehow in the unrolling, processing and rolling of your data it seems to get transposed. You can try to find why that happens, but if you do not care, you can always just transpose the result in the end by
mat = reshape(vecComp, [width, height]).';

implementation sample of a color histogram on an rgb image without using Matlab built-in functions

I've been trying to implement a function called histogram(image) that perform the color histogram of an RGB image.
Can someone show me a sample that is easy to analyze in order to understand how does it exactly work.
I would really appreciate your help.
Here is a different algorithm for your question:
im = imread('lena.png'); % imshow(im);
histogram(im)
function histogram(im)
[rowSize, colSize, rgb] = size(im);
nshades = 256;
hist = zeros(rgb, nshades);
figure,
RGB = ['r', 'g', 'b'];
names = [{'Red Channel'}, {'Green Channel'}, {'Blue Channel'}];
x = 0 : 255;
for colour = 1 : rgb
for k = 1 : rowSize
for m = 1 : colSize
for n = 0 : (nshades - 1) % 0 - 255
if im(k, m, colour) == n
hist(colour, n + 1) = hist(colour, n + 1) + 1;
end
end
end
end
subplot(3, 1, colour)
bar(x, hist(colour, :), RGB(colour)); title(names(colour));
end
end
Here is the code which draws histogram of each color channels of an image.
I=imread('lena.png');
r=I(:,:,1);
g=I(:,:,2);
b=I(:,:,3);
totalNumofPixel=size(I,1)*size(I,2);
FrequencyofRedValues=zeros(256,1);
FrequencyofGreenValues=zeros(256,1);
FrequencyofBlueValues=zeros(256,1);
for x=0:255
FrequencyofRedValues(x+1)=size(r(r==x),1); // number of pixels whoose intensity is x
FrequencyofGreenValues(x+1)=size(g(g==x),1);
FrequencyofBlueValues(x+1)=size(b(b==x),1);
end
stem(0:255,FrequencyofRedValues,'.r');
title('Red Channel Histogram');
figure
stem(0:255,FrequencyofGreenValues,'.g');
title('Green Channel Histogram');
figure
stem(0:255,FrequencyofBlueValues,'.b');
title('Blue Channel Histogram');

Matlab figure keeps the history of the previous images

I am working on rotating image manually in Matlab. Each time I run my code with a different image the previous images which are rotated are shown in the Figure. I couldn't figure it out. Any help would be appreciable.
The code is here:
[screenshot]
im1 = imread('gradient.jpg');
[h, w, p] = size(im1);
theta = pi/12;
hh = round( h*cos(theta) + w*abs(sin(theta))); %Round to nearest integer
ww = round( w*cos(theta) + h*abs(sin(theta))); %Round to nearest integer
R = [cos(theta) -sin(theta); sin(theta) cos(theta)];
T = [w/2; h/2];
RT = [inv(R) T; 0 0 1];
for z = 1:p
for x = 1:ww
for y = 1:hh
% Using matrix multiplication
i = zeros(3,1);
i = RT*[x-ww/2; y-hh/2; 1];
%% Nearest Neighbour
i = round(i);
if i(1)>0 && i(2)>0 && i(1)<=w && i(2)<=h
im2(y,x,z) = im1(i(2),i(1),z);
end
end
end
end
x=1:ww;
y=1:hh;
[X, Y] = meshgrid(x,y); % Generate X and Y arrays for 3-D plots
orig_pos = [X(:)' ; Y(:)' ; ones(1,numel(X))]; % Number of elements in array or subscripted array expression
orig_pos_2 = [X(:)'-(ww/2) ; Y(:)'-(hh/2) ; ones(1,numel(X))];
new_pos = round(RT*orig_pos_2); % Round to nearest neighbour
% Check if new positions fall from map:
valid_pos = new_pos(1,:)>=1 & new_pos(1,:)<=w & new_pos(2,:)>=1 & new_pos(2,:)<=h;
orig_pos = orig_pos(:,valid_pos);
new_pos = new_pos(:,valid_pos);
siz = size(im1);
siz2 = size(im2);
% Expand the 2D indices to include the third dimension.
ind_orig_pos = sub2ind(siz2,orig_pos(2*ones(p,1),:),orig_pos(ones(p,1),:), (1:p)'*ones(1,length(orig_pos)));
ind_new_pos = sub2ind(siz, new_pos(2*ones(p,1),:), new_pos(ones(p,1),:), (1:p)'*ones(1,length(new_pos)));
im2(ind_orig_pos) = im1(ind_new_pos);
imshow(im2);
There is a problem with the initialization of im2, or rather, the lack of it. im2 is created in the section shown below:
if i(1)>0 && i(2)>0 && i(1)<=w && i(2)<=h
im2(y,x,z) = im1(i(2),i(1),z);
end
If im2 exists before this code is run and its width or height is larger than the image you are generating the new image will only overwrite the top left corner of your existing im2. Try initializing im2 by adding adding
im2 = zeros(hh, ww, p);
before
for z = 1:p
for x = 1:ww
for y = 1:hh
...
As a bonus it might make your code a little faster since Matlab won't have to resize im2 as it grows in the loop.