当前位置: 首页 > news >正文

VTK知识学习(26)- 图像基本操作(一)

1、前言

        图像处理离不开一些基本的图像数据操作,例如获取和修改图像的基本信息、访问和修改图像像素值、图像显示、图像类型转换等。熟练掌握这些基本操作有助于使用 VTK进行图像处理应用程序的快速开发。

2、图像信息的访问与修改

1)利用vtkIamgeData方法

        vtkImageData中提供了多个函数用于访问或者获取图像的基本信息,这些函数通常以 Set或者 Get加上相应的信息名的形式进行命名,例如获取图像维数的方法定义为 GetDimensions()。

private void TestGetImageInfo()
{vtkBMPReader reader = vtkBMPReader.New();reader.SetFileName("F:\\code\\VTK\\TestActiViz\\bin\\Debug\\data\\lena.bmp");reader.Update();int[] dims = reader.GetOutput().GetDimensions();Console.WriteLine($"图像维数:{dims[0]} {dims[1]} {dims[2]}");double[] orgin = reader.GetOutput().GetOrigin();Console.WriteLine($"图像原点:{orgin[0]} {orgin[1]} {orgin[2]}");double[] spaceing = reader.GetOutput().GetSpacing();Console.WriteLine($"像素间隔:{spaceing[0]} {spaceing[1]} {spaceing[2]}");vtkImageActor actor = vtkImageActor.New();actor.SetInputData(reader.GetOutput());vtkRenderer renderer = vtkRenderer.New();renderer.AddActor(actor);renderer.ResetCamera();renderer.SetBackground(1, 1, 1);vtkRenderWindow renderWindow = renderWindowControl.RenderWindow;renderWindow.AddRenderer(renderer);renderWindow.Render();
}

        示例主要获取了图像的三个信息,即图像维数、图像原点和像素间隔。

        VTK 中无论是二维图像还是三维图像,都用 vtkImageData表示,因此程序中定义图像维数为 dims[3],然后利用 GetDimensions()函数获取图像的维数;图像的原点和像素间隔都是物理空间数值,其数值类型为 double。从显示结果中可以看到,图像维数为512x512x1,其中Z方向的维数为1,说明该图像为二维图像:而图像的原点为(0,0,0)点,像素间隔为(1,1,1)。

2)利用类vtkChangeImageInformation

        vtkImageData 中提供了多个 Set 函数用于设置图像的基本信息。在对一个图像 Filter的输出图像信息进行修改后,如果 Filter 重新 Update,图像信息又会恢复回原来的值。而vtkChangeImageInformation 类可以作为管线中的一个 Filter 来修改图像信息。利用这个Filter 可以修改图像的原点、像素间隔以及范围,另外还可以实现图像平移缩放等操作。

private void TestChangeImageInfo()
{vtkBMPReader reader = vtkBMPReader.New();reader.SetFileName("F:\\code\\VTK\\TestActiViz\\bin\\Debug\\data\\lena.bmp");reader.Update();int[] dims = reader.GetOutput().GetDimensions();Console.WriteLine($"原图像维数:{dims[0]} {dims[1]} {dims[2]}");double[] orgin = reader.GetOutput().GetOrigin();Console.WriteLine($"原图像原点:{orgin[0]} {orgin[1]} {orgin[2]}");double[] spaceing = reader.GetOutput().GetSpacing();Console.WriteLine($"原像素间隔:{spaceing[0]} {spaceing[1]} {spaceing[2]}");vtkImageChangeInformation changer = vtkImageChangeInformation.New();changer.SetInputData(reader.GetOutput());changer.SetOutputOrigin(100, 100, 0);changer.SetOutputSpacing(5, 5, 1);changer.SetCenterImage(1);changer.Update();dims = changer.GetOutput().GetDimensions();Console.WriteLine($"修改后图像维数:{dims[0]} {dims[1]} {dims[2]}");orgin = changer.GetOutput().GetOrigin();Console.WriteLine($"修改后图像原点:{orgin[0]} {orgin[1]} {orgin[2]}");spaceing = changer.GetOutput().GetSpacing();Console.WriteLine($"修改后像素间隔:{spaceing[0]} {spaceing[1]} {spaceing[2]}");vtkImageActor actor = vtkImageActor.New();actor.SetInputData(changer.GetOutput());vtkRenderer renderer = vtkRenderer.New();renderer.AddActor(actor);renderer.ResetCamera();renderer.SetBackground(1, 1, 1);vtkRenderWindow renderWindow = renderWindowControl.RenderWindow;renderWindow.AddRenderer(renderer);renderWindow.Render();
}

        示例先读入图像,由 vtklmageData提供的函数接口获取图像的维数、图像原点和像素间隔。然后定义 vtkImageChangeInformation 对象,并设置输出图像原点为(100,100,0),输出图像像素间隔为(5,5,1),然后调用 CenterImage()函数将图像的原点置于图像的中心。
        操作后的结果使得图像的原点位于(-1277.5,-1275.5,0)。

        SetOutputOrigin(100,100,0)并没有起作用。查看 CenterImage()函数的注释,可以发现该函数的作用是将(0,0,0)点置于图像的中心。当Centerlmage()函数执行时会重新调用 SetOutputOrigin(),所以开始的 SetOutputOrigin()函数设置的原点将会被覆盖。

        (-1277.5,-1275.5,0)是如何计算出来的呢?

        根据图像的维数和像素间隔计算得到新的图像的宽度和高度为(512-1)x5,初始图像的原点位于(0,0,0),现在将图像的中心平移至原点,平移量为(-(512-1)x5/2,(512-1)x5/2,0)=(-1277.5,-1275.5,0)。

3、图像像素值的访问与修改

        图像像素值的访问与修改是最常用的一种操作。VTK 中提供了两种访问图像像素值的方法第一种方法是直接访问 vtkImageData 的数据数组,这种方法最直接。前面创建图像赋值时也是采用这种方法。vtkImageData中提供了GetScalarPointer()函数获取数据数组指针,该函数有三种形式:

virtual void *GetScalarPointer(int coordinates[3]);
virtual void *GetScalarPointer(int x, int y, int z);
virtual void *GetScalarPointer();

        前两种形式根据给定的像素索引得到指定的像素值,注意返回的是第(x,y,z)个像素值的地址。而第三种形式是返回图像数据数组的头指针,然后根据头指针可以依次访问索引像素。

1)数据数组

一个遍历图像像素的示例:

private void TestVisitPixel()
{vtkBMPReader reader = vtkBMPReader.New();reader.SetFileName("F:\\code\\VTK\\TestActiViz\\bin\\Debug\\data\\lena.bmp");reader.Update();//获取图像的大小int[] dims = reader.GetOutput().GetDimensions();//将图像的100*100大小的区域设置为黑色for (int k = 0; k < dims[2]; k++){for (int j = 0; j < dims[1]; j++){for (int i = 0; i < dims[0]; i++){if (i < 100 && j < 100){//VTK彩色及矢量图像的像素存储格式示意: …R G B R G B…byte[] infos = new byte[] { 0, 0, 0 };var pixel = reader.GetOutput().GetScalarPointer(i, j, k);Marshal.Copy(infos, 0, pixel, 3);}}}}vtkImageActor actor = vtkImageActor.New();actor.SetInputData(reader.GetOutput());vtkRenderer renderer = vtkRenderer.New();renderer.AddActor(actor);renderer.ResetCamera();renderer.SetBackground(1, 1, 1);vtkRenderWindow renderWindow = renderWindowControl.RenderWindow;renderWindow.AddRenderer(renderer);renderWindow.Render();
}

        实现了将图像的 100x100大小的区域设置为黑色。先定义一个 reader 读取一幅 BMP 图像,通过 vtkImageData的 GetDimensionsO)函数获取图像的大小。然后建立三重循环,通过 GetScalarPointer(i,j,k)函数获取访问图像像素值。

        需要注意的是,GetScalarPointer0函数返回的是 void*类型,因此需要根据图像的实际类型进行强制转换。如上面代码中将像素值数组的头指针类型转换为unsignedchar*。如果对数据类型不确定,还可以将图像数据类型强制转换为特定的数据类型,再进行遍历。

当然这个使用是指在c++中,在我们c#中你也看到是使用Marshal对指针进行复制操作了。

VTK 彩色以及矢量图像采用的是类似图 所示的像素存储格式。

        因此在修改 RGB 图像以及矢量图像像素时,需要根据像素的元组的组分数目来访问。例中,需要修改每个像素的 RGB 值时,先获得第(i,i,k)个像素的地址也就是R值的地址,然后将地址加1来访问后续G值以及B值。如果对于像素的元组组分不确定,可以通过函数GetNumberOfScalarComponents()来获取,代码如下所示:

int nbOfComp = reader->GetOutput()->GetNumberOfScalarComponents();
2)迭代器方法访问图像像素

        用 vtkImagelterator 类实现迭代器方法访问图像像素。该类是一个模板类使用时,需要提供迭代的图像像素类型以及迭代的区域大小。

        这个是c++的方式,c#没有找到对应的实现。

void TestVisitImagePixelIteratively(){vtkSmartPointer<vtkBMPReader> reader =vtkSmartPointer<vtkBMPReader>::New();reader->SetFileName("F:\\code\\VTK\\TestActiViz\\bin\\Debug\\data\\lena.bmp");reader->Update();int numComponents = reader->GetOutput()->GetNumberOfScalarComponents();int subRegion[6] = { 0,300, 0, 300, 0, 0 };vtkImageIterator<unsigned char> it(reader->GetOutput(), subRegion);while (!it.IsAtEnd()){unsigned char* inSI = it.BeginSpan();unsigned char* inSIEnd = it.EndSpan();while (inSI!=inSIEnd){*inSI = 255 - *inSI;++inSI;}it.NextSpan();}vtkSmartPointer<vtkImageViewer2> imageViewer =vtkSmartPointer<vtkImageViewer2>::New();imageViewer->SetInputConnection(reader->GetOutputPort());vtkSmartPointer<vtkRenderWindowInteractor> renderWindowInteractor =vtkSmartPointer<vtkRenderWindowInteractor>::New();imageViewer->SetupInteractor(renderWindowInteractor);imageViewer->Render();imageViewer->GetRenderer()->ResetCamera();imageViewer->Render();imageViewer->GetRenderer()->SetBackground(1.0, 1.0, 1.0);imageViewer->SetSize(640, 480);imageViewer->GetRenderWindow()->SetWindowName("VisitImagePixelIterativelyExample");renderWindowInteractor->Start();}

相关文章:

VTK知识学习(26)- 图像基本操作(一)

1、前言 图像处理离不开一些基本的图像数据操作&#xff0c;例如获取和修改图像的基本信息、访问和修改图像像素值、图像显示、图像类型转换等。熟练掌握这些基本操作有助于使用 VTK进行图像处理应用程序的快速开发。 2、图像信息的访问与修改 1&#xff09;利用vtkIamgeData…...

2024年9月AI头条新闻:创新与挑战并存

2024年9月AI头条新闻&#xff1a;创新与挑战并存 9月&#xff0c;人工智能领域继续高速发展&#xff0c;重大产品发布、伦理争议和技术突破交织在一起。让我们回顾一下本月最重要的AI新闻&#xff1a; OpenAI的o1&#xff1a;更强大的语言模型 OpenAI推出了o1&#xff0c;一个…...

[Xshell] Xshell的下载安装使用、连接linux、 上传文件到linux系统-详解(附下载链接)

前言 xshell 链接&#xff1a;https://pan.quark.cn/s/57062561e81a 提取码&#xff1a;TK4K 链接失效&#xff08;可能被官方和谐&#xff09;可评论或私信我重发 安装 下载后解压得到文件 安装路径不要有中文 打开文件 注意&#xff01;360等软件会拦截创建注册表的行为&a…...

count(1)、count(_)与count(列名)的区别?

大家好&#xff0c;我是锋哥。今天分享关于【count(1)、count(_)与count(列名)的区别&#xff1f;】面试题。希望对大家有帮助&#xff1b; count(1)、count(_)与count(列名)的区别&#xff1f; 1000道 互联网大厂Java工程师 精选面试题-Java资源分享网 在 SQL 中&#xff0c…...

代码随想录训练营第二十七天| 贪心理论基础 455.分发饼干 376. 摆动序列 53. 最大子序和

贪心没有套路&#xff0c;说白了就是常识性推导加上举反例 今天的内容比较简单 简单了解贪心是通过局部最优解反推全局最优解&#xff08;有经验成分&#xff09; 455.分发饼干 题目链接&#xff1a;455. 分发饼干 - 力扣&#xff08;LeetCode&#xff09; 讲解链接&#xff…...

List直接使用removeAll报错

List直接使用removeAll报错 需要先将list转换才能使用 原因是&#xff1a; removeAll 方法在 Java 中用于从当前列表中删除另一个列表中存在的所有元素。如果直接对 List 接口的一个实现使用 removeAll 方法抛出异常&#xff0c;可能的原因有&#xff1a; 不同的List实现&am…...

Debian环境安装Docker Engine

Debian环境安装Docker Engine 卸载旧版本使用APT工具安装Docker设置存储库安装Docker设置权限 docker compose命令卸载Docker 卸载旧版本 要卸载的非官方软件包是&#xff1a; docker.iodocker-composedocker-docpodman-docker 此外&#xff0c;Docker Engine 依赖 containe…...

Python常用内置函数总结

目录 1. abs() 2. complex() 3. divmod() 4. eval() 5. float() 6. hash() 7. input() 8. int() 9. len() 10. list() 11. oct() 12. open() 13. pow() 14. print() 15. range() 16. reversed() 17. round() 18. sorted()…...

深入了解蓝牙Profile类型与设备的对应关系

在现代技术中,蓝牙作为一种无线通信技术,广泛应用于各种设备之间的短距离通信。不同的设备在连接时使用不同的蓝牙Profile(配置文件),每种Profile都为特定的设备功能提供支持,例如音频流传输、语音通话、文件传输等。在本文中,我们将详细介绍蓝牙Profile的常见类型及其对…...

[bug]java导出csv用Microsoft Office Excel打开乱码解决

[bug]java导出csv用Microsoft Office Excel打开乱码 ‍ 现象 首先这个csv文件用macbook自带的 "Numbers表格" 软件打开是不乱码的, 但是使用者是Windows系统,他的电脑没有"Numbers表格"工具, ​​ 他用Microsoft Office Excel打开之后出现乱码,如下图…...

2023年区块链职业技能大赛——区块链应用技术(一)模块一

模块一:区块链产品方案设计及系统运维: 任务1-1:区块链产品需求分析与方案设计 1.依据给定区块链食品溯源系统的业务架构图&#xff0c;对考题进行业务分析&#xff0c;可能多的去考虑一个业务系统所需要的模块&#xff0c;使用Visio或思维导图工具展现本系统的基本设计概念和…...

4 软件工程——总体设计

一、设计过程 1.两个主要阶段 系统设计阶段&#xff1a;确定系统的具体实现方案结构设计阶段&#xff1a;确定软件结构 2.九个步骤 设想供选择的方案选取合理的方案推荐最佳方案功能分解设计软件结构设计数据库制定测试计划书写文档审查和复审 二、设计原理 1.模块化 模块…...

Elasticsearch:确保业务规则与语义搜索无缝协作

作者&#xff1a;来自 Elastic Kathleen DeRusso 利用查询规则与语义搜索和重新排序相结合的强大功能。 更多阅读&#xff1a; Elasticsearch 8.10 中引入查询规则 - query rules Elasticsearch 查询规则现已正式发布 - query rules 你是否知道查询规则&#xff08;query ru…...

【大语言模型】ACL2024论文-33 Johnny 如何说服大型语言模型越狱:通过人性化 LLMs 重新思考挑战 AI 安全性的说服技巧

【大语言模型】ACL2024论文-33 Johnny 如何说服大型语言模型越狱&#xff1a;通过人性化 LLMs 重新思考挑战 AI 安全性的说服技巧 目录 文章目录 【大语言模型】ACL2024论文-33 Johnny 如何说服大型语言模型越狱&#xff1a;通过人性化 LLMs 重新思考挑战 AI 安全性的说服技巧目…...

【LuaFramework】LuaFramework_UGUI_V2框架学习

GitHub - jarjin/LuaFramework_UGUI_V2: 基于tolua的热更新框架V2 旧版本是Unity 5.0&#xff0c;这个是新版本支持更高版本的 导入工程后先清除wrap 然后重新生成wrap&#xff0c;你会发现有个报空null&#xff0c;框架的问题总结下所有的框架wrap相关报错问题和修复方法&…...

使用 AOP 在 Spring Boot 中实现跟踪和日志记录

在现代应用程序中&#xff0c;尤其是使用微服务构建的应用程序&#xff0c;跟踪和日志记录在跟踪流经各种服务的请求方面起着至关重要的作用。跟踪可帮助开发人员诊断问题、监控性能并了解用户在多个系统中的旅程。 在此博客中&#xff0c;我们将介绍如何使用traceId从前端生成…...

如何永久解决Apache Struts文件上传漏洞

Apache Struts又双叒叕爆文件上传漏洞了。 自Apache Struts框架发布以来&#xff0c;就存在多个版本的漏洞&#xff0c;其中一些漏洞涉及到文件上传功能。这些漏洞可能允许攻击者通过构造特定的请求来绕过安全限制&#xff0c;从而上传恶意文件。虽然每次官方都发布补丁进行修…...

FPGA远程升级 -- FLASH控制

简介 前文讲到如何实现XILINX芯片程序跳转&#xff0c;但升级程序是事先通过VIVADO工具将两个程序合成一个BIN文件实现升级的&#xff0c;并不能在线更新升级。要实现远程升级的能力需要对FPGA的FLASH进行在线写入升级程序。 FLASH介绍 本次设计FLASH选用的是S25FL128芯片&…...

企业内训|高智能数据构建、Agent研发及AI测评技术内训-吉林省某汽车厂商

吉林省某汽车厂商为提升员工在AI大模型技术方面的知识和实践能力&#xff0c;举办本次为期8天的综合培训课程。本课程分为两大部分&#xff1a;面向全体团队成员的AI大模型技术结构与行业应用&#xff0c;以及针对技术团队的高智能数据构建与Agent研发。课程内容涵盖非结构化数…...

ARM异常处理 M33

1. ARMv8-M异常类型及其详细解释 ARMv8-M Exception分为两类&#xff1a;预定义系统异常(015)和外部中断(1616N)。 各种异常的状态可以通过Status bit查看&#xff0c;获取更信息的异常原因&#xff1a; CFSR是由UFSR、BFSR和MMFSR组成&#xff1a; 下面列举HFSR、MMFSR、…...

调用支付宝接口响应40004 SYSTEM_ERROR问题排查

在对接支付宝API的时候&#xff0c;遇到了一些问题&#xff0c;记录一下排查过程。 Body:{"datadigital_fincloud_generalsaas_face_certify_initialize_response":{"msg":"Business Failed","code":"40004","sub_msg…...

python打卡day49

知识点回顾&#xff1a; 通道注意力模块复习空间注意力模块CBAM的定义 作业&#xff1a;尝试对今天的模型检查参数数目&#xff0c;并用tensorboard查看训练过程 import torch import torch.nn as nn# 定义通道注意力 class ChannelAttention(nn.Module):def __init__(self,…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个医院挂号小程序

一、开发准备 ​​环境搭建​​&#xff1a; 安装DevEco Studio 3.0或更高版本配置HarmonyOS SDK申请开发者账号 ​​项目创建​​&#xff1a; File > New > Create Project > Application (选择"Empty Ability") 二、核心功能实现 1. 医院科室展示 /…...

生成 Git SSH 证书

&#x1f511; 1. ​​生成 SSH 密钥对​​ 在终端&#xff08;Windows 使用 Git Bash&#xff0c;Mac/Linux 使用 Terminal&#xff09;执行命令&#xff1a; ssh-keygen -t rsa -b 4096 -C "your_emailexample.com" ​​参数说明​​&#xff1a; -t rsa&#x…...

sqlserver 根据指定字符 解析拼接字符串

DECLARE LotNo NVARCHAR(50)A,B,C DECLARE xml XML ( SELECT <x> REPLACE(LotNo, ,, </x><x>) </x> ) DECLARE ErrorCode NVARCHAR(50) -- 提取 XML 中的值 SELECT value x.value(., VARCHAR(MAX))…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

稳定币的深度剖析与展望

一、引言 在当今数字化浪潮席卷全球的时代&#xff0c;加密货币作为一种新兴的金融现象&#xff0c;正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而&#xff0c;加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下&#xff0c;稳定…...

代理篇12|深入理解 Vite中的Proxy接口代理配置

在前端开发中,常常会遇到 跨域请求接口 的情况。为了解决这个问题,Vite 和 Webpack 都提供了 proxy 代理功能,用于将本地开发请求转发到后端服务器。 什么是代理(proxy)? 代理是在开发过程中,前端项目通过开发服务器,将指定的请求“转发”到真实的后端服务器,从而绕…...

浪潮交换机配置track检测实现高速公路收费网络主备切换NQA

浪潮交换机track配置 项目背景高速网络拓扑网络情况分析通信线路收费网络路由 收费汇聚交换机相应配置收费汇聚track配置 项目背景 在实施省内一条高速公路时遇到的需求&#xff0c;本次涉及的主要是收费汇聚交换机的配置&#xff0c;浪潮网络设备在高速项目很少&#xff0c;通…...

C++:多态机制详解

目录 一. 多态的概念 1.静态多态&#xff08;编译时多态&#xff09; 二.动态多态的定义及实现 1.多态的构成条件 2.虚函数 3.虚函数的重写/覆盖 4.虚函数重写的一些其他问题 1&#xff09;.协变 2&#xff09;.析构函数的重写 5.override 和 final关键字 1&#…...