1.概述
Itk::PointSet
类是与图像类交互的。因此点集中的点可以很方便地保存从图像计算得到的值。与点相关的值被指定为PixelType
像素类型,以便使它跟图像术语保持一致。工具包中的泛型编程方式提供的灵活性,使得用户可以按自己的意愿来定义类型。PixelType
像素类型是点集PointSet
的第一个模板参数。
2.过程讲解
下面的代码为像素类型定义了一个特殊的类型,并用它实例化一个点集PointSet
类。
typedef unsigned short PixelType;
typedef itk::PointSet< PixelType, 3 > PointSetType;
使用SetPointData( )
方式可以对点集PointSet
插入数据。该方法要求用户提供一个标识符。数据将和具有相同标识符的点相关联。用户需要负责验证插入点和插入数据之间的适当匹配。
下面一行程序阐述了SetPointData( )
方法的用法
unsigned int dataId = 0;
PixelType value = 79;
pointSet->SetPointData( dataId, value );
使用GetPointData( )
方法可以从点集PointSet
读入与点相关的数据。该方法要求用户提供点的标识符和一个能够安全写入像素数据的位置的有效指针。当这个标识符和点集PointSet
中的标识符不相匹配时,将返回false
,并且返回的像素值也是无效的。用户负责在使用点集数据之前检查返回的布尔值。
const bool found = pointSet->GetPointData( dataId, & value );
if( found )
{
std::cout << "Pixel value = " << value << std::endl;
}
SetPointData( )
和GetPointData( )
并不是得到点中存储数据的最有效方法。使用PointDataContainer
提供的迭代器来得到数据会更加有效。
与点相关的数据储存在PointDataContainers
内部。与点使用的方式相同,使用的实际容器类型取决于点集PointSet
的方式是静态的还是动态的。静态点集使用itk::VectorContainer
,而动态点集使用itk::MapContainer
。数据容器的类型是作为点集PointSet
的一个特性来定义的。下面阐述了这个类型如何从特性中提取,并如何用来方便地声明全局命名空间上的一个相似类型:
typedef PointSetType::PointDataContainer PointDataContainer;
现在使用这个类型就可以创建一个数据容器的实例。这是一个标准的引用计数对象,因此使用New( )
方法来创建对象并将刚创建的对象分配给一个智能指针。
PointDataContainer::Pointer pointData = PointDataContainer::New();
使用InsertElement( )
方法将像素数据插入到容器中。这种方式需要为每个点数据提供一个标识符。
unsigned int pointId = 0;
PixelType value0 = 34;
PixelType value1 = 67;
pointData->InsertElement( pointId++ , value0 );
pointData->InsertElement( pointId++ , value1 );
最后使用SetPointData( )
方法将点数据容器PointDataContainer
分配给点集PointSet
。这将替代点集PointSet
上以前存在的任何PointDataContainer
。
使用GetPointData( )
方法可以从点集PointSet
得到PointDataContainer
。该方法返回点集PointSet
拥有的实际容器的指针(分配给一个智能指针)。
PointDataContainer::Pointer pointData2 = pointSet->GetPointData();
顺序访问点数据的最有效方式是使用PointDataContainer
提供的迭代器。Iterator
类型属于PointsContainer
类的特性。迭代器不是一个引用计数类,所以它可以直接从特性创建而不必使用智能指针。
typedef PointDataContainer::Iterator PointDataIterator;
迭代器的后继使用与STL迭代器类似。使用Begin( )
方法从容器得到第指向一个点的迭代器,并分配给另一个迭代器。
PointDataIterator pointDataIterator = pointData2->Begin();
迭代器中的++操作符可以被用来从一个点指向下一个点。迭代器指向的PixelType
的实际值可以使用Value( )
方法得到。通过比较当前迭代器和用End( )
方法返回的点容器PointsContainer
,就可以控制循环遍历所有的点数据。下面的代码阐述了遍历点数据的典型循环:
PointDataIterator end = pointData2->End();
while( pointDataIterator != end )
{
PixelType p = pointDataIterator.Value(); // access the pixel data
std::cout << p << std::endl; // print the pixel data
++pointDataIterator; // advance to next pixel/point
}
注意:与STL中一样,使用End( )
方法返回的迭代器不是一个有效的迭代器。这是一个表示越过末端的,在访问了容器的最后一个元素后再前进一步的迭代器值。
3.代码
// `Itk::PointSet` 类是与图像类交互的。因此点集中的点可以很方便地保存从图像计算得到的值。
// 与点相关的值被指定为`PixelType`像素类型,以便使它跟图像术语保持一致。工具包中的泛型编程方式提供的灵活性,
// 使得用户可以按自己的意愿来定义类型。`PixelType`像素类型是点集`PointSet` 的第一个模板参数。
#include "itkPointSet.h"
int
main(int, char *[])
{
// 下面的代码为像素类型定义了一个特定的类型,并用它实例化一个PointSet类。
using PixelType = unsigned short;
using PointSetType = itk::PointSet<PixelType, 3>;
// 这里实例化了一个点集
PointSetType::Pointer pointSet = PointSetType::New();
// 使用`SetPointData( )`方式可以对点集PointSet 插入数据。该方法要求用户提供一个标识符。
// 数据将和具有相同标识符的点相关联。用户需要负责验证插入点和插入数据之间的适当匹配。
// 下面一行程序阐述了SetPointData( )方法的用法
unsigned int dataId = 0;
PixelType value = 79;
pointSet->SetPointData(dataId, value);
//
// 使用GetPointData( )方法可以从点集PointSet 读入与点相关的数据。该方法要求用户提供点的标识符和一个能够安全写入像素数据的位置的有效指针。
// 当这个标识符和点集PointSet 中的标识符不相匹配时,将返回false,并且返回的像素值也是无效的。用户负责在使用点集数据之前检查返回的布尔值。
const bool found = pointSet->GetPointData(dataId, &value);
if (found)
{
std::cout << "Pixel value = " << value << std::endl;
}
// SetPointData( )和GetPointData( )并不是访问点中存储数据的最有效方法。使用PointDataContainer提供的迭代器来得到数据会更加有效。
// 与点相关的数据储存在PointDataContainers内部。与点使用的方式相同,
// 使用的实际容器类型取决于点集PointSet的方式是静态的还是动态的。静态点集使用itk::VectorContainer,而动态点集使用itk::MapContainer。
// 数据容器的类型是作为点集PointSet 的一个特性来定义的。下面阐述了这个类型如何从特性中提取,并如何用来方便地声明全局命名空间上的一个相似类型:
//
using PointDataContainer = PointSetType::PointDataContainer;
//
// 现在使用这个类型就可以创建一个数据容器的实例。这是一个标准的引用计数对象,因此使用`New( )`方法来创建对象并将刚创建的对象分配给一个智能指针。
PointDataContainer::Pointer pointData = PointDataContainer::New();
// 使用InsertElement( )方法将像素数据插入到容器中。这种方式需要为每个点数据提供一个标识符。
unsigned int pointId = 0;
PixelType value0 = 34;
PixelType value1 = 67;
pointData->InsertElement(pointId++, value0);
pointData->InsertElement(pointId++, value1);
// 最后使用SetPointData( ) 方法将点数据容器PointDataContainer 分配给点集PointSet。这将替代点集PointSet 上以前存在的任何PointDataContainer。
pointSet->SetPointData(pointData);
//
// 使用GetPointData( )方法可以从点集PointSet 得到PointDataContainer。该方法返回点集PointSet拥有的实际容器的指针(分配给一个智能指针)。
PointDataContainer::Pointer pointData2 = pointSet->GetPointData();
// 顺序访问点数据的最有效方式是使用PointDataContainer提供的迭代器。Iterator类型属于PointsContainer 类的特性。
// 迭代器不是一个引用计数类,所以它可以直接从特性创建而不必使用智能指针。
using PointDataIterator = PointDataContainer::Iterator;
// 迭代器的后续使用遵循了STL迭代器的要求。使用\code{Begin()}方法从容器中获得指向第一点的迭代器,并将其赋给另一个迭代器。
PointDataIterator pointDataIterator = pointData2->Begin();
//
// 迭代器中的++操作符可以被用来从一个点指向下一个点。迭代器指向的PixelType的实际值可以使用Value( )方法得到。
// 通过比较当前迭代器和用End( )方法返回的点容器PointsContainer,就可以控制循环遍历所有的点数据。下面的代码阐述了遍历点数据的典型循环:
PointDataIterator end = pointData2->End();
while (pointDataIterator != end)
{
PixelType p = pointDataIterator.Value(); // access the pixel data
std::cout << p << std::endl; // print the pixel data
++pointDataIterator; // advance to next pixel/point
}
// 注意:与STL中一样,使用End( )方法返回的迭代器不是一个有效的迭代器。这是一个表示越过末端的,在访问了容器的最后一个元素后再前进一步的迭代器值。
return EXIT_SUCCESS;
}