MATLAB - How to calculate uniformity of an image - matlab

I want to get uniformity value of an image intensity. In the description sheet it described as the following:
General Description
If Z is a random variable indicating image intensity, its nth moment around the mean is
where m is the mean of Z, p(.) its histogram and L is the number of intensity levels.
For Uniformity
Uniformity, defined as
uniformity's maximum value is reached when all intensity levels are equal.
What I do not understand and I want to know is p and L actually. I do not know how to calculate them. Additionally, what is (.) for, in p(.)?
EDIT
% V component of HSV image, contains 0~1 values in double type
% size(Iv) = 960 720
Z = Iv(:);
IL = unique(Z); % Get all intensity levels
noinle = numel(IL); % Number of intensity levels
p = hist(Ivc, noinle); % Histogram
U = 0;
for i = 1:noinle
U = U + sum( p(i,:).^2 );
end
This operation results very big numbers which are not compatible in the sample dataset given. They all are double numbers between 0 and 1.

Assuming your image is stored in an array called Img, you can obtain L and p with the following code:
IL = unique(Img(:)); % Get all intensity levels
L = numel(IL); % Number of intensity levels
p = histogram(Img, IL); % Histogram
Best,

Unless its defined in the paper otherwise generally these are the definitions:
p is the histogram of the image. What this is a break down of the colors in the image put into buckets. In matlab the function for this is h = histogram(x,nbins).
L is the number of buckets. Generally this is something you decide based on your application.

Related

Calculate the contact length between segments of image in Matlab

I have images made of four colors. Each color represents a specific matter phase. I can segment the image based on the color and calculate the perimeter of the segmented images. Now, I need to calculate the contact length between different phases. An example of the image is shown here. For example, the contact length between the blue phase and the yellow phase is very small, while blue and gray phases have significant contact.
% aa is the image
oil = (aa(:,:,3)==255);
rock =(aa(:,:,2)==179);
gas =(aa(:,:,2)==255);
water =(aa(:,:,2)==0 && aa(:,:,3)==0);
O = bwboundaries(oil);
R = bwboundaries(rock);
G = bwboundaries(gas);
W = bwboundaries(water);
A brute force way would be to iterate through each pixel in your image and based on that pixel value, and the value of the pixel to the right of it, increment a variable representing that phase transition contact length count, if there is a phase transition. Then do the same for the value below your pixel. Do this for every pixel in the image, except edge conditions.
A more efficient way would be to do rows and columns at a time, and increment counters as you do this.
Or you could make multiple matrices of your image, shifted by one pixel, and do comparisons looking for your phase transitions which end up with binary matrix results and simply sum these result binary matrices
Here is the final code that I eventual wrote. The results look correct.
% aa is the image
oil = (aa(:,:,3)==255);
rock =(aa(:,:,2)==179);
gas =(aa(:,:,2)==255);
water =(aa(:,:,2)==0 && aa(:,:,3)==0);
phases(1,:,:)=RockBW;
phases(2,:,:)=WaterBW;
phases(3,:,:)=OilBW;
phases(4,:,:)=GasBW;
outMat = ContactMatrix(phases);
The function ContactMatrix is shown in following:
function [ContactMat] = ContactMatrix(phases)
%CONTACTMATRIX measure the contact area between diferent phases
% The output is a 2D matrix which shows the lengths
% Phase1, Phase2, Phase 3
%phase1 L1 L2 L4
%Phase2 L2 L3 L5
%Phase3 L4 L5 L6
% L1 is zero
% L2 is the contact area of Phase1 and Phase2
nph = size(phases,1);
imSize = size(phases(1,:,:));
xmax =imSize(2);
ymax = imSize(3);
% Idealy we need a check for all sizes :)
ContactMat = zeros(nph);
for i=1:1:nph
counts = zeros(1,nph);
dd2=bwmorph(squeeze(phases(i,:,:)),'dilate',1);
B = bwboundaries(dd2);
nB = size(B,1);
coefs=1:1:nph;
coefs(i)=[];
for j=1:1:nB
fd = B{j};
% Ignore the points at boundary of image
fd(fd(:,1)==1 | fd(:,1)==xmax | fd(:,2)==1 | fd(:,2)==ymax,:)=[];
nL = size(fd,1);
for k=1:1:nL(1)
%bufCheck=false(nph-1,1);
mat=fd(k,1) + (fd(k,2)-1)*xmax;
bufCheck = phases(coefs,mat);
counts(coefs)=counts(coefs)+bufCheck';
end
end
ContactMat(i,coefs)=counts(coefs);
end
ContactMat = 0.5*(ContactMat+ContactMat');
end

Two-dimensional matched filter

I want to implement two dimensional matched filter for blood vessel extraction according to the paper "Detection of Blood Vessels in Retinal Images Using Two-Dimensional Matched Filters" by Chaudhuri et al., IEEE Trans. on Medical Imaging, 1989 (there's a PDF on the author's web site).
A brief discription is that blood vessel's cross-section has a gaussian distribution and therefore I want to use gaussian matched filter to increase SNR. Such a kernel may be mathematically expressed as:
K(x,y) = -exp(-x^2/2*sigma^2) for |x|<3*sigma, |y|<L/2
L here is the length of vessel with fixed orientation. Experimentally sigma=1.5 and L = 7.
My MATLAB code for this part is:
s = 1.5; %sigma
t = -3*s:3*s;
theta=0:15:165; %different rotations
%one dimensional kernel
x = 1/sqrt(6*s)*exp(-t.^2/(2*s.^2));
L=7;
%two dimensional gaussian kernel
x2 = repmat(x,L,1);
Consider the response of this filter for a pixel belonging to the background retina. Assuming the background to have constant intensity with zero mean additive Gaussian white noise, the expected value of the filter output should ideally be zero. The convolution kernel is, therefore, modified by subtracting the mean value of s(t) from the function itself. The mean value of the kernel is determined as: m = Sum(K(x,y))/(number of points).
Thus, the convolutional mask used in this algorithm is given by: K(x, y) = K(x,y) - m.
My MATLAB code:
m = sum(x2(:))/(size(x2,1)*size(x2,2));
x2 = x2-m;
A vessel may be oriented at any angle 0<theta<180 and the matched filter response is maximum when when it is aligned at theta+- 90 (cross-section distribution is gaussian not the vessel itself).
Thus we need to rotate the matched filter 12 times with 15 degree increment.
My MATLAB code is attached here but I don't get a desirable result. Any help is appreciated.
%apply rotated matched filter on image
r = {};
for k = 1:12
x3=imrotate(x2,theta(k),'crop');%figure;imagesc(x3);colormap gray;
r{k}=conv2(img,x3);
end
w=[];h = zeros(584,565);
for i = 1:565
for j = 1:584
for k = 1:32
w= [w ,r{k}(j,i)];
end
h(j,i)=max(abs(w));
w = [];
end
end
%show result
figure('Name','after matched filter');imagesc(h);colormap gray
For rotation I used imrotate which seems more sensible to me but in the paper it is different: suppose p=[x,y] be a discrete point in the kernel. To compute coefficients in the rotated kernel we have [u,v] = p*Rotation_Matrix.
Rotation_Matrix=[cos(theta),sin(theta);-sin(theta),cos(theta)]
And the kernel is:
K(x,y) = -exp(-u^2/2*s^2)
But the new kernel doesn't have a gaussian shape anymore. Using imrotate preserves gaussian shape. So what is the benefit of using Rotation matrix?
Input image is:
Output:
Matched filtering helps increase SNR but background noise is amplified too.
Am I right to use imrotate to rotate the kernel? My main problem is with rotation matrix that why and what is the right code to implement it.
The reason to build the filter from its analytic expression for each rotation, rather than using imrotate, is that the filter extent is not circular, and therefore rotating brings in "new" pixel values and pushes some other pixels out of the kernel. Furthermore, rotating a kernel constructed as here (smooth transition along one direction, step edge along the other dimension) requires different interpolation methods along each dimension, which imrotate cannot do. The resulting rotated kernel will always be wrong.
Both these issues can be easily seen when displaying the kernel you make together with two rotated versions:
This display brings an additional issues to the front: the kernel is not centered on a pixel, causing it to shift the output by half a pixel.
Note also that, when subtracting the mean, it is important that this mean be computed only over the original domain of the filter, and that any zeros used to pad this domain to a rectangular shape remain zero (these should not become negative).
The rotated kernels can be constructed as follows:
m = max(ceil(3*s),(L-1)/2);
[x,y] = meshgrid(-m:m,-m:m); % non-rotated coordinate system, contains (0,0)
t = pi/6; % angle in radian
u = cos(t)*x - sin(t)*y; % rotated coordinate system
v = sin(t)*x + cos(t)*y; % rotated coordinate system
N = (abs(u) <= 3*s) & (abs(v) <= L/2); % domain
k = exp(-u.^2/(2*s.^2)); % kernel
k = k - mean(k(N));
k(~N) = 0; % set kernel outside of domain to 0
This is the result for the three rotations used in the example above (the grey around the edges of the kernel corresponds to the value 0, the black pixels have a negative value):
Another issue is that you use conv2 with the default 'full' output shape, you should be using 'same' here, so that the output of the filter matches the input.
Note that, instead of computing all filter responses, and computing the max afterwards, it is much easier to compute the max as you compute each filter response. All of the above leads to the following code:
img = im2double(rgb2gray(img));
s = 1.5; %sigma
L = 7;
theta = 0:15:165; %different rotations
out = zeros(size(img));
m = max(ceil(3*s),(L-1)/2);
[x,y] = meshgrid(-m:m,-m:m); % non-rotated coordinate system, contains (0,0)
for t = theta
t = t / 180 * pi; % angle in radian
u = cos(t)*x - sin(t)*y; % rotated coordinate system
v = sin(t)*x + cos(t)*y; % rotated coordinate system
N = (abs(u) <= 3*s) & (abs(v) <= L/2); % domain
k = exp(-u.^2/(2*s.^2)); % kernel
k = k - mean(k(N));
k(~N) = 0; % set kernel outside of domain to 0
res = conv2(img,k,'same');
out = max(out,res);
end
out = out/max(out(:)); % force output to be in [0,1] interval that MATLAB likes
imwrite(out,'so_result.png')
I get the following output:

How to quantify pixel changes in a short video

I have been using short (20s) videos as stimulus material in a recent study. I would now like to compare the videos regarding the amount of movements that each video contains.
This is my code until now:
VidObj = VideoReader(video_file);
VidFrames = read(VidObj);
returns 4D Matrix = 2d array of 2d images = a x b x c x VidNoFrames
VidNoFrames = VidObj.NumberofFrames;
VidHeight = VidObj.Height;
VidWidth = VidObj.Width;
for k = 1 : VidNoFrames
k mov(k).cdata = VidFrames(:,:,:,k); %720 x 1280 x 3
end
Now I guess the next step would constructing the loop for correlation/SSD. However, cdata is still 3D (height x width x 3). I do not understand what this third dimension is and how to go on comparing the images... Thanks so much for your help!
Thanks a lot!
Christine
You might want to use correlation to compare 2 images, or in your case I would opt for computing the Sum Square Intensity Difference, which tells you in a more quantitative way maybe how much pixel intensity differs from one image to another. Here is a simple example for both cases;
clear
clc
%// Correlation coefficient. Close to 1 == more similarity
A = imread('coins.png');
B = medfilt2(A);
CorrCoeff = corr2(A,B)
%// Sum Square Intensity Difference
SquareIntDiff = (B-A).^2; %//Compute the square of the pixel intensity difference.
SSID = sum(SquareIntDiff(:)) %// Sum it to get the SSID. A value of 0 means that both images are similar in terms of pixel intensity.
%// Using sum(sum(SquareIntDiff)) would yield the same result in a less efficient manner. MATLAB takes the sum along the columns and then another time to get a single value.
CorrCoeff =
0.9964
SSID =
550746
Of course you can easily implement this in a loop to compare consecutive frames in your video. Hope that helps you a bit :)

matlab padding fft changing frequencies

I'm trying to compare Matlab fft of a cosinus with two different zero padding. I thought that it wouldn't change the frequency response but when I superimpose the two curves, the frequencies are not the same. I suppose that there is something wrong with the way I do my two fft?
Fe = 8000;
F = 1680;
w = 2*pi*F;
N = 50;
P = 50;
T = 1/Fe;
t = (0:T:P*T);
x = real(exp(i*w*t))
x_reduced = x(1:P)
X = fft(x_reduced,N)
N = 1000;
Y = fft(x_reduced,N)
plot(abs(Y))
hold on
plot(abs(X),'*')
Thanks in advance
plot((0:999)/1000*Fe,abs(Y))
hold on
plot((0:49)/50*Fe,abs(X),'*')
You may need to align the frequencies of both cases.
When you pad the FFT you change the resolution of each bin (you are effectively interpolating between bins), so while the corresponding frequencies are still the same of course the actual mapping to bin indices will change. If you were to scale the two FFT plots so that the horizontal axes for both line up (i.e. bin 0 aligned on both, and bin 50 aligned with bin 1000) then the plots would match.

Matlab - Trying to use vectors with grid coordinates and value at each point for a color plot

I'm trying to make a color plot in matlab using output data from another program. What I have are 3 vectors indicating the x-position, y-yposition (both in milliarcseconds, since this represents an image of the surroundings of a black hole), and value (which will be assigned a color) of every point in the desired image. I apparently can't use pcolor, because the values which indicate the color of each "pixel" are not in a matrix, and I don't know a way other than meshgrid to create a matrix out of the vectors, which didn't work due to the size of the vectors.
Thanks in advance for any help, I may not be able to reply immediately.
If we make no assumptions about the arrangement of the x,y coordinates (i.e. non-monotonic) and the sparsity of the data samples, the best way to get a nice image out of your vectors is to use TriScatteredInterp. Here is an example:
% samplesToGrid.m
function [vi,xi,yi] = samplesToGrid(x,y,v)
F = TriScatteredInterp(x,y,v);
[yi,xi] = ndgrid(min(y(:)):max(y(:)), min(x(:)):max(x(:)));
vi = F(xi,yi);
Here's an example of taking 500 "pixel" samples on a 100x100 grid and building a full image:
% exampleSparsePeakSamples.m
x = randi(100,[500 1]); y = randi(100,[500 1]);
v = exp(-(x-50).^2/50) .* exp(-(y-50).^2/50) + 1e-2*randn(size(x));
vi = samplesToGrid(x,y,v);
imagesc(vi); axis image
Gordon's answer will work if the coordinates are integer-valued, but the image will be spare.
You can assign your values to a matrix based on the x and y coordinates and then use imagesc (or a similar function).
% Assuming the X and Y coords start at 1
max_x = max(Xcoords);
max_y = max(Ycoords);
data = nan(max_y, max_x); % Note the order of y and x
indexes = sub2ind(size(data), max_y, max_x);
data(indexes) = Values;
imagesc(data); % note that NaN values will be colored with the minimum colormap value