该实例中data包含速度向量vector和速率标量scalar。
利用向量可视化技术创建vector glyph。但是由于存在的points太多,因此需要使用滤波器filter选择合适的点的子集。进而创建向量符号。
采用的滤波器为:vtkThresholdPoints 和 vtkMaskPoints
vtkThresholdPoints 滤波器通过定义阈值,选择大于或者小于阈值的点作为子集。
vtkMaskPoints 滤波器通过OnRation 来实例化points进而选择子集。 如果OnRatio=1,则所有数据点都被选择,如果OnRatio=10,则每10个数据点被选择。可以使均匀选择也可以是随机选择。通过RandomModeOn() 和 RandomModeO方法控制。
选择子集之后在子集中采用vtkGlyph3D滤波器,创建圆锥(其方向代表血流方向,大小和颜色反映速度的大小)。
实现代码和效果图如下:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
int main (int argc, char *argv[])
{
if (argc < 2)
{
std::cout << "Usage: " << argv[0] << " carotid.vtk" << std::endl;
return EXIT_FAILURE;
}
vtkSmartPointer colors =
vtkSmartPointer::New();
vtkSmartPointer ren1 =
vtkSmartPointer::New();
vtkSmartPointer renWin =
vtkSmartPointer::New();
renWin->AddRenderer(ren1);
vtkSmartPointer iren =
vtkSmartPointer::New();
iren->SetRenderWindow(renWin);
// create pipeline
//
vtkSmartPointer reader =
vtkSmartPointer::New();
reader->SetFileName(argv[1]);
vtkSmartPointer threshold =
vtkSmartPointer::New();
threshold->SetInputConnection(reader->GetOutputPort());
threshold->ThresholdByUpper(200);
vtkSmartPointer mask =
vtkSmartPointer::New();
mask->SetInputConnection(threshold->GetOutputPort());
mask->SetOnRatio(5);
vtkSmartPointer cone =
vtkSmartPointer::New();
cone->SetResolution(11);
cone->SetHeight(1);
cone->SetRadius(0.25);
vtkSmartPointer cones =
vtkSmartPointer::New();
cones->SetInputConnection(mask->GetOutputPort());
cones->SetSourceConnection(cone->GetOutputPort());
cones->SetScaleFactor(0.4);
cones->SetScaleModeToScaleByVector();
vtkSmartPointer lut =
vtkSmartPointer::New();
lut->SetHueRange(.667, 0.0);
lut->Build();
double range[2];
cones->Update();
range[0] = cones->GetOutput()->GetPointData()->GetScalars()->GetRange()[0];
range[1] = cones->GetOutput()->GetPointData()->GetScalars()->GetRange()[1];
std::cout << "range: " << range[0] << ", " << range[1] << std::endl;
vtkSmartPointer vectorMapper =
vtkSmartPointer::New();
vectorMapper->SetInputConnection(cones->GetOutputPort());
vectorMapper->SetScalarRange(range[0], range[1]);
vectorMapper->SetLookupTable(lut);
vtkSmartPointer vectorActor =
vtkSmartPointer::New();
vectorActor->SetMapper(vectorMapper);
// contours of speed
vtkSmartPointer iso =
vtkSmartPointer::New();
iso->SetInputConnection(reader->GetOutputPort());
iso->SetValue(0, 175);
vtkSmartPointer isoMapper =
vtkSmartPointer::New();
isoMapper->SetInputConnection(iso->GetOutputPort());
isoMapper->ScalarVisibilityOff();
vtkSmartPointer isoActor =
vtkSmartPointer::New();
isoActor->SetMapper(isoMapper);
isoActor->GetProperty()->SetRepresentationToWireframe();
isoActor->GetProperty()->SetOpacity(0.25);
// outline
vtkSmartPointer outline =
vtkSmartPointer::New();
outline->SetInputConnection(reader->GetOutputPort());
vtkSmartPointer outlineMapper =
vtkSmartPointer::New();
outlineMapper->SetInputConnection(outline->GetOutputPort());
vtkSmartPointer outlineActor =
vtkSmartPointer::New();
outlineActor->SetMapper(outlineMapper);
outlineActor->GetProperty()->SetColor(colors->GetColor3d("Black").GetData());
// Add the actors to the renderer, set the background and size
//
ren1->AddActor(outlineActor);
ren1->AddActor(vectorActor);
ren1->AddActor(isoActor);
ren1->SetBackground(colors->GetColor3d("Wheat").GetData());
renWin->SetSize(640, 480);
vtkSmartPointer cam1 =
vtkSmartPointer::New();
cam1->SetClippingRange(17.4043, 870.216);
cam1->SetFocalPoint(136.71, 104.025, 23);
cam1->SetPosition(204.747, 258.939, 63.7925);
cam1->SetViewUp(-0.102647, -0.210897, 0.972104);
cam1->Zoom(1.6);
ren1->SetActiveCamera(cam1);
// render the image
//
renWin->Render();
iren->Start();
return EXIT_SUCCESS;
}
生成血管速度的streamtubes,可以采用等值面技术。但是streamtubes的起点很那确定。
原因:许多streamers在动脉外边。(数据的测量方法和速度场的分辨率导致),因为数据的分辨率,血液流的边界层不能被捕获,导致在弯道处血液流速的一个分量将 streamtube 指向动脉的外侧。因此很难找到感兴趣结果的streamtube 的起始位置。
解决:源对象 vtkPointSource 和 vtkThresholdPoints
vtkPointSource 生成以指定半径的球体为中心的随机点。只需要找到流管起始点的一个近似位置,然后生成一个随机种子点云。vtkThresholdPoints 用于筛选可能在高流速区域之外生成的点。
主要代码(其余部分与上述代码一样)如下:
// create pipeline
//
vtkSmartPointer reader =
vtkSmartPointer::New();
reader->SetFileName(argv[1]);
vtkSmartPointer psource =
vtkSmartPointer::New();
psource->SetNumberOfPoints(25);
psource->SetCenter(133.1, 116.3, 5.0);
psource->SetRadius(2.0);
vtkSmartPointer threshold =
vtkSmartPointer::New();
threshold->SetInputConnection(reader->GetOutputPort());
threshold->ThresholdByUpper(275);
vtkSmartPointer streamers =
vtkSmartPointer::New();
streamers->SetInputConnection(reader->GetOutputPort());
streamers->SetSourceConnection(psource->GetOutputPort());
// streamers->SetMaximumPropagationUnitToTimeUnit();
streamers->SetMaximumPropagation(100.0);
// streamers->SetInitialIntegrationStepUnitToCellLengthUnit();
streamers->SetInitialIntegrationStep(0.2);
streamers->SetTerminalSpeed(.01);
streamers->Update();
double range[2];
range[0] = streamers->GetOutput()->GetPointData()->GetScalars()->GetRange()[0];
range[1] = streamers->GetOutput()->GetPointData()->GetScalars()->GetRange()[1];
vtkSmartPointer tubes =
vtkSmartPointer::New();
tubes->SetInputConnection(streamers->GetOutputPort());
tubes->SetRadius(0.3);
tubes->SetNumberOfSides(6);
tubes->SetVaryRadius(0);
vtkSmartPointer lut =
vtkSmartPointer::New();
lut->SetHueRange(.667, 0.0);
lut->Build();
vtkSmartPointer streamerMapper =
vtkSmartPointer::New();
streamerMapper->SetInputConnection(tubes->GetOutputPort());
streamerMapper->SetScalarRange(range[0], range[1]);
streamerMapper->SetLookupTable(lut);
vtkSmartPointer streamerActor =
vtkSmartPointer::New();
streamerActor->SetMapper(streamerMapper);
实现结果图如下: