Image直接继承自SlicedData。BaseData在MITK中相当于是其他Datatype的老妈。SlicedData继承了这个类后又在功能上做了细化,在类中包含了image slices, 引入了能够完整定义geometry的属性和函数。mitk::Image又进一步具体化,包含了multiple channels, volumes, slices以及额外的属性如image properties。
下面我们介绍三个不同的方面:
1. SlicedData and Geometry
2. ImageData
3. Image Properties
SlicedData and Geometry
作为Image的父类,引入了一个重要概念:Geometry,用来定义图像的空间属性:dimention和orientation。深入了解这一概念参照这里:Geometry Overview。
ImageData
mitk::Image的实例化对象存储着实际的图像数据。理清下面这四个概念很重要:
- Channels,表示数据是哪种类型(比如说是灰度图像还是矢量图像)。每个channel包含一个或多个volume。
- Volumes, 含有特定类型的数据。一个volume由多个表示volume属性的ImageDataItem表示。每个volume由多个slices组成。
- Slices, 每一个slice含有一个二维图像。
mitk::Image含有一个指针成员m_CompleteData ,指向数据整体(所有volume)。当你想把一个图像数据拷贝至另一个图像数据里时,这个成员非常有用。
![这里写图片描述](http://docs.mitk.org/nightly-qt4/mitkimagememory.png)
Image Properties
Properties是一组附加信息,主要用来保存DICOM信息。这个功能在BaseData类中就引入了。工作机制与哈希表类似,使用property key和properties的对应。更多请参考 BaseData::GetProperty() ,例子参照USImage::GetMetadata()。
获取图像数据
MITK中多个模块和plugin都可能工作在同一图像上,所以理解和管理正在进行的image access十分困难,因此image accessor的概念被引入。image accessor负责管理图像的access并保证数据一致性。每个图像都管理自己的image accessors。下面详细解释。
Image accessors
Image accessors提供获取图像数据的功能,它负责:
1. 监管:任何时间它都知道有多少个实例在访问某个部分的数据。
2. 一致性和线程安全性:上锁机制允许并行读图像,保证过程中数据的状态一致性。
3.可限制部分图像的获取:可限制仅能访问图像的某个部分(volume或slice)。这个部分由ImageDataItem表示。
4. 可使用pixel index:方便地获取图像像素值。
目前可实例化的image accessor类包括 mitk::ImageReadAccessor, mitk::ImageWriteAccessor和mitk::ImageVtkAccessor。mitk::ImageReadAccessor 和 mitk::ImageWriteAccessor提供对一个mitk::Image或 mitk::ImageDataItem的访问,并提供一个 (const) void *指针。 mitk::ImageVtkAccessor提供 legacy mode 下的VTK图像获取(不能实例化)。
![这里写图片描述](http://docs.mitk.org/nightly-qt4/mitkimageaccessorhierarchy.png)
如何access
尽管image accessor概念有点复杂,但使用起来很方便。先创建一个image accessor对象。image accessor的构造器需要一个指向mitk::Image的指针,指向图像某个部分的指针(mitk::ImageDataItem)则可选。由于构造器可能抛出 mitk::Exception,所以尽量使用try–catch语句。可能的错误包括无效图像、维度不对等等。
如果只需一个指向图像的指针,下面代码展示了如何获得一个const或 non-const指针。 mitk::ImageReadAccessor只提供了一个指向image data 的const void* 指针,而mitk::ImageWriteAccessor提供了一个 void*指针。
// we assume you already have an mitk::Image::Pointer image
try
{
mitk::ImageReadAccessor readAccess(image, image->GetVolumeData(0));
const void* cPointer = readAccess.GetData();
mitk::ImageWriteAccessor writeAccess(image);
void* vPointer = writeAccess.GetData();
}
catch(mitk::Exception& e)
{
// deal with the situation not to have access
}
注意,write access完成后应显示调用Modified()函数。
访问图像数据更为方便的途径是mitk::ImagePixelReadAccessor和mitk::ImagePixelWriteAccessor。它们有基于pixel index的set和get方法。这两个都是模板类,需要事先知道pixel type和image dimension。
// we assume you already have an mitk::Image::Pointer image
try
{
itk::Index<2> idx = {{ 12, 34 }};
mitk::ImagePixelReadAccessor<short,2> readAccess(image, image->GetSliceData(2));
short value = readAccess.GetPixelByIndex(idx);
mitk::ImagePixelWriteAccessor<short,2> writeAccess(image, image->GetSliceData(4));
writeAccess.SetPixelByIndex(idx, 42);
}
catch(mitk::Exception& e)
{
// deal with the situation not to have access
}
Additional properties
image accessor构造器函数可选一些行为。使用枚举(比如mitk::ImageAccessorBase::ExceptionIfLocked)指明具体属性。如果请求的image part被锁住,ExceptionIfLocked将导致异常抛出。
try
{
mitk::ImageReadAccessor imageAccess(image, image->GetSliceData(2), mitk::ImageAccessorBase::ExceptionIfLocked);
const void* pointer = imageAccess.GetData();
}
catch(mitk::MemoryIsLockedException& e) {
// do something else
}
catch(mitk::Exception& e) {
// deal with the situation not to have access
}
克隆MITK image
mitk::Image::Pointer testMethod(const mitk::Image* image)
{
mitk::Image::Pointer nIm = image->Clone();
return nIm;
}
克隆还可人工完成,这需要复制Geometry,visual Data以及其他具体属性。最简单的方式是首先调用Image::Initialize(const Image * image),这会复制geometry,但不会复制data或各种属性。然后,复制图像data(比如用SetVolume),如有需要,用SetPropertyList(image->GetPropertyList())复制属性。
继承mitk Image
通常应该避免继承mitk::Image。原因是继承后的类可能无法与已经写好的各种filters愉快地合作。当然,如果你非要继承,还是查查相关文档,看看一些继承的例子为好。