VTK医学图像处理---世界坐标系中的相机和物体
左侧是成像结果 右侧是世界坐标系中的相机与被观察物体
目录
[1 在三维空间中添加坐标系](#1 在三维空间中添加坐标系)
[2 世界坐标系中的相机](#2 世界坐标系中的相机)
[3 世界坐标系中vtkImageData的参数](#3 世界坐标系中vtkImageData的参数)
简介
上图右侧的图像是模拟的世界坐标系和世界坐标系中相机以及被观察物体; 左侧是在右侧世界坐标系中相机设置参数和物体位置的条件下成像(渲染)的结果。 相机或物体的任何参数的改变都会导致成像结果的改变。
VTK中vtkCamera类对应右图中的相机,可以通过vtkCamera来设置相机在世界坐标系中的位置,焦点(对准三维坐标系中的那个位置),相机的正方向,相机的最近和最远裁减平面(在最近和最远平面内的物体才会被渲染)等;三维坐标系中的物体,对于目前我们的例子来说就是要渲染显示的DICOM图像,也就是存储在vtkImageData中的数据,通过vtkImageData origin参数可以设置其在三维坐标系中的位置,当然也可以通过旋转矩阵对vtkImageData的数据进行旋转或平移。
1 在三维空间中添加坐标系
VTK官网例子:VTK: vtkAxesActor Class Reference
在我们显示的DICOM图像中增加X Y Z三个轴,以便我们直观的观察到vtkImageData中图像在世界坐标系中的位置。主要使用了vtkAxesActor类,通过SetOrigin函数,设置轴的原点是世界坐标系中的原点(0,0,0); 通过SetTotalLength函数,设置XYZ三个轴的长短。
cpp
vtkNew<vtkAxesActor> axes;
axes->SetOrigin(0,0,0);
axes->SetTotalLength(100, 100, 100);
增加坐标轴后的完整代码:
cpp
#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"
#include "vtkAxesActor.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());
//-------------------------------------------------
vtkNew<vtkAxesActor> axes;
axes->SetOrigin(0,0,0);
axes->SetTotalLength(100, 100, 100);
// The renderer generates the image which is then displayed on the render window.
vtkNew<vtkRenderer> renderer;
renderer->AddActor(imageActor);
renderer->AddActor(axes);
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();
}
运行后的效果:
小练习:修改相机的位置到反方向,观察和之前的显示结果又什么差异,想想为什么?
cpp
cam->SetPosition(center[0], center[1], center[2] + bounds[5]);
2 世界坐标系中的相机
相机有两种成像方法,透视投影和平行投影,通常对于医学图像来说会经常使用平行投影(关于平行投影和获取鼠标所在图像的位置,在下节博文中会详细介绍),关于VTK中相机的相关介绍,网上有很多说的也很全面,这里只给出链接,就不再展开了,大家也可以自行在网络上检索。
vtkCamera介绍:VTK笔记-相机vtkCamera_vtk camera 穿刺-CSDN博客
3 世界坐标系中vtkImageData的参数
vtkImageData类中的SetOrigin函数用来设置其在世界坐标系中的位置;
vtkImageData中数据的长 宽 和 高分别乘以其像素间距,就是其在三维坐标系中的实际长 宽和高;也可以通过调用GetExtent函数直接获取其在三维坐标系中XYZ三个方向的起点和终点;
在这里强烈建议大家去VTK官网,查看关于vtkImageData类的详细说明
vtkImageData类的链接:VTK: vtkImageData Class Reference
总结:
通过动态GIF示意图简单介绍了一下VTK中的世界坐标系,为后面介绍完整的坐标系统做些铺垫;另外介绍了和显示密切相关的连个类vtkImageData和vtkCamera关于这两个类的介绍也比较简单,是因为官网有非常详细的介绍,大家一定要学会看官网上的资料,在博文中我们就不详细展开说明了。在示例中我们添加了坐标轴信息,从而可以直观的观察到图像在世界坐标中的位置,再下一节中,我们将重点介绍如果获取鼠标所在图像的坐标和时间坐标的位置,并输出出来,以验证和加深对世界坐标的理解。