004: VTK读入数据---vtkImageData具体阐明

铁佛  论坛元老 | 2024-9-10 19:25:49 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 1029|帖子 1029|积分 3087

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
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

 老例子,先看下代码,也可以拷贝到自己的项目中,运行下:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include "vtkImageMapToWindowLevelColors.h"
  3. #include "vtkImageActor.h"
  4. #include "vtkImageMapper3D.h"
  5. #include "vtkImageData.h"
  6. #include "vtkNew.h"
  7. #include "vtkDICOMImageReader.h"
  8. #include "vtkRenderWindow.h"
  9. #include "vtkRenderWindowInteractor.h"
  10. #include "vtkRenderer.h"
  11. #include "vtkCamera.h"
  12. int ImageSlice = 0;
  13. void main()
  14. {
  15.         vtkNew<vtkImageData> imageData;
  16.         imageData->SetDimensions(512, 512, 10);
  17.         imageData->SetSpacing(.49, .49, .7);
  18.         imageData->SetOrigin(0.0, 0.0, 0.0);
  19.         imageData->AllocateScalars(VTK_SHORT, 1);
  20.         void *ptr = imageData->GetScalarPointer();
  21.         size_t bSize = 512 * 512 * 10;
  22.         FILE* pFile = fopen("D:\\DicomFiles\\test.img","rb+");
  23.         if (NULL == pFile)
  24.                 return;
  25.         fread(ptr, sizeof(short), bSize, pFile);
  26.         fclose(pFile);
  27.         int* ext = imageData->GetExtent();
  28.         // map the input image through a lookup table and window / level it
  29.         vtkNew<vtkImageMapToWindowLevelColors> windowLevel;
  30.         windowLevel->SetWindow(1000);
  31.         windowLevel->SetLevel(800);
  32.         windowLevel->SetInputData(imageData);
  33.         //vtkImageActor: draw an image in a rendered 3D scene
  34.         vtkNew<vtkImageActor> imageActor;
  35.         imageActor->SetDisplayExtent(ext[0], ext[1], ext[2], ext[3], ImageSlice, ImageSlice);
  36.         imageActor->GetMapper()->SetInputConnection(windowLevel->GetOutputPort());
  37.         // The renderer generates the image which is then displayed on the render window.
  38.         vtkNew<vtkRenderer> renderer;
  39.         renderer->AddActor(imageActor);
  40.         renderer->SetBackground(.2,.2,.2);
  41.         vtkCamera *cam = renderer->GetActiveCamera();
  42.         if (cam)
  43.         {
  44.                 // 获取物体在三维空间中的原点,XYZ范围和中心
  45.                 //vtkImageData* idata = reader->GetOutput();
  46.                 vtkImageData* idata = imageData;
  47.                 double* origins = idata->GetOrigin(); // 三维坐标中的起点
  48.                 double* bounds = idata->GetBounds();  // 包围盒的xyz范围
  49.                 double* center = idata->GetCenter();  // 中心
  50.                 cam->SetFocalPoint(center);
  51.                 cam->SetPosition(center[0], center[1], center[2] - bounds[5]); // -1 if medical ?
  52.                 cam->SetViewUp(0, 1, 0);
  53.                 cam->SetClippingRange(0.1,1000);
  54.                 renderer->ResetCamera();
  55.         }
  56.         // The render window is the actual GUI window that appears on the computer screen
  57.         vtkNew<vtkRenderWindow> renderWindow;
  58.         renderWindow->SetSize(512, 512);
  59.         renderWindow->AddRenderer(renderer);
  60.         renderWindow->SetWindowName("Dicom Image");
  61.         // The render window interactor captures mouse events
  62.     // and will perform appropriate camera or actor manipulation
  63.     // depending on the nature of the events.
  64.         vtkNew<vtkRenderWindowInteractor> interactor;
  65.         interactor->SetRenderWindow(renderWindow);
  66.         // This starts the event loop and as a side effect causes an initial render.
  67.         renderWindow->Render();
  68.         interactor->Start();
  69. }
复制代码
重要修改的代码如下:
  1.     vtkNew<vtkImageData> imageData;
  2.         imageData->SetDimensions(512, 512, 10);
  3.         imageData->SetSpacing(.49, .49, .7);
  4.         imageData->SetOrigin(0.0, 0.0, 0.0);
  5.         imageData->AllocateScalars(VTK_SHORT, 1);
  6.         void *ptr = imageData->GetScalarPointer();
  7.         size_t bSize = 512 * 512 * 10;
  8.         FILE* pFile = fopen("D:\\DicomFiles\\test.img","rb+");
  9.         if (NULL == pFile)
  10.                 return;
  11.         fread(ptr, sizeof(short), bSize, pFile);
  12.         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打开查看。
完整源代码如下:
  1. #define _CRT_SECURE_NO_WARNINGS
  2. #include "vtkImageMapToWindowLevelColors.h"
  3. #include "vtkImageActor.h"
  4. #include "vtkImageMapper3D.h"
  5. #include "vtkImageData.h"
  6. #include "vtkNew.h"
  7. #include "vtkDICOMImageReader.h"
  8. #include "vtkRenderWindow.h"
  9. #include "vtkRenderWindowInteractor.h"
  10. #include "vtkRenderer.h"
  11. #include "vtkCamera.h"
  12. #include "vtkWindowLevelLookupTable.h"
  13. int ImageSlice = 0;
  14. void Convert2RGB(vtkImageData* pData);
  15. void main()
  16. {
  17.         vtkNew<vtkImageData> imageData;
  18.         imageData->SetDimensions(512, 512, 10);
  19.         imageData->SetSpacing(.49, .49, .7);
  20.         imageData->SetOrigin(0.0, 0.0, 0.0);
  21.         imageData->AllocateScalars(VTK_SHORT, 1);
  22.         void *ptr = imageData->GetScalarPointer();
  23.         size_t bSize = 512 * 512 * 10;
  24.         FILE* pFile = fopen("D:\\DicomFiles\\test.img","rb+");
  25.         if (NULL == pFile)
  26.                 return;
  27.         fread(ptr, sizeof(short), bSize, pFile);
  28.         fclose(pFile);
  29.         Convert2RGB(imageData);
  30.         int* ext = imageData->GetExtent();
  31.         // map the input image through a lookup table and window / level it
  32.         vtkNew<vtkImageMapToWindowLevelColors> windowLevel;
  33.         windowLevel->SetWindow(1000);
  34.         windowLevel->SetLevel(800);
  35.         windowLevel->SetInputData(imageData);
  36.         //vtkImageActor: draw an image in a rendered 3D scene
  37.         vtkNew<vtkImageActor> imageActor;
  38.         imageActor->SetDisplayExtent(ext[0], ext[1], ext[2], ext[3], ImageSlice, ImageSlice);
  39.         imageActor->GetMapper()->SetInputConnection(windowLevel->GetOutputPort());
  40.         // The renderer generates the image which is then displayed on the render window.
  41.         vtkNew<vtkRenderer> renderer;
  42.         renderer->AddActor(imageActor);
  43.         renderer->SetBackground(.2,.2,.2);
  44.         vtkCamera *cam = renderer->GetActiveCamera();
  45.         if (cam)
  46.         {
  47.                 // 获取物体在三维空间中的原点,XYZ范围和中心
  48.                 //vtkImageData* idata = reader->GetOutput();
  49.                 vtkImageData* idata = imageData;
  50.                 double* origins = idata->GetOrigin(); // 三维坐标中的起点
  51.                 double* bounds = idata->GetBounds();  // 包围盒的xyz范围
  52.                 double* center = idata->GetCenter();  // 中心
  53.                 cam->SetFocalPoint(center);
  54.                 cam->SetPosition(center[0], center[1], center[2] - bounds[5]); // -1 if medical ?
  55.                 cam->SetViewUp(0, 1, 0);
  56.                 cam->SetClippingRange(0.1,1000);
  57.                 renderer->ResetCamera();
  58.         }
  59.         // The render window is the actual GUI window that appears on the computer screen
  60.         vtkNew<vtkRenderWindow> renderWindow;
  61.         renderWindow->SetSize(512, 512);
  62.         renderWindow->AddRenderer(renderer);
  63.         renderWindow->SetWindowName("Dicom Image");
  64.         // The render window interactor captures mouse events
  65.     // and will perform appropriate camera or actor manipulation
  66.     // depending on the nature of the events.
  67.         vtkNew<vtkRenderWindowInteractor> interactor;
  68.         interactor->SetRenderWindow(renderWindow);
  69.         // This starts the event loop and as a side effect causes an initial render.
  70.         renderWindow->Render();
  71.         interactor->Start();
  72. }
  73. void Convert2RGB(vtkImageData* pData)
  74. {
  75.         void *ptr = pData->GetScalarPointer();
  76.         vtkNew<vtkWindowLevelLookupTable> table;
  77.         table->SetWindow(1000);
  78.         table->SetLevel(800);
  79.         table->Build();
  80.         table->BuildSpecialColors();
  81.         long iCount = 512 * 512;
  82.         void *rgbPtr = malloc(iCount * 3);
  83.         unsigned char *desPtr = (unsigned char *)rgbPtr;
  84.         table->MapScalarsThroughTable2(ptr, desPtr, VTK_UNSIGNED_SHORT, iCount, VTK_LUMINANCE, VTK_RGB);
  85.         FILE* pFile = fopen("color2.img", "wb+");
  86.         if (!pFile)
  87.                 return;
  88.         fwrite(rgbPtr, 1, iCount * 3, pFile);
  89.         fclose(pFile);
  90.         free(rgbPtr);
  91. }
复制代码
打开源代码地点文件夹,会发现多了一个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软件打开查看是否精确;
总结


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

铁佛

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表