簡體   English   中英

Python VTK“標准化”點雲

[英]Python VTK “normalize” a point cloud

我已經做了很多搜索,但是還沒有找到答案。 我目前正在處理一些農作物的數據。 我有用於多個字段的PLY文件,這些文件已使用Python和VTK成功讀取,過濾和可視化。 我的主要目標是最終對各個農作物地段進行細分並進行分析。

但是,為了簡化該任務,我首先要對點雲進行“歸一化”,以便所有圖基本上都處於“同一水平”上。 從我附帶的圖像中,您可以看到點塊從一個角向相反的角度傾斜。 因此,我想弄平圖像,使接地點都在同一平面/水平上。 並相應調整了積分的重置。

點雲

我還包含了我的代碼,以說明如何達到這一點。 如果有人對我如何實現對一架飛機的標准化有任何建議,我將非常感激。 遺憾的是,我無法包含我的數據,因為它與工作相關。

謝謝。 喬希

import vtk
from vtk.util import numpy_support
import numpy as np

filename = 'File.ply'

# Reader
r = vtk.vtkPLYReader()
r.SetFileName(filename)

# Filters
vgf = vtk.vtkVertexGlyphFilter()
vgf.SetInputConnection(r.GetOutputPort())

# Elevation
pc = r.GetOutput()
bounds = pc.GetBounds()
#print(bounds)
minz = bounds[4]
maxz = bounds[5]
#print(bounds[4], bounds[5])
evgf = vtk.vtkElevationFilter()
evgf.SetInputConnection(vgf.GetOutputPort())
evgf.SetLowPoint(0, 0, minz)
evgf.SetHighPoint(0, 0, maxz)
#pc.GetNumberOfPoints()

# Look up table
lut = vtk.vtkLookupTable()
lut.SetHueRange(0.667, 0)
lut.SetSaturationRange(1, 1)
lut.SetValueRange(1, 1)
lut.Build

# Renderer
mapper = vtk.vtkPolyDataMapper()
mapper.SetInputConnection(evgf.GetOutputPort())
mapper.SetLookupTable(lut)

actor = vtk.vtkActor()
actor.SetMapper(mapper)

renderer = vtk.vtkRenderer()
renWin = vtk.vtkRenderWindow()
renWin.AddRenderer(renderer)
iren = vtk.vtkRenderWindowInteractor()
iren.SetRenderWindow(renWin)

renderer.AddActor(actor)
renderer.SetBackground(0, 0, 0) 

renWin.Render()
iren.Start()

我曾經解決過類似的問題。 在下面找到我當時使用的一些代碼。 它使用兩個函數fitPlanefindTransformFromVectors ,您可以用自己的實現替換它們。

請注意,有多種方法可以通過一組點擬合平面。 該SO帖子討論將scipy.optimize.minimizescipy.linalg.lstsq進行比較。 另一篇SO文章中 ,建議使用PCA或RANSAC以及其他方法。 您可能要使用sklearnnumpy或其他模塊提供的方法。 我的解決方案簡單地(並且非穩健地)計算普通最小二乘回歸。

import vtk
import numpy as np
# Convert vtk to numpy arrays
from vtk.util.numpy_support import vtk_to_numpy as vtk2np

# Create a random point cloud.
center = [3.0, 2.0, 1.0]
source = vtk.vtkPointSource()
source.SetCenter(center)
source.SetNumberOfPoints(50)
source.SetRadius(1.)
source.Update()
source = source.GetOutput()
# Extract the points from the point cloud.
points = vtk2np(source.GetPoints().GetData())
points = points.transpose()

# Fit a plane. nRegression contains the normal vector of the
# regression surface.
nRegression = fitPlane(points)
# Compute a transform that maps the source center to the origin and
# plane normal to the z-axis.
trafo = findTransformFromVectors(originFrom=center,
                                 axisFrom=nRegression.transpose(),
                                 originTo=(0,0,0),
                                 axisTo=(0.,0.,1.))

# Apply transform to source.
sourceTransformed = vtk.vtkTransformFilter()
sourceTransformed.SetInputData(source)
sourceTransformed.SetTransform(trafo)
sourceTransformed.Update()

# Visualize output...

這是我的fitPlanefindTransformFromVectors

# The following code has been written by normanius under the CC BY-SA 4.0 
# license.
# License:    https://creativecommons.org/licenses/by-sa/4.0/
# Author:     normanius: https://stackoverflow.com/users/3388962/normanius
# Date:       October 2018
# Reference:  https://stackoverflow.com/questions/52716438

