<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
前言:
VTK,(visualizationtoolkit)是一個開放資源的免費軟體系統,主要用於三維計算機圖學、影象處理和視覺化。Vtk是在物件導向原理的基礎上設計和實現的,它的核心是用C++構建的,包含有大約250,000行程式碼,2000多個類,還包含有幾個轉換介面,因此也可以自由的通過Java,Tcl/Tk和Python各種語言使用vtk。
本文介紹了 如何使使用者Python版本的VTK計算曲面的高斯曲率並對映在曲面上。本例中使用了兩個不同的表面,每個表面根據其高斯曲率和平均曲率著色。
為了獲得漂亮的彩色影象,使用VTKColorTransfer函數為vtkLookupTable表生成一組顏色。我們使用了發散的顏色空間。由於為查詢表選擇的範圍對稱,白色表示中點值,而藍色表示小於中點值的值,橙色表示大於中點值的顏色。在隨機Hills高斯曲率曲面的情況下,這種顏色非常好地顯示了曲面的性質。藍色區域為鞍點(負高斯曲率),橙色區域為正高斯曲率。在平均曲率的情況下,藍色表示垂直於一個主軸的負曲率。
主要函數介紹:
vtkSuperquadricSource: vtkSuperquadricSource 建立以原點為中心的多邊形超二次曲面,可以設定尺寸。可以設定兩個(φ)的緯度和經度(θ)方向的解析度(多邊形離散化)。渾圓度引數(緯度渾圓度和經度渾圓度)控制超二次曲面的形狀。環形布林值控制是否產生環形的超二次曲面。如果是的話,厚度引數控制的厚度的環形:0是最薄的環形,和1具有最小尺寸的孔。縮放尺度引數允許超二次曲面,在x,y,和z(在任何情況下,正確地生成法線向量)進行縮放。 尺寸引數控制的超二次曲面的size。原理是基於“剛性基於物理的超二次曲面”。
基本方法:
vtkParametricRandomHills: 生成覆蓋隨機放置的山丘的曲面。山丘的形狀和高度會有所不同,因為附近山丘的存在會影響給定山丘的形狀和高度。提供了一個選項,用於將山丘放置在曲面上的規則柵格上。在這種情況下,所有山丘的形狀和高度都相同。
adjust_edge_curvatures: 此函數通過將該值替換為鄰域中點曲率的平均值來調整曲面邊緣的曲率。在呼叫此函數之前,請記住更新vtkCurvatures物件。
source:與vtkCurvatures物件相對應的vtkPolyData物件。
curvature_name:曲率的名稱,“Gauss_curvature”或“Mean_curvature”。
epsilon:小於此值的絕對曲率值將設定為零。
mport numpy as np import vtk from vtk.util import numpy_support from vtkmodules.numpy_interface import dataset_adapter as dsa def main(argv): colors = vtk.vtkNamedColors() #產生曲面 torus = vtk.vtkSuperquadricSource() torus.SetCenter(0.0, 0.0, 0.0) torus.SetScale(1.0, 1.0, 1.0) torus.SetPhiResolution(64) torus.SetThetaResolution(64) torus.SetThetaRoundness(1) torus.SetThickness(0.5) torus.SetSize(0.5) torus.SetToroidal(1) # 改變觀察視角 toroid_transform = vtk.vtkTransform() toroid_transform.RotateX(55) toroid_transform_filter = vtk.vtkTransformFilter() toroid_transform_filter.SetInputConnection(torus.GetOutputPort()) toroid_transform_filter.SetTransform(toroid_transform) # The quadric is made of strips, so pass it through a triangle filter as # the curvature filter only operates on polys tri = vtk.vtkTriangleFilter() tri.SetInputConnection(toroid_transform_filter.GetOutputPort()) #二次曲面在生成邊的方式上存在嚴重的不連續性,因此讓我們將其通過CleanPolyDataFilter併合並 #任何重合或非常接近的點 cleaner = vtk.vtkCleanPolyData() cleaner.SetInputConnection(tri.GetOutputPort()) cleaner.SetTolerance(0.005) cleaner.Update() # 生成覆蓋隨機放置的山丘的曲面 rh = vtk.vtkParametricRandomHills() rh_fn_src = vtk.vtkParametricFunctionSource() rh_fn_src.SetParametricFunction(rh) rh_fn_src.Update() sources = list() for i in range(0, 4): cc = vtk.vtkCurvatures() if i < 2: cc.SetInputConnection(cleaner.GetOutputPort()) else: cc.SetInputConnection(rh_fn_src.GetOutputPort()) if i % 2 == 0: cc.SetCurvatureTypeToGaussian() curvature_name = 'Gauss_Curvature' else: cc.SetCurvatureTypeToMean() curvature_name = 'Mean_Curvature' cc.Update() adjust_edge_curvatures(cc.GetOutput(), curvature_name) sources.append(cc.GetOutput()) curvatures = { 0: 'Gauss_Curvature', 1: 'Mean_Curvature', 2: 'Gauss_Curvature', 3: 'Mean_Curvature', } # lut = get_diverging_lut() lut = get_diverging_lut1() renderers = list() mappers = list() actors = list() text_mappers = list() text_actors = list() scalar_bars = list() # Create a common text property. text_property = vtk.vtkTextProperty() text_property.SetFontSize(24) text_property.SetJustificationToCentered() # RenderWindow Dimensions # renderer_size = 512 grid_dimensions = 2 window_width = renderer_size * grid_dimensions window_height = renderer_size * grid_dimensions for idx, source in enumerate(sources): curvature_name = curvatures[idx].replace('_', 'n') source.GetPointData().SetActiveScalars(curvatures[idx]) scalar_range = source.GetPointData().GetScalars(curvatures[idx]).GetRange() mappers.append(vtk.vtkPolyDataMapper()) mappers[idx].SetInputData(source) mappers[idx].SetScalarModeToUsePointFieldData() mappers[idx].SelectColorArray(curvatures[idx]) mappers[idx].SetScalarRange(scalar_range) mappers[idx].SetLookupTable(lut) actors.append(vtk.vtkActor()) actors[idx].SetMapper(mappers[idx]) text_mappers.append(vtk.vtkTextMapper()) text_mappers[idx].SetInput(curvature_name) text_mappers[idx].SetTextProperty(text_property) text_actors.append(vtk.vtkActor2D()) text_actors[idx].SetMapper(text_mappers[idx]) text_actors[idx].SetPosition(250, 16) # Create a scalar bar scalar_bars.append(vtk.vtkScalarBarActor()) scalar_bars[idx].SetLookupTable(mappers[idx].GetLookupTable()) scalar_bars[idx].SetTitle(curvature_name) scalar_bars[idx].UnconstrainedFontSizeOn() scalar_bars[idx].SetNumberOfLabels(5) scalar_bars[idx].SetMaximumWidthInPixels(window_width // 8) scalar_bars[idx].SetMaximumHeightInPixels(window_height // 3) scalar_bars[idx].SetBarRatio(scalar_bars[idx].GetBarRatio() * 0.5) scalar_bars[idx].SetPosition(0.85, 0.1) renderers.append(vtk.vtkRenderer()) for idx in range(len(sources)): if idx < grid_dimensions * grid_dimensions: renderers.append(vtk.vtkRenderer) # Create the RenderWindow # render_window = vtk.vtkRenderWindow() render_window.SetSize(renderer_size * grid_dimensions, renderer_size * grid_dimensions) render_window.SetWindowName('CurvaturesDemo') viewport = list() for row in range(grid_dimensions): for col in range(grid_dimensions): idx = row * grid_dimensions + col viewport[:] = [] viewport.append(float(col) / grid_dimensions) viewport.append(float(grid_dimensions - (row + 1)) / grid_dimensions) viewport.append(float(col + 1) / grid_dimensions) viewport.append(float(grid_dimensions - row) / grid_dimensions) if idx > (len(sources) - 1): continue renderers[idx].SetViewport(viewport) render_window.AddRenderer(renderers[idx]) renderers[idx].AddActor(actors[idx]) renderers[idx].AddActor(text_actors[idx]) renderers[idx].AddActor(scalar_bars[idx]) renderers[idx].SetBackground(colors.GetColor3d('SlateGray')) interactor = vtk.vtkRenderWindowInteractor() interactor.SetRenderWindow(render_window) style = vtk.vtkInteractorStyleTrackballCamera() interactor.SetInteractorStyle(style) render_window.Render() interactor.Start() def get_diverging_lut(): ctf = vtk.vtkColorTransferFunction() ctf.SetColorSpaceToDiverging() # Cool to warm. ctf.AddRGBPoint(0.0, 0.230, 0.299, 0.754) ctf.AddRGBPoint(0.5, 0.865, 0.865, 0.865) ctf.AddRGBPoint(1.0, 0.706, 0.016, 0.150) table_size = 256 lut = vtk.vtkLookupTable() lut.SetNumberOfTableValues(table_size) lut.Build() for i in range(0, table_size): rgba = list(ctf.GetColor(float(i) / table_size)) rgba.append(1) lut.SetTableValue(i, rgba) return lut def get_diverging_lut1(): colors = vtk.vtkNamedColors() # Colour transfer function. ctf = vtk.vtkColorTransferFunction() ctf.SetColorSpaceToDiverging() p1 = [0.0] + list(colors.GetColor3d('MidnightBlue')) p2 = [0.5] + list(colors.GetColor3d('Gainsboro')) p3 = [1.0] + list(colors.GetColor3d('DarkOrange')) ctf.AddRGBPoint(*p1) ctf.AddRGBPoint(*p2) ctf.AddRGBPoint(*p3) table_size = 256 lut = vtk.vtkLookupTable() lut.SetNumberOfTableValues(table_size) lut.Build() for i in range(0, table_size): rgba = list(ctf.GetColor(float(i) / table_size)) rgba.append(1) lut.SetTableValue(i, rgba) return lut def vtk_version_ok(major, minor, build): requested_version = (100 * int(major) + int(minor)) * 100000000 + int(build) ver = vtk.vtkVersion() actual_version = (100 * ver.GetVTKMajorVersion() + ver.GetVTKMinorVersion()) * 100000000 + ver.GetVTKBuildVersion() if actual_version >= requested_version: return True else: return False def adjust_edge_curvatures(source, curvature_name, epsilon=1.0e-08): def point_neighbourhood(pt_id): cell_ids = vtk.vtkIdList() source.GetPointCells(pt_id, cell_ids) neighbour = set() for cell_idx in range(0, cell_ids.GetNumberOfIds()): cell_id = cell_ids.GetId(cell_idx) cell_point_ids = vtk.vtkIdList() source.GetCellPoints(cell_id, cell_point_ids) for cell_pt_idx in range(0, cell_point_ids.GetNumberOfIds()): neighbour.add(cell_point_ids.GetId(cell_pt_idx)) return neighbour def compute_distance(pt_id_a, pt_id_b): #計算距離. pt_a = np.array(source.GetPoint(pt_id_a)) pt_b = np.array(source.GetPoint(pt_id_b)) return np.linalg.norm(pt_a - pt_b) # 獲取活動標量 source.GetPointData().SetActiveScalars(curvature_name) np_source = dsa.WrapDataObject(source) curvatures = np_source.PointData[curvature_name] # 獲得邊緣點的ID array_name = 'ids' id_filter = vtk.vtkIdFilter() id_filter.SetInputData(source) id_filter.SetPointIds(True) id_filter.SetCellIds(False) id_filter.SetPointIdsArrayName(array_name) id_filter.SetCellIdsArrayName(array_name) id_filter.Update() edges = vtk.vtkFeatureEdges() edges.SetInputConnection(id_filter.GetOutputPort()) edges.BoundaryEdgesOn() edges.ManifoldEdgesOff() edges.NonManifoldEdgesOff() edges.FeatureEdgesOff() edges.Update() edge_array = edges.GetOutput().GetPointData().GetArray(array_name) boundary_ids = [] for i in range(edges.GetOutput().GetNumberOfPoints()): boundary_ids.append(edge_array.GetValue(i)) # Remove duplicate Ids. p_ids_set = set(boundary_ids) #迭代邊緣點並計算曲率作為相鄰點的加權平均值。 count_invalid = 0 for p_id in boundary_ids: p_ids_neighbors = point_neighbourhood(p_id) # Keep only interior points. p_ids_neighbors -= p_ids_set # Compute distances and extract curvature values. curvs = [curvatures[p_id_n] for p_id_n in p_ids_neighbors] dists = [compute_distance(p_id_n, p_id) for p_id_n in p_ids_neighbors] curvs = np.array(curvs) dists = np.array(dists) curvs = curvs[dists > 0] dists = dists[dists > 0] if len(curvs) > 0: weights = 1 / np.array(dists) weights /= weights.sum() new_curv = np.dot(curvs, weights) else: # Corner case. count_invalid += 1 # Assuming the curvature of the point is planar. new_curv = 0.0 # Set the new curvature value. curvatures[p_id] = new_curv # 將小值設定為0 if epsilon != 0.0: curvatures = np.where(abs(curvatures) < epsilon, 0, curvatures) # Curvatures is now an ndarray curv = numpy_support.numpy_to_vtk(num_array=curvatures.ravel(), deep=True, array_type=vtk.VTK_DOUBLE) curv.SetName(curvature_name) source.GetPointData().RemoveArray(curvature_name) source.GetPointData().AddArray(curv) source.GetPointData().SetActiveScalars(curvature_name) if __name__ == '__main__': import sys main(sys.argv)
顯示效果如下:
到此這篇關於Python VTK計算曲面的高斯曲率和平均曲率的文章就介紹到這了,更多相關 Python-VTK計算 內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45