Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to estimate local tangent plane for 3d points?

Let's say I have a set of points,

R = [[x1, y1, z1],[x2, y2, z2],...,[xn, yn, zn]]

For each point (p) in R, I have identified a local neighborhood with radius (r) and height (2r) using scipy.cKDTree

import numpy as np
import scipy.spatial

R = np.array(R)
r = 1 # search radius

xy = R[:,0:2] # make array of ONLY xy
tree = scipy.spatial.cKDTree(xy)

for p in range(len(R)):
    2d_nbr_indices = tree.query_ball_point(xy[p], r) # indices w/in xy neighborhood
    2d_nbr_array = R[2d_nbr_indices] # 3d array of 2d neighbors
    z = R[p][1] # get z value
    zMin = z - r
    zMax = z + r
    # Create boolean array to filter 3d array
    hgt_filter = np.any([2d_nbr_array[:, 2] >= zMin,
                         2d_nbr_array[:, 2] <= zMax], axis=0)
    3d_nbr_array = 2d_nbr_array[hgt_filter] # points in xyz neighborhood

I would like to calculate an orthogonal regression plane for each neighborhood, determine the distance (orthogonal) from each point to the plane, and calculate normal vector of plane. Does anyone have any advice on how to go about this in python?

EDIT: I found an odr user guide. It appears to handle 3d points. Any advice on it's implementation and use is welcome. I also found this similar question.

EDIT: I should mention that the data may contain vertical or near vertical surfaces, so an implicit model is necessary. I found this example in the scipy codebook, but only with xy data.

like image 940
Barbarossa Avatar asked Dec 05 '13 20:12

Barbarossa


People also ask

What is a tangent plane to a surface in 3D?

Well tangent planes to a surface are planes that just touch the surface at the point and are “parallel” to the surface at the point. Note that this gives us a point that is on the plane. Since the tangent plane and the surface touch at (x0,y0) ( x 0 , y 0 ) the following point will be on both the surface and the plane.


1 Answers

This a general example of how to fit a 3d surface to a point cloud with scipy.odr. Hope it helps.

from scipy.odr import ODR, Model, Data
import numpy as np
import matplotlib.pyplot as plt

from mpl_toolkits.mplot3d import Axes3D

def func(beta,data):
    x,y = data
    a,b,c = beta
    return a*x+b*y+c

N = 20
x = np.random.randn(N)
y = np.random.randn(N)
z = func([-3,-1,2],[x,y])+np.random.normal(size=N)


data = Data([x,y],z)
model = Model(func)
odr = ODR(data, model, [0.0,0.0,0.0])
odr.set_job(fit_type = 0)
res = odr.run()

Y,X = np.mgrid[y.min():y.max():20j,x.min():x.max():20j]
Z = func(res.beta, [X,Y])
f = plt.figure()
pl = f.add_subplot(111,projection='3d')
pl.scatter3D(x,y,z)
pl.plot_surface(X,Y,Z,alpha=0.4)
like image 96
Christian K. Avatar answered Sep 24 '22 00:09

Christian K.