VTK医学图像处理---世界坐标系中的相机和物体
简介
上图右侧的图像是模拟的世界坐标系和世界坐标系中相机以及被观察物体; 左侧是在右侧世界坐标系中相机设置参数和物体位置的条件下成像(渲染)的结果。
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三个轴的长短。
vtkNew<vtkAxesActor> axes;
axes->SetOrigin(0,0,0);
axes->SetTotalLength(100, 100, 100);
增加坐标轴后的完整代码:
#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();
}
运行后的效果:
2 世界坐标系中的相机
关于VTK中相机的相关介绍,网上有很多说的也很全面,这里只给出链接,就不再展开了,大家也可以自行在网络上检索。
vtkCamera介绍:VTK笔记-相机vtkCamera_vtk camera 穿刺-CSDN博客
3 世界坐标系中vtkImageData的参数
vtkImageData类中的SetOrigin函数用来设置其在世界坐标系中的位置;
vtkImageData中数据的长 宽 和 高分别乘以其像素间距,就是其在三维坐标系中的实际长 宽和高;也可以通过调用GetExtent函数直接获取其在三维坐标系中XYZ三个方向的起点和终点;
在这里强烈建议大家去VTK官网,查看关于vtkImageData类的详细说明
vtkImageData类的链接:VTK: vtkImageData Class Reference