005:VTK世界坐标系中的相机和物体

VTK医学图像处理---世界坐标系中的相机和物体

左侧是成像结果 右侧是世界坐标系中的相机与被观察物体

目录

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关于这两个类的介绍也比较简单,是因为官网有非常详细的介绍,大家一定要学会看官网上的资料,在博文中我们就不详细展开说明了。在示例中我们添加了坐标轴信息,从而可以直观的观察到图像在世界坐标中的位置,再下一节中,我们将重点介绍如果获取鼠标所在图像的坐标和时间坐标的位置,并输出出来,以验证和加深对世界坐标的理解。

相关推荐
霁月风1 小时前
设计模式——适配器模式
c++·适配器模式
萧鼎1 小时前
Python并发编程库:Asyncio的异步编程实战
开发语言·数据库·python·异步
学地理的小胖砸1 小时前
【一些关于Python的信息和帮助】
开发语言·python
疯一样的码农1 小时前
Python 继承、多态、封装、抽象
开发语言·python
^velpro^1 小时前
数据库连接池的创建
java·开发语言·数据库
秋の花1 小时前
【JAVA基础】Java集合基础
java·开发语言·windows
jrrz08281 小时前
LeetCode 热题100(七)【链表】(1)
数据结构·c++·算法·leetcode·链表
小松学前端1 小时前
第六章 7.0 LinkList
java·开发语言·网络
可峰科技1 小时前
斗破QT编程入门系列之二:认识Qt:编写一个HelloWorld程序(四星斗师)
开发语言·qt
咖啡里的茶i1 小时前
Vehicle友元Date多态Sedan和Truck
c++