Unexpected result when calculating mean curvature in MatLab - matlab

I am running simulations of a protein/membrane system, and want to quantify the degree of membrane deformation. I have averaged the membrane surface on a grid during the simulation, which results in a text file with three columns, containing the x, y, and z points of the membrane. I then convert this information to a mesh surface in matlab, which I then use to calculate the gaussian and/or mean curvature. The problem is, I'm getting similar values at the very beginning of the simulation, when the surface (membrane) is very flat, and at the end, when it is completely deformed. Unless I'm misunderstanding what curvature is, this is not correct and I believe I am doing something wrong in the matlab portion of this process. Here's the script where I loop over many frames (each of which is a different file containing x,y,z coordinates of the averaged membrane) and convert it to a mesh:
https://pastebin.com/reqWAz01
for i = 0:37
file = strcat('cg-topmem_pos-', num2str(i), '.out');
A = load(file);
x = A(:,1);
y = A(:,2);
z = A(:,3);
xv = linspace(min(x), max(x), 20);
yv = linspace(min(y), max(y), 20);
[X,Y] = meshgrid(xv, yv);
Z = griddata(x,y,z,X,Y);
[K,H,Pmax,Pmin] = surfature(X,Y,Z);
M = max(max(H))
if i == 0
fileID = fopen('Average2-NoTMHS-5nmns.txt', 'a');
fprintf(fileID, '%f %f\n',M);
fclose(fileID);
else
fileID = fopen('Average2-NoTMHS-5nmns.txt', 'a');
fprintf(fileID, '\n%f %f\n',M);
fclose(fileID);
end
end
Then using the following calculates curvature:
https://pastebin.com/5D21PdBQ
function [K,H,Pmax,Pmin] = surfature(X,Y,Z),
% SURFATURE - COMPUTE GAUSSIAN AND MEAN CURVATURES OF A SURFACE
% [K,H] = SURFATURE(X,Y,Z), WHERE X,Y,Z ARE 2D ARRAYS OF POINTS ON THE
% SURFACE. K AND H ARE THE GAUSSIAN AND MEAN CURVATURES, RESPECTIVELY.
% SURFATURE RETURNS 2 ADDITIONAL ARGUMENTS,
% [K,H,Pmax,Pmin] = SURFATURE(...), WHERE Pmax AND Pmin ARE THE MINIMUM
% AND MAXIMUM CURVATURES AT EACH POINT, RESPECTIVELY.
% First Derivatives
[Xu,Xv] = gradient(X);
[Yu,Yv] = gradient(Y);
[Zu,Zv] = gradient(Z);
% Second Derivatives
[Xuu,Xuv] = gradient(Xu);
[Yuu,Yuv] = gradient(Yu);
[Zuu,Zuv] = gradient(Zu);
[Xuv,Xvv] = gradient(Xv);
[Yuv,Yvv] = gradient(Yv);
[Zuv,Zvv] = gradient(Zv);
% Reshape 2D Arrays into Vectors
Xu = Xu(:); Yu = Yu(:); Zu = Zu(:);
Xv = Xv(:); Yv = Yv(:); Zv = Zv(:);
Xuu = Xuu(:); Yuu = Yuu(:); Zuu = Zuu(:);
Xuv = Xuv(:); Yuv = Yuv(:); Zuv = Zuv(:);
Xvv = Xvv(:); Yvv = Yvv(:); Zvv = Zvv(:);
Xu = [Xu Yu Zu];
Xv = [Xv Yv Zv];
Xuu = [Xuu Yuu Zuu];
Xuv = [Xuv Yuv Zuv];
Xvv = [Xvv Yvv Zvv];
% First fundamental Coeffecients of the surface (E,F,G)
E = dot(Xu,Xu,2);
F = dot(Xu,Xv,2);
G = dot(Xv,Xv,2);
m = cross(Xu,Xv,2);
p = sqrt(dot(m,m,2));
n = m./[p p p];
% Second fundamental Coeffecients of the surface (L,M,N)
L = dot(Xuu,n,2);
M = dot(Xuv,n,2);
N = dot(Xvv,n,2);
[s,t] = size(Z);
% Gaussian Curvature
K = (L.*N - M.^2)./(E.*G - F.^2);
K = reshape(K,s,t);
% Mean Curvature
H = (E.*N + G.*L - 2.*F.*M)./(2*(E.*G - F.^2));
H = reshape(H,s,t);
% Principal Curvatures
Pmax = H + sqrt(H.^2 - K);
Pmin = H - sqrt(H.^2 - K);
Any help would be greatly appreciated. I'm afraid that there is some issue between how the mesh is created and how curvature is calculated, but I am not matlab literate and could use some help. Thanks very much.

