Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Overlay segmentations #248

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
154 changes: 154 additions & 0 deletions Assets/Editor/VolumeLoader.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
using UnityEditor;
using UnityEngine;
using System.IO;
using System.Collections.Generic;
using System;
using System.Linq;
using System.Threading.Tasks;

namespace UnityVolumeRendering
{
public class VolumeLoader
{

public static void LoadNRRDDataset(VolumeRenderedObject renderedObject)
{
LoadNRRDDatasetAsync(renderedObject);
}

public static void LoadNIFTIDataset(VolumeRenderedObject renderedObject)
{
LoadNIFTIDatasetAsync(renderedObject);
}

public static void LoadImageFileDataset(VolumeRenderedObject renderedObject)
{
LoadImageFileDatasetAsync(renderedObject);

}

public static void LoadParDataset(VolumeRenderedObject renderedObject)
{
LoadParDatasetAsync(renderedObject);
}

// TODO : Load Dicom Async

public static async void LoadNRRDDatasetAsync(VolumeRenderedObject renderedObject)
{
if (!SimpleITKManager.IsSITKEnabled())
{
if (EditorUtility.DisplayDialog("Missing SimpleITK", "You need to download SimpleITK to load NRRD datasets from the import settings menu.\n" +
"Do you want to open the import settings menu?", "Yes", "No"))
{
ImportSettingsEditorWindow.ShowWindow();
}
}

string file = EditorUtility.OpenFilePanel("Select a dataset to load (.nrrd)", "DataFiles", "");
if (File.Exists(file))
{
Debug.Log("Async dataset load. Hold on.");
using (ProgressHandler progressHandler = new ProgressHandler(new EditorProgressView(), "NRRD import"))
{
progressHandler.ReportProgress(0.0f, "Importing NRRD dataset");

IImageFileImporter importer = ImporterFactory.CreateImageFileImporter(ImageFileFormat.NRRD);

VolumeDataset dataset = await importer.ImportAsync(file);

renderedObject.SetSegmentationDataset(dataset);

progressHandler.ReportProgress(0.8f, "Loading object");

}
}
else
{
Debug.LogError("File doesn't exist: " + file);
}
}

public static async void LoadNIFTIDatasetAsync(VolumeRenderedObject renderedObject)
{
string file = EditorUtility.OpenFilePanel("Select a dataset to load (.nii)", "DataFiles", "");
if (File.Exists(file))
{
Debug.Log("Async dataset load. Hold on.");
using (ProgressHandler progressHandler = new ProgressHandler(new EditorProgressView(), "NIFTI import"))
{
progressHandler.ReportProgress(0.0f, "Importing NIfTI dataset");

IImageFileImporter importer = ImporterFactory.CreateImageFileImporter(ImageFileFormat.NIFTI);

VolumeDataset dataset = await importer.ImportAsync(file);

renderedObject.SetSegmentationDataset(dataset);

progressHandler.ReportProgress(0.0f, "Loaded object");


}
}
else
{
Debug.LogError("File doesn't exist: " + file);

}
}

public static async void LoadImageFileDatasetAsync(VolumeRenderedObject renderedObject)
{
string file = EditorUtility.OpenFilePanel("Select a dataset to load", "DataFiles", "");
if (File.Exists(file))
{
Debug.Log("Async dataset load. Hold on.");
using (ProgressHandler progressHandler = new ProgressHandler(new EditorProgressView(), "Image file import"))
{
progressHandler.ReportProgress(0.0f, "Importing image file dataset");

IImageFileImporter importer = ImporterFactory.CreateImageFileImporter(ImageFileFormat.Unknown);

VolumeDataset dataset = await importer.ImportAsync(file);

renderedObject.SetSegmentationDataset(dataset, progressHandler);

progressHandler.ReportProgress(0.0f, "Loaded object");

}
}
else
{
Debug.LogError("File doesn't exist: " + file);
}
}

public static async void LoadParDatasetAsync(VolumeRenderedObject renderedObject)
{
string file = EditorUtility.OpenFilePanel("Select a dataset to load", "DataFiles", "");
if (File.Exists(file))
{
Debug.Log("Async dataset load. Hold on.");
using (ProgressHandler progressHandler = new ProgressHandler(new EditorProgressView(), "AVSP import"))
{
progressHandler.ReportProgress(0.0f, "Importing VASP dataset");

IImageFileImporter importer = ImporterFactory.CreateImageFileImporter(ImageFileFormat.VASP);

VolumeDataset dataset = await importer.ImportAsync(file);

renderedObject.SetSegmentationDataset(dataset, progressHandler);

progressHandler.ReportProgress(0.0f, "Loaded object");

}
}
else
{
Debug.LogError("File doesn't exist: " + file);
}
}

// TODO : Load Sequence Async
}
}
34 changes: 34 additions & 0 deletions Assets/Editor/VolumeRenderedObjectCustomInspector.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,40 @@ public override void OnInspectorGUI()
volrendObj.SetGradientVisibilityThreshold(newThreshold);
}


