VTK 的可视化方法:颜色映射

news2025/2/24 6:31:15

VTK 的可视化方法:颜色映射

  • VTK 的可视化方法:颜色映射
    • 颜色映射过程
    • vtkDataSet
    • vtkDataSetAttributes
    • vtkLookUpTable
    • vtkScalarBarActor
    • 实例
    • 参考

VTK 的可视化方法:颜色映射

颜色映射的操作对象是数据集中的标量属性。它是一种常用的标量算法。它会根据数据集中各个部分不同的标量值,对各个部分上不同的颜色。与此相关的另一种上色方法是控制演员的颜色属性,但这样整个图形只有单一的颜色,这显然没有颜色映射方法灵活。

颜色映射的本质就是将标量数据附加到单元或者点上,然后再绘制的时候通过点集或者单元集的数据在颜色表中查找标量值对应的颜色,然后进行绘制。

颜色映射过程

假设有一个共256种颜色的查询表,且颜色的索引号范围为0~255,那么颜色映射就是将数据集的标量值映射到这些索引号的过程。在渲染时,与索引号对应的颜色将作为数据中相应部分的颜色显示出来。映射的方法如下图所示:

在这里插入图片描述

上图中,scalar表示数据集中的标量值,index表示映射后的索引号。smin和smax表示的是标量值的映射范围(注意不是数据集中标量值的取值范围)。若一个标量值小于smin,则其映射的索引号为0;若一个标量值大于smax,其映射的索引号为255;若一个标量值在这个范围之间,则映射过程就是一个求一元一次函数值的过程,其对应的曲线是一条直线,不过需要对函数值取整。实际上,在范围外的标量值也可以被看作smin和smax,然后对其求函数值。

在VTK中,颜色映射的过程是由映射器mapper完成的。可以通过调用映射器的方法SetScalarRange()来设置标量值的范围[smin, smax]。映射过程只是为每个标量值确定了一个索引号,最终该标量值映射为何种颜色,还需要看颜色查询表中颜色的分配情况。如果不手动创建一个查询表,则映射器会使用一个默认的映射表。

vtkDataSet

vtkDataSet是一个抽象类,不能直接实例化,它是VTK所有数据集类型的父类,主要为数据集类型声明了一些通用接口以及成员。

在这里插入图片描述

从这个继承树中可以看到vtkDataSet所有的子类。

实现颜色标量映射主要关注的只有两个接口:

  1. vtkCellData* GetCellData();
  2. vtkPointData* GetPointData();

这两个数据分别对应的是单元数据集点数据集。

单元数据集中的单元指得是计算机图形的图元集合,如果是多边形数据集那么它就是一个三角网格中所有三角形的集合,如果使用结构或者非结构化网格数据,那么它就是网格单元数据的集合。

点数据集合是单元集合中所用到所有的点的集合,根据数据集的类型不同,包含的数据也略微有点不同。

vtkDataSetAttributes

在这里插入图片描述

上述的vtkCellData和vtkPointData都继承于vtkDataSetAttributes,它可以用于包含标量、向量、法线、纹理坐标、张量、全局 id、谱系 id 和字段数据等数据。

// Description:
// Set/Get the scalar data.
int SetScalars(vtkDataArray* da);
int SetActiveScalars(const char* name);
vtkDataArray* GetScalars();// Description:
// Set/Get the vector data.
int SetVectors(vtkDataArray* da);
int SetActiveVectors(const char* name);
vtkDataArray* GetVectors();// Description:
// Set/get the normal data.
int SetNormals(vtkDataArray* da);
int SetActiveNormals(const char* name);
vtkDataArray* GetNormals();// Description:
// Set/Get the texture coordinate data.
int SetTCoords(vtkDataArray* da);
int SetActiveTCoords(const char* name);
vtkDataArray* GetTCoords();// Description:
// Set/Get the tensor data.
int SetTensors(vtkDataArray* da);
int SetActiveTensors(const char* name);
vtkDataArray* GetTensors();// Description:
// Set/Get the global id data.
int SetGlobalIds(vtkDataArray* da);
int SetActiveGlobalIds(const char* name);
vtkDataArray* GetGlobalIds();// Description:
// Set/Get the pedigree id data.
int SetPedigreeIds(vtkAbstractArray* da);
int SetActivePedigreeIds(const char* name);
vtkAbstractArray* GetPedigreeIds();

以上接口对应了每种数据的获取与设置,每种数据似乎可以添加多个序列,然后可以使用序列名称调整当前使用的数据,序列名称通过vtkDataArray类setName函数进行设置。序列数据中的顺序需要对应实际数据的顺序。这里的顺序指的是ID,如Point数据,每个点都会有一个ID,那么为这些点数据附加标量数据的时候,标量数据的传入顺序就需要与id一一对应,如果是cellData那么也同理。

vtkLookUpTable

图像彩色映射的原理是首先生成一个颜色查找表,然后根据图像的一个标量值向颜色查找表中查找对应的颜色,并用新颜色值替代原来的像素值。

VTK中vtkImageMapToColors负责图像彩色映射,vtkLookUpTable提供一个从标量到颜色的映射表。

//设置颜色的过渡模式
void SetRamp(int);
void SetRampToLinear();//线性
void SetRampToSCurve();//s曲线
void SetRampToSQRT();//y=sqrt(x)
int GetRamp();
//设置颜色的与标量的映射模式
void SetScale(int);
void SetScaleToLinear();//线性
void SetScaleToLog10();//对数
int GetScale();

void SetTableRang(double r[2]);//设置标量的范围(最小,最大值)
void SetHueRang(double,double);//设置色调范围,取[0,1]之间
void SetSaturationRange(double,double);//设置饱和度,取[0,1]之间
void SetValueRange(double,double);//设置颜色值的取值范围,取[0,1]之间
void SetAlphaRange();//设置透明的取值范围,取[0,1]之间
void SetNanColor(double,double,double,double);//设置遇到Nan(非数)时使用的颜色
void SetBelowRangeColor(double,double,double,double);//设置当低于范围使用的颜色
void SetAboveRangeColor(double,double,double,double);//设置当超出范围时使用的颜色
void SetNumberOfTableValues(vtkIdType number);//设置颜色数量(色块)
void SetTableValue(vtkIdType indx,double r, double g, double b, double a=1.0);//直接设置颜色值
//根据各种参数生成颜色表
void Build();

这是它的一些关键接口,通过这些结构可以构造一个完整的颜色表,然后再调用映射器对象的SetLookupTable (vtkScalarsToColors *lut)函数设置即可。

vtkScalarBarActor

这个类不是颜色映射时必须要的类,但是它可以直观的将颜色映射表显示到窗口上,非常的方便。

使用起来也很简单,它继承于vtkActor,只需要调用SetLookupTable (vtkScalarsToColors *)函数设置好对应的颜色表,然后将Actor添加到渲染器中即可。

实例:

//为三角形准备三个顶点
vtkNew<vtkPoints> points;
points->InsertNextPoint(1, 0, 0);
points->InsertNextPoint(0, 0, 0);
points->InsertNextPoint(0, 1, 0);

//生成点的标量数据
vtkNew<vtkIntArray> scalar;
scalar->InsertNextTuple1(30);
scalar->InsertNextTuple1(50);
scalar->InsertNextTuple1(100);

//使用顶点构建一个三角形 点使用ID传入
vtkNew<vtkTriangle> triangle;
triangle->GetPointIds()->SetId(0, 0);
triangle->GetPointIds()->SetId(1, 1);
triangle->GetPointIds()->SetId(2, 2);

//将三角形传入单元集
vtkNew<vtkCellArray> cellArray;
cellArray->InsertNextCell(triangle);

//为多边形数据添加单元集和点集
vtkNew<vtkPolyData> polydata ;
polydata->SetPolys(cellArray);
polydata->SetPoints(points);
//为点数据添加标量
polydata->GetPointData()->SetScalars(scalar);

vtkNew<vtkPolyDataMapper> mapper;
mapper->SetInputData(polydata);
mapper->SetScalarRange(scalar->GetRange());
mapper->Update();
//为映射器添加一个颜色映射表
vtkNew<vtkLookupTable> lookupTable;
lookupTable->SetTableRange(scalar->GetRange());
lookupTable->Build();
mapper->SetLookupTable(lookupTable);

//为窗口添加一个图例
vtkNew<vtkScalarBarActor> scalarBarActor;
scalarBarActor->SetLookupTable(lookupTable);

vtkNew<vtkActor> actor;
actor->SetMapper(mapper);
actor->GetProperty()->SetColor(255, 0, 0);

vtkNew<vtkRenderer> renderer;
vtkNew<vtkRenderWindow> window;
window->AddRenderer(renderer);

vtkNew<vtkRenderWindowInteractor> interactor;
interactor->SetRenderWindow(window);

renderer->AddActor(actor);
renderer->AddActor(scalarBarActor);
window->Render();
interactor->Start();

运行结果:

在这里插入图片描述

代码实现了一个三角形的构建,并为三角形的三个顶点添加标量,然后在显示时使用标量进行颜色映射,可以说这是一个最简单的标量映射的一个例子。

需要注意的是因为代码中是为point添加的标量,除了顶点以外的其他位置的标量值都是经过线性插值得到的。

实例

#include "VTKColorMapping.h"

#include <vtkConeSource.h>
#include <vtkSTLReader.h>
#include <vtkMultiBlockPLOT3DReader.h>
#include <vtkDataSet.h>
#include <vtkMultiBlockDataSet.h>
#include <vtkShrinkPolyData.h>
#include <vtkStructuredGridGeometryFilter.h>
#include <vtkStructuredGridOutlineFilter.h>
#include <vtkLookupTable.h>
#include <vtkPolyDataMapper.h>
#include <vtkActor.h>
#include <vtkRenderer.h>
#include <vtkRenderWindow.h>

VTKColorMapping::VTKColorMapping(QWidget* parent)
	: QMainWindow(parent)
{
	ui.setupUi(this);

	_pVTKWidget = new QVTKOpenGLNativeWidget();
	this->setCentralWidget(_pVTKWidget);
	// this->showMaximized();

	// 1. generate data
	// vtkSmartPointer<vtkConeSource> cone = vtkSmartPointer<vtkConeSource>::New();
	// or, read data
	// vtkMultiBlockPLOT3DReader 是一个读取器对象,用于读取 PLOT3D 格式的文件并在输出时生成结构化网格
	vtkSmartPointer<vtkMultiBlockPLOT3DReader> plot3dReader = vtkSmartPointer<vtkMultiBlockPLOT3DReader>::New();
	plot3dReader->SetXYZFileName("combxyz.bin");
	plot3dReader->SetQFileName("combq.bin");
	plot3dReader->SetScalarFunctionNumber(100);
	plot3dReader->SetVectorFunctionNumber(202);
	qDebug() << plot3dReader->GetOutput()->GetNumberOfBlocks();
	// 反向更新管线
	plot3dReader->Update();
	qDebug() << plot3dReader->GetOutput()->GetNumberOfBlocks();
	vtkDataSet* plot3dOutput = (vtkDataSet*)(plot3dReader->GetOutput()->GetBlock(0));


	// 2. filter
	// 提取作为多边形几何(点,线,表面)的栅格的一部分
	vtkSmartPointer<vtkStructuredGridGeometryFilter> plane = vtkSmartPointer<vtkStructuredGridGeometryFilter>::New();
	plane->SetInputData(plot3dOutput);
	plane->SetExtent(1, 100, 1, 100, 7, 7);
	// 产生结构化栅格边界的一个线轮廓
	vtkSmartPointer<vtkStructuredGridOutlineFilter> outline = vtkSmartPointer<vtkStructuredGridOutlineFilter>::New();
	outline->SetInputData(plot3dOutput);
	// 颜色映射表
	vtkSmartPointer<vtkLookupTable> lut = vtkSmartPointer<vtkLookupTable>::New();
	lut->SetNumberOfColors(256); // 指定颜色映射表中有多少种颜色
	lut->Build();

	// 3. mapper
	vtkSmartPointer<vtkPolyDataMapper> planeMapper = vtkSmartPointer<vtkPolyDataMapper>::New();
	vtkSmartPointer<vtkPolyDataMapper> outlineMapper = vtkSmartPointer<vtkPolyDataMapper>::New();

	// 4. actor
	vtkSmartPointer<vtkActor> planeActor = vtkSmartPointer<vtkActor>::New();
	vtkSmartPointer<vtkActor> outlineActor = vtkSmartPointer<vtkActor>::New();

	// 5. renderer
	vtkSmartPointer<vtkRenderer> renderer = vtkSmartPointer<vtkRenderer>::New();
	renderer->SetBackground(0.3, 0.6, 0.3); // Background Color: Green

	// 6. connect
	planeMapper->SetLookupTable(lut);
	planeMapper->SetInputConnection(plane->GetOutputPort());
	planeMapper->SetScalarRange(plot3dOutput->GetScalarRange()); // 设置标量值的范围
	outlineMapper->SetInputConnection(outline->GetOutputPort());
	planeActor->SetMapper(planeMapper);
	outlineActor->SetMapper(outlineMapper);
	renderer->AddActor(planeActor);
	renderer->AddActor(outlineActor);

	this->_pVTKWidget->renderWindow()->AddRenderer(renderer);
	this->_pVTKWidget->renderWindow()->Render();
}

VTKColorMapping::~VTKColorMapping()
{}

本程序采用 vtkMultiBlockPLOT3DReader 读取数据,它是一个读取器对象,用于读取 PLOT3D 格式的文件并在输出时生成结构化网格。本程序读取了 combxyz.bin 和 combq.bin 两个文件。

读取完之后,需要 plot3dReader->Update() 来更新数据源对象,我们在更新前后分别使用 plot3dReader->GetOutput()->GetNumberOfBlocks() 打印了数据源的块数,更新前是 0,更新后变为 1。

之后,从 plot3dReader 的输出中取出下标为 0 的块作为 plot3dOutput。创建一个 vtkStructuredGridGeometryFilter 类型的过滤器 plane,它可以提取作为多边形几何(点,线,表面)的栅格的一部分,使用 plane->SetExtent(1, 100, 1, 100, 7, 7) 提取指定3D范围的数据;还创建了一个 vtkStructuredGridOutlineFilter 类型的过滤器 outline,它可以产生结构化栅格边界的一个线轮廓。这两个过滤器的输入都是 plot3dOutput。新建一个颜色映射表 lut,指定颜色映射表中有256种颜色,使用 lut->Build() 把这个颜色映射表构建好。

对 plane 和 outline 分别创建 mapper 和 actor,planeMapper 还需要设置 lut 和标量值的范围,都绑定到渲染器上,就可以在屏幕上显示了。

运行结果:

在这里插入图片描述

参考

  1. http://cppdebug.com/archives/242
  2. https://blog.csdn.net/Littlehero_121/article/details/131204958
  3. https://shenchunxu.blog.csdn.net/article/details/54696460
  4. https://blog.csdn.net/webzhuce/article/details/78077561

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

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

相关文章

.net core ef 连表查询

Information和TypeInfo连表查询 类似&#xff1a; select st.Title1,si.* from [Star_Information] si left join Star_TypeInfo st on si.typeId2st.id 先在EfCoreDbContext.cs配置 protected override void OnModelCreating(ModelBuilder builder){base.OnModelCreating(b…

C++数据结构——二叉搜索树

二叉搜索树的概念 二叉树又称二叉排序树(BST&#xff0c;Binary Search Tree)&#xff0c;它是一颗空树&#xff0c;也可以是一颗具有下列性质的二叉树&#xff1a; 1.假如它的左子树不为空&#xff0c;那么左子树上的结点值都小于根结点的值。 2.假如它的右子树不为空&…

K8S controller编写之Informer的原理+使用[drift]

概念 核心思想&#xff08;重点&#xff09;watch-list 机制 Watch 通过 HTTP 协议与 Kubernetes API Server 建立长连接&#xff0c;接收 Kubernetes API Server 发来的资源变更事件。Watch 操作的实现机制使用 HTTP 协议的分块传输编码——当 client-go 调用 Kubernetes API…

nacos(docker部署)+springboot集成

文章目录 说明零nacos容器部署初始化配置高级配置部分访问权限控制命名空间设置新建配置文件 springboot配置nacos添加依赖编写测试controller 说明 nacos容器部署采用1Panel运维面板&#xff0c;进行部署操作&#xff0c;简化操作注意提前安装好1Panel和配置完成docker镜像加…

三、VUE数据代理

一、初识VUE 二、再识VUE-MVVM 三、VUE数据代理 Object.defineProperty() Object.defineProperty() 静态方法会直接在一个对象上定义一个新属性&#xff0c;或修改其现有属性&#xff0c;并返回此对象。 Object.defineProperty() 数据代理 通过一个对象代理另一个对象中属…

CSS 06

精灵图 为什么要使用精灵图 一个网页中往往会应用很多小的背景图像作为修饰&#xff0c;当网页中的图像过多时&#xff0c;服务器就会频繁地接收和发送请求图片&#xff0c;造成服务器请求压力过大&#xff0c;这将大大降低页面的加载速度,因此&#xff0c;为了有效地减少服务…

Python来计算 1,2,3,4 能组成多少个不相同且不重复的三位数?

我们今天的例子是 有 1&#xff0c;2&#xff0c;3&#xff0c;4 四个数字&#xff0c;它们能组成多省个互不相同且无重复的三位数&#xff1f;都分别是多少&#xff1f; 话不多说&#xff0c;我们先上代码 num 0 # 我们写了三个for循环&#xff0c;表示生成的三位数 for i…

YOLOv5模型训练处理自己数据集(标签统计、数据集划分、数据增强)

上一节中我们讲到如何使用Labelimg工具标注自己的数据集&#xff0c;链接&#xff1a;YOLOv5利用Labelimg标注自己数据集&#xff0c;完成1658张数据集的预处理&#xff0c;接下来将进一步处理这批数据&#xff0c;通常是先划分再做数据增强。 目录 一、统计txt文件各标签类型…

在项目中添加日志功能-Python logging模块新手入门

Python Logging 日志模块新手入门 这也是规划里的一篇工具文章&#xff0c;在写项目代码的时候不但要考虑代码的架构代码的后期维护和调试等也是一个比较关键的问题&#xff0c;之前写代码的时候日志这块的代码直接是任务驱动简单搜了一下就用了&#xff0c;但是秉持着打好基础…

十八、Java解析XML文件

1、XML文档语法和DTD约束 1)XML定义 XML即可扩展的标记语言,可以定义语义标记(标签),是元标记语言。XML不像超文本标记语言HTML,HTML只能使用规定的标记,对于XML,用户可以定义自己需要的标记。 XML(Extensible Markup Language)和HTML(Hyper Text Markup Language)师出同…

智能体可靠性的革命性提升,揭秘知识工程领域的参考架构新篇章

引言&#xff1a;知识工程的演变与重要性 知识工程&#xff08;Knowledge Engineering&#xff0c;KE&#xff09;是一个涉及激发、捕获、概念化和形式化知识以用于信息系统的过程。自计算机科学和人工智能&#xff08;AI&#xff09;历史以来&#xff0c;知识工程的工作流程因…

救护员证学习笔记

第一节 红十字运动基础知识 红十字运动的优势 197个主权国家、191个红十字会 四次获得诺贝尔和平奖 红十字运动的组成 红十字运动七项准则 红十字运动的标志 新中国红十字运动宗旨 保护人的生命与健康 维护人的尊严 发扬人道主义精神 促进和平事业进步 红十字会的主要工作 …

VGG16简单部署(使用自己的数据集)

一.注意事项 1.本文主要是引用大佬的文章&#xff08;侵权请联系&#xff0c;马上删除&#xff09;&#xff0c;做的工作为简单补充 二.介绍 ①简介&#xff1a;VGG16是一种卷积神经网络模型&#xff0c;由牛津大学视觉几何组&#xff08;Visual Geometry Group&#xff09;开…

【错题集-编程题】组队竞赛(排序 + 贪心)

牛客对应题目链接&#xff1a;组队竞赛_牛客笔试题_牛客网 (nowcoder.com) 一、分析题目 运用 贪心 思想&#xff1a; 先将数组排好序。总和最大 -> 每个小组的分数尽可能大。最大的数拿不到&#xff0c;只能退而求其次拿到倒数第⼆个⼈的分数&#xff0c;再补上一个小的数…

shell脚本-监控系统内存和磁盘容量

监控内存和磁盘容量除了可以使用zabbix监控工具来监控&#xff0c;还可以通过编写Shell脚本来监控。 #! /bin/bash #此脚本用于监控内存和磁盘容量&#xff0c;内存小于500MB且磁盘容量小于1000MB时报警#提取根分区剩余空间 disk_size$(df / | awk /\//{print $4})#提取内存剩…

西圣发布全新磁吸无线充电宝:打破传统,让充电更加高效、便捷

手机作为日常生活中最不能离开的数码单品之一&#xff0c;出门在外&#xff0c;电量情况总是让人担忧&#xff0c;一款靠谱的移动电源简直就是救星&#xff01;近日&#xff0c;西圣品牌推出了一款集高效、安全、便携于一体的无线充电宝——西圣PB无线磁吸充电宝&#xff0c;以…

Maven解决找不到依赖项

报错如图 方案一&#xff1a;Maven的Setting文件中添加albaba的镜像文件 1.下载maven &#xff1a;Maven – Download Apache Maven 2. 配置镜像 更改成这个&#xff1a; <mirror> <id>alimaven</id> <name>aliyun maven</name> <url&g…

webpack 常用插件

clean-webpack-plugin 这个插件的主要作用是清除构建目录中的旧文件&#xff0c;以确保每次构建时都能得到一个干净的环境。 var { CleanWebpackPlugin } require("clean-webpack-plugin") const path require("path");module.exports {mode: "de…

第十五届蓝桥杯省赛第二场C/C++B组H题【质数变革】题解

解题思路 首先&#xff0c;我们考虑一下整个数组都是由质数构成的情况。 当我们要将质数 x x x 向后移 k k k 个时&#xff0c;如果我们可以知道质数 x x x 在质数数组的下标 j j j&#xff0c;那么就可以通过 p r i m e s [ j k ] primes[j k] primes[jk] 来获取向后…

牛客NC279 二叉树的下一个结点【中等 二叉树中序遍历 C++/Java/Go/PHP】

题目 题目链接&#xff1a; https://www.nowcoder.com/practice/9023a0c988684a53960365b889ceaf5e 思路 思路&#xff1a;我们首先要根据给定输入中的结点指针向父级进行迭代&#xff0c; 直到找到该树的根节点&#xff1b;然后根据根节点进行中序遍历&#xff0c;当遍历到和…