第四章--数据表达

4.1 图像

4.1.1 创建图像

#include "itkImage.h"

int main()
{
	using ImageType = itk::Image<unsigned short, 3>;
	ImageType::Pointer  image = ImageType::New();

	// region is define by two classes : index / size
	// 当一个图像被手动创建出来后,需要定义图像的尺寸和起始坐标【在图像空间中】
	ImageType::IndexType start;
	start[0] = 0;
	start[1] = 0;
	start[2] = 0;

	ImageType::SizeType size;
	size[0] = 200;
	size[1] = 200;
	size[2] = 200;

	ImageType::RegionType region;
	region.SetSize(size);
	region.SetIndex(start);

	/*
	SetRegions()默认设置了LargestPossibleRegion、
	BufferedRegion、RequestedRegion范围
	*/
	image->SetRegions(region);
	image->Allocate(); // 开辟空间

	return EXIT_SUCCESS;
}

4.1.2 从文件读取图像(rbg)

#include "itkImage.h"
#include "itkImageFileReader.h"
int main()
{
	using PixelType = itk::RGBPixel<unsigned char>;
	constexpr unsigned int Dimension = 2;

	using ImageType = itk::Image<PixelType, Dimension>;

	using ReaderType = itk::ImageFileReader<ImageType>;
	ReaderType::Pointer reader = ReaderType::New();

	const char* filename = "C:/Users/rw/Desktop/1.jpg";

	reader->SetFileName(filename);
	reader->Update();
	
	// GetOupt()必须放在Update之后,否则将会得到一个无像素数据的图像
	ImageType::Pointer image = reader->GetOutput();
	
	return EXIT_SUCCESS;
}

4.1.3 访问像素数据

#include "itkImage.h"
#include "itkImageFileReader.h"
int main()
{
	using ImageType = itk::Image<unsigned short, 3>;
	ImageType::Pointer image = ImageType::New();

	const ImageType::SizeType size = { 200,200,200 };
	const ImageType::IndexType start = { 0,0,0 };

	ImageType::RegionType region;
	region.SetSize(size);
	region.SetIndex(start);

	image->SetRegions(region);
	image->Allocate();

	// 定义一个索引值
	const ImageType::IndexType pixelIndex = { 27,29,37 };

	// 获取索引对应的图像中的值
	ImageType::PixelType pixelValue = image->GetPixel(pixelIndex);

	// 根据索引设置对应元素值。
	image->SetPixel(pixelIndex, pixelValue + 1);

	return EXIT_SUCCESS;
}

4.1.4 定义原点和间距

#include "itkImage.h"
#include "itkImageFileReader.h"
int main()
{
	constexpr unsigned int Dimension = 3;
	using ImageType = itk::Image<unsigned short, Dimension>;
	ImageType::Pointer image = ImageType::New();

	const ImageType::SizeType size = { 200,200,200 };
	const ImageType::IndexType start = { 0,0,0 };

	ImageType::RegionType region;
	region.SetSize(size);
	region.SetIndex(start);

	image->SetRegions(region);
	image->Allocate(true);

	// spacing是一个固定的Array(FixedArray)
	ImageType::SpacingType spacing;
	spacing[0] = 0.33;
	spacing[1] = 0.33;
	spacing[2] = 1.20;

	image->SetSpacing(spacing);
	const ImageType::SpacingType &sp = image->GetSpacing();
	std::cout << "Spacing = " << sp[0] << ", " << sp[1] << ", " << sp[2] << std::endl;

	ImageType::PointType newOrigin;
	newOrigin.Fill(0.0); // 或写成 newOrigin[0] = newOrigin[1] = newOrigin[2]= 0.0
	image->SetOrigin(newOrigin);

	const ImageType::PointType &orgn = image->GetOrigin();
	std::cout << "Origin = ";
	std::cout << orgn[0] << ", " << orgn[1] << ", " << orgn[2]
		<< std::endl;


	ImageType::DirectionType direction;
	direction.SetIdentity(); // 这是标准正交
	image->SetDirection(direction);
	const ImageType::DirectionType & direct = image->GetDirection();
	std::cout << "Direction = " << std::endl;
	std::cout << direct << std::endl;

	/*
	origin和spacing被初始化后,就会以武力空间坐标来正确映射到图像像素上
	*/

	// Point是一个简单的对象,可以使用传统的数列符号进行访问
	// 1.45,7.21,9.28是世界坐标系下的一个坐标索引
	using PointType = itk::Point<double, ImageType::ImageDimension>;
	PointType point;
	point[0] = 1.45; // x coordinate
	point[1] = 7.21; // y coordinate
	point[2] = 9.28; // z coordinate

					 // 将当前的远点和间距把point映射到index。
	ImageType::IndexType pixelIndex;
	/*
	TransformPhysicalPointToIndex()核对这个 index 是否被包含在一个当前的缓冲像素数据里。
	这个方法返回一个布尔类型数据,表示这个 index 结果是否在这个缓冲区间内。
	当返回值是 false 时,表示输出的 index 无用。
	*/
	bool isInside = image->TransformPhysicalPointToIndex(point, pixelIndex);

	if (isInside) {
		ImageType::PixelType pixelValue = image->GetPixel(pixelIndex);
		pixelValue += 5;
		image->SetPixel(pixelIndex, pixelValue);
	}

	std::cout << "===========================================" << std::endl;
	ImageType::PixelType pValue = image->GetPixel(pixelIndex);
	std::cout << pValue << std::endl;

	return EXIT_SUCCESS;
}

4.1.5 rgb图像元素值获取

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkRGBPixel.h"
#include "itkJPEGImageIOFactory.h"
#include 

using namespace std;

int main()
{
	// RGBPixel代表了一个类, 包括了 红绿蓝三个成分
	using PixelType = itk::RGBAPixel<unsigned char>;
	using ImageType = itk::Image<PixelType, 3>;
	using ReaderType = itk::ImageFileReader<ImageType>;

	//显示说明读取图片类型
	itk::ObjectFactoryBase::RegisterFactory(itk::JPEGImageIOFactory::New());

	ReaderType::Pointer reader = ReaderType::New();

	const char * const filename = "C:/Users/rw/Desktop/1.jpg";
	reader->SetFileName(filename);
	reader->Update();

	ImageType::Pointer image = reader->GetOutput();

	const ImageType::IndexType pixelIndex =  {  23,35,0 } ;
	PixelType onePixel = image->GetPixel(pixelIndex);
	
	PixelType::ValueType red = onePixel.GetRed();
	PixelType::ValueType green = onePixel.GetGreen();
	PixelType::ValueType blue = onePixel.GetBlue();

	std::cout << "Pixel values from GetRed,GetGreen,GetBlue:" << std::endl;
	std::cout << "Red = "
		<< itk::NumericTraits<PixelType::ValueType>::PrintType(red)
		<< std::endl;
	std::cout << "Green = "
		<< itk::NumericTraits<PixelType::ValueType>::PrintType(green)
		<< std::endl;
	std::cout << "Blue = "
		<< itk::NumericTraits<PixelType::ValueType>::PrintType(blue)
		<< std::endl;

	// 由于RGBPixel从itk::FixedArray类继承了[]操作,所以也可以使用subindex符号。
	red = onePixel[0];   // extract Red   component
	green = onePixel[1]; // extract Green component
	blue = onePixel[2];  // extract Blue  component

	std::cout << "Pixel values:" << std::endl;
	std::cout << "Red = "
		<< itk::NumericTraits<PixelType::ValueType>::PrintType(red)
		<< std::endl;
	std::cout << "Green = "
		<< itk::NumericTraits<PixelType::ValueType>::PrintType(green)
		<< std::endl;
	std::cout << "Blue = "
		<< itk::NumericTraits<PixelType::ValueType>::PrintType(blue)
		<< std::endl;
	return 0;
}

4.1.6 向量图像 [暂时不理解]

// 向量图像的定义

#include "itkVector.h"
#include "itkImage.h"


int main()
{
	// 使用一个三维的向量来作为像素来定义一个四维的图像
	using PixelType = itk::Vector<float, 3>;
	using ImageType = itk::Image<PixelType, 3>;

	ImageType::Pointer image = ImageType::New();
	const ImageType::IndexType start = {{ 0, 0, 0 }};
	const ImageType::SizeType size = { { 200, 200, 200 } };
	ImageType::RegionType region;
	region.SetSize(size);
	region.SetIndex(start);

	image->SetRegions(region);
	image->Allocate();

	ImageType::PixelType initialValue;
	initialValue.Fill(0.0);

	image->FillBuffer(initialValue); // 图像全部初始化为一个值

	const ImageType::IndexType pixelIndex = { { 27, 29, 37 } };

	ImageType::PixelType pixelValue;
	pixelValue[0] = 1.345; // x component
	pixelValue[1] = 6.841; // y component
	pixelValue[2] = 3.295; // x component

	image->SetPixel(pixelIndex, pixelValue);
	ImageType::PixelType value = image->GetPixel(pixelIndex);
	std::cout << value << std::endl;
	return 0;
}

4.1.7 从缓冲器中加载图像

// 从缓冲器(内存中)中输入图像数据

#include "itkImage.h"
#include "itkImportImageFilter.h" // importance
#include "itkImageFileWriter.h"
#include "itkRawImageIO.h"

int main()
{
	using PixelType = unsigned char;
	constexpr unsigned int Dimension = 3;
	using ImageType = itk::Image<PixelType, Dimension>;
	using ImportImageFilterType = itk::ImportImageFilter<PixelType, Dimension>;
	ImportImageFilterType::Pointer importFilter = ImportImageFilterType::New();

	// 这个滤波器需要用户去设置被输出的图像的大小等信息,所以需要使用SetRegion()
	ImportImageFilterType::SizeType size;
	size[0] = 200; // size along X
	size[1] = 200; // size along Y
	size[2] = 200; // size along Z

	ImportImageFilterType::IndexType start;
	start.Fill(0);

	ImportImageFilterType::RegionType region;
	region.SetIndex(start);
	region.SetSize(size);
	importFilter->SetRegion(region);

	// 还有分辨率的信息
	double origin[Dimension];
	origin[0] = 0.0;
	origin[1] = 0.0;
	origin[2] = 0.0;
	importFilter->SetOrigin(origin);

	double spacing[Dimension];
	spacing[0] = 1.0; // along X direction 
	spacing[1] = 1.0; // along Y direction 
	spacing[2] = 1.0; // along Z direction 
	importFilter->SetSpacing(spacing);

	/*
	分配包含像素数据的内存块传递信息到ImportImageFilter, 
	需使用与SetRegion()指定大小完全相同的尺寸
	*/
	const unsigned int numberOfPixels = size[0] * size[1] * size[2];
	PixelType* localBuffer = new PixelType[numberOfPixels];

	constexpr double radius = 80.0;
	constexpr double radius2 = radius * radius;

	PixelType * it = localBuffer;

	for (unsigned int z = 0; z < size[2]; z++) {
		const double dz = static_cast<double>(z) - static_cast<double>(size[2]) / 2.0;
		for (unsigned int y = 0; y < size[1]; y++) {
			const double dy = static_cast<double>(y) - static_cast<double>(size[1]) / 2.0;
			for (unsigned int x = 0; x < size[0]; x++) {
				const double dx = static_cast<double>(x) - static_cast<double>(size[0]) / 2.0;
				const double d2 = dx * dx + dy * dy + dz * dz;
				*it++ = (d2 < radius2) ? 255 : 0;
			}
		}
	}

	// 缓冲器在SetImportPointer()作用下传递到ImportImageFilter。
	// ImportImageFilter的最后一参数K, 当K为假时, 表示当调用析构时, ImportImageFilter并不会释放缓存器
	// 假如若为真是,表示允许释放析构的输入滤镜上的内存块, 避免了使用malloc和free操作
	const bool importImageFilterWillOwnTheBuffer = true;
	importFilter->SetImportPointer(localBuffer, numberOfPixels, importImageFilterWillOwnTheBuffer);

	using WriterType = itk::ImageFileWriter<ImageType>;
	WriterType::Pointer writer = WriterType::New();

	writer->SetFileName("D:\\img.jpg");
	writer->SetInput(importFilter->GetOutput());

	try
	{
		using rawIOType = itk::RawImageIO<PixelType>;
		rawIOType::Pointer rawIO = rawIOType::New();

		writer->SetImageIO(rawIO);
		writer->Update();
	}
	catch (const itk::ExceptionObject & exp)
	{
		std::cerr << "Exception caught !" << std::endl;
		std::cerr << exp << std::endl;
		return EXIT_FAILURE;
	}

	return EXIT_SUCCESS;
}

4.2.4得到点中存储的数据

#include "itkPointSet.h"

int main() {

	using PixelType = unsigned short;
	using PointSetType = itk::PointSet<PixelType, 3>;

	PointSetType::Pointer pointset = PointSetType::New();

	unsigned int dataId = 0;
	PixelType value = 79;
	pointset->SetPointData(dataId++, value); // 插入点, 这种方式需要用户提供一个标识符

	// GetPointData()访问时可以从点集中读入与点相关的数据。 
	/*
	这种方式需用用户提供一个点的标识符(found)和一个指向能安全读取像素数据的位置的指针。
	当标识符和点集的标识符不匹配的是,返回flase,这像素值也是无效的。
	*/
	const bool found = pointset->GetPointData(dataId, &value);
	if (found)
	{
		std::cout << "Pixel value = " << value << std::endl;
	}
	// 上述方式是一种低效的方式。还可以使用迭代器 

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

	unsigned int pointId = 0;

	PixelType value0 = 34;
	PixelType value1 = 67;

	pointData->InsertElement(pointId++, value0);
	pointData->InsertElement(pointId++, value1);
	pointset->SetPointData(pointData);

	PointDataContainer::Pointer pointData2 = pointset->GetPointData();
	using PointDataIterator = PointDataContainer::Iterator;
	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
	}
	return EXIT_SUCCESS;
}

4.2.4 RGB作为像素类型

#include "itkRGBPixel.h"
#include "itkPointSet.h"

int main() {
	using PixelType = itk::RGBPixel<float>;
	// 使用点集进行实例化
	using PointSetType = itk::PointSet<PixelType, 3>;
	PointSetType::Pointer pointSet = PointSetType::New();

	PointSetType::PixelType pixel;
	PointSetType::PointType point;
	unsigned int            pointId = 0;
	constexpr double        radius = 3.0;

	// 创建内容
	for (unsigned int i = 0; i < 360; i++) {
		const double angle = i * atan(1.0) / 45.0;
		point[0] = radius * sin(angle);
		point[1] = radius * cos(angle);
		point[2] = 1.0;

		pixel.SetRed(point[0] * 2.0);
		pixel.SetGreen(point[1] * 2.0);
		pixel.SetBlue(point[2] * 2.0);

		pointSet->SetPoint(pointId, point);
		pointId++;
	}

	// 容器迭代式打印点坐标
	// 因为rgbPixel是一个常量,所以使用常量迭代器,对应的值是不能被改变的
	using PointIterator = PointSetType::PointsContainer::ConstIterator;
	PointIterator pointIterator = pointSet->GetPoints()->Begin();
	PointIterator pointEnd = pointSet->GetPoints()->End();
	while (pointIterator != pointEnd)
	{
		point = pointIterator.Value();
		std::cout << point << std::endl;
		++pointIterator;
	}

	// 迭代打印点的内容
	using PointDataIterator = PointSetType::PointDataContainer::ConstIterator;
	PointDataIterator pixelIterator = pointSet->GetPointData()->Begin();
	PointDataIterator pixelEnd = pointSet->GetPointData()->End();
	while (pixelIterator != pixelEnd)
	{
		pixel = pixelIterator.Value();
		std::cout << pixel << std::endl;
		++pixelIterator;
	}

	return EXIT_SUCCESS;
}

上述是itk::RGBPixel类所具有的特性

4.2.5 向量作为像素类型

#include "itkVector.h"
#include "itkPointset.h"

int main()
{
	constexpr unsigned int Dimensim = 3;
	using PixelType = itk::Vector<float, Dimensim>;

	using PointSetType = itk::PointSet<PixelType, Dimensim>;
	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;
	// 这边是itk::vector类
	PointIterator pointIterator = pointSet->GetPoints()->Begin();
	PointIterator pointEnd = pointSet->GetPoints()->End();

	while (pixelIterator != pixelEnd && pointIterator != pointEnd)
	{
		/*Itk::Vector 类拓展了  itk::Point 中的 + 操作。
		换句话说,向量可以加到点上来产生一个新的点。
		在循环的中心开发出这种特性是为了使用一个单独的声明来更新点的位置。*/
		pointIterator.Value() = pointIterator.Value() + pixelIterator.Value();
		++pixelIterator;
		++pointIterator;
	}

	pointIterator = pointSet->GetPoints()->Begin();
	pointEnd = pointSet->GetPoints()->End();
	while (pointIterator != pointEnd)
	{
		std::cout << pointIterator.Value() << std::endl;
		++pointIterator;
	}

	return EXIT_SUCCESS;
}

4.3 网格

4.3.1 创建网格

itk::Mesh类用于表示空间中的形状。它源自itk::PointSet类, 因此集成了与点相关的所有功能,而且接近与点相关的像素数据。网格类是n维的。
ITK 中有两种基本类型的网格,它们分别是静态的和动态的。

  1. 使用静态格式的条件是:当预先知道设置的点的数目,并且在设置后执行操作以后期望结果不被改变的情况;
  2. 使用动态格式的条件是:支持在有效的方式下对点进行插值和移动的情况。区 分这两种格式的区别,在进行性能优化和内存管理时就能方便地转变它的行为。

网格类是通过像素类型和空间维来参数化的。

#include "itkMesh.h"

int main()
{
	// 像素类型
	using PixelType = float;

	// 空间维度
	constexpr unsigned int Dimension = 3;
	using MeshType = itk::Mesh<PixelType, Dimension>;

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

	// 设置4个点
	MeshType::PointType p0;
	MeshType::PointType p1;
	MeshType::PointType p2;
	MeshType::PointType p3;

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

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

	// 获取网格内点的数量
	std::cout << "Points = " << mesh->GetNumberOfPoints() << std::endl;

	// 使用点容器迭代器遍历网络点
	using PointsIterator = MeshType::PointsContainer::Iterator;
	PointsIterator pointIterator = mesh->GetPoints()->Begin();
	PointsIterator end = mesh->GetPoints()->End();
	while (pointIterator != end)
	{
		MeshType::PointType p = pointIterator.Value(); 
		std::cout << p << std::endl;                   
		++pointIterator;
	}

	return EXIT_SUCCESS;
}

4.3.2 插入单元

一个Mesh中应该存在许多单元类型, 就比如在一个树结构上我们不能只有节点,但是没有连接关系,这是不合理的。 类似的Mesh也是如此,那就出现了单元类型。典型的单元有 itk::LineCell 、 itk::TriangleCell 、itk::QuadrilateralCell 和 itk::TetrahedronCell。

为了和网格一致,使用从网格特征提取的许多常见类型来设置单元类型。和网格类所包含的单元相关的特征设置为 CellType 特征。这个特征需要在它们实例化的时候传递给当前单元类型。

网格管理单元和点的方式的主要不同就是:

  1. 点是通过拷贝到点容器上来储存的,
  2. 单元是使用指针来储存到单元容器中的。使用指针的原因是单元使用 C++的多形态。

这就意味着网格使用指向一个通用信元,它是所有指定单元类型的基类。这种体系机构就使得在一个网格中可以综合使用不同的单元类型。另一方面,点是一个单一的类型,只有一个很小的内存需求量,这使得可以直接将它们拷贝到容器。【人话: 网格中的单元类型是通过一个共有基类去访问的】。

这样问题就来到了 单元和指针的问题,因为单元是通过通用基类来访问的,为了应答单元内存的分配与释放,则需要一个特定的指针类型: CellAutoPointer。


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

int main(int, char *[])
{
	using PixelType = float;
	using MeshType = itk::Mesh<PixelType, 3>;
	using CellType = MeshType::CellType;
	
	// 和网格类所包含的单元相关的特征设为CellType特征
	using LineType = itk::LineCell<CellType>;
	
	// 定义指针 来管理单元,他所指向的是通用基类,这样符合多态操作
	using CellAutoPointer = CellType::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);
	
	CellAutoPointer line0;
	CellAutoPointer line1;
	
	// 接下来的代码创建了两个 CellAutoPointer,并使用刚刚创建的单元对象对它们进行初始化。
	//这种情况下创建的当前单元类型是 LineCell
	// cellautopointer 通过TakeOwnShip()来得到接收指针的所有权 
	line0.TakeOwnership(new LineType);
	line1.TakeOwnership(new LineType);

	/*
	单元对点的使用有一个内在的编号系统,它是在范围{0,NumberOfPoints-1}中的一个简单标识。
	使用 SetPointId( )方式来完成点和单元的关联,
	这种方式需要用户提供单元中点的内部标识和网格中相关的点标识符。
	*/
	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()一个变量之后,CellAutoPointer将不再拥有单元的所有权
	mesh->SetCell(0, line0);
	mesh->SetCell(1, line1);

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

	std::cout << "Cells  = " << mesh->GetNumberOfCells() << std::endl;
	
	// 单元迭代器 
	using CellIterator = MeshType::CellsContainer::Iterator;
	CellIterator cellIterator = mesh->GetCells()->Begin();
	CellIterator end = mesh->GetCells()->End();
	
	while (cellIterator != end)
	{
		// 使用指针的形式去管理单元
		MeshType::CellType * cellptr = cellIterator.Value();
		// 安全向下转换
		auto * line = dynamic_cast<LineType *>(cellptr);
		if (line == nullptr)
		{
			continue;
		}
		std::cout << line->GetNumberOfPoints() << std::endl;
		++cellIterator;
	}
	

	return EXIT_SUCCESS;
}

4.3.3管理单元中的数据

代码特点:

  1. 将用户数据关联到单元-- 如何将一系列点变成一个mesh。
  2. 如何方位单元关联的数据: GetCellData() 、 .Value()
// 管理单元中的数据

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

int main() {

	// 网格类型实例化
	using PiexelType = float;
	using MeshType = itk::Mesh<PiexelType, 2>;

	// Cell实例化
	using CellType = MeshType::CellType;
	using LineType = itk::LineCell<CellType>;

	MeshType::Pointer mesh = MeshType::New();
	
	using PointType = MeshType::PointType;
	PointType point;

	constexpr unsigned int numberofPoints = 10;

	// 创建一些点, 点的维度要和网格的维度相匹配, 这边插入一个类似log()函数的序列点
	for (unsigned int id = 0; id < numberofPoints; id++) {
		point[0] = static_cast<PointType::ValueType>(id);
		point[1] = std::log(static_cast<double>(id) + itk::Math::eps); 
		mesh->SetPoint(id, point);
	}

	// 将点进行连接在一起。
	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);  // 设置第一个点
		line->SetPointId(1, cellId + 1); // 设置第二个点
		mesh->SetCell(cellId, line);
	}

	std::cout << "Points = " << mesh->GetNumberOfPoints() << std::endl;
	std::cout << "Cells  = " << mesh->GetNumberOfCells() << std::endl;
	
	// 设置空间上Mesh上每个cell对应的值。
	for (unsigned int cellId = 0; cellId < numberofCells; cellId++) {
		mesh->SetCellData(cellId, static_cast<PiexelType>(cellId * cellId)); // 设置点对应的值
	}

	// 迭代输出
	for (unsigned int cellId = 0; cellId < numberofCells; ++cellId) {
		auto value = static_cast<PiexelType>(0.0);
		mesh->GetCellData(cellId, &value);
		std::cout << "Cell " << cellId << " = " << value << std::endl;
	}

	using CellDataIterator = MeshType::CellDataContainer::ConstIterator;
	CellDataIterator cellDataIterator = mesh->GetCellData()->Begin();
	CellDataIterator end = mesh->GetCellData()->End();

	while(cellDataIterator != end) {
		PiexelType cellValue = cellDataIterator.Value();
		std::cout << cellValue << std::endl;
		++cellDataIterator;
	}

	return 0;
}

4.3.4 自定义网格

这个代码感觉有点毒, 设置了多个一样的点坐标,然后赋予不同的line, 并给不同的line给 celldata.

#include "itkMesh.h"
#include "itkDefaultConvertPixelTraits.h"
#include "itkLineCell.h"
#include "itkVector.h"
#include "itkMatrix.h"

int main() {

	constexpr unsigned int PointDimension = 3;
	constexpr unsigned int MaxTopologicalDimension = 2;

	using PixelType = itk::Vector<double, 4>;
	using CellDataType = itk::Matrix<double, 4, 3>;

	using CoordinateType = double;
	using InterpolationWeightType = double;

	// 自定义Mesh
	using MeshTraits = itk::DefaultStaticMeshTraits<PixelType,
		PointDimension,
		MaxTopologicalDimension,
		CoordinateType,
		InterpolationWeightType,
		CellDataType>;

	// 构建类型
	using MeshType = itk::Mesh<PixelType, PointDimension, MeshTraits>;
	using CellType = MeshType::CellType;
	using LineType = itk::LineCell<CellType>;


	//实例化
	MeshType::Pointer  mesh = MeshType::New();

	using PointType = MeshType::PointType;  // 表示点的坐标
	PointType point;

	constexpr unsigned int numberOfPoints = 10;

	for (unsigned id = 0; id < numberOfPoints; id++) {
		point[0] = 1.565;
		point[1] = 3.647;
		point[2] = 4.129;
		mesh->SetPoint(id, point); // 这个点都什么意义???
	}

	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);
		line->SetPointId(1, cellId + 1);
		mesh->SetCell(cellId, line); // 不理解, 这就是一样的点啊
	}

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

	for (unsigned int cellId = 0; cellId < numberofCells; cellId++)
	{
		CellDataType value;
		mesh->SetCellData(cellId, value);  // 这边默认就是4*3个0
	}

	for (unsigned int cellId = 0; cellId < numberofCells; ++cellId)
	{
		CellDataType value;
		mesh->GetCellData(cellId, &value);
		std::cout << "Cell " << cellId << " = " << value << std::endl;
	}

	using CellDataIterator = MeshType::CellDataContainer::ConstIterator;
	CellDataIterator cellDataIterator = mesh->GetCellData()->Begin();
	CellDataIterator end = mesh->GetCellData()->End();

	while (cellDataIterator != end)
	{
		CellDataType cellValue = cellDataIterator.Value();
		std::cout << cellValue << std::endl;
		++cellDataIterator;
	}
	return EXIT_SUCCESS;
}

4.3.6 构建polyLine结构

有个疑问: 为什么当前点不SetData
解答:
第四章--数据表达_第1张图片


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

int main(int, char *[])
{

	using PixelType = float;
	using MeshType = itk::Mesh<PixelType, 2>;

	using CellType = MeshType::CellType;
	using VertexType = itk::VertexCell<CellType>;
	using LineType = itk::LineCell<CellType>;

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

	MeshType::PointType point0;
	MeshType::PointType point1;
	MeshType::PointType point2;
	MeshType::PointType point3;

	point0[0] = -1;
	point0[1] = -1;
	point1[0] = 1;
	point1[1] = -1;
	point2[0] = 1;
	point2[1] = 1;
	point3[0] = -1;
	point3[1] = 1;

	mesh->SetPoint(0, point0);
	mesh->SetPoint(1, point1);
	mesh->SetPoint(2, point2);
	mesh->SetPoint(3, point3);

	CellType::CellAutoPointer cellpointer;

	cellpointer.TakeOwnership(new LineType);
	cellpointer->SetPointId(0, 0);
	cellpointer->SetPointId(1, 1);
	mesh->SetCell(0, cellpointer);

	cellpointer.TakeOwnership(new LineType);
	cellpointer->SetPointId(0, 1);
	cellpointer->SetPointId(1, 2);
	mesh->SetCell(1, cellpointer);

	cellpointer.TakeOwnership(new LineType);
	cellpointer->SetPointId(0, 2);
	cellpointer->SetPointId(1, 0);
	mesh->SetCell(2, cellpointer);

	cellpointer.TakeOwnership(new VertexType);
	cellpointer->SetPointId(0, 0);
	mesh->SetCell(3, cellpointer);

	cellpointer.TakeOwnership(new VertexType);
	cellpointer->SetPointId(0, 1);
	mesh->SetCell(4, cellpointer);

	cellpointer.TakeOwnership(new VertexType);
	cellpointer->SetPointId(0, 2);
	mesh->SetCell(5, cellpointer);

	cellpointer.TakeOwnership(new VertexType);
	cellpointer->SetPointId(0, 3);
	mesh->SetCell(6, cellpointer);

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


	using PointIterator = MeshType::PointsContainer::ConstIterator;
	
	PointIterator pointIterator = mesh->GetPoints()->Begin();
	PointIterator pointEnd = mesh->GetPoints()->End();

	while (pointIterator != pointEnd)
	{
		std::cout << pointIterator.Value() << std::endl;
		++pointIterator;
	}


	using CellIterator = MeshType::CellsContainer::ConstIterator;

	CellIterator cellIterator = mesh->GetCells()->Begin();
	CellIterator cellEnd = mesh->GetCells()->End();


	while (cellIterator != cellEnd)
	{
		CellType * cell = cellIterator.Value();
		std::cout << cell->GetNumberOfPoints() << std::endl;
		++cellIterator;
	}

	cellIterator = mesh->GetCells()->Begin();
	cellEnd = mesh->GetCells()->End();

	while (cellIterator != cellEnd)
	{
		CellType * cell = cellIterator.Value();

		std::cout << "cell with " << cell->GetNumberOfPoints();
		std::cout << " points   " << std::endl;

		using PointIdIterator = CellType::PointIdIterator;

		PointIdIterator pointIditer = cell->PointIdsBegin();
		PointIdIterator pointIdend = cell->PointIdsEnd();

		while (pointIditer != pointIdend)
		{
			std::cout << *pointIditer << std::endl;
			++pointIditer;
		}

		++cellIterator;
	}

	return EXIT_SUCCESS;
}

你可能感兴趣的:(ITK,开发语言,ITK,C++)