// Segmentations
EditorGUILayout.Space();
var segmentationSettings = EditorGUILayout.Foldout(tfSettings, "Segmentations");
if (segmentationSettings)
{
// File Format
ImageFileFormat format = (ImageFileFormat)EditorGUILayout.EnumPopup("File Format", ImageFileFormat.NIFTI);

// Import Button
if (GUILayout.Button("Import"))
{
switch (format)
{
case ImageFileFormat.VASP:
VolumeLoader.LoadParDataset(volrendObj);
break;
case ImageFileFormat.NRRD:
VolumeLoader.LoadNRRDDataset(volrendObj);
break;
case ImageFileFormat.NIFTI:
VolumeLoader.LoadNIFTIDataset(volrendObj);
break;
case ImageFileFormat.Unknown:
Debug.Log("The file format is unknown.");
break;
default:
Debug.Log("Invalid file format.");
break;
}

}
}

// Transfer function settings
EditorGUILayout.Space();
tfSettings = EditorGUILayout.Foldout(tfSettings, "Transfer function");
Expand Down
25 changes: 22 additions & 3 deletions Assets/Scripts/VolumeObject/VolumeRenderedObject.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ public class VolumeRenderedObject : MonoBehaviour
[SerializeField, HideInInspector]
public VolumeDataset dataset;

[SerializeField, HideInInspector]
public VolumeDataset segmentationDataset;

[SerializeField, HideInInspector]
public MeshRenderer meshRenderer;

Expand Down Expand Up @@ -96,6 +99,15 @@ public async Task SetRenderModeAsync(RenderMode mode, IProgressHandler progressH
}
await UpdateMaterialPropertiesAsync(progressHandler);
}

public void SetSegmentationDataset(VolumeDataset dataset, IProgressHandler progressHandler = null)
{
this.segmentationDataset = dataset;

UpdateMaterialProperties(progressHandler);

}


