第1章 MITK基础知识
Source、Filter、Data、Target等都是一些高层抽象的类,封装的是一些概念,具体工作通过继承由它们的子类来完成。
Source: 负责生成数据,具体的例子包括从磁盘上读文件进来(在MITK中叫做Reader),或者用某些算法生成数据,比如随机数产生器(在MITK中叫做
ProcedualSource)。
Filter: 对数据进行处理,也就是各种各样的算法。
Target:顾名思义,就是数据的终点。具体的例子包括:将得到的结果数据保存至磁盘(在MITK中叫做Writer),或者将得到的结果在屏幕上显示出来(在MITK中叫做View)。
Data: 上面的三种对象实际上都是封装的算法的行为,而Data 就是对算法要处理的数据所进行的抽象。当然一个系统要能处理多种不同的数据,在MITK中是通过Data 的各个具体的子类来描述不同的数据对象的。
mitk 用于MFC :1. 头文件路径 2. mitk_dll.lib 3.lib的目录位置 4. mitk_dll.dll 考到system32
3个重要的头文件 PLYReader SurfaceModel View
简单的显示
case WM_CREATE: // 响应窗口创建消息
{
// 得到当前客户区大小
RECT clientRect;
GetClientRect(hWnd,&clientRect);
int wWidth = clientRect.right - clientRect.left;
int wHeight = clientRect.bottom - clientRect.top;
// 产生mitkView对象
view=new mitkView;
// 设置父窗口句柄
view->SetParent(hWnd);
// 设置mitkView的背景颜色(这里将其设置为黑色)
view->SetBackColor(0,0,0);
// 显示mitkView
view->Show();
// 设置mitkView在父窗口中显示的位置和大小
view->SetLeft(0);
view->SetTop(0);
view->SetWidth(wWidth);
view->SetHeight(wHeight);
// 生成一个mitkSurfaceModel
mitkSurfaceModel *model=new mitkSurfaceModel;
// 设置表面材质属性(这些属性可以随时调整)
model->GetProperty()->SetAmbientColor(0.75f, 0.75f, 0.75f, 1.0f);
model->GetProperty()->SetDiffuseColor(1.0f, 0.57f, 0.04f, 1.0f);
model->GetProperty()->SetSpecularColor(1.0f, 1.0f, 1.0f, 1.0f);
model->GetProperty()->SetSpecularPower(100.0f);
model->GetProperty()->SetEmissionColor(0.0f, 0.0f, 0.0f, 0.0f);
model->GetProperty()->SetEdgeColor(1.0f, 0.0f, 0.0f, 1.0f);
// 这里采用面绘制的方式
model->GetProperty()->SetRepresentationTypeToSurface();
// 将Model加入到View中
view->AddModel(model);
// 生成一个reader
mitkPLYReader *reader = new mitkPLYReader;
// 设置要读入的文件
//reader->AddFileName("111.ply");
reader->AddFileName("dragon_vrip.ply");
reader->AddFileName("dragon_vrip_res2.ply");
reader->AddFileName("drill_1.6mm_150_cyb.ply");
// 如果读取成功,则将类型为mitkMesh的数据交给model
if (reader->Run())
model->SetData(reader->GetOutput());
// 删除Reader
reader->Delete();
break;
WM_SIZE的响应
case WM_SIZE:
{
RECT clientRect;
GetClientRect(hWnd,&clientRect);
int wWidth = clientRect.right - clientRect.left;
int wHeight = clientRect.bottom - clientRect.top;
// 更新mitkView在父窗口中的位置和尺寸
view->SetLeft(0);
view->SetTop(0);
view->SetWidth(wWidth);
view->SetHeight(wHeight);
break;
}
另外,WM_DESTROY 要释放
两个model共用同一个mesh是允许的,两次SetData 增加两次引用计数,删除两个model时再减少两次引用计数,mesh即可被正常删除。
第2章 用MITK实现基本的图像浏览
直接以切片的形式对数据进行浏览是一种基本的需要。
mitkVolume:首先,mitkVolume是一个Data,也就是说它是代表一个数据对象的。它是整个MITK中最重要的数据对象,代表一个三维断层图像数据。
mitkIM0Reader mitkJPEGReader mitkDICOMReader mitkTIFFReader mitkBMPReader mitkRawReader:这几个Reader负责从磁盘上不同格式的图像文件中读取数据。它们都是mitkVolumeReader 的子类,读取后,通过它们的GetOutput可以得到统一的mitkVolume数据。
使用mitk*Reader,首先要告诉它要读取的文件名,一个Reader可以处理一系列的文件,所以可以通过AddFileName()添加多个文件名;然后要设置一些读取参数,比如对于JPEG、TIFF、BMP,还需要设定像素间距和切片间距,因为这些信息文件本身并不提供,但它们对以后的处理是很重要的。对于Raw,要设定的就更多了,还包括图像长宽等基本信息,而对于IM0和DICOM文件,由于其文件本身包含了所有与图像相关的信息,包括切片及像素之间的间距等等,所以不用什么额外的设定,另外Raw和IM0由于一个文件就包含了一个Volume,所以只用设一个文件名,实际上,你加入的所有文件名对于这两个Reader来说,只有第一个是有用的,其他的都被忽略了;接着,就可以调用Run()来运行这个Reader,读取文件里面的数据,注意,该函数返回一个bool 型的变量,可以根据返回值来判断读文件过程中是否发生错误。
mitkImageView:第一章已经介绍了,用来以2D切片的方式浏览图像,默认的mitkImageViewManipulatorStantard 提供了平移、放缩、窗宽、窗位等默认的鼠标行为。
mitkImageModel:是一个对应于mitkVolume的Data Model,用在2D的mitkImageView当中。
m_Volume->AddReference(); 这条语句非常重要。在第一章的例子里,我们在删除reader之前,已经知道了将要使用数据的对象,我们可以直接通过SetInput/GetOutput机制将数据pass 到下一级(通过智能指针自动完成引用计数的加减),但是这里,我们希望暂时保留输出数据,因为“使用者”mitkImageModel将被我们放在CMITKView中。于是,我们用AddReference向MITK表明“我也在引用这个对象,请不要删除它”,而当我们需要要删除它的时候(clearVolume中),调用RemoveReference()函数解除引用,该函数会判断当前此对象的被引用数,如果值为0则删除这个对象。
因为每次载入新的数据,我们都会在CMITKTestDoc中调用UpdateAllViews函数,而这正会引起CMITKView中OnUpdate 被调用,我们可以利用这个机会来更新Model 的数据,在此例中,我们还可以决定是否显示窗口下方的滚动条,
GetClientRect 该函数获取窗口客户区的坐标
::GetClientRect(this->m_hWnd,rectClient);
API函数:
BOOL GetClientRect(HWND hWnd,
LPRECT lpRect);
还有一个为CWnd类成员函数:
void GetClientRect(LPRECT lpRect)
const;
第3章 用MITK实现基本的面绘制
是对第一章的一种更加规范的实现。
第4章 用MITK进行表面重建
我们常常需要以三维的方式在二维的显示设备上对医学图像进行显示,这个要求可以通过两个途径达到:
1、从三维断层图像中提取出等值面,表示成三维网格的形式(表面重建),再利用第三章面绘制的方法进行绘制。
2、直接对体数据进行绘制。针对这两种方法,MITK都提供了强大的算法工具。
mitkMarchingCubes:是一个Filter,也就是说它是代表一个算法对象的。它封装了三维重建算法,是我们这里要使用的主要的算法。它的类继承图如图
可见它是一个VolumeToMeshFilter,输入是Volume,输出是Mesh。顾名思义,它使用的是Marching Cubes算法,从体数据中抽取等值面。用户可以通过它的成员函数void SetThreshold (float lowThreshold, float highThreshold)设置一个高阈值和一个低阈值。
mitkPLYBinaryWriter:是一个Writer,用来把Mesh以PLY(二进制)的格式写入磁盘文件。
第5章 用MITK进行网格化简
三角面片化简(mesh simplification)指的是在尽量保持原模型几何形状的前提下,根据对原始模型逼近精度的要求,删除对模型整体结构影响较小的细节部分,用更少的面片反映模型的显著几何特征,从而达到减少模型的面片数、边数或顶点数的目的。网格化简方法主要有顶点删除、顶点聚类和边折叠三类,在我们的实现中使用了实验室改进的算法以及半边数据结构,即以QEM(Quadric Error Metric)为基础,针对医学成像的特点进行了改进。本例中用到的比较重要的类是mitkQEMSimplification 。
mitkQEMSimplification:mitkQEMSimplification 是对基于QEM(Quadric Error Metrics)的simplification算法的一个应用。 从继承图可以看出,它实际上是一个MeshToMeshFilter,即输入和输出都是Mesh数据
mitkObserver:在mitk中所有的mitkObject都可以附到一个observer上。 可以从这个派生出的具体的Observer来获得MITK对象mitkObject的状态信息。这个类有个虚成员函数Update(),它可以根据它所附着的mitkObject的变化来更新observer 。一个实际上工作的observer需要给这个Update()补充相应的代码。这里,我们实现的是由它派生的一个类MySimplificationObserver,我们要用它读取简化函数的进度。
第一步:将第三章的工程复制到一个新的文件夹下 先更改显示图片的光学效果,
第二步:打开ResouceView的ToolBar选项
第三步:添加设置目标面片数的对话框CSimSetDlg
第四步:添加进度条对话框CProgressDlg
第五步:增加一个MySimplificationObserver 类,用于动态的访问简化过程的进度
第六步:给CMITKTestApp类添加几个接口函数
第七步:给MainFrame.h文件添加代码。
第八步:给MySimplificationObserver类添加代码。
第九步:填写OnSimplificatoin()函数。
第十步:为了能将简化后的数据保存下来,在CMITKTestDoc类中添命令处理函数OnFileSave()。别忘了添加头文件#include "mitkPLYBinaryWriter.h"
第6章 用MITK进行体绘制
mitkVolumeModel:是一个对应于mitkVolume的Data Model,但是与mitkImageModel不同,mitkVolumeModel表示一个以体绘制(Volume Rendering)的方式显示在场景中的实体。通过SetData 函数得到mitkVolume数据。
mitkVolumeProperty:负责为mitkVolumeModel 管理属性结构。可以通过mitkVolumeModel的GetProperty取得。mitkVolumeProperty主要管理着以下属性:
a. 光源参数:通过 SetAmbient SetDiffuse SetSpecular SetSpecularPower几个函数指定。
b. 插值类型:可以是最近插值或线性插值。可以通过SetInterpolationType等几个函数指定。
c. 传递函数:
灰度-阻光度传递函数:通过GetScalarOpacity 取得mitkTransferFunction1D类型的指针,后者负责管理函数的具体定义。
灰度-颜色传递函数:通过GetScalarColor取得mitkColorTransferFunction类型的指针,后者负责管理函数的具体定义。
梯度-阻光度传递函数:通过GetGradientOpacity取得mitkTransferFunction1D类型的指针,后者负责管理函数的具体定义。
d. 两个开关:
光照开关:ShadeOn / ShadeOff决定是否启用梯度-阻光度传递函数的开关:GradientOpacityCalculationOn / GradientOpacityCalculationOff
mitkTransferFunction1D:一维传递函数,通过一系列关键点来定义。使用时首先通过SetMax 来指定最大的输入值及其对应的输出值,再通过AddPoint来指定中间各个关键点。
mitkColorTransferFunction:颜色传递函数,与mitkTransferFunction1D类似,只不过输出有R、G、B三个分量。
mitkVolumeRenderer:抽象的体绘制类。其父类为mitkRenderer(抽象绘制类)。实际在面绘制中,也隐含地用到了一个派生自mitkRenderer 的类mitkSurfaceRenderer,只不过我们通常不需要手工设置。父类mitkRenderer提供了平面裁剪的接口,而mitkVolumeRenderer扩展了这一接口,并针对体绘制,增加了“分类方式(ClassifyMethod)”的设置接口,提供了先插值、后分类和先分类、后插值的选择。此类有若干子类,可以通过mitkVolumeModel的SetRenderer函数将合适的子类实例指定给Model,实现对体绘制具体算法的选择。
mitkVolumeRendererRayCastingLoD:一个具体的体绘制类,使用光线投射算法,支持LOD(Level Of Detail,层次细节),可以粗绘和细绘,增强了交互性。
mitkVolumeRendererTexture3D:一个具体的体绘制类,基于3D纹理加速,暂不支持光照,对硬件要求较高。
mitkVolumeRendererShearWarp:一个具体的体绘制类,使用目前被认为是最快的软件体绘制算法的错切变形算法。支持LOD。
mitkVolumeRendererSplatting:一个具体的体绘制类,使用Splatting算法(一种物体控件的经典绘制算法)。
mitkSplatCamera:使用Splatting算法时要求mitkView使用的Camera类。
mitkPlane:封装“平面”概念,采用点法式表示。在本例中用来做平面裁剪,通过mitkRenderer的AddClippingPlane函数加入到Renderer中。
mitkReslicePlaneWidgetModel:一个用来做切片重组的3D Widget类,其类继承图如下
显然,它是一个Model,不过mitkWidgetModel这一枝的特色是在模型中内包含独特的交互行为。
mitkWidgetsViewManipulator:第一章曾提到,这个类是mitkManipulator的子类,它在这一家族中的位置如图 6-2所示。mitkWidgetsViewManipulator用在mitkView中使用3D Widget的情况下,与Widget相配合,Widget实现所需要的交互行为。
mitkObserver:是一个抽象类,用来接收MITK对象的状态信息。这里,我们要实现它的一个子类MyReslicePlaneObserver,用来在裁剪平面被激活时,将其记录为当前的Widget,以便将选中平面删除。
第7章 用MITK进行图像分割
damned! i find out this release was outofdate !!! means i have to change my way again