ITK学习笔记:1.Data presentation-1.2PointSet(一)点集:创建、获取与访问

1.创建

PointSet是一个基本类,旨在以n维空间中一组点的形式表示几何。
它是itk::Mesh的基类,提供了操作点集所需的方法。点可以有与之相关的值。这些值的类型是由itk::PointSet类的模板参数定义的。

ITK中有两种基本的切入点集交互样式。这些样式分别称为静态样式(static )和动态样式( dynamic)。点集的数量是固定并且不希望改变时用第一种,要增改删则用第二种。

#include "itkPointSet.h"

//我们必须决定什么类型的值与这些点相关联。
//为了使术语与itk::Image一致,通常称为PixelType。
//点集还在表示点的空间维度上模板化。下面的声明说明了PointSet类的典型实例化:
typedef itk::PointSet< unsigned short, 3 > PointSetType;

//PointSet对象是通过对其类型调用New()方法创建的。
//产生的对象必须分配给一个智能指针。然后点集是引用计数的,可以由多个对象共享。当对对象的引用数量减少到零时,为PointSet分配的内存将被释放。
//这仅仅意味着用户不需要关心调用该类上的Delete()方法。实际上,不应该在任何引用计数的ITK类中直接调用Delete()方法。
PointSetType::Pointer pointsSet = PointSetType::New();

//遵循泛型编程的原则,PointSet类拥有一组相关的已定义类型,以确保使用兼容类型声明交互对象。这组类型定义通常称为一组特征。
//例如,我们可以在其中找到PointType类型。这是点集用来表示空间中的点的类型。下面的声明采用点集特征中定义的点类型.
//这里将其重命名,以便在全局名称空间中使用。
typedef PointSetType::PointType PointType;

//现在可以使用PointType来声明要插入到切入点集中的点对象。点是相当小的对象,所以使用引用计数和智能指针来管理它们很不方便。它们只是被实例化为典型的c++类。
//Point类从itk::Array类继承了[]操作符。这使得使用索引表示法访问其组件成为可能。
//为了提高效率,在索引访问期间不执行边界检查。用户负责确保所使用的索引在{0,维−1}范围内。
PointType p0; 
p0[0] = -1.0; // x coordinate 
p0[1] = -1.0; // y coordinate 
p0[2] = 0.0; // z coordinate

//使用SetPoint()方法将点插入到点集中。此方法要求用户为该点提供唯一标识符。
//标识符通常是一个无符号整数,将在插入点时枚举它们。
//下面的代码显示了如何将三个点插入到切入点中:
pointsSet->SetPoint( 0, p0 );
pointsSet->SetPoint( 1, p1 ); 
pointsSet->SetPoint( 2, p2 );

//可以查询切入点集,以确定插入了多少个点。
//这是通过GetNumberOfPoints()方法完成的,如下所示:
const unsigned int numberOfPoints = pointsSet->GetNumberOfPoints();
std::cout << numberOfPoints << std::endl;

//可以使用GetPoint()方法和整数标识符从点集读取点。
//该点存储在用户提供的指针中。如果提供的标识符与现有的点不匹配,该方法将返回false,点的内容将无效。
//下面的代码演示了使用防御性编程的点访问:
PointType pp; 
bool pointExists = pointsSet->GetPoint( 1, & pp );
if( pointExists ) 
{ std::cout << "Point is = " << pp << std::endl; }

同样的GetPoint()和SetPoint()不是访问点集中点的最有效方法。
最好是直接访问由特征定义的内部点容器,并使用迭代器按顺序遍历点列表
如后节的示例所示:

2.点的获取

ITK::PointSet类使用一个内部容器来管理itk::PointSet的存储。通常,通过使用points容器上直接提供的访问方法来管理点更有效。下面的示例说明了如何与点容器交互以及如何使用点迭代器:

//类型由PointSet类的traits定义。
//下面一行方便地从PointSet traits中获取PointsContainer类型
//并以便在全局命名空间中声明它
typedef PointSetType::PointsContainer PointsContainer;

//PointsContainer的实际类型取决于所使用的切入点的样式。
//动态点集使用itk::MapContainer
//而静态点集使用itk::VectorContainer
//vector和map容器基本上是STL类std::map和std::vector的ITK包装器。
//默认情况下,PointSet使用静态样式,因此点容器的默认类型是VectorContainer。映射和向量容器都是在它们包含的元素类型上模板化的。
//在本例中,它们是在PointType上模板化的。容器是引用计数对象。然后使用New()方法创建它们,并在创建后分配给itk::SmartPointer。
//下面的行创建了一个点容器,它与特征所在的点集的类型兼容
PointsContainer::Pointer points = PointsContainer::New();

//现在可以使用切入点集中的切入点类型特征来定义点。
typedef PointSetType::PointType PointType;
PointType p0;
PointType p1;
p0[0] = -1.0;p0[1] = 0.0;p0[2] = 0.0; // Point 0 = {-1,0,0 } 
p1[0] = 1.0; p1[1] = 0.0; p1[2] = 0.0; // Point 1 = { 1,0,0 }

//可以使用通用方法InsertElement()将创建的点插入到PointsContainer中
//该方法需要为每个点提供标识符
unsigned int pointId = 0; 
points->InsertElement( pointId++ , p0 );
points->InsertElement( pointId++ , p1 );

//最后,可以将PointsContainer分配给点集。
//这将替代切入点集中以前存在的任何PointsContainer。
//该赋值是使用SetPoints()方法完成的。
pointSet->SetPoints( points );

//可以使用GetPoints()方法从点集获得PointsContainer对象。
//这个方法返回一个指向PointSet所拥有的实际容器的指针
//该指针随后被分配给一个SmartPointer。
PointsContainer::Pointer points2 = pointSet->GetPoints();

//顺序访问点的最有效方法是使用PointsContainer提供的迭代器。
//迭代器类型属于PointsContainer类的特征trait。它的行为很像STL迭代器。
//Points迭代器不是一个引用计数类,是直接从特征创建而不使用smartpointer。
typedef PointsContainer::Iterator PointsIterator;

//迭代器的后续使用遵循了STL迭代器第一个点的迭代器是从带有Begin()方法的容器中获得的,并被分配给另一个迭代器。
PointsIterator pointIterator = points->Begin();

//迭代器上的++运算符可用于从一点前进到下一点。
//迭代器所指向的点的实际值可以通过value()方法获得。
//通过比较当前迭代器和PointsContainer的End()方法返回的迭代器,可以控制遍历所有点的循环。
//下面的线条说明了遍历这些点的典型循环:
PointsIterator end = points->End();
while( pointIterator != end ) 
{ 
PointType p = pointIterator.Value(); // access the point 
std::cout << p << std::endl; // print the point 
++pointIterator; // advance to next point
 }

//注意,在STL中,End()方法返回的迭代器不是有效的迭代器。
//这被称为past-end迭代器,以表明它是在访问容器中的最后一个元素后向前推进一步后得到的值。
//容器中存储的元素数量可以使用Size()方法查询。
//对于切入点,下面两行代码是等效的,它们都返回切入点中的点数:
std::cout << pointSet->GetNumberOfPoints() << std::endl; 
std::cout << pointSet->GetPoints()->Size() << std::endl;

3.以点访问数据

PointSet类被设计为与Image类交互。因此,允许集合中的点保存可以从图像中计算的值是很方便的。
与点关联的值称为PixelType,以便与图像术语保持一致。由于工具箱中使用的泛型编程方法提供了灵活性,用户可以随意定义类型。PixelType是切入点的第一个模板参数。

下面的代码为像素类型定义了一个特定的类型,并用它实例化一个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()方法从点集中读取与点相关的数据。此方法要求用户提供指向点的标识符和指向可以安全写入像素数据的位置的有效指针。如果标识符与点集上的任何现有标识符不匹配,该方法将返回false,并且返回的像素值将无效。用户有责任在尝试使用返回的布尔值之前检查它。

const bool found = pointSet->GetPointData( dataId, & value );
 if( found )
  { std::cout << "Pixel value = " << value << std::endl; }

SetPointData()和GetPointData()方法不是访问点数据的最有效方法。
使用PointDataContainer提供的迭代器要高效得多。
与点关联的数据内部存储在PointDataContainers中。与点相同,实际使用的容器类型取决于切入点集的样式是静态的还是动态的。静态点集将使用itk::VectorContainer,而动态点集将使用itk::MapContainer。数据容器的类型被定义为切入点中的一个特征。下面的声明说明了如何从特征中提取类型,并用于方便地在全局名称空间中声明类似的类型。

typedef PointSetType::PointDataContainer PointDataContainer;

使用该类型,现在可以创建数据容器的实例。这是一个标准的引用计数对象,因此它使用New()方法创建并将新创建的对象赋值给一个SmartPointer。

PointDataContainer::Pointer pointData = PointDataContainer::New();

像素数据可以通过InsertElement()方法插入到容器中。这种方法需要为每个点数据提供一个标识。

unsigned int pointId = 0;
PixelType value0 = 34;
 PixelType value1 = 67;
pointData->InsertElement( pointId++ , value0 ); pointData->InsertElement( pointId++ , value1 );

最后,可以将PointDataContainer分配给切入点集。这将替代切入点集中以前存在的任何PointDataContainer。该赋值是使用SetPointData()方法完成的。

pointSet->SetPointData( pointData );

PointDataContainer可以使用GetPointData()方法从切入点集中获得。这个方法返回一个指向PointSet所拥有的实际容器的指针(分配给一个SmartPointer)。

PointDataContainer::Pointer pointData2 = pointSet->GetPointData();

顺序访问与点关联的数据的最有效方法是使用PointDataContainer提供的迭代器。迭代器类型属于PointsContainer类的特征。iterator不是一个引用计数类,因此它只是直接从特征创建的,而没有使用smartpointer。

typedef PointDataContainer::Iterator PointDataIterator;
PointDataIterator pointDataIterator = pointData2->Begin();

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 
 }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值