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

2024-09-07 07:44

本文主要是介绍004: VTK读入数据---vtkImageData详细说明,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

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 itvtkNew<vtkImageMapToWindowLevelColors> windowLevel;windowLevel->SetWindow(1000);windowLevel->SetLevel(800);windowLevel->SetInputData(imageData);//vtkImageActor: draw an image in a rendered 3D scenevtkNew<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 screenvtkNew<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 itvtkNew<vtkImageMapToWindowLevelColors> windowLevel;windowLevel->SetWindow(1000);windowLevel->SetLevel(800);windowLevel->SetInputData(imageData);//vtkImageActor: draw an image in a rendered 3D scenevtkNew<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 screenvtkNew<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软件打开查看是否正确;

总结

这篇关于004: VTK读入数据---vtkImageData详细说明的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!


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

相关文章

使用C#删除Excel表格中的重复行数据的代码详解

《使用C#删除Excel表格中的重复行数据的代码详解》重复行是指在Excel表格中完全相同的多行数据,删除这些重复行至关重要,因为它们不仅会干扰数据分析,还可能导致错误的决策和结论,所以本文给大家介绍... 目录简介使用工具C# 删除Excel工作表中的重复行语法工作原理实现代码C# 删除指定Excel单元

Linux lvm实例之如何创建一个专用于MySQL数据存储的LVM卷组

《Linuxlvm实例之如何创建一个专用于MySQL数据存储的LVM卷组》:本文主要介绍使用Linux创建一个专用于MySQL数据存储的LVM卷组的实例,具有很好的参考价值,希望对大家有所帮助,... 目录在Centos 7上创建卷China编程组并配置mysql数据目录1. 检查现有磁盘2. 创建物理卷3. 创

Python实现一键PDF转Word(附完整代码及详细步骤)

《Python实现一键PDF转Word(附完整代码及详细步骤)》pdf2docx是一个基于Python的第三方库,专门用于将PDF文件转换为可编辑的Word文档,下面我们就来看看如何通过pdf2doc... 目录引言:为什么需要PDF转Word一、pdf2docx介绍1. pdf2docx 是什么2. by

Nacos日志与Raft的数据清理指南

《Nacos日志与Raft的数据清理指南》随着运行时间的增长,Nacos的日志文件(logs/)和Raft持久化数据(data/protocol/raft/)可能会占用大量磁盘空间,影响系统稳定性,本... 目录引言1. Nacos 日志文件(logs/ 目录)清理1.1 日志文件的作用1.2 是否可以删除

使用Python获取JS加载的数据的多种实现方法

《使用Python获取JS加载的数据的多种实现方法》在当今的互联网时代,网页数据的动态加载已经成为一种常见的技术手段,许多现代网站通过JavaScript(JS)动态加载内容,这使得传统的静态网页爬取... 目录引言一、动态 网页与js加载数据的原理二、python爬取JS加载数据的方法(一)分析网络请求1

Logback在SpringBoot中的详细配置教程

《Logback在SpringBoot中的详细配置教程》SpringBoot默认会加载classpath下的logback-spring.xml(推荐)或logback.xml作为Logback的配置... 目录1. Logback 配置文件2. 基础配置示例3. 关键配置项说明Appender(日志输出器

8种快速易用的Python Matplotlib数据可视化方法汇总(附源码)

《8种快速易用的PythonMatplotlib数据可视化方法汇总(附源码)》你是否曾经面对一堆复杂的数据,却不知道如何让它们变得直观易懂?别慌,Python的Matplotlib库是你数据可视化的... 目录引言1. 折线图(Line Plot)——趋势分析2. 柱状图(Bar Chart)——对比分析3

Spring Boot 整合 Redis 实现数据缓存案例详解

《SpringBoot整合Redis实现数据缓存案例详解》Springboot缓存,默认使用的是ConcurrentMap的方式来实现的,然而我们在项目中并不会这么使用,本文介绍SpringB... 目录1.添加 Maven 依赖2.配置Redis属性3.创建 redisCacheManager4.使用Sp

Python Pandas高效处理Excel数据完整指南

《PythonPandas高效处理Excel数据完整指南》在数据驱动的时代,Excel仍是大量企业存储核心数据的工具,Python的Pandas库凭借其向量化计算、内存优化和丰富的数据处理接口,成为... 目录一、环境搭建与数据读取1.1 基础环境配置1.2 数据高效载入技巧二、数据清洗核心战术2.1 缺失

Java内存区域与内存溢出异常的详细探讨

《Java内存区域与内存溢出异常的详细探讨》:本文主要介绍Java内存区域与内存溢出异常的相关资料,分析异常原因并提供解决策略,如参数调整、代码优化等,帮助开发者排查内存问题,需要的朋友可以参考下... 目录一、引言二、Java 运行时数据区域(一)程序计数器(二)Java 虚拟机栈(三)本地方法栈(四)J