vtk学习过程中的笔记

有位专家大佬讲的特别好,图画的也非常好,多有借鉴:https://blog.csdn.net/shenziheng1/category_9277349.html
若有错误和不同的见解,还望多多指点和交流。

VTK基础了解

1.搭建编译环境,此略;

2.下载VTK源码、data(各种格式的图片数据,在source源码同级目录进行解压)、对应版本的帮助文档包(vtkDocHtml-*.tar.gz),VTK官网下载地址:https://vtk.org/download/;

3.学会查看帮助文档,首先打开annotated.html网页,可跳转到各其他帮助页面Main Page、Related Pages、Modules、Namespaces、Classes、Files;

4.进入学习,推荐《VTK图形图像开发进阶》,先对总体只是架构有基本的认识。结合源码example代码跑出效果,对每个组件的使用有更深入的认识;

VTK数据流程:

  1. —-source/data(Actor 定性,主角是什么样的)
  2. —-filter(数据转换,数据怎么给到下一个处理器才可以被处理和接收)
  3. ——mapper(实现source到actor的映射)
  4. ——actor(Actor 实例):color、position
  5. ——render(Actor 、Window上色打光):light、Camera、BackGroundcolor、
  6. ——renderwindow(显示窗口):size、
  7. ——interactor(互动器,鼠标)

若整个VTK是一场表演,那么下图就是各角色之间的对应关系(来源与借鉴资料);

  vtk学习过程中的笔记_第1张图片

  vtk学习过程中的笔记_第2张图片

vtk学习过程中的笔记_第3张图片



vtkCylinderSource/vtkCubeSource/vtkSphereSource:
= 实例创建
  vtkAlgorithmOutput* vtkAlgorithm::GetOutputPort() 

  Eg1.vtkCylinderSource,VTK-9.0.1/Examples/Rendering/Cxx/Cylinder.cpp,可以尝试做参数修改,观察图形的改变。

  vtkCylinderSource* cylinder = vtkCylinderSource::New();
  cylinder->SetResolution(3);//三边
  cylinder->SetCapping(0);//0不封闭,1封闭

 


vtkCoordinate:
= 坐标系统

  ├── Model 笛卡尔/直角/斜角坐标系(二维、三维),是actor的实体坐标系
  ├── World 三维空间坐标系,light、camera、
  ├── View 视觉二维坐标系,view(x,y)面,camera.(z)
  └── Display 视图坐标系,坐标取值来自与屏幕像素值,

vtk学习过程中的笔记_第4张图片

reference source:
二维坐标到三维坐标之间的转换:https://blog.csdn.net/weixin_39827728/article/details/111105515

vtkPoints/vtkCellArray:
= Points定义数据几何结构;Cell Array定义数据拓扑结构;

vtkDataReader-Write/vtkDicomImageReader/vtkMetaImageReader/vtkBMPReader:
= 图像数据的处理;
Eg1:基于vtkMetaImageReader( read binary UNC meta image data)读取*.mhd文件 .

#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
main(int argc, char * argv [])
{
	vtkSmartPointer Metareader = vtkSmartPointer::New();
	Metareader->SetFileName("../data/brain.mhd");
	Metareader->Update();

	vtkSmartPointer reader = vtkSmartPointer::New();
	reader->SetFileName("../data/VTK-logo.bmp");
	reader->Update();

	//vtkSmartPointer mapper = vtkSmartPointer::New();
	//mapper->SetInputConnection(reader->GetOutput());

	vtkSmartPointer actor = vtkSmartPointer::New();
	actor->SetInputData(reader->GetOutput());

	vtkSmartPointer render = vtkSmartPointer::New();
	render->AddActor(actor);

	vtkSmartPointer renderwin = vtkSmartPointer::New();
	renderwin->AddRenderer(render);

	vtkSmartPointer renderwinInter = vtkSmartPointer::New();
	renderwinInter->SetRenderWindow(renderwin);

	vtkSmartPointer InteStyle = vtkSmartPointer::New();
	InteStyle->SetCurrentRenderer(render);

	renderwinInter->SetInteractorStyle(InteStyle);
	renderwinInter->Initialize();
	renderwinInter->Start();
}

   vtk学习过程中的笔记_第5张图片     

Eg2:基于vtkDicomImageReader进行数据读取;

vtkMarchingCubes/vtkContourFilter:
= Filter,不同的标量值代表的是人体的不同部分,因而可以分别提取出人的皮肤或骨头。SetValue(0, 1)设置第一条是值为1的等值线/GenerateValues(5.0, 0.0, 1.2)从0.0-1.2之间抽取5个抽取值。

vtk学习过程中的笔记_第6张图片

vtkPolyDataMapper/vtkPolyDataMapper2D:
= 数据获取,SetInputConnection()/SetInputData()

vtkActor/vtkActor2D:
=
实例对象,输入数据需要为unsigned char类型;

vtkRender(vtkLight/vtkCamera):
= 用于对Actor/window渲染;G/SetActiveCamera()设置视窗相机/;SetViewport((xmin,ymin,xmax,ymax) 0~1设置view坐标系中各视窗的位置;

    reader->GetOutput()->GetExtent(extent);//坐标轴尺寸[XMin,XMax,YMin,YMax,ZMin,ZMax]
    reader->GetOutput()->GetSpacing(spacing);//体素大小,如一个立方体的长宽高
    reader->GetOutput()->GetOrigin(origin);//3D空间中第一像素位置
    center[i] = origin[i] + spacing[i] * 0.5 * (extent[2*i] + extent[2*i+1]);//计算图形中心

Eg1.renderer1->SetViewport(0.0,0.0,0.5,0.5)左下;renderer2->SetViewport(0.5,0.0,1.0,0.5)右下;renderer3->SetViewport(0.0,0.5,0.5,1.0)左上;renderer4->SetViewport(0.5,0.5,1.0,1.0)右上;

  cylinderren1->AddActor(cylinderActor);
  cylinderren1->SetViewport(0.0,0.0,0.5,0.5);

vtk学习过程中的笔记_第7张图片

Eg2.vtkCamera,SetPosition(*,*,*)/SetFocusPoint()/SetClippingRange()/ComputeViewPlaneNormal()/SetViewUp()等

    camera->SetViewUp(0,0,-1);//摄像机的视图向上方向
    camera->SetPosition(0.1,0.1,0.1);//相机在世界坐标系中的位置
    camera->SetFocalPoint(0,0,1);//摄像机在世界坐标系中的焦距
    camera->ComputeViewPlaneNormal();//计算视图平面法线

Eg3.vtkLight,SetColor()/SetPosition()/SetFocalPoint()/SetIntensity()/SetSwitch()/SwitchOn()/SwitchOff()等

  vtkCamera* Camera = vtkCamera::New();
  Camera->SetClippingRange(50,50);
  Camera->SetPosition(-6,0,0);
  Camera->SetFocalPoint(0.0573,-0.2134, -0.0523);
  Camera->ComputeViewPlaneNormal();
  Camera->SetViewUp(0, 1, 0);
  cylinderren1->SetActiveCamera(Camera);

  vtkLight* light = vtkLight::New();
  light->SetColor(0,1,0);
  light->SetPosition(6,0,0);
  light->SetFocalPoint(cylinderren1->GetActiveCamera()->GetFocalPoint());
  light->SetIntensity(0.5);//0~1
  cylinderren1->AddLight(light);

  vtkLight* light1 = vtkLight::New();
  light1->SetColor(1,0,0);
  light1->SetPosition(-6,0,0);
  light1->SetFocalPoint(cylinderren1->GetActiveCamera()->GetFocalPoint());
  light1->SwitchOff();
  cylinderren1->AddLight(light1);

vtkRenderWindow:
= 创建渲染窗口;

vtkImageViewer2:
= 图片显示与交互、切片选择、切片方向,汇集actor/render/window/interactor/等功能;

Eg1:基于vtkImageViewer2 实现的水平试图切片

#include 
#include 
#include 
#include 
#include 
#include 
#include 
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
main(int argc, char * argv [])
{
	vtkSmartPointer reader= vtkSmartPointer::New();
	reader->SetFileName("../data/HeadMRVolume.mhd");
	reader->Update();
	
	vtkSmartPointer View= vtkSmartPointer::New();
	View->SetInputConnection(reader->GetOutputPort());

	vtkSmartPointer RenWinInter=vtkSmartPointer::New();

	vtkSmartPointer Style= vtkSmartPointer::New();
	
	//设置基本属性
	View->SetSize(640,480);
	View->SetColorLevel(400);
	View->SetColorWindow(2000);
	
	//默认选择第50张切片
	View->SetSlice(40);
	//View->SetSliceOrientationToXZ();
	//View->SetSliceOrientationToXY();
	View->SetSliceOrientationToYZ();
	View->SetupInteractor(RenWinInter);
	View->GetRenderer()->SetBackground(1,1,1);
	View->GetRenderer()->ResetCamera();
	View->Render();	

	RenWinInter->Initialize();
	RenWinInter->Start();	
}

vtk学习过程中的笔记_第8张图片

Eg2:基于vtkImageViewer2实现有异常的三视图显示

#include 
#include 
#include 
#include 
#include 
#include 
VTK_MODULE_INIT(vtkRenderingOpenGL2);
VTK_MODULE_INIT(vtkInteractionStyle);
main(int argc, char * argv [])
{
	vtkSmartPointer reader= vtkSmartPointer::New();
	reader->SetFileName("../data/brain.mhd");
	reader->Update();
	
	vtkSmartPointer View= vtkSmartPointer::New();
	View->SetInputConnection(reader->GetOutputPort());

	vtkSmartPointer RenWinInter=vtkSmartPointer::New();
	
	vtkSmartPointer Style= vtkSmartPointer::New();

	View->SetupInteractor(RenWinInter);
	//设置基本属性
	View->SetSize(500,200);
	View->SetColorLevel(400);
	View->SetColorWindow(2000);
	
	//默认选择第50张切片
	View->SetSlice(40);
	View->SetSliceOrientationToXZ();	
	//View->GetRenderer()->SetBackground(0.1, 0.2, 1.4);
	View->GetRenderer()->SetViewport(0.5,0.5,1.0,1.0);	

	//默认选择第50张切片
	View->SetSlice(40);
	View->SetSliceOrientationToXY();
	View->GetRenderer()->SetViewport(0.5,0.0,1.0,0.5);

	//默认选择第50张切片
	View->SetSlice(40);
	View->SetSliceOrientationToYZ();
	View->GetRenderer()->SetViewport(0.0,0.0,0.5,0.5);		

	View->Render();
	
	RenWinInter->Initialize();
	RenWinInter->Start();	
}

vtk学习过程中的笔记_第9张图片   vtk学习过程中的笔记_第10张图片

vtkImageBlend:
= 图片融合处理;

vtkImageReslice:
= 沿一组新轴重新切割;SetOutputDimensionality(int *)设置维数;SetInterpolationModeToLinear()切面提取中的差值方式为线性差值;SetResliceAxes(* *)设置切面矩阵;

vtkMatrix4x4:
=矩阵转换;
三维基础几何变换矩阵:https://max.book118.com/html/2018/0423/162757315.shtm
//轴状面变换矩阵
static double axialElements[16] = {
        1, 0, 0, 0,//x轴向量(第四个元素必须设置为0)
        0, 1, 0, 0,//y轴
        0, 0, 1, 0,//z轴
        0, 0, 0, 1 //第四个元素必须设置为1
    };

vtk学习过程中的笔记_第11张图片

x[1,0,0] - y[0,1,0] - z[0,0,1] - 经过变换矩阵处理之后的新的原点[0,0,0]

       //冠状面变换矩阵
    double Coronal [16] = {
        1, 0, 0, 0,
        0, 0, -1, 0,
        0, 1, 0, 0,
        0, 0, 0, 1 };

    //矢状面变换矩阵
    double Sagittal [16] = {
        0, 0, 1, 0,
        1, 0, 0, 0,
        0, 1, 0, 0,
        0, 0, 0, 1 };

    //斜切面变换矩阵
    double Oblique[16] = {
        1, 0, 0, 0,
        0, 0.866025, -0.5, 0,
        0, 0.5, 0.866025, 0,
        0, 0, 0, 1 };

--AxialResliceMatrix,轴切面/2
--CoronalResliceMatrix,冠状面/1
--SagittalResliceMatrix,矢状面/0

vtk学习过程中的笔记_第12张图片

vtk学习过程中的笔记_第13张图片

CT文件数据到三维立体图形

vtk学习过程中的笔记_第14张图片


vtk学习过程中的笔记_第15张图片

交互
    -观察值/指令模式方式
       1.定义事件回调函数
            1.1 定义回调函数 ,形式如下
                void func(vtkObject* obj, unsigned long eid, void* clientdata, void* calldata);
            1.2 创建vtkCallbackCommand对象,调用vtkCallBackCommand::SetCallback()设置的回调函数;
                vtkSmartPoint eventcallback = vtkSmartPoint::New();
                eventcallback->setCallBack(mycallbackFunc);
            1.3 添加vtkCallBack对象到观察者列表
                interactor->AddObserver(vtkCommand::LeftButtonParessEvent, eventcallback);            
       2.扩展vtkCommand,实现它的超类,实现新的excuse函数。
            2.1 扩展vtkCommand子类,实现excuse函数
            2.2 实例化vtkCommand子类,调用相关函数
                vtkSmartPoint callback = vtkSmartPoint::New();
                callback->SetObject(coneSource);
            2.3 调用AddObserver进行事件监听,监听到对应事件后调用实现子类的excuse函数;                

    -交互器
        1.事件捕捉
            1.1 用户界面事件捕捉,平台驱动事件消息;
            1.2 vtkRenderwindowinteractor回调函数vtkHandleMessage接收到消息,并分发到其对应的响应函数中;
            1.3 响应函数中的vtkObject::invokeEvent,将消息转换为VTK消息,函数中的被动观察者Passive/焦点观察者Focus/other做消息捕获;
                    -被动观察者Passive:不改变系统状态;
                    -焦点观察者Focus:使窗口获得焦点(如:LeftButtonParessEvent焦点观察者)
                    -other
            1.4 消息路由至vtkInteractorOberserver或其子类(比如widget处理类),其vtkSubjectHelper::invokeEvent将消息发送观察者;
            1.5 观察者调用vtkInteractorStyle::ProcessEvent处理事件,将事件发送到对应的消息响应函数;
        
      2.render渲染实现,依据当前请求渲染库类型,进而创建对应的子类。
      3.interactorstyle是事件处理样式定义,不同的样式对同一个动作会给出不同的界面响应效果。

    -widget(vtk5.0及以上版本)
        -作用
            交互部件,交互器表达的实体化,做到操作的可视化,方便用户的操作
        -类关系
            -父类
                vtkInteractorOberserver是widget基类的父类
            -基础类
                -vtk3DWidget
                    主要应用于控制数据可视化,如画点、线、面、立体球框等;
                -vtkAbstractWidget
                    主要应用与交互/表达实体(interaction/representation);
        -表达实体对应对象
            -vtkprop
            -vtkWidgetRepresentation子类
        -事件转换
            widgeteventtranslator将vtk事件转换为widget事件;
            vtkWidgetCallBackMapper将对应widget事件 -> 与操作函数进行关联,通过vtkWidgetCallBackMapper::setCallBackMethod方法;
        -widget创建步骤:
              1.实例化widget。
              2.指定渲染窗口 的 交互器,widget可通过interactor监听用户信息。
              3.用户可以创建自己的观察者/命令模式回调函数,可监听需要的事件消息做出事件响应。
              4.创建对应的几何表达实体,可以用setrepresentation将几何实体与widget关联起来;也可使用默认几何实体。
              5.激活widget,使其在渲染场景中显示。
        -其他一些widget类
            -测量类widget
                vtkDistanceWidget(测量二维平面两点之间的距离)、vtkAngleWidget(二维平面的较低测量)、vtkBiDimensionalWidget(二维平面任意正交方向轴长)等。
            -标注类widget
                vtkTextWidget(在渲染场景中生成一串标识文本)、vtkScalarBarWidget(生成标量条)、vtkCaptionWidget(带线框和箭头的文本信息标注对象)、vtkOrientationMarkerWidget(渲染数据的方向指示标志)、vtkBalloonWidget(鼠标在某actor停留之后弹出提示信息)等。
           -分割/配准类
                vtkContourWidget(绘制闭合/不不闭合轮廓线)、vtkSeedWidget(放置种子点)、vtkImageTraceWidget(绘制轨迹线)、vtkCheckerboardWidget(在二维图像上生成自定义棋盘格)、 vtkRectilinearWipeWidget(生成2x2棋盘格)等。


    Q:事件处理与widget表达实体是如何同步的?
    A:

.拾取
    -作用
        选择和控制角色
    -基类
        vtkAbstractPicker
    -按理解析
        -点拾取-vtkPointPicker
            1.RenderWindowInteractor 接收到事件之后,分发到响应函数,进行处理;
            2.使用SetPicker(*)函数设置 需要拾取操作的 拾取对象;
            3.定制相应的鼠标处理函数,并在其中 完成拾取操作;

  

vtkImagePlaneWidget:
= 切片图像提取,切面三视图可视化部件;

vtkResliceCursorWidget:
=交互式图像切分,定义了“十”字坐标轴,支持坐标轴的旋转平移等鼠标操作;
一个该对象对应一个vtkResliceCursor对象,当坐标系发生改变时调用vtkResliceCursor来进行图像切分并进行更新到vtkRenderer对象中;

vtkAbstractTransform/vtkTransform:
=旋转、平移、缩放等操作;PreMultiply()/PostMultiply() 

vtkImagePlaneWidget:
=三维图像的实时切割

vtkCommand:
= 指令交互模式,

Widget 使用:
1.SetEnabled(int *)可以对widget进行使能/开关控制;

Interaction/Widgets/Testing/Cxx的栗子跑出来的效果:

vtk学习过程中的笔记_第16张图片

==================================分析伪代码
基于widget实现图片切片
//window/interaction创建
vtkSmartPointer renWin->AddRenderer(ren[i]);
vtkSmartPointer iren->SetRenderWindow(renWin);//只有一个RenderWindowInteractor

//三维切面图
vtkSmartPointer planeWidget[i]->SetInteractor(iren);
									 planeWidget[i]->SetDefaultRenderer(ren[3]);
//回调函数
vtkSmartPointer cbk = vtkSmartPointer::New();//我们实现的VTKcommand派生类
vtkSmartPointer< vtkResliceCursor> resliceCursor = vtkSmartPointer< vtkResliceCursor >::New();//创建vtkResliceCursor,一个vtkResliceCursor将所有的vtkResliceCursorWidget链接起来
resliceCursorRep[i] =vtkSmartPointer< vtkResliceCursorLineRepresentation >::New();//显示图像切分时的“十”字坐标轴
vtkSmartPointer< vtkResliceCursorWidget > resliceCursorWidget[i]->SetInteractor(iren);
										  resliceCursorWidget[i]->SetDefaultRenderer(ren[i]);
										  resliceCursorWidget[i]->SetRepresentation(resliceCursorRep[i]);
										  resliceCursorRep[i]->GetResliceCursorActor()->GetCursorAlgorithm()->SetResliceCursor(resliceCursor);//设置同一个vtkResliceCursor使得所有的resliceCursorWidget同步
//回调函数注册 
cbk->IPW[i] = planeWidget[i];
cbk->RCW[i] = resliceCursorWidget[i];
resliceCursorWidget[i]->AddObserver(vtkResliceCursorWidget::ResliceAxesChangedEvent, cbk);//监听ResliceAxesChangedEvent事件,Execute实现回调功能


vtkResliceCursorWidget : 
	vtkAbstractWidget : 
		vtkWidgetCallbackMapper : SetCallbackMethod/SelectAction/RotateAction/EndSelectAction/MoveAction/ResetResliceCursorAction
		vtkWidgetEventTranslator : 
		vtkWidgetRepresentation : 
	vtkInteractorObserver : SetInteractor(AddObserver)/ComputeDisplayToWorld.../SetCurrentRenderer/SetDefaultRenderer
		vtkCallbackCommand : Execute()  --  vtkCommand :SetCallback/event type/
		vtkRenderWindowInteractor :	
		vtkRenderer : 
-vtkResliceCursorLineRepresentation:

vtkImagePlaneWidget : SetInteractor()/SetDefaultRenderer()//三维切面图
	vtkImageReslice : 
	

debug调试

1.Linux

2.Android

vtk学习过程中的笔记_第17张图片


基础解读:

color:
          控色M1:SetColor(RGB 0~1),红,绿,蓝;
          控色M2:AmbientColor, 环境光颜色;DiffuseColor, 散射光颜色;SpecularColor, 镜面光颜色;

灰度:
          一般的非灰度图像unsigned char类型来表示。但是在医学图像处理中常见像素数据类型为unsigned short,灰度范围为0-65536。

4x4矩阵变换:
          1.图形的伸缩、旋转、对称、错切、平移;
          2.图形透视变换;
          3.图形比例变换;

图形结构中的隐形层之间的疏密:层是紧密连接的(dense)/稀疏连接的(sparse)
图片文件格式:1.二进制图片数据,2.图片数据+fileinfo,读写ram(裸数据)格式数据时需要指定维度、字节顺序、存储像素值等属性;

VTK常识了解:
Q1.为什么需要了解类之间的继承?
A1.超类是父类的扩充,有些功能接口在父类中,有些在新加的子类中;开发者也可以继承的方式开发扩展自己的类。

Q2.camera和light 数量是如何规定的?
A2.camera只有一个,light可以多个,多个light的效果都将呈现到一个camera上。

Q3.vtkResliceCursorWidget与vtkImagePlaneWidget是如何实现同步更新的?
A3.这两个类,ResliceCursor是实现切面光标可视化,ImagePlane实现图像切面可视化。

Q4:what is mesa?
A4:

QA.1.实践很重要,多跑代码验证和加深了解。
       2.点是属于零维。

图形学问答:
Q1.what is OpenGL ?
A1.Open Graphics Library,用于图形的绘制、渲染。

Q2.What is OpenCV?
A2.Open Source Computer Vision Library,图形视频基础处理算法库。

Q3.what is Volume rendering?
A3.

Q5.what is ITK (insight segmentation registration toolkit)?
A5:医学图像分割与配准工具包,主要提供算法技术,不支持可视化功能,可以通过相关实现与vtk的配合使用。

常用英文单词:
1.线:line
2.圆:sphere
3.三角形:triangle
4.四边形:quadri-quadru  四边多边形:four-sided polygons
5.正方形:
6.长方形:
7.多边形柱体:polygonal cylinder
8.立方体:cube
9.圆锥体:cone
10.渲染窗口交互器:render window interactor
11.图形结构:graphics structure
12.缩放:zoom
13.辨识度 :Resolution
14.经度-纬度:longitude - latitude 
15.位置:Position
16.PNM图片(黑白、灰度、彩色);PPM->Portable PixMap、PGM->Portable GreyMap、PBM->Portable BitMap
17.切片方向:slice orientation -xzy
18.切面坐标矩阵


资源外接:

paraView Tutorial:https://blog.csdn.net/dsfsdffgfd/category_10102763.html?utm_source=BWXQ_bottombtn&spm=1001.2101.3001.4225

东灵出版社 :https://blog.csdn.net/www_doling_net/category_1331102.html

VTK官网 : https://vtk.org/,其中有VTK-Source/VTK-Data/VTK-Doc等重要学习资源

图像处理VTK/ITK博文列表:https://blog.csdn.net/calmreason/article/details/88075073

图像切片vtkImagePlaneWidget与vtkResliceCursorWidget的使用:https://blog.csdn.net/www_doling_net/article/details/8939115

vtkcommand使用解析:https://blog.csdn.net/webzhuce/article/details/71245134

你可能感兴趣的:(#,图形图像)