Python VTK计算曲面的高斯曲率和平均曲率

news2024/12/23 17:45:14

introduction:

Python VTK计算曲面的高斯曲率和平均曲率,如何使用户Python版本的VTK计算曲面的高斯曲率并映射在曲面上。使用了两个不同的表面,每个表面根据其高斯曲率和平均曲率着色.

Display:

 

Step:

本文介绍了 如何使用户Python版本的VTK计算曲面的高斯曲率并映射在曲面上。本例中使用了两个不同的表面,每个表面根据其高斯曲率和平均曲率着色。

  • 第一个曲面是一个超二次曲面,这演示了如何使用额外的过滤器来获得一个平滑的曲面。
  • 第二个曲面是参数化曲面,在这种情况下,该曲面已被三角剖分,因此无需额外处理。

为了获得漂亮的彩色图像,使用VTKColorTransfer函数为vtkLookupTable表生成一组颜色。我们使用了发散的颜色空间。由于为查找表选择的范围对称,白色表示中点值,而蓝色表示小于中点值的值,橙色表示大于中点值的颜色。在随机Hills高斯曲率曲面的情况下,这种颜色非常好地显示了曲面的性质。蓝色区域为鞍点(负高斯曲率),橙色区域为正高斯曲率。在平均曲率的情况下,蓝色表示垂直于一个主轴的负曲率。

主要函数介绍:

vtkSuperquadricSource: vtkSuperquadricSource 创建以原点为中心的多边形超二次曲面,可以设置尺寸。可以设置两个(φ)的纬度和经度(θ)方向的分辨率(多边形离散化)。浑圆度参数(纬度浑圆度和经度浑圆度)控制超二次曲面的形状。环形布尔值控制是否产生环形的超二次曲面。如果是的话,厚度参数控制的厚度的环形:0是最薄的环形,和1具有最小尺寸的孔。缩放尺度参数允许超二次曲面,在x,y,和z(在任何情况下,正确地生成法线向量)进行缩放。 尺寸参数控制的超二次曲面的size。原理是基于“刚性基于物理的超二次曲面”。

基本方法:

  •   SetCenter()设置中心点
  •   SetThickness()厚度参数控制的厚度的环形:0是最薄的环形,和1具有最小尺寸的孔
  •   ToroidalOn()开启环形
  •   SetPhiRoundness(),SetThetaRoundness设置经纬度的环形度
  •   SetScale()设置在x,y,z方向的超二次曲面的拉伸系数。

vtkParametricRandomHills: 生成覆盖随机放置的山丘的曲面。山丘的形状和高度会有所不同,因为附近山丘的存在会影响给定山丘的形状和高度。提供了一个选项,用于将山丘放置在曲面上的规则栅格上。在这种情况下,所有山丘的形状和高度都相同。

adjust_edge_curvatures: 此函数通过将该值替换为邻域中点曲率的平均值来调整曲面边缘的曲率。在调用此函数之前,请记住更新vtkCurvatures对象。

source:与vtkCurvatures对象相对应的vtkPolyData对象。

curvature_name:曲率的名称,“Gauss_curvature”或“Mean_curvature”。

epsilon:小于此值的绝对曲率值将设置为零。

Code:

import numpy as np
import vtk

from vtkmodules.numpy_interface import dataset_adapter as dsa
from vtkmodules.util import numpy_support


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)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/433075.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是软件开发脚手架?为什么需要脚手架?常用的脚手架有哪些?

什么是软件开发脚手架&#xff1f;为什么需要脚手架&#xff1f;常用的脚手架有哪些&#xff1f; 微服务本身是一种架构风格&#xff0c;也是指导组织构建软件的一系列最佳实践集合。然而&#xff0c;业务团队在拆分应用后&#xff0c;会产生更多细粒度服务&#xff0c;并面临…

基于LINUX实现ping发送与接收

作用 Linux ping 命令用于检测主机&#xff1a;执行 ping 会使用 ICMP 传输协议&#xff0c;发出要求回应的信息&#xff0c;若远端主机的网络功能没有问题&#xff0c;就会回应该信息&#xff0c;因而得知该主机运作正常。 基础使用 #ping 192.168.1.1//ping 主机ip#ping -…

【项目】视频列表滑动,自动播放

自动播放 期望效果&#xff0c;当滑动列表结束后&#xff0c;屏幕中间的视频自动播放HTML页面data变量实践操作&#xff01;重点来了&#xff01;滚动获得的数据实现效果源码&#xff08;粘贴即可运行&#xff09; 期望效果&#xff0c;当滑动列表结束后&#xff0c;屏幕中间的…

C. Anna, Svyatoslav and Maps(floyd + 思维)

Problem - C - Codeforces 给你一个有n个顶点的无权图&#xff0c;以及由m个顶点的序列p1,p2,...,pm给出的路径&#xff08;该路径不一定简单&#xff09;&#xff1b;对于每个1≤i<m&#xff0c;有一个弧从pi到pi1。 如果v是p的子序列&#xff0c;v1p1&#xff0c;vkpm&a…

重学Java设计模式-行为型模式-命令模式

重学Java设计模式-行为型模式-命令模式 内容摘自&#xff1a;https://bugstack.cn/md/develop/design-pattern/2020-06-21-重学 Java 设计模式《实战命令模式》.html#重学-java-设计模式-实战命令模式「模拟高档餐厅八大菜系-小二点单厨师烹饪场景」 命令模式介绍 图片来自&a…

后端查询到数据,前端显示该数据为null

问题展示&#xff1a; 数据库可视化界面。我们要展示record属性里面的值。 前端form表单&#xff1a; 后端属性&#xff1a; 后端sql语句&#xff1a; 接下来我们查询订单详情&#xff0c;ID8的订单。 后端控制台&#xff1a; 我们明显的看到&#xff0c;record这个属…

CSS选择器进阶1.2

一&#xff0c;复合选择器 1.1后代选择器&#xff1a;Space 作用&#xff1a;根据HTML标签的嵌套关系&#xff0c;选择父元素后代中满足条件的元素。 选择器语法&#xff08;选择器1为父选择器&#xff0c;选择器2为后代选择器&#xff09;&#xff1a; 选择器1 选择器2{CSS…

【HTML5】HTML5 语义化标签 ( HTML5 简介 | 新增特性 | 语义化标签及代码示例 )

文章目录 一、HTML5 简介二、HTML5 语义化标签三、HTML5 语义化标签代码示例 一、HTML5 简介 HTML5 指的是 对 HTML 语言的第五次重大修改 , 新增了新的元素 / 属性 / 行为 ; HTML5 新增的特性 : 语义特性本地存储特性设备兼容特性连接特性网页多媒体特性三维特性图形及特效特…

故障重现, JAVA进程内存不够时突然挂掉模拟

背景&#xff0c;服务器上的一个JAVA服务进程突然挂掉&#xff0c;查看产生了崩溃日志&#xff0c;如下&#xff1a; # Set larger code cache with -XX:ReservedCodeCacheSize # This output file may be truncated or incomplete. # # Out of Memory Error (os_linux.cpp:26…

什么是跳表?

文章目录文章目的注意事项1.什么是跳表-skiplist2.skiplist的效率如何保证&#xff1f;2.1 一个节点的平均层数3. skiplist的实现文章目的 让你知道什么是跳表,梳理跳表跳表的设计思路及实现 注意事项 下面有数学公式,需要数学功底,只要弄清楚用来干嘛就行有兴趣的人可以了解…

FVCOM模型数值模拟流域、海洋水动力、水环境,解决水交换及污染物扩散问题、溢油及物质输运问题

目录 FVCOM流域、海洋水环境数值模拟方法及实践技术应用 第一章、FVCOM水动力相关理论 第二章、Linux系统下FVCOM运行环境搭建 第三章、FVCOM三维水动力数值模拟前处理 第四章、FVCOM三维水动力数值模拟 第五章、FVCOM三维水动力计算结果可视化及率定方法 第六章、FVCOM…

算法的空间复杂度

空间复杂度也是一个数学表达式&#xff0c;是对一个算法在运行过程中临时占用存储空间大小的量度 空间复杂度不是程序占用了多少bytes的空间&#xff0c;因为这个也没太大意义 所以空间复杂度算的是变量的个数 空间复杂度计算规则基本跟实践复杂度类似&#xff0c;也使用大O渐进…

Ajax详解

1、什么是Ajax ajax 全名 async javascript and XML是前后台交互的能力也就是我们客户端给服务端发送消息的工具&#xff0c;以及接受响应的工具是一个 默认异步 执行机制的功能。 2、 AJAX 的优势 不需要插件的支持&#xff0c;原生 js 就可以使用用户体验好&#xff08;不…

学生成绩管理系统的设计与实现

一、系统需求分析 实现对一个有32个学生的班级&#xff0c;每个学生有7门课程&#xff0c;实现对他们的班级成绩进行添加、修改、删除、查找、统计输出等基本信息进行一系列的操作。每个学生包括如下信息&#xff1a;学号、姓名、7门课程名称。 二、系统功能模块设计 主要包含…

zookeeper 搭建 linux

jdk安装 1.从网盘里下载jkd 2.创建安装目录&#xff0c;然后将jdk包解压到目录中 mkdir jdktar -zxvf jdk-8u271-linux-x64.tar.gz -C /home/ubuntu/app/jdk/ 3.设置环境变量 修改 vi /etc/profile, 在 profile 文件中添加如下内容并保存&#xff1a; set java environment JAV…

OpenAI-ChatGPT最新官方接口《AI绘图》全网最详细中英文实用指南和教程,助你零基础快速轻松掌握全新技术(三)(附源码)

ChatGPT-AI绘图 Image generation Beta 图片生成前言IntroductionUsageGenerationsEdits 编辑 VariationsLanguage-specific tips 特定语言提示Python 语言Using in-memory image data 使用内存中的图像数据Operating on image data 操作图像数据Error handling Node.js 语言Us…

手把手教你使用Python调用 ChatGPT!支持http代理

手把手教你使用Python调用 ChatGPT&#xff01;支持http代理 作者&#xff1a;虚坏叔叔 博客&#xff1a;https://xuhss.com 早餐店不会开到晚上&#xff0c;想吃的人早就来了&#xff01;&#x1f604; 前段时间OpenAI 开放了两个新模型的api接口&#xff0c;专门为聊天而生的…

《JavaEE初阶》多线程基础

《JavaEE初阶》多线程基础 文章目录《JavaEE初阶》多线程基础前言:多线程的概念简单创建线程并运行:简述Thread中run方法与start方法的区别创建线程的几种方法:探讨串行执行与并行执行的执行时间多线程的使用场景:Thread类简单介绍:构造方法:获取线程的常见属性:线程的常用方法…

Nacos 客户端服务发现源码分析-篇六

Nacos 客户端服务发现源码分析-篇六 &#x1f550;Nacos 客户端服务注册源码分析-篇一 &#x1f551;Nacos 客户端服务注册源码分析-篇二 &#x1f552;Nacos 客户端服务注册源码分析-篇三 &#x1f553;Nacos 服务端服务注册源码分析-篇四 &#x1f554;Nacos 服务端健康…

ChatGPT神器免费使用,告别昂贵低效工具

大家好&#xff0c;今天我要向大家介绍一款免费的ChatGPT使用网址&#xff0c;它可以让你轻松地使用ChatGPT进行AI创作&#xff01;而且&#xff0c;这个网址还是免费的&#xff0c;不需要担心会有额外的费用。 ChatGPT是一种非常强大的AI技术&#xff0c;可以用于各种领域&…