Gradient histograms in matlab - matlab

I am trying to figure out how to create an array of histogram to compare the magnitude and direction of gradient vectors of an image in matlab. I am to use sobel masks to find the gradients, so far I have:
sobel_x = [-1 -2 -1;0 0 0;1 2 1];
sobel_y = [-1 0 1;-2 0 2;-1 0 1];
gx = filter2(sobel_x,im,'same');
gy = filter2(sobel_y,im,'same');
Now I need to figure out how to create a histogram to compare it with other images.

You can take the computed gx and gy matrices and treat them as long vectors, then group them into a gradient vector that is size: 2 x (# number of elements in gx or gy)
% create the gradient vectors
grad_vector(1,:) = gx(:);
grad_vector(2,:) = gy(:);
then you can find the magnitude and direction of each gradient vector in a variety of ways, for example:
%find magnitude and direction of each gradient vector
for i=1:size(grad_vector,2);
magn(i) = norm(grad_vector(:,i));
dir(i) = atand(grad_vector(2,i)/grad_vector(1,i));
end
the histogram can then be created by deciding how to divide up the results into a number of bins. For example, you may choose to divide the direction into 4 bins and the magnitude into 3, then:
% find histograms, dividing into appropriate bins
histdir = hist(dir,4);
histmag = hist(magn,3);

Related

How to find the displacement vector between two points in a matrix?

Example:
Formula:
The difference between the two points gets the difference of the value of the received points of the matrix. If possible, could you suggest me a formula.
Minimum Distance between two points which are n-dimensional vectors in R^n can be found as below ( e.g: x= [ 1 3 5], y= [4 -4 7] 3-D points)
function result = minDistance (x, y) {
if ~isvector(x)
error('Input must be a vector')
result = sqrt(sum((x-y).^2))
end
if any additional information needed please explain the formula then solution can be fullfilled.
Based on your clarification, I think you only need a loop to do the job. The loop will go through each pixel, or point, in the picture, compare it with all other pixels and calculate the displacement vectors.
So for example, if you have a picture of 10x10, this means you have 100 pixels in the picture. For each pixel, you can calculate 99 displacement vectors. For the entire picture, you will have 99*100 displacement vectors.
% read your picture
im = imread('myImage.jpg');
imageSize = size(im);
xsize = imageSize(1);
ysize = imageSize(2);
% construct pixel matrix
pixelPosXM = repmat(1:xsize, ysize, 1);
pixelPosYM = repmat(1:ysize, 1, xsize);
% convert into array
pixelPosX = pixelPosXM(:);
pixelPosY = pixelPosYM(:);
nsize = length(pixelPosX);
for i = 1:nsize
% construct matrix for calculation
px = repmat([pixelPosX(i), pixelPosY(i)], nsize - 1, 1);
otherPixels = [pixelPosX, pixelPosY]; otherPixels(i,:) = [];
% calculate displacement vectors
displacementVectors(:,:,i) = [px - otherPixels];
end
If you are not familiar with 3-dimentional matrix, you can replace
displacementVectors(:,:,i) = [px - otherPixels];
with
displacementVectors{i} = [px - otherPixels];

How to apply a function for each of the various entries from different matrices as index?

I'm writing a function in matlab which mimics the built-in 'imwarp' function (applying geometric transformation) without using any kind of loops. i'm in the final step when i have to call my function for bi-linear interpolation for every index in final 2D image.
I have 3 arrays here , 'pts' have homogenized vectors (x,y,1) for which i interpolate and 'row' and 'cols' have x and y coordinates respectively for resultant image where interpolated intensity value would be placed.
finalImage (rows(1,:),cols(1,:))=bilinear(pts(:,:),im);
Kindly correct my syntax here to do it properly. thanks in advance.
The following is a simple implementation of applying an affine transformation to an image. Some of the matrices may be reversed because I did this from memory. I don't know exactly how you are formatting your pts array so I figure a working example is the best I can do. The interp2 function applies bilinear interpolation, the bilinear function performs the bilinear transform which describes analog filters as digital filters. This is not what you want.
P.S. You have to make sure to use the inverse transform when applying image warping (that is, define the point you want to sample in the input image for each point in the output image). If you perform the forward transform (i.e. define the point in the output image that each point in the input image maps to) then you will end up with some serious aliasing effects and potentially holes in the output image.
Hope this helps. Let me know if you have questions.
img = double(imread('rice.png'))/255;
theta = 30; % rotate 30 degrees
R = [cosd(theta) -sind(theta) 0; ...
sind(theta) cosd(theta) 0; ...
0 0 1];
sx = 15; % skew by 15 degrees in x
Skx = [1 tand(sx) 0; ...
0 1 0; ...
0 0 1];
% Translate by 1/2 size of image
tx = -size(img, 2)/2;
ty = -size(img, 1)/2;
T = [1 0 tx; ...
0 1 ty; ...
0 0 1];
% Scale image down by 1/2
sx = 0.5;
sy = 0.5;
S = [sx 0 0; ...
0 sy 0; ...
0 0 1];
% translate, scale, rotate, skew, then translate back
A = inv(T)*Skx*R*S*T;
% create meshgrid points
[x, y] = meshgrid(1:size(img,2), 1:size(img,1));
% reshape so we can apply matrix op
V = [reshape(x, 1, []); reshape(y, 1, []); ones(1, numel(x))];
Vq = inv(A)*V;
% probably not necessary for these transformations but project back to the z=1 plane
Vq(1,:) = Vq(1,:) ./ V(3,:);
Vq(2,:) = Vq(2,:) ./ V(3,:);
% reshape back into a meshgrid
xq = reshape(Vq(1,:), size(img));
yq = reshape(Vq(2,:), size(img));
% use interp2 to perform bilinear interpolation
imgnew = interp2(x, y, img, xq, yq);
% show the resulting image
imshow(imgnew);

Create a pulse train from a vector

Is there an easy way (a function or something like that) to create a pulse train from a vector in MATLAB? The vector has 1 and -1 as its values. The pulse should be the same.
For example take the samples of this vector plotted in the above figure and make pulses like here:
stem(vector) is a quick and simple way to visualize pulse data. If you're looking to visualize pulses in a more continuous way (either edges or centered) you can implement either in simple for loops.
Centered:
vec = [0 0 1 0 0 0 -1 0]; % vector
dom = [1:length(vec)]; % domain
% plot (dom,vec)
% edge plot
der = [0 diff(vec~=0)];
for i = length(der):-1:2
if der(i) ~= 0
vec = [vec(1:i-1),vec(i-1:end)]
dom = [dom(1:i),dom(i:end)]
end
end
% plot (dom,vec)
% centered plot
width = 1
for i = length(vec)-1:-1:2
vec = [vec(1:i-1),vec(i),vec(i),vec(i+1:end)]
dom = [dom(1:i-1),dom(i)-width/2,dom(i)+width/2,dom(i+1:end)]
end
% plot (dom,vec)

How to plot colorful histogram type constellation diagram in Matlab

I would like to plot constellation diagram similar to the figure below.
.
My approach is something like this
clc;
clear all;
close all;
N=30000;
M=16;
Sr=randint(N,1,[0,(M-1)]);
S=qammod(Sr,16,0,'gray'); S=S(:);
Noisy_Data=awgn(S,20,'measured'); % Add AWGN
figure(2)
subplot(1,2,1)
plot(S,'o','markersize',10);
grid on
subplot(1,2,2)
plot(Noisy_Data,'.');
grid on
May you assist me to make necessary modification to get graph similar to the figure attached above. Thank you.
The first thing to do would be to compute a 2D histogram of your data. This can be done with the following:
% Size of the histogram matrix
Nx = 160;
Ny = 160;
% Choose the bounds of the histogram to match min/max of data samples.
% (you could alternatively use fixed bound, e.g. +/- 4)
ValMaxX = max(real(Noisy_Data));
ValMinX = min(real(Noisy_Data));
ValMaxY = max(imag(Noisy_Data));
ValMinY = min(imag(Noisy_Data));
dX = (ValMaxX-ValMinX)/(Nx-1);
dY = (ValMaxY-ValMinY)/(Ny-1);
% Figure out which bin each data sample fall into
IdxX = 1+floor((real(Noisy_Data)-ValMinX)/dX);
IdxY = 1+floor((imag(Noisy_Data)-ValMinY)/dY);
H = zeros(Ny,Nx);
for i=1:N
if (IdxX(i) >= 1 && IdxX(i) <= Nx && IdxY(i) >= 1 && IdxY(i) <= Ny)
% Increment histogram count
H(IdxY(i),IdxX(i)) = H(IdxY(i),IdxX(i)) + 1;
end
end
Note that you can play around with parameters Nx and Ny to adjust the desired resolution of the plot. Keep in mind that the larger the histogram, the more data samples (controlled by the parameter N of your simulation) you'll need to have enough data in the histogram bins to avoid getting a spotty plot.
You can then plot the histogram as a color map based on this answer. In doing so, you likely would want to add a constant to all non-zero bins of the histogram so that the white band is reserved for zero valued bins. This would provide a better correlation with the scatter plot. This can be done with:
% Colormap that approximate the sample figures you've posted
map = [1 1 1;0 0 1;0 1 1;1 1 0;1 0 0];
% Boost histogram values greater than zero so they don't fall in the
% white band of the colormap.
S = size(map,1);
Hmax = max(max(H));
bias = (Hmax-S)/(S-1);
idx = find(H>0);
H(idx) = H(idx) + bias;
% Plot the histogram
pcolor([0:Nx-1]*dX+ValMinX, [0:Ny-1]*dY+ValMinY, H);
shading flat;
colormap(map);
After increasing N to 1000000, this gives the following plot for the data generated according to your sample:

Ellipse around the data in MATLAB

I would like to reproduce the following figure in MATLAB:
There are two classes of points with X and Y coordinates. I'd like to surround each class with an ellipse with one parameter of standard deviation, which determine how far the ellipse will go along the axis.
The figure was created with another software and I don't exactly understand how it calculates the ellipse.
Here is the data I'm using for this figure. The 1st column is class, 2nd - X, 3rd - Y. I can use gscatter to draw the points itself.
A = [
0 0.89287 1.54987
0 0.69933 1.81970
0 0.84022 1.28598
0 0.79523 1.16012
0 0.61266 1.12835
0 0.39950 0.37942
0 0.54807 1.66173
0 0.50882 1.43175
0 0.68840 1.58589
0 0.59572 1.29311
1 1.00787 1.09905
1 1.23724 0.98834
1 1.02175 0.67245
1 0.88458 0.36003
1 0.66582 1.22097
1 1.24408 0.59735
1 1.03421 0.88595
1 1.66279 0.84183
];
gscatter(A(:,2),A(:,3),A(:,1))
FYI, here is the SO question on how to draw ellipse. So, we just need to know all the parameters to draw it.
Update:
I agree that the center can be calculated as the means of X and Y coordinates. Probably I have to use principal component analysis (PRINCOMP) for each class to determine the angle and shape. Still thinking...
Consider the code:
%# generate data
num = 50;
X = [ mvnrnd([0.5 1.5], [0.025 0.03 ; 0.03 0.16], num) ; ...
mvnrnd([1 1], [0.09 -0.01 ; -0.01 0.08], num) ];
G = [1*ones(num,1) ; 2*ones(num,1)];
gscatter(X(:,1), X(:,2), G)
axis equal, hold on
for k=1:2
%# indices of points in this group
idx = ( G == k );
%# substract mean
Mu = mean( X(idx,:) );
X0 = bsxfun(#minus, X(idx,:), Mu);
%# eigen decomposition [sorted by eigen values]
[V D] = eig( X0'*X0 ./ (sum(idx)-1) ); %#' cov(X0)
[D order] = sort(diag(D), 'descend');
D = diag(D);
V = V(:, order);
t = linspace(0,2*pi,100);
e = [cos(t) ; sin(t)]; %# unit circle
VV = V*sqrt(D); %# scale eigenvectors
e = bsxfun(#plus, VV*e, Mu'); %#' project circle back to orig space
%# plot cov and major/minor axes
plot(e(1,:), e(2,:), 'Color','k');
%#quiver(Mu(1),Mu(2), VV(1,1),VV(2,1), 'Color','k')
%#quiver(Mu(1),Mu(2), VV(1,2),VV(2,2), 'Color','k')
end
EDIT
If you want the ellipse to represent a specific level of standard deviation, the correct way of doing is by scaling the covariance matrix:
STD = 2; %# 2 standard deviations
conf = 2*normcdf(STD)-1; %# covers around 95% of population
scale = chi2inv(conf,2); %# inverse chi-squared with dof=#dimensions
Cov = cov(X0) * scale;
[V D] = eig(Cov);
I'd try the following approach:
Calculate the x-y centroid for the center of the ellipse (x,y in the linked question)
Calculate the linear regression fit line to get the orientation of the ellipse's major axis (angle)
Calculate the standard deviation in the x and y axes
Translate the x-y standard deviations so they're orthogonal to the fit line (a,b)
I'll assume there is only one set of points given in a single matrix, e.g.
B = A(1:10,2:3);
you can reproduce this procedure for each data set.
Compute the center of the ellipsoid, which is the mean of the points. Matlab function: mean
Center your data. Matlab function bsxfun
Compute the principal axis of the ellipsoid and their respective magnitude. Matlab function: eig
The successive steps are illustrated below:
Center = mean(B,1);
Centered_data = bsxfun(#minus,B,Center);
[AX,MAG] = eig(Centered_data' * Centered_data);
The columns of AX contain the vectors describing the principal axis of the ellipsoid while the diagonal of MAG contains information on their magnitude.
To plot the ellipsoid, scale each principal axis with the square root of its magnitude.