vtkImageData是由vtkDataSet所派生出的一个子类,由之前的笔记VTK笔记-数据集与数据属性中可以知道,数据集由组织结构以及组织结构相关联的属性数据;数据集的组织结构由拓扑结构和几何结构两部分组成。vtkDataSet是一个抽象基类,结构的实现及表达由其具体的子类来完成;
vtkImageData用于表示VTK中的图像数据,是VTK中常见的数据集之一;vtkImageData可以表示3维立体图像也可以表示2维平面图像,在VTK内与图像相关的数据集以及图像处理的管线中,vtkImageData都占据了极为的重要地位;
vtkImageData可以用于不同格式图像的读取Reader和保存Writer;
vtkImageData可以用于规则的离散点或者序列图像的的float数据和short数据转换vtkImageData,用于图像的渲染显示;
// 获取单元个数
vtkIdType GetNumberOfCells() override;
// 获取点个数
inline vtkIdType vtkImageData::GetNumberOfPoints()
{
const int* extent = this->Extent;
vtkIdType dims[3];
dims[0] = extent[1] - extent[0] + 1;
dims[1] = extent[3] - extent[2] + 1;
dims[2] = extent[5] - extent[4] + 1;
return dims[0] * dims[1] * dims[2];
}
// 根据点ID获取点坐标(x,y,z),非线性安全;
double* GetPoint(vtkIdType ptId) VTK_SIZEHINT(3) override;
// 根据点ID获取点坐标(x,y,z),非线性安全(如果只是读取,可以是线性安全的);
void GetPoint(vtkIdType id, double x[3]) override;
// 根据单元ID获取单元信息;
vtkCell* GetCell(vtkIdType cellId) override;
vtkCell* GetCell(int i, int j, int k) override;
void GetCell(vtkIdType cellId, vtkGenericCell* cell) override;
// 获取单元的边界信息;
void GetCellBounds(vtkIdType cellId, double bounds[6]) override;
int GetCellType(vtkIdType cellId) override;
void GetCellPoints(vtkIdType cellId, vtkIdList* ptIds) override
{
vtkStructuredData::GetCellPoints(cellId, ptIds, this->DataDescription, this->GetDimensions());
}
void GetPointCells(vtkIdType ptId, vtkIdList* cellIds) override
{
vtkStructuredData::GetPointCells(ptId, cellIds, this->GetDimensions());
}
// 获取指定单元周围单元
void GetCellNeighbors(vtkIdType cellId, vtkIdList* ptIds, vtkIdList* cellIds) override;
void GetCellNeighbors(vtkIdType cellId, vtkIdList* ptIds, vtkIdList* cellIds, int* seedLoc);
// 查找与给定坐标(x,y,z)最为接近的点;
virtual vtkIdType FindPoint(double x, double y, double z)
{
return this->vtkDataSet::FindPoint(x, y, z);
}
vtkIdType FindPoint(double x[3]) override;
// 根据给定坐标(x,y,z)和公差平方定位几何图元信息;
vtkIdType FindCell(double x[3], vtkCell* cell, vtkIdType cellId, double tol2, int& subId,
double pcoords[3], double* weights) override;
vtkIdType FindCell(double x[3], vtkCell* cell, vtkGenericCell* gencell, vtkIdType cellId,
double tol2, int& subId, double pcoords[3], double* weights) override;
vtkCell* FindAndGetCell(double x[3], vtkCell* cell, vtkIdType cellId, double tol2, int& subId,
double pcoords[3], double* weights) override;
vtkImageData使用Dimensions记录各个维度上的数据点个数;
每个维度中的值可以具有最小值“1”,这样计算数据点总数可以通过简单地通过dims[0]*dims[1]*dims[2]来实现。
int Dimensions[3];
void GetCellDims(int cellDims[3]);
virtual void SetDimensions(int i, int j, int k);
virtual void SetDimensions(const int dims[3]);
virtual int* GetDimensions() VTK_SIZEHINT(3);
virtual void GetDimensions(int dims[3]);
// 获取维度个数
virtual int GetDataDimension();
为vtkImageData设置数据类型(VTK_FLOAT, VTK_INT,VTK_SHORT),numComponents为每个数据点的元组内个数;
virtual void AllocateScalars(int dataType, int numComponents);
virtual void AllocateScalars(vtkInformation* pipeline_info);
double Spacing[3];
vtkGetVector3Macro(Spacing, double);
virtual void SetSpacing(double i, double j, double k);
virtual void SetSpacing(const double ijk[3]);
double Origin[3];
vtkGetVector3Macro(Origin, double);
virtual void SetOrigin(double i, double j, double k);
virtual void SetOrigin(const double ijk[3]);
int Extent[6];
virtual void SetExtent(int extent[6]);
virtual void SetExtent(int x1, int x2, int y1, int y2, int z1, int z2);
vtkGetVector6Macro(Extent, int);
virtual void SetAxisUpdateExtent(int axis, int min, int max, const int* updateExtent, int* axisUpdateExtent);
virtual void GetAxisUpdateExtent(int axis, int& min, int& max, const int* updateExtent);
static void SetScalarType(int, vtkInformation* meta_data);
static int GetScalarType(vtkInformation* meta_data);
static bool HasScalarType(vtkInformation* meta_data);
int GetScalarType();
const char* GetScalarTypeAsString() { return vtkImageScalarTypeNameMacro(this->GetScalarType()); }
static void SetNumberOfScalarComponents(int n, vtkInformation* meta_data);
static int GetNumberOfScalarComponents(vtkInformation* meta_data);
static bool HasNumberOfScalarComponents(vtkInformation* meta_data);
int GetNumberOfScalarComponents();
virtual double GetScalarTypeMin(vtkInformation* meta_data);
virtual double GetScalarTypeMin();
virtual double GetScalarTypeMax(vtkInformation* meta_data);
virtual double GetScalarTypeMax();
virtual int GetScalarSize(vtkInformation* meta_data);
virtual int GetScalarSize();
vtkIdType Increments[3];
virtual vtkIdType* GetIncrements() VTK_SIZEHINT(3);
virtual void GetIncrements(vtkIdType& incX, vtkIdType& incY, vtkIdType& incZ);
virtual void GetIncrements(vtkIdType inc[3]);
virtual vtkIdType* GetIncrements(vtkDataArray* scalars) VTK_SIZEHINT(3);
virtual void GetIncrements(vtkDataArray* scalars, vtkIdType& incX, vtkIdType& incY, vtkIdType& incZ);
virtual void GetIncrements(vtkDataArray* scalars, vtkIdType inc[3]);
类名 | 功能 |
---|---|
vtkBMPReader | 读BMP图像 |
vtkBMPWriter | 写BMP图像 |
vtkJPEGReader | 读JPEG图像 |
vtkJPEGWriter | 写JPEG图像 |
vtkPNGReader | 读PNG图像 |
vtkPNGWriter | 写PNG图像 |
vtkTIFFReader | 读TIFF图像 |
vtkTIFFWriter | 写TIFF图像 |
vtkMetaImageReader | 读MHA|MHD图像 |
vtkMetaImageWriter | 写MHA|MHD图像 |
vtkDicomImageReader | 读DICOM图像 |
vtkXMLImageDataReader | 读基于XML文件格式图像 |
vtkXMLImageDataWriter | 写基于XML文件格式图像 |
vtkImageReader | 读RAW格式图像 |
vtkImageWriter | 写RAW格式图像 |
注意:读写RAW裸数据格式,要指定图像各个维度的大小、字节顺序(大端法或小端法)、存储像素值的类型等信息;
一般需要指定的数据信息有:图像的维度、图像各维度的大小、图像像素的大小、图像像素的间隔、图像像素值的数据类型等;
int extent[6] = { 0,511,0,511,0,272 };
double spacing[3] = { 0.3, 0.3, 0.75 };
double origin[3] = { 0 };
vtkNew<vtkShortArray> dataArray;
// 设置short*的缓存指针和数组大小,设定每个数据点元组个数为1;
dataArray->SetArray(pBuf, size_all, 1);
vtkNew<vtkImageData> pImageData;
// 给vtkImageData指定VTK_SHORT类型,元组个数为1;
pImageData->AllocateScalars(VTK_SHORT, 1);
pImageData->SetDimensions(512, 512, 273);
pImageData->GetPointData()->SetScalars(dataArray);
pImageData->SetSpacing(spacing);
pImageData->SetOrigin(origin);
VTK中与vtkImageData相关的类实在太多了,基本上以vtkImage开头的类都是跟图像处理相关的类,这里不一一列举,以后有机会再增加;
将之前的体渲染的例子进行了修改;
1.使用一个序列的DICOM图像,获取每张图像内的像素矩阵,生成一个vtkShortArray数据;
2.定义一个vtkImageData对象,设置数据类型为SHORT类型,设定三维每个维度上的数值和像素间距等信息;
3.体渲染;
#pragma once
#include "vtk_include.h"
#include "vtkNIFTIImageReader.h"
#include "vtkInformation.h"
#include "dcmtk\config\osconfig.h"
#include "dcmtk\dcmdata\dctk.h"
#include /* for dcmjpeg decoders */
#include
#include //for JPEG-LS decode
#include //for JPEG-LS encode
class Test_volume
{
public:
static void Test()
{
DJDecoderRegistration::registerCodecs();
DJLSEncoderRegistration::registerCodecs(); //JPEG-LS encoder registerCodecs
DJLSDecoderRegistration::registerCodecs(); //JPEG-LS decoder registerCodecs
int count = 273;
int single_img = 512 * 512;
int size_all = count * single_img;
short* pBuf = new short[size_all] {0};
for (int i = 1; i < 274; i++)
{
std::string fileName = "G:\\Data\\" + std::to_string(i) + ".DCM";
DcmFileFormat *myFileFormat = new DcmFileFormat;
OFCondition cond = myFileFormat->loadFile(fileName.c_str());
DcmElement* pElement = nullptr;
myFileFormat->getDataset()->chooseRepresentation(EXS_DeflatedLittleEndianExplicit, NULL);
myFileFormat->getDataset()->findAndGetElement(DCM_PixelData, pElement);
if (pElement != NULL) {
int size = pElement->getLength() / 2;
OFCondition cond = pElement->loadAllDataIntoMemory();
if (cond.good()) {
Uint16 * ptr;
cond = pElement->getUint16Array(ptr);
if (cond.good()) {
memcpy(pBuf + (i - 1)*single_img, ptr, size * sizeof(short));
}
}
}
delete myFileFormat;
}
int extent[6] = { 0,511,0,511,0,272 };
double spacing[3] = { 0.3, 0.3, 0.75 };
double origin[3] = { 0 };
vtkNew<vtkShortArray> dataArray;
dataArray->SetArray(pBuf, size_all, 1);
vtkNew<vtkImageData> pImageData;
pImageData->AllocateScalars(VTK_SHORT, 1);
pImageData->SetDimensions(512, 512, 273);
pImageData->GetPointData()->SetScalars(dataArray);
pImageData->SetSpacing(spacing);
pImageData->SetOrigin(origin);
vtkNew<vtkFixedPointVolumeRayCastMapper> volumeMapper;
volumeMapper->SetInputData(pImageData);
vtkNew<vtkVolumeProperty> volumeProperty;
volumeProperty->SetInterpolationTypeToLinear();
volumeProperty->ShadeOn(); //打开或者关闭阴影测试
volumeProperty->SetAmbient(0.4);
volumeProperty->SetDiffuse(1.6); //漫反射
volumeProperty->SetSpecular(0.2); //镜面反射
//设置不透明度
vtkNew<vtkPiecewiseFunction> compositeOpacity;
compositeOpacity->AddPoint(70, 0.00);
compositeOpacity->AddPoint(90, 0.40);
compositeOpacity->AddPoint(180, 0.60);
volumeProperty->SetScalarOpacity(compositeOpacity); //设置不透明度传输函数
vtkNew<vtkPiecewiseFunction> volumeGradientOpacity;
volumeGradientOpacity->AddPoint(10, 0.0);
volumeGradientOpacity->AddPoint(90, 0.5);
volumeGradientOpacity->AddPoint(100, 1.0);
vtkNew<vtkColorTransferFunction> color;
color->AddRGBPoint(0.000, 0.00, 0.00, 0.00);
color->AddRGBPoint(64.00, 1.00, 0.52, 0.30);
color->AddRGBPoint(190.0, 1.00, 1.00, 1.00);
color->AddRGBPoint(220.0, 0.20, 0.20, 0.20);
volumeProperty->SetColor(color);
vtkNew<vtkVolume> volume;
volume->SetMapper(volumeMapper);
volume->SetProperty(volumeProperty);
vtkNew<vtkRenderer> ren;
ren->SetBackground(0.3, 0.4, 0.3);
ren->AddVolume(volume);
vtkNew<vtkRenderWindow> rw;
rw->AddRenderer(ren);
rw->SetSize(640, 480);
rw->Render();
rw->SetWindowName("VolumeRendering PipeLine");
vtkNew<vtkRenderWindowInteractor> rwi;
rwi->SetRenderWindow(rw);
ren->ResetCamera();
rw->Render();
rwi->Start();
}
};
注意:代码中没注意内存释放的情况;
关闭颜色和不透明度后的图像;
调整不透明度和颜色对应表,显示效果
//设置不透明度
vtkNew<vtkPiecewiseFunction> compositeOpacity;
compositeOpacity->AddPoint(600, 0.00);
compositeOpacity->AddPoint(800, 0.40);
compositeOpacity->AddPoint(1000, 0.60);
compositeOpacity->AddPoint(1500, 1.0);
volumeProperty->SetScalarOpacity(compositeOpacity); //设置不透明度传输函数
vtkNew<vtkPiecewiseFunction> volumeGradientOpacity;
volumeGradientOpacity->AddPoint(10, 0.0);
volumeGradientOpacity->AddPoint(200, 0.5);
volumeGradientOpacity->AddPoint(300, 1.0);
vtkNew<vtkColorTransferFunction> color;
color->AddRGBPoint(0.000, 0.00, 0.00, 0.00);
color->AddRGBPoint(600.0, 1.00, 0.52, 0.30);
color->AddRGBPoint(1000., 1.00, 1.00, 1.00);
color->AddRGBPoint(1500, 0.20, 0.20, 0.20);
volumeProperty->SetColor(color);
1.vtkImageData Class Reference