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

相关文章

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2

Goland debug失效详细解决步骤(合集)

《Golanddebug失效详细解决步骤(合集)》今天用Goland开发时,打断点,以debug方式运行,发现程序并没有断住,程序跳过了断点,直接运行结束,网上搜寻了大量文章,最后得以解决,特此在这... 目录Bug:Goland debug失效详细解决步骤【合集】情况一:Go或Goland架构不对情况二:

Python itertools中accumulate函数用法及使用运用详细讲解

《Pythonitertools中accumulate函数用法及使用运用详细讲解》:本文主要介绍Python的itertools库中的accumulate函数,该函数可以计算累积和或通过指定函数... 目录1.1前言:1.2定义:1.3衍生用法:1.3Leetcode的实际运用:总结 1.1前言:本文将详

Deepseek R1模型本地化部署+API接口调用详细教程(释放AI生产力)

《DeepseekR1模型本地化部署+API接口调用详细教程(释放AI生产力)》本文介绍了本地部署DeepSeekR1模型和通过API调用将其集成到VSCode中的过程,作者详细步骤展示了如何下载和... 目录前言一、deepseek R1模型与chatGPT o1系列模型对比二、本地部署步骤1.安装oll

Spring Boot整合log4j2日志配置的详细教程

《SpringBoot整合log4j2日志配置的详细教程》:本文主要介绍SpringBoot项目中整合Log4j2日志框架的步骤和配置,包括常用日志框架的比较、配置参数介绍、Log4j2配置详解... 目录前言一、常用日志框架二、配置参数介绍1. 日志级别2. 输出形式3. 日志格式3.1 PatternL

Springboot 中使用Sentinel的详细步骤

《Springboot中使用Sentinel的详细步骤》文章介绍了如何在SpringBoot中使用Sentinel进行限流和熔断降级,首先添加依赖,配置Sentinel控制台地址,定义受保护的资源,... 目录步骤 1: 添加 Sentinel 依赖步骤 2: 配置 Sentinel步骤 3: 定义受保护的

Redis的数据过期策略和数据淘汰策略

《Redis的数据过期策略和数据淘汰策略》本文主要介绍了Redis的数据过期策略和数据淘汰策略,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一... 目录一、数据过期策略1、惰性删除2、定期删除二、数据淘汰策略1、数据淘汰策略概念2、8种数据淘汰策略

轻松上手MYSQL之JSON函数实现高效数据查询与操作

《轻松上手MYSQL之JSON函数实现高效数据查询与操作》:本文主要介绍轻松上手MYSQL之JSON函数实现高效数据查询与操作的相关资料,MySQL提供了多个JSON函数,用于处理和查询JSON数... 目录一、jsON_EXTRACT 提取指定数据二、JSON_UNQUOTE 取消双引号三、JSON_KE

Python给Excel写入数据的四种方法小结

《Python给Excel写入数据的四种方法小结》本文主要介绍了Python给Excel写入数据的四种方法小结,包含openpyxl库、xlsxwriter库、pandas库和win32com库,具有... 目录1. 使用 openpyxl 库2. 使用 xlsxwriter 库3. 使用 pandas 库