ITK学习笔记:1.Data presentation-1.3Mesh网格(一)基操:创建mesh,嵌入cell,管理数据

1.创建网格

网格类用于表示空间中的形状。

  • 它源于itk::PointSet类,因此继承了与点相关的所有功能以及对与点关联的像素数据的访问。
  • Mesh类也是n维的,这使得它的使用具有很大的灵活性。
  • 实际上,Mesh类可以看作是一个点集,其中添加了许多不同维度和形状的单元格(也称为元素)。网格中的单元格使用它们的点标识符根据现有的点定义

与PointSet相同,ITK中有静态和动态两种基本的网格样式。

  • 第一个用于使用点的数量可预知,并不需要对其修改操作。
  • 第二个支持插入和删除点。
  • 区分这两种样式的原因是为了方便对其行为进行微调,以优化性能和内存管理。
    实例:
#include "itkMesh.h"

typedef float PixelType;

const unsigned int Dimension = 3; 
typedef itk::Mesh< PixelType, Dimension > MeshType;

MeshType::Pointer mesh = MeshType::New();

MeshType::PointType p0;
MeshType::PointType p1;
MeshType::PointType p2; 
MeshType::PointType p3;

// first point ( -1, -1, 0 )
p0[0]= -1.0;
p0[1]= -1.0; 
p0[2]= 0.0; 
// second point ( 1, -1, 0 )
p1[0]= 1.0;
p1[1]= -1.0;
p1[2]= 0.0; 
// third point ( 1, 1, 0 )
p2[0]= 1.0; 
p2[1]= 1.0; 
p2[2]= 0.0; 
// fourth point ( -1, 1, 0 )
p3[0]= -1.0; 
p3[1]= 1.0; 
p3[2]= 0.0; 

mesh->SetPoint( 0, p0 );
mesh->SetPoint( 1, p1 ); 
mesh->SetPoint( 2, p2 );
mesh->SetPoint( 3, p3 );

std::cout << "Points = " << mesh->GetNumberOfPoints() << std::endl;

typedef MeshType::PointsContainer::Iterator PointsIterator;
PointsIterator pointIterator = mesh->GetPoints()->Begin();
PointsIterator end = mesh->GetPoints()->End(); 
while( pointIterator != end ) 
{ 
MeshType::PointType p = pointIterator.Value(); // access the point 
std::cout << p << std::endl; // print the point 
pointIterator; // advance to next point
 }

2.嵌入单元

itk::Mesh中包含了多种单元类型,典型的有:

  • itk::LineCell
  • itk::TriangleCell
  • itk::QuadrilateralCell
  • itk::TetrahedronCell.

网格管理单元格和点的主要区别是

  • 点是通过复制存储在点容器中
  • 而单元格是使用指针存储在单元格容器中

使用指针的原因是单元格在网格上使用c++多态性。

  • 这意味着网格只知道有指向泛型单元格的指针,泛型单元格是所有特定单元格类型的基类。
  • 这种架构使得在同一个网格中组合不同的单元格类型成为可能。另一方面,点属于单一类型,占用的内存较小,因此可以高效地复制它们

通过指针管理细胞增加了另一个层次的复杂性,因为现在有必要建立一个协议来明确谁负责分配和释放细胞的内存。

  • 该协议以一种称为CellAutoPointer的特定类型的指针的形式实现。

这款指针基于itk::AutoPointer,与智能指针有许多不同之处。

  • CellAutoPointer有一个指向实际对象的内部指针和一个布尔标志,用于指示CellAutoPointer是否负责释放细胞内存,无论何时需要对其进行销毁

下面的代码创建了一条多边形线,以演示网格中单元管理的最简单情况。这里使用的唯一单元格类型是线单元。

#include "itkLineCell.h"
typedef MeshType::CellType CellType;
typedef itk::LineCell< CellType > LineType;
typedef CellType::CellAutoPointer CellAutoPointer;

MeshType::Pointer mesh = MeshType::New();
MeshType::PointType p0; 
MeshType::PointType p1;
MeshType::PointType p2;
p0[0] = -1.0; p0[1] = 0.0; p0[2] = 0.0;
p1[0] = 1.0; p1[1] = 0.0; p1[2] = 0.0;
p2[0] = 1.0; p2[1] = 1.0; p2[2] = 0.0;
mesh->SetPoint( 0, p0 );
mesh->SetPoint( 1, p1 ); 
mesh->SetPoint( 2, p2 );

//下面的代码创建了两个CellAutoPointers,并用new初始化它们。
//在本例中创建的实际单元格类型是LineCell。
///CellAutoPointer通过使用TakeOwnership()方法获取接收的指针的所有权。
//尽管这看起来很冗长,但它是必要的,以便从代码中明确表明自动发送器承担内存释放的责任。
CellAutoPointer line0; 
CellAutoPointer line1;
line0.TakeOwnership( new LineType ); 
line1.TakeOwnership( new LineType );

//设置line的索引关联
line0->SetPointId( 0, 0 ); // line between points 0 and 1 
line0->SetPointId( 1, 1 );
line1->SetPointId( 0, 1 ); // line between points 1 and 2 
line1->SetPointId( 1, 2 );

//使用SetCell()方法将单元格插入网格中。
//它需要一个标识符和对单元格的自动转换。
//网格将获得AutoPointer所指向的单元格的所有权。
//这是通过SetCell()方法在内部完成的。
mesh->SetCell( 0, line0 ); 
mesh->SetCell( 1, line1 );
//作为SetCell()方法的参数之后,CellAutoPointer不再拥有单元格的所有权。
//在不首先确保另一个单元格的所有权的情况下,不要再次使用相同的CellAutoPointer作为SetCell()的参数,这一点很重要。

std::cout << "Cells = " << mesh->GetNumberOfCells() << std::endl;

//与点类似,可以使用迭代器访问网格中的单元格容器。
//单元格迭代器的特征可以从网格中提取出来,并用于定义局部类型。
typedef MeshType::CellsContainer::Iterator CellIterator
CellIterator cellIterator = mesh->GetCells()->Begin(); 
CellIterator end = mesh->GetCells()->End();

//最后,使用一个标准循环遍历所有单元格。
//注意,Value()方法用于从CellIterator获取单元格的实际指针。
//还要注意,返回的值是指向泛型单元格类型的指针。
while( cellIterator != end )
 {
  MeshType::CellType * cellptr = cellIterator.Value();

//为了作为实际的LineCell类型使用,这些指针必须向下映射。
//安全的向下转换使用动态转换操作符执行,如果转换不能安全执行,该操作符将抛出异常。
   LineType * line = dynamic_cast<LineType *>( cellptr );
    std::cout << line->GetNumberOfPoints() << std::endl; 
    ++cellIterator; 
    }

3.管理单元数据

与定制数据与网格中的点关联的方式相同,也可以将定制数据与单元格关联。与单元格关联的数据类型可能与与点关联的数据类型不同。但是,默认情况下,这两种类型是相同的。下面的示例说明如何访问与单元格关联的数据。该方法类似于用于访问点数据的方法。

#include "itkMesh.h" 
#include "itkLineCell.h"

typedef float PixelType; 
typedef itk::Mesh< PixelType, 2 > MeshType;

typedef MeshType::CellType CellType; 
typedef itk::LineCell< CellType > LineType;

MeshType::Pointer mesh = MeshType::New();
//创建一个网格并插入一些点。
//注意点的dimension与网格的dimention匹配
//插入一个点序列,它看起来像log()函数的图形。
typedef MeshType::PointType PointType; 
PointType point;
const unsigned int numberOfPoints = 10; 
for(unsigned int id=0; id<numberOfPoints; id++) 
{ 
point[0] = static_cast<PointType::ValueType>( id ); // x 
point[1] = log( static_cast<double>( id ) ); // y 
mesh->SetPoint( id, point ); 
}

//通过使用点标识符,将创建一组line cells并与现有的点关联。
//在这个简单的例子中,单元标识符可以从点标识符推导出,因为行单元格的排序方式相同。
CellType::CellAutoPointer line;
const unsigned int numberOfCells = numberOfPoints-1; 
for(unsigned int cellId=0; cellId<numberOfCells; cellId++)
 {
  line.TakeOwnership( new LineType );
  line->SetPointId( 0, cellId ); // first point 
  line->SetPointId( 1, cellId+1 ); // second point 

  mesh->SetCell( cellId, line ); // insert the cell 
  
  }
 //通过使用SetCellData()方法,将与单元格关联的数据插入到itk::Mesh中。
 //它要求用户提供一个标识符和要插入的值。标识符应该匹配插入的一个单元格。
 //在这个简单的示例中,单元格标识符的方形被用作单元格数据。注意在赋值中使用了对PixelType的静态转换。
for(unsigned int cellId=0; cellId<numberOfCells; cellId++)
 {
  mesh->SetCellData( cellId, static_cast<PixelType>( cellId * cellId ) ); 
  }
  
typedef MeshType::CellDataContainer::ConstIterator CellDataIterator;
CellDataIterator cellDataIterator = mesh->GetCellData()->Begin(); 
CellDataIterator end = mesh->GetCellData()->End();

while( cellDataIterator != end )
 {
 //注意,Value()方法用于获取数据条目的实际值。
 //将PixelType元素复制到局部变量cellValue中。
  PixelType cellValue = cellDataIterator.Value();
  std::cout << cellValue << std::endl; 
  ++cellDataIterator; }

注意

  • MeshType::CellsContainer::Iterator cellIterator中的cellIterator调用value方法,返回的是指向实际位置的指针
  • MeshType::CellDataContainer::ConstIterator cellDataIterator中的cellDataIterator调用value方法,返回的是指针所在位置的数据值
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值