public void SetTransferFunctionMode(TFRenderMode mode)
{
Expand Down Expand Up @@ -307,14 +319,20 @@ public void UpdateMaterialProperties(IProgressHandler progressHandler = null)
private async Task UpdateMaterialPropertiesAsync(IProgressHandler progressHandler = null)
{
await updateMatLock.WaitAsync();

try
{

bool useGradientTexture = tfRenderMode == TFRenderMode.TF2D || renderMode == RenderMode.IsosurfaceRendering || lightingEnabled;
Texture3D gradientTexture = useGradientTexture ? await dataset.GetGradientTextureAsync(progressHandler) : null;

Texture3D dataTexture = await dataset.GetDataTextureAsync(progressHandler);
meshRenderer.sharedMaterial.SetTexture("_DataTex", dataTexture);
Texture3D segmentationTexture = await segmentationDataset.GetDataTextureAsync(progressHandler);

meshRenderer.sharedMaterial.SetTexture("_DataTex", dataTexture);
meshRenderer.sharedMaterial.SetTexture("_SegmentationTex", segmentationTexture);
meshRenderer.sharedMaterial.SetTexture("_GradientTex", gradientTexture);

UpdateMatInternal();
}
finally
Expand All @@ -329,7 +347,8 @@ private void UpdateMatInternal()
{
meshRenderer.sharedMaterial.SetTexture("_DataTex", dataset.GetDataTexture());
}

meshRenderer.sharedMaterial.SetTexture("_SegmentationTex", segmentationDataset.GetDataTexture());

if (meshRenderer.sharedMaterial.GetTexture("_NoiseTex") == null)
{
const int noiseDimX = 512;
Expand Down
15 changes: 15 additions & 0 deletions Assets/Shaders/DirectVolumeRenderingShader.shader
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
Properties
{
_DataTex ("Data Texture (Generated)", 3D) = "" {}
_SegmentationTex ("Segmentation Texture (Generated)", 3D) = "" {}
_GradientTex("Gradient Texture (Generated)", 3D) = "" {}
_NoiseTex("Noise Texture (Generated)", 2D) = "white" {}
_TFTex("Transfer Function Texture (Generated)", 2D) = "" {}
Expand Down Expand Up @@ -72,6 +73,7 @@
};

sampler3D _DataTex;
sampler3D _SegmentationTex;
sampler3D _GradientTex;
sampler2D _NoiseTex;
sampler2D _TFTex;
Expand Down Expand Up @@ -207,6 +209,12 @@
return tex3Dlod(_DataTex, float4(pos.x, pos.y, pos.z, 0.0f));
}

// Get segmentation label
float getLabel(float3 pos)
{
return tex3Dlod(_SegmentationTex, float4(pos.x, pos.y, pos.z, 0.0f));
}

// Gets the gradient at the specified position
float3 getGradient(float3 pos)
{
Expand Down Expand Up @@ -312,13 +320,20 @@

// Get the dansity/sample value of the current position
const float density = getDensity(currPos);
const float segmentationLabel = getLabel(currPos);

// Apply visibility window
if (density < _MinVal || density > _MaxVal) continue;

// Apply 1D transfer function
#if !TF2D_ON

float4 src = getTF1DColour(density);
if (segmentationLabel == 1 )
{
src = float4(1.0, 0.0, 0.0, 1.0);
}

if (src.a == 0.0)
continue;
#endif
Expand Down
20 changes: 11 additions & 9 deletions CREDITS.md
Original file line number Diff line number Diff line change
@@ -1,22 +1,24 @@
Contributors:

- [Matias Lavik](https://github.com/mlavik1)
Original project.
Original project.
- [jasonks2](https://github.com/jasonks2):
Implemented support for PARCHG (.vasp) datasets.
Implemented support for PARCHG (.vasp) datasets.
- [denistribouillois](https://github.com/denistribouillois)
Slicing plane improvements. Histogram GPU calculation.
Slicing plane improvements. Histogram GPU calculation.
- [Michael Ovens](https://github.com/MichaelOvens)
Image sequence import. Other contributions.
Image sequence import. Other contributions.
- [Chiara Di Vece](https://github.com/chiaradivece)
GUI for modifying slicing plane positiomn/orientation.
GUI for modifying slicing plane positiomn/orientation.
- [btsai-dev](https://github.com/btsai-dev)
Memory leak fix
Memory leak fix
- [Vahid](https://github.com/vahpy)
Texture downscaling, optimisation.
Texture downscaling, optimisation.
- [SitronX](https://github.com/SitronX)
Async loading
Async loading
- [Riccardo Lops](https://github.com/riccardolops)
Modified shader to handle stereo rendering.
Modified shader to handle stereo rendering.
- [Juan Pablo Montoya](https://github.com/JuanPabloMontoya271)
- Overlay Segmentations

Feel free to add yourself to this list when contributing to this project.