1.概述
这个例子阐述了如何参数化一个点集来管理一个特定的像素类型。将向量值和点相关联以创建一个几何表示是很普遍的。
下面的代码展示了如何使用向量值作为点集PointSet
类的像素类型。在这里使用itk::Vector
类作为像素类型。这个类很适合表示两个点之间的相对位置。然后就可以使用它来管理例如位移。
2.过程详解
为了使用向量类必须包含它的头文件和点集的头文件。
#include "itkVector.h"
#include "itkPointSet.h"
向量类是在用来表示空间坐标和空间维数的类型上进行模板化的。由于像素类型PixelType
独立于点类型PointType
,所以我们可以自由地选择任意维数的向量作为像素类型。但是,为了创建一个有趣的例子,我们使用的向量将可以代表点集PointSet
中的点的位移。然后选择这些向量的维数与点集PointSet
的维数相同。
const unsigned int Dimension = 3;
typedef itk::Vector< float, Dimension > PixelType;
然后我们使用像素类型(事实上是向量)来对点集PointSet
类型进行实例化,进而创建一个点集对象。
typedef itk::PointSet< PixelType, Dimension > PointSetType;
PointSetType::Pointer pointSet = PointSetType::New();
下面的代码生成了一个球体,并分配向量值给点。如下图所示,这个例子中计算得到的向量元素用来表示圆上的切线。
PointSetType::PixelType tangent;
PointSetType::PointType point;
unsigned int pointId = 0;
const double radius = 300.0;
for(unsigned int i=0; i<360; i++)
{
const double angle = i * itk::Math::pi / 180.0;
point[0] = radius * std::sin( angle );
point[1] = radius * std::cos( angle );
point[2] = 1.0; // flat on the Z plane
tangent[0] = std::cos(angle);
tangent[1] = -std::sin(angle);
tangent[2] = 0.0; // flat on the Z plane
pointSet->SetPoint( pointId, point );
pointSet->SetPointData( pointId, tangent );
pointId++;
}
现在我们可以访问所有的点,并使用像素值表示的向量来执行点上的一个位移。这遵循一种在它的每次迭代中都可以进行位移的可形变模型的原则。
typedef PointSetType::PointDataContainer::ConstIterator PointDataIterator;
PointDataIterator pixelIterator = pointSet->GetPointData()->Begin();
PointDataIterator pixelEnd = pointSet->GetPointData()->End();
typedef PointSetType::PointsContainer::Iterator PointIterator;
PointIterator pointIterator = pointSet->GetPoints()->Begin();
PointIterator pointEnd = pointSet->GetPoints()->End();
while( pixelIterator != pixelEnd && pointIterator != pointEnd )
{
pointIterator.Value() = pointIterator.Value() + pixelIterator.Value();
++pixelIterator;
++pointIterator;
}
注意:这里我们使用的是常量迭代器ConstIterator
而不是一般的迭代器Iterator
,因为像素值仅仅用来读取而不能更改。ITK 在API级别支持const-correctness
。
Itk::Vector
类重载了itk::Point
类中的+操作。换句话说,向量可以加到点上来产生一个新的点。在循环体中利用这个特性就可以使用一条语句来更新点的位置。
最后我们可以访问所有的点并打印输出新的数值。
pointIterator = pointSet->GetPoints()->Begin();
pointEnd = pointSet->GetPoints()->End();
while( pointIterator != pointEnd )
{
std::cout << pointIterator.Value() << std::endl;
++pointIterator;
}
注意:itk::Vector
并不是表示表面法线和函数梯度的合适的类,这是由于向量在仿射变换(affine transforms
)上的行为方式决定的。ITK 有一种表示法线和函数梯度的特殊类,就是itk::ConvariantVector
类。
3.代码
// 这个例子阐述了如何参数化一个点集来管理一个特定的像素类型。将向量值和点相关联以创建一个几何表示是很普遍的。
// 下面的代码展示了如何使用向量值作为点集PointSet类的像素类型。在这里使用itk::Vector 类作为像素类型。
// 这个类很适合表示两个点之间的相对位置。然后就可以使用它来管理例如位移。
//
//
// 为了使用向量类必须包含它的头文件和点集的头文件。
#include "itkVector.h"
#include "itkPointSet.h"
int main(int, char *[])
{
// Vector类是在用来表示空间坐标和空间维数的类型上进行模板化的。由于像素类型PixelType独立于点类型PointType,
// 所以我们可以自由地选择任意维数的向量作为像素类型。但是,为了创建一个有趣的例子,
// 我们使用的向量将可以代表点集PointSet 中的点的位移。然后选择这些向量的维数与点集PointSet的维数相同。
//
constexpr unsigned int Dimension = 3;
using PixelType = itk::Vector<float, Dimension>;
// 然后我们使用PixelType(实际上是vector)实例化PointSet类型,并随后创建一个PointSet对象。
using PointSetType = itk::PointSet<PixelType, Dimension>;
PointSetType::Pointer pointSet = PointSetType::New();
//
// 下面的代码是生成一个球体并为这些点分配向量值。 在这个例子中,向量的分量被计算来表示与圆的切线,如下所示
PointSetType::PixelType tangent;
PointSetType::PointType point;
unsigned int pointId = 0;
constexpr double radius = 300.0;
for (unsigned int i = 0; i < 360; i++)
{
const double angle = i * itk::Math::pi / 180.0;
point[0] = radius * std::sin(angle);
point[1] = radius * std::cos(angle);
point[2] = 1.0; // flat on the Z plane
tangent[0] = std::cos(angle);
tangent[1] = -std::sin(angle);
tangent[2] = 0.0; // flat on the Z plane
pointSet->SetPoint(pointId, point);
pointSet->SetPointData(pointId, tangent);
pointId++;
}
// 现在我们可以访问所有的点,并使用像素值表示的向量来执行点上的一个位移。这遵循一种在它的每次迭代中都可以进行位移的可形变模型的原则。
using PointDataIterator = PointSetType::PointDataContainer::ConstIterator;
PointDataIterator pixelIterator = pointSet->GetPointData()->Begin();
PointDataIterator pixelEnd = pointSet->GetPointData()->End();
using PointIterator = PointSetType::PointsContainer::Iterator;
PointIterator pointIterator = pointSet->GetPoints()->Begin();
PointIterator pointEnd = pointSet->GetPoints()->End();
while (pixelIterator != pixelEnd && pointIterator != pointEnd)
{
std::cout << pointIterator.Value() << std::endl;
std::cout << pointIterator.Value() << std::endl;
pointIterator.Value() = pointIterator.Value() + pixelIterator.Value();
++pixelIterator;
++pointIterator;
}
//
// 注意:这里我们使用的是常量迭代器ConstIterator而不是一般的迭代器Iterator,
// 因为像素值仅仅用来读取而不能更改。ITK 在API级别支持const-correctness。
// Itk::Vector 类重载了itk::Point类中的+操作。换句话说,向量可以加到点上来产生一个新的点。
// 在循环体中利用这个特性就可以使用一条语句来更新点的位置。
// 最后我们可以访问所有的点并打印输出新的数值。
pointIterator = pointSet->GetPoints()->Begin();
pointEnd = pointSet->GetPoints()->End();
while (pointIterator != pointEnd)
{
std::cout << pointIterator.Value() << std::endl;
++pointIterator;
}
// 注意:itk::Vector 并不是表示表面法线和函数梯度的合适的类,这是由于向量在仿射变换(affine transforms)上的行为方式决定的。
// ITK 有一种表示法线和函数梯度的特殊类,就是itk::ConvariantVector类。
return EXIT_SUCCESS;
}