一、效果预览
20240627_150614
二、实现代码
public partial class Form1 : Form
{
private int _organCount;//组织数量
private List<vtkPolyDataMapper> _multOrganMapper = new List<vtkPolyDataMapper>();//多组织映射器
private List<vtkActor> _organActors = new List<vtkActor>();
private vtkRenderer _organRenderer;//渲染器
private vtkRenderWindow _organRenderWindow;//渲染窗口
private vtkRenderWindowInteractor _renderWindowInteractor;//渲染窗口交互器
private int[] _organValue;
private RenderWindowControl _renderWindowControl;
private double[] center;
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
_renderWindowControl = renderWindowControl1;
_organRenderWindow = _renderWindowControl.RenderWindow;
_organRenderer = _organRenderWindow.GetRenderers().GetFirstRenderer();
_renderWindowInteractor = _organRenderWindow.GetInteractor();
}
private void bt1_Click(object sender, EventArgs e)
{
CreateActors(new int[] { 1, 2, 3, 4, 5, 6, 7, 8 });
ColorConverter colorConverter = new ColorConverter();
List<Color> colors = new List<Color>
{
(Color)colorConverter.ConvertFromString("#752830"),
(Color)colorConverter.ConvertFromString("#1ee4a5"),
(Color)colorConverter.ConvertFromString("#125717"),
(Color)colorConverter.ConvertFromString("#5854FA"),
(Color)colorConverter.ConvertFromString("#bfdc35"),
(Color)colorConverter.ConvertFromString("#8b5d0e"),
(Color)colorConverter.ConvertFromString("#b929d3"),
(Color)colorConverter.ConvertFromString("#15a2af"),
};
List<double> opacitys = new List<double>() { 1, 1, 1, 1, 1, 1, 1, 1 };
List<int> visiInts = new List<int>() { 1, 1, 1, 1, 1, 1, 1, 1, };
SetActorProperty(colors, opacitys, visiInts);
string str = "Resources\\heart.nii.gz";
LoadedNiiHeartData(str);
}
/// <summary>
/// 根据心脏组织数量创建角色
/// </summary>
/// <param name="organValue"></param>
public void CreateActors(int[] organValue)
{
_organValue = organValue;
_organCount = organValue.Length;
for (int i = 0; i < _organCount; i++)
{
vtkPolyDataMapper mapper = new vtkPolyDataMapper();
_multOrganMapper.Add(mapper);
vtkActor actor = new vtkActor();
_organActors.Add(actor);
_organRenderer.AddActor(actor);
}
}
/// <summary>
/// 设置角色参数,并渲染角色
/// </summary>
/// <param name="actorColors"></param>
/// <param name="opacitys"></param>
/// <param name="visiInts"></param>
public void SetActorProperty(List<Color> actorColors, List<double> opacitys, List<int> visiInts)
{
for (int i = 0; i < _organCount; i++)
{
Color c = actorColors[i];
_organActors[i].GetProperty().SetColor(c.R / 255.0, c.G / 255.0, c.B / 255.0);//设置角色颜色
_organActors[i].GetProperty().SetOpacity(opacitys[i]);//设置角色透明度
_organActors[i].SetVisibility(visiInts[i]);//设置角色显隐
}
_organRenderer.Render();
}
vtkAppendPolyData appendFilter;
public void LoadedNiiHeartData(string niiPath)
{
vtkNIFTIImageReader reader = vtkNIFTIImageReader.New();
reader.SetFileName(niiPath);
reader.Update();
vtkImageData imageData = reader.GetOutput();
appendFilter = vtkAppendPolyData.New();
for (int i = 0; i < _organCount; i++)
{
vtkImageData tempData = new vtkImageData();
tempData.DeepCopy(imageData);
vtkImageData iData = SepImageData(tempData, i + 1);
vtkPolyDataAlgorithm edge = CreateEdges3D(iData, i + 1);
vtkPolyDataNormals smooth = CreateSmooth(edge.GetOutputPort());
_multOrganMapper[i].SetInputConnection(smooth.GetOutputPort());
_multOrganMapper[i].ScalarVisibilityOff();
_organActors[i].SetMapper(_multOrganMapper[i]);
_organActors[i].GetProperty().SetSpecular(0.3);//反射率
_organActors[i].GetProperty().SetOpacity(1);//透明度
_organActors[i].GetProperty().SetSpecularPower(20);//反射光强度
appendFilter.AddInputData(_multOrganMapper[i].GetInput());
}
appendFilter.Update();
center = appendFilter.GetOutput().GetCenter();
//创建一个camera
vtkCamera aCamera = vtkCamera.New();
aCamera.SetViewUp(0, 0, 1);
aCamera.SetPosition(0, 10, 0);
aCamera.SetFocalPoint(0, 0, 0);
_organRenderer.SetActiveCamera(aCamera);
_organRenderer.UseDepthPeelingOn();
_organRenderer.SetUseFXAA(true);
_organRenderer.ResetCamera();//450ms
aCamera.SetPosition(0, 10, 0);
aCamera.OrthogonalizeViewUp();
_organRenderer.ResetCameraClippingRange();
_renderWindowInteractor.Start();
}
private vtkImageData SepImageData(vtkImageData imageData, int organNum)
{
var pointNum = imageData.GetNumberOfPoints();
var type = imageData.GetScalarType();
imageData.AllocateScalars(type, 1);//90ms
unsafe
{
byte* pt = (byte*)imageData.GetScalarPointer();//130ms
}
return imageData;
}
private vtkPolyDataAlgorithm CreateEdges3D(vtkImageData imageData, int organNum)
{
vtkFlyingEdges3D flyingEdges3D = vtkFlyingEdges3D.New();
flyingEdges3D.SetInputData(imageData);
flyingEdges3D.ComputeGradientsOff();
flyingEdges3D.ComputeNormalsOff();
flyingEdges3D.SetValue(0, organNum);
flyingEdges3D.ComputeScalarsOff();
flyingEdges3D.Update();//50ms
return flyingEdges3D;
}
private vtkPolyDataNormals CreateSmooth(vtkAlgorithmOutput algorithmOutput)
{
vtkWindowedSincPolyDataFilter smooth = vtkWindowedSincPolyDataFilter.New();
smooth.SetInputConnection(algorithmOutput);
smooth.SetNumberOfIterations(30);
double passBand = 0.01;
smooth.SetPassBand(passBand);
smooth.BoundarySmoothingOff();
smooth.FeatureEdgeSmoothingOff();
smooth.NonManifoldSmoothingOn();
smooth.NormalizeCoordinatesOn();
vtkPolyDataNormals smoothnormals = vtkPolyDataNormals.New();
smoothnormals.SetInputConnection(smooth.GetOutputPort());
smoothnormals.SetFeatureAngle(60);
return smoothnormals;
}
}
三、源码地址
踩坑创作不易,白嫖党勿扰:源码