def fitPlane(X, tolerance=1e-10):
    '''
    Estimate the plane normal by means of ordinary least dsquares.
    Requirement: points X span the full column rank. If the points lie in a
    perfect plane, the regression problem is ill-conditioned!

    Formulas:
        a = (XX^T)^(-1)*X*z
    Surface normal:
        n = [a[0], a[1], -1]
        n = n/norm(n)
    Plane intercept:
        c = a[2]/norm(n)

    NOTE: The condition number for the pseudo-inverse improves if the
          formulation is changed to homogenous notation.
    Formulas (homogenous):
        a = (XX^T)^(-1)*[1,1,1]^T
        n = a[:-1]
        n = n/norm(n)
        c = a[-1]/norm(n)

    Arguments:
        X:          A matrix with n rows and 3 columns
        tolerance:  Minimal condition number accepted. If the condition
                    number is lower, the algorithm returns None.

    Returns:
        If the computation was successful, a numpy array of length three is
        returned that represents the estimated plane normal. On failure,
        None is returned.
    '''
    X = np.asarray(X)
    d,N = X.shape
    X = np.vstack([X,np.ones([1,N])])
    z = np.ones([d+1,1])
    XXT = np.dot(X, np.transpose(X)) # XXT=X*X^T
    if np.linalg.det(XXT) < 1e-10:
        # The test covers the case where n<3
        return None
    n = np.dot(np.linalg.inv(XXT), z)
    intercept = n[-1]
    n = n[:-1]
    scale = np.linalg.norm(n)
    n /= scale
    intercept /= scale
    return n

def findTransformFromVectors(originFrom=None, axisFrom=None,
                             originTo=None, axisTo=None,
                             origin=None,
                             scale=1):
    '''
    Compute a transformation that maps originFrom and axisFrom to originTo
    and axisTo respectively. If scale is set to 'auto', the scale will be
    determined such that the axes will also match in length:
        scale = norm(axisTo)/norm(axisFrom)

    Arguments:  originFrom:     sequences with 3 elements, or None
                axisFrom:       sequences with 3 elements, or None
                originTo:       sequences with 3 elements, or None
                axisTo:         sequences with 3 elements, or None
                origin:         sequences with 3 elements, or None,
                                overrides originFrom and originTo if set
                scale:          - scalar (isotropic scaling)
                                - sequence with 3 elements (anisotropic scaling),
                                - 'auto' (sets scale such that input axes match
                                  in length after transforming axisFrom)
                                - None (no scaling)

    Align two axes alone, assuming that we sit on (0,0,0)
        findTransformFromVectors(axisFrom=a0, axisTo=a1)
    Align two axes in one point (all calls are equivalent):
        findTransformFromVectors(origin=o, axisFrom=a0, axisTo=a1)
        findTransformFromVectors(originFrom=o, axisFrom=a0, axisTo=a1)
        findTransformFromVectors(axisFrom=a0, originTo=o, axisTo=a1)
    Move between two points:
        findTransformFromVectors(orgin=o0, originTo=o1)
    Move from one position to the other and align axes:
        findTransformFromVectors(orgin=o0, axisFrom=a0, originTo=o1, axisTo=a1)
    '''
    # Prelude with trickle-down logic.
    # Infer the origins if an information is not set.
    if origin is not None:
        # Check for ambiguous input.
        assert(originFrom is None and originTo is None)
        originFrom = origin
        originTo = origin
    if originFrom is None:
        originFrom = originTo
    if originTo is None:
        originTo = originFrom
    if originTo is None:
        # We arrive here only if no origin information was set.
        originTo = [0.,0.,0.]
        originFrom = [0.,0.,0.]
    originFrom = np.asarray(originFrom)
    originTo = np.asarray(originTo)
    # Check if any rotation will be involved.
    axisFrom = np.asarray(axisFrom)
    axisTo = np.asarray(axisTo)
    axisFromL2 = np.linalg.norm(axisFrom)
    axisToL2 = np.linalg.norm(axisTo)
    if axisFrom is None or axisTo is None or axisFromL2==0 or axisToL2==0:
        rotate = False
    else:
        rotate = not np.array_equal(axisFrom, axisTo)
    # Scale.
    if scale is None:
        scale = 1.
    if scale == 'auto':
        scale = axisToL2/axisFromL2 if axisFromL2!=0. else 1.
    if np.isscalar(scale):
        scale = scale*np.ones(3)
    if rotate:
        rAxis = np.cross(axisFrom.ravel(), axisTo.ravel())  # rotation axis
        angle = np.dot(axisFrom, axisTo) / axisFromL2 / axisToL2
        angle = np.arccos(angle)

    # Here we finally compute the transform.
    trafo = vtk.vtkTransform()
    trafo.Translate(originTo)
    if rotate:
        trafo.RotateWXYZ(angle / np.pi * 180, rAxis[0], rAxis[1], rAxis[2])
    trafo.Scale(scale[0],scale[1],scale[2])
    trafo.Translate(-originFrom)
    return trafo

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM