I was trying to calculate the curvature of a surface given by array of points (x,y,z). Initially I was trying to fit a polynomial equation z=a + bx + cx^2 + dy + exy + fy^2)
heltonbiker's answer about mean curvature is great, but it assumes data points in the 2d arrays are 1 unit apart from each other. If your data points are, for example, .3 units apart from each other, you would need to divide every data point in the answer by .3 squared (.09) to account for this.
For the gaussian curvature in Michael's answer, you would need to multiply each data point by (1/.3**2)**2
(123.45)
BSD-licensed Python source code for surface fits can be found at
https://github.com/zunzun/pyeq2
(I'm the author).
Although very late, but no harm in posting. I modified the "surfature" function for use in Python. Disclaimer: I'm not the author original code. Credits wherever they are due.
def surfature(X,Y,Z):
# where X, Y, Z matrices have a shape (lr+1,lb+1)
#First Derivatives
Xv,Xu=np.gradient(X)
Yv,Yu=np.gradient(Y)
Zv,Zu=np.gradient(Z)
#Second Derivatives
Xuv,Xuu=np.gradient(Xu)
Yuv,Yuu=np.gradient(Yu)
Zuv,Zuu=np.gradient(Zu)
Xvv,Xuv=np.gradient(Xv)
Yvv,Yuv=np.gradient(Yv)
Zvv,Zuv=np.gradient(Zv)
#Reshape to 1D vectors
nrow=(lr+1)*(lb+1) #total number of rows after reshaping
Xu=Xu.reshape(nrow,1)
Yu=Yu.reshape(nrow,1)
Zu=Zu.reshape(nrow,1)
Xv=Xv.reshape(nrow,1)
Yv=Yv.reshape(nrow,1)
Zv=Zv.reshape(nrow,1)
Xuu=Xuu.reshape(nrow,1)
Yuu=Yuu.reshape(nrow,1)
Zuu=Zuu.reshape(nrow,1)
Xuv=Xuv.reshape(nrow,1)
Yuv=Yuv.reshape(nrow,1)
Zuv=Zuv.reshape(nrow,1)
Xvv=Xvv.reshape(nrow,1)
Yvv=Yvv.reshape(nrow,1)
Zvv=Zvv.reshape(nrow,1)
Xu=np.c_[Xu, Yu, Zu]
Xv=np.c_[Xv, Yv, Zv]
Xuu=np.c_[Xuu, Yuu, Zuu]
Xuv=np.c_[Xuv, Yuv, Zuv]
Xvv=np.c_[Xvv, Yvv, Zvv]
#% First fundamental Coeffecients of the surface (E,F,G)
E=np.einsum('ij,ij->i', Xu, Xu)
F=np.einsum('ij,ij->i', Xu, Xv)
G=np.einsum('ij,ij->i', Xv, Xv)
m=np.cross(Xu,Xv,axisa=1, axisb=1)
p=sqrt(np.einsum('ij,ij->i', m, m))
n=m/np.c_[p,p,p]
#% Second fundamental Coeffecients of the surface (L,M,N)
L= np.einsum('ij,ij->i', Xuu, n)
M= np.einsum('ij,ij->i', Xuv, n)
N= np.einsum('ij,ij->i', Xvv, n)
#% Gaussian Curvature
K=(L*N-M**2)/(E*G-L**2)
K=K.reshape(lr+1,lb+1)
#% Mean Curvature
H = (E*N + G*L - 2*F*M)/(2*(E*G - F**2))
H = H.reshape(lr+1,lb+1)
#% Principle Curvatures
Pmax = H + sqrt(H**2 - K)
Pmin = H - sqrt(H**2 - K)
return Pmax,Pmin
In case others stumble across this question, for completeness I offer the following code, inspired by heltonbiker.
Here is some python code to calculate Gaussian curvature as described by equation (3) in "Computation of Surface Curvature from Range Images Using Geometrically Intrinsic Weights"*, T. Kurita and P. Boulanger, 1992.
import numpy as np
def gaussian_curvature(Z):
Zy, Zx = np.gradient(Z)
Zxy, Zxx = np.gradient(Zx)
Zyy, _ = np.gradient(Zy)
K = (Zxx * Zyy - (Zxy ** 2)) / (1 + (Zx ** 2) + (Zy **2)) ** 2
return K
Note:
Dot Product in Python
Derivates in Python
Reshaping in Python
Oddly enough all of these are SO questions. Take a gander around next time and you can likely find an answer. Also note that you'll want to be using NumPy for Python to do this. It's fairly intuitive to use. Matlibplot (or something like that) might be helpful for you too!
I hope I'm not too late here. I work with exactly the same problem (a product for the company I work to).
The first thing you must consider is that the points must represent a rectangular mesh. X is a 2D array, Y is a 2D array, and Z is a 2D array. If you have an unstructured cloudpoint, with a single matrix shaped Nx3 (the first column being X, the second being Y and the third being Z) then you can't apply this matlab function.
I have developed a Python equivalent of this Matlab script, where I only calculate Mean curvature (I guess you can get inspired by the script and adapt it to get all your desired curvatures) for the Z matrix, ignoring the X and Y by assuming the grid is square. I think you can "grasp" what and how I am doing, and adapt it for your needs:
note: This assumes that your data points are 1 unit apart.
def mean_curvature(Z):
Zy, Zx = numpy.gradient(Z)
Zxy, Zxx = numpy.gradient(Zx)
Zyy, _ = numpy.gradient(Zy)
H = (Zx**2 + 1)*Zyy - 2*Zx*Zy*Zxy + (Zy**2 + 1)*Zxx
H = -H/(2*(Zx**2 + Zy**2 + 1)**(1.5))
return H