Related

Ordered Isoline Calculation from 3D Triangular Surface in MATLAB

I need to extract the isoline coordinates of a 4D variable from a 3D surface defined using a triangulated mesh in MATLAB. I need the isoline coordinates to be a ordered in such a manner that if they were followed in order they would trace the path i.e. the order of the points a 3D printer would follow.
I have found a function that can calculate the coordinates of these isolines (see Isoline function here) but the problem is this function does not consider the isolines to be joined in the correct order and is instead a series of 2 points separated by a Nan value. This makes this function only suitable for visualisation purposes and not the path to follow.
Here is a MWE of the problem of a simplified problem, the surface I'm applying it too is much more complex and I cannot share it. Where x, y and z are nodes, with TRI providing the element connectivity list and v is the variable of which I want the isolines extracted from and is not equal to z.
If anyone has any idea on either.....
A function to extract isoline values in the correct order for a 3D tri mesh.
How to sort the data given by the function Isoline so that they are in the correct order.
.... it would be very much appreciated.
Here is the MWE,
% Create coordinates
[x y] = meshgrid( -10:0.5:10, -10:0.5:10 );
z = (x.^2 + y.^2)/20; % Z height
v = x+y; % 4th dimension value
% Reshape coordinates into list to be converted to tri mesh
x = reshape(x,[],1); y = reshape(y,[],1); z = reshape(z,[],1); v = reshape(v,[],1);
TRI = delaunay(x,y); % Convertion to a tri mesh
% This function calculates the isoline coordinates
[xTows, yTows, zTows] = IsoLine( {TRI,[x, y, z]}, v, -18:2:18);
% Plotting
figure(1); clf(1)
subplot(1,2,1)
trisurf(TRI,x,y,z,v)
hold on
for i = 1:size(xTows,1)
plot3( xTows{i,1}, yTows{i,1}, zTows{i,1}, '-k')
end
hold off
shading interp
xlabel('x'); ylabel('y'); zlabel('z'); title('Isolines'), axis equal
%% This section is solely to show that the isolines are not in order
for i = 1:size(xTows,1)
% Arranging data into colums and getting rid of Nans that appear
xb = xTows{i,1}; yb = yTows{i,1}; zb = zTows{i,1};
xb = reshape(xb, 3, [])'; xb(:,3) = [];
yb = reshape(yb, 3, [])'; yb(:,3) = [];
zb = reshape(zb, 3, [])'; zb(:,3) = [];
subplot(1,2,2)
trisurf(TRI,x,y,z,v)
shading interp
view(2)
xlabel('x'); ylabel('y'); zlabel('z'); title('Plotting Isolines in Order')
axis equal; axis tight; hold on
for i = 1:size(xb,1)
plot3( [xb(i,1) xb(i,2)], [yb(i,1) yb(i,2)], [zb(i,1) zb(i,2)], '-k')
drawnow
end
end
and here is the function Isoline, which I have slightly adpated.
function [xTows, yTows, zTows] = IsoLine(Surf,F,V,Col)
if length(Surf)==3 % convert mesh to triangulation
P = [Surf{1}(:) Surf{2}(:) Surf{3}(:)];
Surf{1}(end,:) = 1i;
Surf{1}(:,end) = 1i;
i = find(~imag(Surf{1}(:)));
n = size(Surf{1},1);
T = [i i+1 i+n; i+1 i+n+1 i+n];
else
T = Surf{1};
P = Surf{2};
end
f = F(T(:));
if nargin==2
V = linspace(min(f),max(f),22);
V = V(2:end-1);
elseif numel(V)==1
V = linspace(min(f),max(f),V+2);
V = V(2:end-1);
end
if nargin<4
Col = 'k';
end
H = NaN + V(:);
q = [1:3 1:3];
% -------------------------------------------------------------------------
% Loop over iso-values ----------------------------------------------------
xTows = [];
yTows = [];
zTows = [];
for k = 1:numel(V)
R = {[],[]};
G = F(T) - V(k);
C = 1./(1-G./G(:,[2 3 1]));
f = unique(T(~isfinite(C))); % remove degeneracies by random perturbation
F(f) = F(f).*(1+1e-12*rand(size(F(f)))) + 1e-12*rand(size(F(f)));
G = F(T) - V(k);
C = 1./(1-G./G(:,[2 3 1]));
C(C<0|C>1) = -1;
% process active triangles
for i = 1:3
f = any(C>=0,2) & C(:,i)<0;
for j = i+1:i+2
w = C(f,q([j j j]));
R{j-i} = [R{j-i}; w.*P(T(f,q(j)),:)+(1-w).*P(T(f,q(j+1)),:)];
end
end
% define isoline
for i = 1:3
X{i} = [R{1}(:,i) R{2}(:,i) nan+R{1}(:,i)]';
% X{i} = [R{1}(:,i) R{2}(:,i)]'; % Changed by Matt
X{i} = X{i}(:)';
end
% plot isoline
if ~isempty(R{1})
% hold on
% H(k) = plot3(X{1},X{2},X{3},Col);
% Added by M.Thomas
xTows{k,1} = X{1};
yTows{k,1} = X{2};
zTows{k,1} = X{3};
end
end
What you will notice is that the isolines (xTows, yTows and zTows) are not in order there "jump around" when plotted sequentially. I need to sort the tows so that they give a smooth plot in order.

Output of streamline in Matlab is empty

I want to use streamline to show a vector field. The vector field is singular in a point. I want to remove regions near the singularity (fo example regions which their distance to singularity is less than 1). I wrote below code but it doesn't show anything. Could anyone help me?
clear all;
close all;
r1 = 1; r2 = 5; % Radii of your circles
x_0 = 0; y_0 = 0; % Centre of circles
[x,y] = meshgrid(x_0-r2:0.2:x_0+r2,y_0-r2:0.2:y_0+r2); % meshgrid of points
idx = ((x-x_0).^2 + (y-y_0).^2 > r1^2 & (x-x_0).^2 + (y-y_0).^2 < r2^2);
x = sort(x(idx));
[x, index] = unique(x);
y = sort(y(idx));
[y, index] = unique(y);
U=cos(x)/sqrt(x.^2+y.^2);
V=sin(x)/sqrt(x.^2+y.^2);
streamslice(x,y,U,V);
The problem with your code is that U and V are all zeros, so you get white space. The reason for that is that you don't use elementwise division with ./. So as a first step you should write:
U = cos(x)./sqrt(x.^2+y.^2);
V = sin(x)./sqrt(x.^2+y.^2);
Now U and V are not zeros but are also not matrices anymore, so they are not a valid input for streamslice. The reason for that is that x and y are converted to vectors when calling:
x = sort(x(idx));
y = sort(y(idx));
My guess is that you can remove all this indexing, and simply write:
r1 = 1; r2 = 5; % Radii of your circles
x_0 = 0; y_0 = 0; % Centre of circles
[x,y] = meshgrid(x_0-r2:0.2:x_0+r2,y_0-r2:0.2:y_0+r2); % meshgrid of points
U = cos(x)./sqrt(x.^2+y.^2);
V = sin(x)./sqrt(x.^2+y.^2);
streamslice(x,y,U,V);
so you get:
I think you misunderstood the concept of streamslice. Is this you expecting?
close all;
r1 = 1; r2 = 5; % Radii of your circles
x_0 = 0; y_0 = 0; % Centre of circles
[xx,yy] = meshgrid(x_0-r2:0.2:x_0+r2,y_0-r2:0.2:y_0+r2); % meshgrid of points
% idx = ((xx-x_0).^2 + (yy-y_0).^2 > r1^2 & (xx-x_0).^2 + (yy-y_0).^2 < r2^2);
% x = sort(xx(idx));
% [x, index] = unique(x);
% y = sort(yy(idx));
% [y, index] = unique(y);
U=cos(xx)./sqrt(xx.^2+yy.^2);
V=sin(xx)./sqrt(xx.^2+yy.^2);
streamslice(xx,yy,U,V);

Providing correct inputs for surface curvature calculation

I want to calculate the mean and Gaussian curvatures of some points in a point cloud.
I have x,y,z, that are coordinates and are 1d arrays. I want to use the below code src but in the input parameters X, Y and Z are 2d arrays, I don't know what means that, and how I can calculate 2d arrays corresponding to them.
function [K,H,Pmax,Pmin] = surfature(X,Y,Z),
% SURFATURE - COMPUTE GAUSSIAN AND MEAN CURVATURES OF A SURFACE
% [K,H] = SURFATURE(X,Y,Z), WHERE X,Y,Z ARE 2D ARRAYS OF POINTS ON THE
% SURFACE. K AND H ARE THE GAUSSIAN AND MEAN CURVATURES, RESPECTIVELY.
% SURFATURE RETURNS 2 ADDITIONAL ARGUMENTS,
% [K,H,Pmax,Pmin] = SURFATURE(...), WHERE Pmax AND Pmin ARE THE MINIMUM
% AND MAXIMUM CURVATURES AT EACH POINT, RESPECTIVELY.
% First Derivatives
[Xu,Xv] = gradient(X);
[Yu,Yv] = gradient(Y);
[Zu,Zv] = gradient(Z);
% Second Derivatives
[Xuu,Xuv] = gradient(Xu);
[Yuu,Yuv] = gradient(Yu);
[Zuu,Zuv] = gradient(Zu);
[Xuv,Xvv] = gradient(Xv);
[Yuv,Yvv] = gradient(Yv);
[Zuv,Zvv] = gradient(Zv);
% Reshape 2D Arrays into Vectors
Xu = Xu(:); Yu = Yu(:); Zu = Zu(:);
Xv = Xv(:); Yv = Yv(:); Zv = Zv(:);
Xuu = Xuu(:); Yuu = Yuu(:); Zuu = Zuu(:);
Xuv = Xuv(:); Yuv = Yuv(:); Zuv = Zuv(:);
Xvv = Xvv(:); Yvv = Yvv(:); Zvv = Zvv(:);
Xu = [Xu Yu Zu];
Xv = [Xv Yv Zv];
Xuu = [Xuu Yuu Zuu];
Xuv = [Xuv Yuv Zuv];
Xvv = [Xvv Yvv Zvv];
% First fundamental Coeffecients of the surface (E,F,G)
E = dot(Xu,Xu,2);
F = dot(Xu,Xv,2);
G = dot(Xv,Xv,2);
m = cross(Xu,Xv,2);
p = sqrt(dot(m,m,2));
n = m./[p p p];
% Second fundamental Coeffecients of the surface (L,M,N)
L = dot(Xuu,n,2);
M = dot(Xuv,n,2);
N = dot(Xvv,n,2);
[s,t] = size(Z);
% Gaussian Curvature
K = (L.*N - M.^2)./(E.*G - F.^2);
K = reshape(K,s,t);
% Mean Curvature
H = (E.*N + G.*L - 2.*F.*M)./(2*(E.*G - F.^2));
H = reshape(H,s,t);
% Principal Curvatures
Pmax = H + sqrt(H.^2 - K);
Pmin = H - sqrt(H.^2 - K);
You have ways to convert your x,y,z data to surface matrices/ 2D arrays. Way depends on, how and what your data is.
Structured grid data:
(i). If your x,y,z corresponds to a structured grid, then you can straight a way get unique values of x,y which gives number of points along (nx,ny) along x and y axes respectively. With this (nx,ny), you need to reshape x,y,z data into matrices X,Y,Z respectively and use your function.
(ii). If you are not okay with reshaping, you can get min and max values of x,y make your own grid using meshgrid and do interpolation using griddata.
Unstructured grid data: If your data is unstructured/ scattered, get min and max, make your grid using meshgrid and do interpolation using griddata , scatteredInterpolant.
Also have a look in the following links:
https://in.mathworks.com/matlabcentral/fileexchange/56533-xyz2grd
https://in.mathworks.com/matlabcentral/fileexchange/56414-xyz-file-functions

Create a plane of points from a row of points

I am trying to create a "plane", so to speak, of points in MATLAB from a set of initial points. I have so far been able to create only one row of points, with the algorithm shown below:
% Generate molecular orientation and position
a = 4.309; % lattice constant in angstroms
l = 10; % number of lattices desired
placeHolder = [0 0 0 ; a/2 a/2 0; a/2 0 a/2; 0 a/2 a/2]; % centers of molecules
numMol = 4; %input('how many molecules are in the unit cell? \n # molecules = ');
numAtoms = 2; %input('how many atoms per molecule? \n # atoms per molecule = ');
atomPerUC = numMol*numAtoms; % number of atoms per unit cell
dir = zeros(numMol,3); % array for orientations
atomPosition = zeros(numAtoms*l^3,3,numMol); % array for positions of atoms
theta = zeros(numMol,1); % array for theta values
phi = zeros(numMol,1); % array for phi values
b = 1.54; % bond length in angstroms
for kk = 1:numMol % generate unit cell
% disp(['What is the molecular orientation for molecule ',num2str(kk),' ?']);
% dir(kk,1) = input('u = '); % ask for user input for molecular orientations
% dir(kk,2) = input('v = ');
% dir(kk,3) = input('w = ');
dir = [1,1,1;-1,1,1;-1,-1,1;1,-1,1];
u = dir(kk,1); % set variables for theta, phi computation
v = dir(kk,2);
w = dir(kk,3);
theta(kk) = w/sqrt(u^2+v^2+w^2); % theta value for molecule k
if v<0 % phi value for molecule k
phi(kk) = 2*pi - acos(abs(v)/sqrt(u^2+v^2+w^2));
else if v>0
phi(kk) = acos(u/sqrt(u^2+v^2+w^2));
end
end
theta = theta(kk); phi = phi(kk); % set variables for theta, phi for x,y,z computation
xp = placeHolder(kk,1); % cooridnates of center of molecule k
yp = placeHolder(kk,2);
zp = placeHolder(kk,3);
x1 = (b/2)*sin(theta)*cos(phi) + xp; % cooridnates for atoms in molecule
x2 = -(b/2)*sin(theta)*cos(phi) + xp;
y1 = (b/2)*sin(theta)*sin(phi) + yp;
y2 = -(b/2)*sin(theta)*sin(phi) + yp;
z1 = (b/2)*cos(theta) + zp;
z2 = -(b/2)*cos(theta) + zp;
atomPosition(1,:,kk) = [x1 y1 z1];
atomPosition(2,:,kk) = [x2 y2 z2];
end
for k = 1:numMol
x01 = atomPosition(1,1,k); y01 = atomPosition(1,2,k); z01 = atomPosition(1,3,k);
x02 = atomPosition(2,1,k); y02 = atomPosition(2,2,k); z02 = atomPosition(2,3,k);
for ii = 1:l-1
atomPosition(2*ii+1,:,k) = [(atomPosition(2*ii-1,1,k) + a) y01 z01];
atomPosition(2*ii+2,:,k) = [(atomPosition(2*ii,1,k) + a) y02 z02];
end
end
My problem is that I do not know how to, from here, turn this "row" of points into a "plane" of points. This can be thought of as taking the points that are known on the x-axis, and creating similar rows moving up in the y-direction to create an x-y plane of points.
Any help/suggestions would be appreciated!
Though I do not understand exactly what you are trying to do. In a simple case you can move from a row of points to a plane by adding the extra dimension.
ie.
x=[1,2,3,4,5]
y=x^2
changes to
x=[1,2,3,4,5]
y=[1,2,3,4,5]
[x,y] = meshgrid(x,y)
z=x^2+y^2

Harris Feature Detection is not accurate

I have implemented Harris feature detection algorithm and the results are not accurate as compared to using the inbuilt function of Matlab: corner(I,'Harris'). Any ideas why so? Or am i missing something in it?
Results of my code:
im=imread('D:\lena_256.pgm');
im=im2double(im);
% im = double(im(:,:,1));
sigma = 2;k = 0.04;
% derivative masks
s_D = 0.7*sigma;
x = -round(3*s_D):round(3*s_D);
dx = x .* exp(-x.*x/(2*s_D*s_D)) ./ (s_D*s_D*s_D*sqrt(2*pi));
dy = dx';
% image derivatives
Ix = conv2(im, dx, 'same');
Iy = conv2(im, dy, 'same');
% sum of the Auto-correlation matrix
s_I = sigma;
g = fspecial('gaussian',max(1,fix(6*s_I+1)), s_I);
Ix2 = conv2(Ix.^2, g, 'same'); % Smoothed squared image derivatives
Iy2 = conv2(Iy.^2, g, 'same');
Ixy = conv2(Ix.*Iy, g, 'same');
% interest point response
cim = (Ix2.*Iy2 - Ixy.^2) - k*(Ix2 + Iy2).^2; % Original Harris measure.
%cim=(Ix2.*Iy2 - Ixy.^2)./(Ix2 + Iy2); % harmonic mean
% find local maxima on 3x3 neighborgood
[r,c,max_local] = findLocalMaximum(cim,3*s_I);
% set threshold 1% of the maximum value
t = 0.005*max(max_local(:));
% find local maxima greater than threshold
[r,c] = find(max_local>=t);
% build interest points
points = [r,c];
figure, imshow(im),title('Harris Feature Points');
hold on
plot(points(:,1),points(:,2),'r*');
function [row,col,max_local] = findLocalMaximum(val,radius)
mask = fspecial('disk',radius)>0;
val2 = imdilate(val,mask);
index = val==val2;
[row,col] = find(index==1);
max_local = zeros(size(val));
max_local(index) = val(index);
end
Results using inbuilt corner() function: