ActiViz实战:基于ActiViz 9.3读取分割后的心脏模型并实现面绘制

发布于:2024-07-01 ⋅ 阅读:(8) ⋅ 点赞:(0)


一、效果预览

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;
    }    
}

三、源码地址

踩坑创作不易,白嫖党勿扰:源码