004: VTK读入数据---vtkImageData详细说明

news2024/9/24 11:32:20

VTK医学图像处理---vtkImageData类

目录

VTK医学图像处理---vtkImageData类

简介:

1 Mricro软件的安装和使用

(1) Mricro安装

(2) Mricro转换DICOM为裸数据 

2 从硬盘读取数据到vtkImageData

3 vtkImageData转RGB或RGBA格式

4 练习

总结


简介:

        对于医学图像来说,vtkImageData是使用频率非常高的类,因为医学图像通常为较为规则的矩形或容积类型(三维),而vtkImageData类主要就是用于存储此类数据的,vtk中相关算法(比如阈值、缩放等)的输入和输出也是vtkImageData类,熟练掌握vtkImageData类非常重要。

        vtkDICOMImageReader类读取文件夹中的DICOM文件后,DICOM数据也存储在vtkImageData类中,本篇博文将跳过vtkDICOMImageReader类,直接从硬盘读取数据到vtkImageData类中,以增强大家对vtkImageData类的熟悉。

        由于DICOM格式非常负责,有专门的开源库对DICOM文件进行解析,比如DCMTK(DCMTK - dicom.offis.de),我们不打算详细介绍DICOM标准,因此我们将借助一个免费的软件Mricro(建议大家学会使用给软件,不管是开发还是做科研都非常有用)来将DICOM文件转换为原始数据,采用C语言从硬盘读取原始数据到vtkImageData类中。

        本博文主要包括为 Mricro的安装和使用,从硬盘读取数据到vtkImageData类,vtkImageData类的详细介绍。

1 Mricro软件的安装和使用

下载地址:MRIcro software guide (sc.edu)   

打开网页后,点击下图中红色方框中的链接开始下载。

(1) Mricro安装

下载后,解压会看到下面的图标,双击安装,提出是否安装,选择是,一路默认安装,详细步骤如下图:

(2) Mricro转换DICOM为裸数据 

 在开始栏中搜索Mricro,或从所有应用程序里面找到Mricro启动,启动后的界面为:

DICOM数据下载地址:【免费】VTK-医学图像处理博文中需要的DICOM测试数据资源-CSDN文库

下载DICOM数据解压,在Mricro软件的菜单项中选择 Import--Convert foreign to Analyze,跳出选择对话框。

在Number of Files中要输入待转换的DICOM文件张数, 例如这里我们转换10张,就在该输入框内填写10,记得勾选 Open sequential files:ignore filename选项,然后点击  Select。

在Conversion Options框中,继续点击 OK

这里有时候会跳出一个或两个提示框,不用管它,点击OK继续

到 Select 对话框后,随便选中一张待转换的DICOM文件,然后再文件名中输入要保存为裸数据的名称,点击  打开。

 

单击  打开后,会跳出导出保存框,在保存框中输入要保存的名称,点击  保存按钮进行保存。

 

打开DicomFiles所在文件夹,会发现里面多了两个文件:test.hdr和  test.img

其中 test.hdr文件中保存的数据的长宽高,空间位置等信息

test.img文件中就是纯粹的裸数据,接下来我们将读取test.img中的数据到vtkImageData中。

双击test.hdr,用Mricro软件打开它,在软件的左侧,可以看到test.img中的数据长为512,宽为512,一共有10张图像,数据类型为short。

2 从硬盘读取数据到vtkImageData

 老规矩,先看下代码,也可以拷贝到自己的项目中,运行下:

#define _CRT_SECURE_NO_WARNINGS

#include "vtkImageMapToWindowLevelColors.h"
#include "vtkImageActor.h"
#include "vtkImageMapper3D.h"
#include "vtkImageData.h"
#include "vtkNew.h"
#include "vtkDICOMImageReader.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkCamera.h"
int ImageSlice = 0;
void main()
{
	vtkNew<vtkImageData> imageData;
	imageData->SetDimensions(512, 512, 10);
	imageData->SetSpacing(.49, .49, .7);
	imageData->SetOrigin(0.0, 0.0, 0.0);
	imageData->AllocateScalars(VTK_SHORT, 1);
	void *ptr = imageData->GetScalarPointer();
	size_t bSize = 512 * 512 * 10;

	FILE* pFile = fopen("D:\\DicomFiles\\test.img","rb+");
	if (NULL == pFile)
		return;

	fread(ptr, sizeof(short), bSize, pFile);
	fclose(pFile);

	int* ext = imageData->GetExtent();

	// map the input image through a lookup table and window / level it
	vtkNew<vtkImageMapToWindowLevelColors> windowLevel;
	windowLevel->SetWindow(1000);
	windowLevel->SetLevel(800);
	windowLevel->SetInputData(imageData);

	//vtkImageActor: draw an image in a rendered 3D scene
	vtkNew<vtkImageActor> imageActor;
	imageActor->SetDisplayExtent(ext[0], ext[1], ext[2], ext[3], ImageSlice, ImageSlice);
	imageActor->GetMapper()->SetInputConnection(windowLevel->GetOutputPort());

	// The renderer generates the image which is then displayed on the render window.
	vtkNew<vtkRenderer> renderer;
	renderer->AddActor(imageActor);
	renderer->SetBackground(.2,.2,.2);

	vtkCamera *cam = renderer->GetActiveCamera();
	if (cam)
	{
		// 获取物体在三维空间中的原点,XYZ范围和中心
		//vtkImageData* idata = reader->GetOutput();
		vtkImageData* idata = imageData;
		double* origins = idata->GetOrigin(); // 三维坐标中的起点
		double* bounds = idata->GetBounds();  // 包围盒的xyz范围
		double* center = idata->GetCenter();  // 中心

		cam->SetFocalPoint(center);
		cam->SetPosition(center[0], center[1], center[2] - bounds[5]); // -1 if medical ?
		cam->SetViewUp(0, 1, 0);
		cam->SetClippingRange(0.1,1000);
		renderer->ResetCamera();
	}

	// The render window is the actual GUI window that appears on the computer screen
	vtkNew<vtkRenderWindow> renderWindow;
	renderWindow->SetSize(512, 512);
	renderWindow->AddRenderer(renderer);
	renderWindow->SetWindowName("Dicom Image");

	// The render window interactor captures mouse events
    // and will perform appropriate camera or actor manipulation
    // depending on the nature of the events.
	vtkNew<vtkRenderWindowInteractor> interactor;
	interactor->SetRenderWindow(renderWindow);

	// This starts the event loop and as a side effect causes an initial render.
	renderWindow->Render();
	interactor->Start();
}

主要修改的代码如下:

    vtkNew<vtkImageData> imageData;
	imageData->SetDimensions(512, 512, 10);
	imageData->SetSpacing(.49, .49, .7);
	imageData->SetOrigin(0.0, 0.0, 0.0);
	imageData->AllocateScalars(VTK_SHORT, 1);
	void *ptr = imageData->GetScalarPointer();
	size_t bSize = 512 * 512 * 10;

	FILE* pFile = fopen("D:\\DicomFiles\\test.img","rb+");
	if (NULL == pFile)
		return;

	fread(ptr, sizeof(short), bSize, pFile);
	fclose(pFile);

 SetDimensions 函数主要用来设置图像的长宽高信息

SetSpacing 是像素间距,图像的(512 - 1)* 0.49 就是图像宽的实际尺寸;

SetOrigin  是图像在世界坐标中的位置;

AllocateScalars有两个参数,第一个参数指定数据类型(16bit short);第二个参数1是 一个像素是有一个元素组成(对于BMP位图来说,一个像素是有RGB/RGBA组成的);

AllocateScalars 同时还分配内存空间;

GetScalarPointer函数可以获取分配内存空间的地址;有了地址,有了数据的大小,就可以直接从硬盘读取裸数据了。读取的代码用C语言来写的,这里就不解释了。

运行结果如下: 

3 vtkImageData转RGB或RGBA格式

接下来我们增加了个一个Convert2RGB函数,用户将vtkImageData中的数据转换为RGB格式的数据,并保存的硬盘,然后用Mricro打开查看。

完整源代码如下:

#define _CRT_SECURE_NO_WARNINGS

#include "vtkImageMapToWindowLevelColors.h"
#include "vtkImageActor.h"
#include "vtkImageMapper3D.h"
#include "vtkImageData.h"
#include "vtkNew.h"
#include "vtkDICOMImageReader.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkRenderer.h"
#include "vtkCamera.h"
#include "vtkWindowLevelLookupTable.h"
int ImageSlice = 0;

void Convert2RGB(vtkImageData* pData);

void main()
{
	vtkNew<vtkImageData> imageData;
	imageData->SetDimensions(512, 512, 10);
	imageData->SetSpacing(.49, .49, .7);
	imageData->SetOrigin(0.0, 0.0, 0.0);
	imageData->AllocateScalars(VTK_SHORT, 1);
	void *ptr = imageData->GetScalarPointer();
	size_t bSize = 512 * 512 * 10;

	FILE* pFile = fopen("D:\\DicomFiles\\test.img","rb+");
	if (NULL == pFile)
		return;

	fread(ptr, sizeof(short), bSize, pFile);
	fclose(pFile);

	Convert2RGB(imageData);


	int* ext = imageData->GetExtent();

	// map the input image through a lookup table and window / level it
	vtkNew<vtkImageMapToWindowLevelColors> windowLevel;
	windowLevel->SetWindow(1000);
	windowLevel->SetLevel(800);
	windowLevel->SetInputData(imageData);

	//vtkImageActor: draw an image in a rendered 3D scene
	vtkNew<vtkImageActor> imageActor;
	imageActor->SetDisplayExtent(ext[0], ext[1], ext[2], ext[3], ImageSlice, ImageSlice);
	imageActor->GetMapper()->SetInputConnection(windowLevel->GetOutputPort());

	// The renderer generates the image which is then displayed on the render window.
	vtkNew<vtkRenderer> renderer;
	renderer->AddActor(imageActor);
	renderer->SetBackground(.2,.2,.2);

	vtkCamera *cam = renderer->GetActiveCamera();
	if (cam)
	{
		// 获取物体在三维空间中的原点,XYZ范围和中心
		//vtkImageData* idata = reader->GetOutput();
		vtkImageData* idata = imageData;
		double* origins = idata->GetOrigin(); // 三维坐标中的起点
		double* bounds = idata->GetBounds();  // 包围盒的xyz范围
		double* center = idata->GetCenter();  // 中心

		cam->SetFocalPoint(center);
		cam->SetPosition(center[0], center[1], center[2] - bounds[5]); // -1 if medical ?
		cam->SetViewUp(0, 1, 0);
		cam->SetClippingRange(0.1,1000);
		renderer->ResetCamera();
	}

	// The render window is the actual GUI window that appears on the computer screen
	vtkNew<vtkRenderWindow> renderWindow;
	renderWindow->SetSize(512, 512);
	renderWindow->AddRenderer(renderer);
	renderWindow->SetWindowName("Dicom Image");

	// The render window interactor captures mouse events
    // and will perform appropriate camera or actor manipulation
    // depending on the nature of the events.
	vtkNew<vtkRenderWindowInteractor> interactor;
	interactor->SetRenderWindow(renderWindow);

	// This starts the event loop and as a side effect causes an initial render.
	renderWindow->Render();
	interactor->Start();
}

void Convert2RGB(vtkImageData* pData)
{
	void *ptr = pData->GetScalarPointer();

	vtkNew<vtkWindowLevelLookupTable> table;
	table->SetWindow(1000);
	table->SetLevel(800);
	table->Build();
	table->BuildSpecialColors();

	long iCount = 512 * 512;
	void *rgbPtr = malloc(iCount * 3);
	unsigned char *desPtr = (unsigned char *)rgbPtr;

	table->MapScalarsThroughTable2(ptr, desPtr, VTK_UNSIGNED_SHORT, iCount, VTK_LUMINANCE, VTK_RGB);

	FILE* pFile = fopen("color2.img", "wb+");
	if (!pFile)
		return;

	fwrite(rgbPtr, 1, iCount * 3, pFile);
	fclose(pFile);

	free(rgbPtr);

}

打开源代码所在文件夹,会发现多了一个color2.img,打开Mricro软件,将 color2.img拖到Mricro软件中,发现打开后是乱码,这是由于Mricro软件左侧的参数信息不正确。

将左侧X Y Z分别填入512  512 1

将Data,选中 24-bit rgb,

然后点击菜单中的Header,Save header;

保存完成后,双击 color2.hdr,打开,显示结果如下:

在这里例子中,我们只保存了一张RGB,而图像是有10张的,请自己动手,把10张图像全部保存成为RGB数据,练习一下。 

4 练习

(1)用vtkImageData读取一张BMP图像,并显示;

(2)将相机的位置这是在现在位置的反方向,对比下显示结果;

(3)将vtkImageData中的数据重新保存一份,用Mricro软件打开查看是否正确;

总结

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

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

相关文章

Minikube Install Kubernetes v1.18.1

文章目录 简介安装工具配置代理运行集群检查集群加入rancher 简介 模拟客户环境&#xff0c;测试 kubernetes v1.18.x 是否可以被 rancher v2.9.1 纳管。 安装工具 docker 安装Install and Set Up kubectl on Linux 安装 minikube 配置代理 docker proxylinux proxy 运行…

python进阶篇-day07-进程与线程

day06进程与线程 一. 进程 每个软件都可以看作是一个进程(数据隔离) 软件内的多个任务可以看作是多个线程(数据共享) 单核CPU: 宏观并行, 微观并发 真正的并行必须有多核CPU 多任务介绍 概述 多任务指的是, 多个任务"同时"执行 目的 节约资源, 充分利用CPU资源, …

万龙觉醒辅助:VMOS云手机辅助前期宝物选择!万龙觉醒怎么挂机?

《万龙觉醒》作为一款策略战争类游戏&#xff0c;玩家们在日常进行游戏时&#xff0c;可能会遇到游戏时间不足或无法长时间在线的问题。而通过使用VMOS云手机&#xff0c;可以实现24小时游戏云端在线托管&#xff0c;无需手动操作&#xff0c;彻底解放双手&#xff0c;随时随地…

【人工智能学习笔记】1_人工智能基础

本系列是个人学习《阿里云人工智能工程师ACA认证免费课程&#xff08;2023版&#xff09;》的笔记&#xff0c;仅为个人学习记录&#xff0c;欢迎交流&#xff0c;感谢批评指正 人工智能概述 智能的三大能力&#xff1a;感知、记忆与思维、学习与适应能力人工智能的定义 明斯基…

4 个最佳 3D 数据可视化工具(免费和付费)

摘要: 在当今的技术时代,数据可视化在软件测试领域发挥着相当重要的作用。简而言之,数据可视化是设计并分析数据视觉表示的过程。其中有一些顶级的数据可视化工具超出了工作范围。在数据可视化工具的帮助下,变得相当简单、更加准确。这是因为这些工具进一步消除了对手工劳动…

经济不景气?相反,这才是普通人赚钱的绝佳机会!

“日子越来越难了!”身边类似的抱怨越来越多。 想想也是&#xff0c;这两年市场低迷、房地产暴雷、各行业内卷.....即便兜里有钱的&#xff0c;也面临资产缩水的风险。 但好在从去年开始&#xff0c;国内外AI企业黑马连出&#xff0c;AI文本、图片、视频生产模型直接颠覆了传…

1990-2022年各地级市gdp、一二三产业gdp及人均gdp数据

1990-2022年各地级市gdp、一二三产业gdp及人均gdp数据 1、时间&#xff1a;1990-2022年 2、来源&#xff1a;城市统计年鉴 3、指标&#xff1a;年度、城市名称、城市代码、城市类别、省份标识、省份名称、国内生产总值/亿元、第一产业占GDP比重(%)、第二产业占GDP比重(%)、第…

Redis - 主从复制

文章目录 目录 文章目录 前言 1. 配置 建立复制 断开复制 传输延时 2. 主从拓扑结构 一主一从 一主多从 树状 三. 原理 数据同步 psync replicationid/replid(复制id) master_replid 和 master_replid2 offset (偏移量) psync 运行流程 全量复制 部分复制 …

算法进阶 | 必知!5大深度生成模型!

本文来源公众号“算法进阶”&#xff0c;仅用于学术分享&#xff0c;侵权删&#xff0c;干货满满。 原文链接&#xff1a;必知&#xff01;5大深度生成模型&#xff01; 随着Sora、diffusion、GPT等模型的大火&#xff0c;深度生成模型又成为了大家的焦点。 深度生成模型是一…

【简历】25届南京某一本JAVA简历:简历通过率还好,但是拿不到OFFER

注&#xff1a;为保证用户信息安全&#xff0c;姓名和学校等信息已经进行同层次变更&#xff0c;内容部分细节也进行了部分隐藏 简历说明 今天看一份25届南京某一本大学的Java简历。 这个简历呢&#xff0c;学校是一本。我们说上来先要定校招层次&#xff0c;这个层次就按照…

D35XT120-ASEMI新能源专用D35XT120

编辑&#xff1a;ll D35XT120-ASEMI新能源专用D35XT120 型号&#xff1a;D35XT120 品牌&#xff1a;ASEMI 封装&#xff1a;DXT-5 批号&#xff1a;2024 现货&#xff1a;50000 正向电流&#xff08;Id&#xff09;&#xff1a;35A 反向耐压&#xff08;VRRM&#xff0…

dubbo是什么?,能做什么?以及其工作流程

1.Dubbo是什么&#xff1f;能做什么&#xff1f; Dubbo是阿里巴巴开源的基于Java的高性能RPC分布式服务框架&#xff0c;现已成为Apache基金会孵化项目&#xff0c;致力于提供高性能和透明化的RPC远程服务调用方案&#xff0c;以及SOA服务治理方案 简单来说&#xff0c;dubbo…

通义灵码怎么样?分为哪些版本,看看基础能力多少分?

通义灵码&#xff0c;是一款基于通义大模型的智能编码辅助工具&#xff0c;提供行级/函数级实时续写、自然语言生成代码、单元测试生成、代码优化、注释生成、代码解释、研发智能问答、异常报错排查等能力&#xff0c;并针对阿里云的云服务使用场景调优&#xff0c;助力开发者高…

【计算机组成原理】计算机系统层次结构

计算机系统层次结构 计算机系统是一个层次结构系统&#xff0c;每一层都通过向上层用户提供一个抽象的简洁接口而将低层的实现细节隐藏起来。计算机解决应用问题的过程就是不同抽象层进行转换的过程 计算机系统抽象层的转换 下图描述了从最终用户希望计算机完成的应用(问题)…

Java重修笔记 第四十九天 Collections 工具类

Collections 工具类 1. public static void reverse(List<?> list) 反转集合中元素的顺序 2. public static void shuffle(List<?> list) 将集合里的元素顺序打乱 3. public static <T extends Comparable<? super T>> void sort(List<T>…

Java项目: 基于SpringBoot+mysql企业客户管理系统(含源码+数据库+答辩PPT+毕业论文)

一、项目简介 本项目是一套基于SpringBootmysql企业客户管理系统 包含&#xff1a;项目源码、数据库脚本等&#xff0c;该项目附带全部源码可作为毕设使用。 项目都经过严格调试&#xff0c;eclipse或者idea 确保可以运行&#xff01; 该系统功能完善、界面美观、操作简单、功…

工业相机飞拍的原理及工作原理

工业相机飞拍&#xff08;或称为工业高速相机飞行拍摄&#xff09;是一种利用高速图像捕捉技术和精密运动控制系统进行高效图像采集的先进技术。它广泛应用于工业检测、质量控制和自动化生产等领域。本文将详细探讨工业相机飞拍的原理及其工作方式。 一、工业相机飞拍的基本概…

【深度学习】卷积神经网络与 LeNet

在 softmax 回归中&#xff0c;我们使用的数据集是图像数据。这种数据的每个样本都是由一个二维像素网格组成&#xff0c;每个像素可能是一个或多个数值&#xff0c;取决于是黑白还是彩色图像。 我们之前的处理方式是通过“展平”&#xff0c;用一个标量表示一个像素&#xff…

electron 客户端 windows linux(麒麟V10)多系统离线打包 最新版 <一>

electron客户端下载、构建、打包在国内网络情况下&#xff0c;绝对不是什么易事。更不要说离线干活&#xff0c;更是难上加难。 这一篇主要讲下windows离线环境下&#xff0c;如何完成electron的下载打包。咱废话不多说&#xff0c;直接上干货。注意&#xff0c;我的大前提是完…

Nacos部分漏洞2 附POC

@[toc] Nacos部分漏洞2 附POC 免责声明:请勿利用文章内的相关技术从事非法测试,由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失,均由使用者本人负责,所产生的一切不良后果与文章作者无关。该文章仅供学习用途使用。 1. Nacos简介 微信公…