예제 #1
0
        static void ShowSequenceImporter()
        {
            string dir = EditorUtility.OpenFolderPanel("Select a folder to load", "", "");

            if (Directory.Exists(dir))
            {
                ImageSequenceImporter importer = new ImageSequenceImporter(dir);

                VolumeDataset dataset = importer.Import();
                if (dataset != null)
                {
                    if (EditorPrefs.GetBool("DownscaleDatasetPrompt"))
                    {
                        if (EditorUtility.DisplayDialog("Optional DownScaling",
                                                        $"Do you want to downscale the dataset? The dataset's dimension is: {dataset.dimX} x {dataset.dimY} x {dataset.dimZ}", "Yes", "No"))
                        {
                            dataset.DownScaleData();
                        }
                    }
                    VolumeObjectFactory.CreateObject(dataset);
                }
            }
            else
            {
                Debug.LogError("Directory doesn't exist: " + dir);
            }
        }
예제 #2
0
        private void OnOpenRAWDatasetResult(RuntimeFileBrowser.DialogResult result)
        {
            if (!result.cancelled)
            {
                // We'll only allow one dataset at a time in the runtime GUI (for simplicity)
                DespawnAllDatasets();

                // Did the user try to import an .ini-file? Open the corresponding .raw file instead
                string filePath = result.path;
                if (System.IO.Path.GetExtension(filePath) == ".ini")
                {
                    filePath = filePath.Replace(".ini", ".raw");
                }

                // Parse .ini file
                DatasetIniData initData = DatasetIniReader.ParseIniFile(filePath + ".ini");
                if (initData != null)
                {
                    // Import the dataset
                    RawDatasetImporter importer = new RawDatasetImporter(filePath, initData.dimX, initData.dimY, initData.dimZ, initData.format, initData.endianness, initData.bytesToSkip);
                    VolumeDataset      dataset  = importer.Import();
                    // Spawn the object
                    if (dataset != null)
                    {
                        VolumeObjectFactory.CreateObject(dataset);
                    }
                }
            }
        }
        public static void ImportDataset(string filePath)
        {
            DatasetType datasetType = DatasetImporterUtility.GetDatasetType(filePath);

            switch (datasetType)
            {
            case DatasetType.Raw:
            {
                RAWDatasetImporterEditorWindow wnd = (RAWDatasetImporterEditorWindow)EditorWindow.GetWindow(typeof(RAWDatasetImporterEditorWindow));
                if (wnd != null)
                {
                    wnd.Close();
                }

                wnd = new RAWDatasetImporterEditorWindow(filePath);
                wnd.Show();
                break;
            }

            case DatasetType.DICOM:
            {
                DatasetImporterBase importer = new DICOMImporter(new FileInfo(filePath).Directory.FullName, false);
                VolumeDataset       dataset  = importer.Import();

                if (dataset != null)
                {
                    VolumeRenderedObject obj = VolumeObjectFactory.CreateObject(dataset);
                }
                break;
            }
            }
        }
        /// <summary>
        /// Generates a histogram where:
        ///   X-axis = the data sample (density) value
        ///   Y-axis = the sample count (number of data samples with the specified density)
        /// </summary>
        /// <param name="dataset"></param>
        /// <returns></returns>
        public static Texture2D GenerateHistogramTexture(VolumeDataset dataset)
        {
            int minValue  = dataset.GetMinDataValue();
            int maxValue  = dataset.GetMaxDataValue();
            int numValues = maxValue - minValue + 1;

            float valRangeRecip = 1.0f / (maxValue - minValue);

            int numSamples = System.Math.Min(numValues, 1024);

            int[]     values  = new int[numSamples];
            Color[]   cols    = new Color[numSamples];
            Texture2D texture = new Texture2D(numSamples, 1, TextureFormat.RGBAFloat, false);

            int maxFreq = 0;

            for (int iData = 0; iData < dataset.data.Length; iData++)
            {
                int   dataValue  = dataset.data[iData];
                float tValue     = (dataValue - minValue) * valRangeRecip;
                int   valueIndex = Mathf.RoundToInt((numSamples - 1) * tValue);
                values[valueIndex] += 1;
                maxFreq             = System.Math.Max(values[valueIndex], maxFreq);
            }

            for (int iSample = 0; iSample < numSamples; iSample++)
            {
                cols[iSample] = new Color(Mathf.Log10((float)values[iSample]) / Mathf.Log10((float)maxFreq), 0.0f, 0.0f, 1.0f);
            }

            texture.SetPixels(cols);
            texture.Apply();

            return(texture);
        }
예제 #5
0
        private void OnOpenDICOMDatasetResult(RuntimeFileBrowser.DialogResult result)
        {
            if (!result.cancelled)
            {
                // We'll only allow one dataset at a time in the runtime GUI (for simplicity)
                DespawnAllDatasets();

                bool recursive = true;

                // Read all files
                IEnumerable <string> fileCandidates = Directory.EnumerateFiles(result.path, "*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                                                      .Where(p => p.EndsWith(".dcm", StringComparison.InvariantCultureIgnoreCase) || p.EndsWith(".dicom", StringComparison.InvariantCultureIgnoreCase) || p.EndsWith(".dicm", StringComparison.InvariantCultureIgnoreCase));

                // Import the dataset
                DICOMImporter importer = new DICOMImporter(fileCandidates, Path.GetFileName(result.path));
                List <DICOMImporter.DICOMSeries> seriesList = importer.LoadDICOMSeries();
                float numVolumesCreated = 0;
                foreach (DICOMImporter.DICOMSeries series in seriesList)
                {
                    VolumeDataset dataset = importer.ImportDICOMSeries(series);
                    // Spawn the object
                    if (dataset != null)
                    {
                        VolumeRenderedObject obj = VolumeObjectFactory.CreateObject(dataset);
                        obj.transform.position = new Vector3(numVolumesCreated, 0, 0);
                        numVolumesCreated++;
                    }
                }
            }
        }
        public static Texture2D GenerateHistogramTexture(VolumeDataset dataset)
        {
            int minValue = dataset.GetMinDataValue();
            int maxValue = dataset.GetMaxDataValue();

            int numSamples = maxValue - minValue + 1;

            int[]     values  = new int[numSamples];
            Color[]   cols    = new Color[numSamples];
            Texture2D texture = new Texture2D(numSamples, 1, TextureFormat.RGBAFloat, false);

            int maxFreq = 0;

            for (int iData = 0; iData < dataset.data.Length; iData++)
            {
                int dataValue = dataset.data[iData] - minValue;
                values[dataValue] += 1;
                maxFreq            = System.Math.Max(values[dataValue], maxFreq);
            }

            for (int iSample = 0; iSample < numSamples; iSample++)
            {
                cols[iSample] = new Color(Mathf.Log10((float)values[iSample]) / Mathf.Log10((float)maxFreq), 0.0f, 0.0f, 1.0f);
            }

            texture.SetPixels(cols);
            texture.Apply();

            return(texture);
        }
예제 #7
0
        static void ShowDICOMImporter()
        {
            string dir = EditorUtility.OpenFolderPanel("Select a folder to load", "", "");

            if (Directory.Exists(dir))
            {
                bool recursive = true;

                // Read all files
                IEnumerable <string> fileCandidates = Directory.EnumerateFiles(dir, "*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                                                      .Where(p => p.EndsWith(".dcm", StringComparison.InvariantCultureIgnoreCase) || p.EndsWith(".dicom", StringComparison.InvariantCultureIgnoreCase) || p.EndsWith(".dicm", StringComparison.InvariantCultureIgnoreCase));

                if (!fileCandidates.Any())
                {
#if UNITY_EDITOR
                    if (UnityEditor.EditorUtility.DisplayDialog("Could not find any DICOM files",
                                                                $"Failed to find any files with DICOM file extension.{Environment.NewLine}Do you want to include files without DICOM file extension?", "Yes", "No"))
                    {
                        fileCandidates = Directory.EnumerateFiles(dir, "*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
                    }
#endif
                }

                if (fileCandidates.Any())
                {
                    DICOMImporter importer = new DICOMImporter(fileCandidates, Path.GetFileName(dir));
                    List <DICOMImporter.DICOMSeries> seriesList = importer.LoadDICOMSeries();
                    float numVolumesCreated = 0;

                    foreach (DICOMImporter.DICOMSeries series in seriesList)
                    {
                        VolumeDataset dataset = importer.ImportDICOMSeries(series);
                        if (dataset != null)
                        {
                            if (EditorPrefs.GetBool("DownscaleDatasetPrompt"))
                            {
                                if (EditorUtility.DisplayDialog("Optional DownScaling",
                                                                $"Do you want to downscale the dataset? The dataset's dimension is: {dataset.dimX} x {dataset.dimY} x {dataset.dimZ}", "Yes", "No"))
                                {
                                    dataset.DownScaleData();
                                }
                            }

                            VolumeRenderedObject obj = VolumeObjectFactory.CreateObject(dataset);
                            obj.transform.position = new Vector3(numVolumesCreated, 0, 0);
                            numVolumesCreated++;
                        }
                    }
                }
                else
                {
                    Debug.LogError("Could not find any DICOM files to import.");
                }
            }
            else
            {
                Debug.LogError("Directory doesn't exist: " + dir);
            }
        }
        /// <summary>
        /// Creates a histogram texture for 2D transfer functions.
        ///   X-axis = data sample (density) value
        ///   Y-axis = gradient magnitude
        ///   colour = white (if there is a data sample with the specified value and gradient magnitude) or black (if not)
        /// </summary>
        /// <param name="dataset"></param>
        /// <returns></returns>
        public static Texture2D Generate2DHistogramTexture(VolumeDataset dataset)
        {
            float minValue = dataset.GetMinDataValue();
            float maxValue = dataset.GetMaxDataValue();

            // Value range of the density values.
            float densityValRange   = maxValue - minValue + 1.0f;
            float densityRangeRecip = 1.0f / (maxValue - minValue); // reciprocal
            // Clamp density value samples.
            int numDensitySamples  = System.Math.Min((int)densityValRange, 512);
            int numGradientSamples = 256;

            Color[]   cols    = new Color[numDensitySamples * numGradientSamples];
            Texture2D texture = new Texture2D(numDensitySamples, numGradientSamples, TextureFormat.RGBAFloat, false);

            // Zero-initialise colours.
            for (int iCol = 0; iCol < cols.Length; iCol++)
            {
                cols[iCol] = new Color(0.0f, 0.0f, 0.0f, 0.0f);
            }

            float       maxRange = dataset.GetMaxDataValue() - dataset.GetMinDataValue();
            const float maxNormalisedMagnitude = 1.75f; // sqrt(1^2 + 1^2 + 1^2) = swrt(3) = a bit less than 1.75

            for (int x = 1; x < dataset.dimX - 1; x++)
            {
                for (int y = 1; y < dataset.dimY - 1; y++)
                {
                    for (int z = 1; z < dataset.dimZ - 1; z++)
                    {
                        int iData   = x + y * dataset.dimX + z * (dataset.dimX * dataset.dimY);
                        int density = Mathf.RoundToInt(dataset.data[iData]); // FIXME

                        float x1 = dataset.data[(x + 1) + y * dataset.dimX + z * (dataset.dimX * dataset.dimY)];
                        float x2 = dataset.data[(x - 1) + y * dataset.dimX + z * (dataset.dimX * dataset.dimY)];
                        float y1 = dataset.data[x + (y + 1) * dataset.dimX + z * (dataset.dimX * dataset.dimY)];
                        float y2 = dataset.data[x + (y - 1) * dataset.dimX + z * (dataset.dimX * dataset.dimY)];
                        float z1 = dataset.data[x + y * dataset.dimX + (z + 1) * (dataset.dimX * dataset.dimY)];
                        float z2 = dataset.data[x + y * dataset.dimX + (z - 1) * (dataset.dimX * dataset.dimY)];

                        // Calculate gradient
                        Vector3 grad = new Vector3((x2 - x1) / (float)maxRange, (y2 - y1) / (float)maxRange, (z2 - z1) / (float)maxRange);

                        // Calculate density and gradient value indices (in flattened 2D array)
                        float tDensity = (density - minValue) * densityRangeRecip;
                        int   iDensity = Mathf.RoundToInt((numDensitySamples - 1) * tDensity);
                        int   iGrad    = (int)(grad.magnitude * numGradientSamples / maxNormalisedMagnitude);

                        // Assign a white colour to all samples (in a histogram where x = density and y = gradient magnitude).
                        cols[iDensity + iGrad * numDensitySamples] = Color.white;
                    }
                }
            }

            texture.SetPixels(cols);
            texture.Apply();

            return(texture);
        }
        public override VolumeDataset Import()
        {
            VolumeDataset dataset = new VolumeDataset();

            dataset.dimX = dimX;
            dataset.dimY = dimY;
            dataset.dimZ = dimZ;

            FileStream   fs     = new FileStream(filePath, FileMode.Open);
            BinaryReader reader = new BinaryReader(fs);

            if (skipBytes > 0)
            {
                reader.ReadBytes(skipBytes);
            }

            int uDimension = dimX * dimY * dimZ;

            dataset.data = new int[uDimension];

            int val = 0;

            for (int i = 0; i < uDimension; i++)
            {
                switch (contentFormat)
                {
                case DataContentFormat.Int8:
                    val = (int)reader.ReadSByte();
                    break;

                case DataContentFormat.Int16:
                    val = (int)reader.ReadInt16();
                    break;

                case DataContentFormat.Int32:
                    val = (int)reader.ReadInt32();
                    break;

                case DataContentFormat.Uint8:
                    val = (int)reader.ReadByte();
                    break;

                case DataContentFormat.Uint16:
                    val = (int)reader.ReadUInt16();
                    break;

                case DataContentFormat.Uint32:
                    val = (int)reader.ReadUInt32();
                    break;
                }
                dataset.data[i] = val;
            }
            Debug.Log("Loaded dataset in range: " + dataset.GetMinDataValue() + "  -  " + dataset.GetMaxDataValue());

            return(dataset);
        }
예제 #10
0
        public VolumeDataset Import()
        {
            // Check that the file exists
            if (!File.Exists(filePath))
            {
                Debug.LogError("The file does not exist: " + filePath);
                return(null);
            }

            FileStream   fs     = new FileStream(filePath, FileMode.Open);
            BinaryReader reader = new BinaryReader(fs);

            // Check that the dimension does not exceed the file size
            long expectedFileSize = (long)(dimX * dimY * dimZ) * GetSampleFormatSize(contentFormat) + skipBytes;

            if (fs.Length < expectedFileSize)
            {
                Debug.LogError($"The dimension({dimX}, {dimY}, {dimZ}) exceeds the file size. Expected file size is {expectedFileSize} bytes, while the actual file size is {fs.Length} bytes");
                reader.Close();
                fs.Close();
                return(null);
            }

            VolumeDataset dataset = new VolumeDataset();

            dataset.datasetName = Path.GetFileName(filePath);
            dataset.filePath    = filePath;
            dataset.dimX        = dimX;
            dataset.dimY        = dimY;
            dataset.dimZ        = dimZ;

            // Skip header (if any)
            if (skipBytes > 0)
            {
                reader.ReadBytes(skipBytes);
            }

            int uDimension = dimX * dimY * dimZ;

            dataset.data = new float[uDimension];

            // Read the data/sample values
            for (int i = 0; i < uDimension; i++)
            {
                dataset.data[i] = (float)ReadDataValue(reader);
            }
            Debug.Log("Loaded dataset in range: " + dataset.GetMinDataValue() + "  -  " + dataset.GetMaxDataValue());

            reader.Close();
            fs.Close();

            dataset.FixDimensions();

            return(dataset);
        }
        public static Material CreateMaterialDVR(VolumeDataset dataset)
        {
            Shader   shader   = Shader.Find("VolumeRendering/DirectVolumeRenderingShader");
            Material material = new Material(shader);

            const int noiseDimX    = 512;
            const int noiseDimY    = 512;
            Texture2D noiseTexture = NoiseTextureGenerator.GenerateNoiseTexture(noiseDimX, noiseDimY);

            material.SetTexture("_NoiseTex", noiseTexture);
            material.SetTexture("_DataTex", dataset.GetDataTexture());

            return(material);
        }
예제 #12
0
 private void OnOpenPARDatasetResult(RuntimeFileBrowser.DialogResult result)
 {
     if (!result.cancelled)
     {
         DespawnAllDatasets();
         string             filePath    = result.path;
         ParDatasetImporter parimporter = new ParDatasetImporter(filePath);
         VolumeDataset      dataset     = parimporter.Import(); //overriden somewhere
         if (dataset != null)
         {
             VolumeObjectFactory.CreateObject(dataset);
         }
     }
 }
        public static VolumeRenderedObject CreateObject(VolumeDataset dataset)
        {
            GameObject           outerObject = new GameObject("VolumeRenderedObject_" + dataset.datasetName);
            VolumeRenderedObject volObj      = outerObject.AddComponent <VolumeRenderedObject>();

            GameObject meshContainer = GameObject.Instantiate((GameObject)Resources.Load("VolumeContainer"));

            meshContainer.transform.parent        = outerObject.transform;
            meshContainer.transform.localScale    = Vector3.one;
            meshContainer.transform.localPosition = Vector3.zero;
            meshContainer.transform.parent        = outerObject.transform;
            outerObject.transform.localRotation   = Quaternion.Euler(90.0f, 0.0f, 0.0f);

            MeshRenderer meshRenderer = meshContainer.GetComponent <MeshRenderer>();

            meshRenderer.sharedMaterial = new Material(meshRenderer.sharedMaterial);
            volObj.meshRenderer         = meshRenderer;
            volObj.dataset = dataset;

            const int noiseDimX    = 512;
            const int noiseDimY    = 512;
            Texture2D noiseTexture = NoiseTextureGenerator.GenerateNoiseTexture(noiseDimX, noiseDimY);

            TransferFunction tf        = TransferFunctionDatabase.CreateTransferFunction();
            Texture2D        tfTexture = tf.GetTexture();

            volObj.transferFunction = tf;

            TransferFunction2D tf2D = TransferFunctionDatabase.CreateTransferFunction2D();

            volObj.transferFunction2D = tf2D;

            meshRenderer.sharedMaterial.SetTexture("_DataTex", dataset.GetDataTexture());
            meshRenderer.sharedMaterial.SetTexture("_GradientTex", null);
            meshRenderer.sharedMaterial.SetTexture("_NoiseTex", noiseTexture);
            meshRenderer.sharedMaterial.SetTexture("_TFTex", tfTexture);

            meshRenderer.sharedMaterial.EnableKeyword("MODE_DVR");
            meshRenderer.sharedMaterial.DisableKeyword("MODE_MIP");
            meshRenderer.sharedMaterial.DisableKeyword("MODE_SURF");

            if (dataset.scaleX != 0.0f && dataset.scaleY != 0.0f && dataset.scaleZ != 0.0f)
            {
                float maxScale = Mathf.Max(dataset.scaleX, dataset.scaleY, dataset.scaleZ);
                volObj.transform.localScale = new Vector3(dataset.scaleX / maxScale, dataset.scaleY / maxScale, dataset.scaleZ / maxScale);
            }

            return(volObj);
        }
        private void ImportDataset()
        {
            DatasetImporterBase importer = new RawDatasetImporter(fileToImport, dimX, dimY, dimZ, dataFormat, endianness, bytesToSkip);

            VolumeDataset dataset = importer.Import();

            if (dataset != null)
            {
                VolumeRenderedObject obj = VolumeObjectFactory.CreateObject(dataset);
            }
            else
            {
                Debug.LogError("Failed to import datset");
            }

            this.Close();
        }
예제 #15
0
        private void OnOpenDICOMDatasetResult(RuntimeFileBrowser.DialogResult result)
        {
            if (!result.cancelled)
            {
                // We'll only allow one dataset at a time in the runtime GUI (for simplicity)
                DespawnAllDatasets();

                // Import the dataset
                DICOMImporter importer = new DICOMImporter(result.path, true);
                VolumeDataset dataset  = importer.Import();
                // Spawn the object
                if (dataset != null)
                {
                    VolumeObjectFactory.CreateObject(dataset);
                }
            }
        }
        /// <summary>
        /// Generates a histogram (but computaion is done on GPU) where:
        ///   X-axis = the data sample (density) value
        ///   Y-axis = the sample count (number of data samples with the specified density)
        /// </summary>
        /// <param name="dataset"></param>
        /// <returns></returns>
        public static Texture2D GenerateHistogramTextureOnGPU(VolumeDataset dataset)
        {
            double actualBound = dataset.GetMaxDataValue() - dataset.GetMinDataValue() + 1;
            int    numValues   = System.Convert.ToInt32(dataset.GetMaxDataValue() - dataset.GetMinDataValue() + 1); // removed +1
            int    sampleCount = System.Math.Min(numValues, 256);

            ComputeShader computeHistogram = Resources.Load("ComputeHistogram") as ComputeShader;
            int           handleInitialize = computeHistogram.FindKernel("HistogramInitialize");
            int           handleMain       = computeHistogram.FindKernel("HistogramMain");

            ComputeBuffer histogramBuffer = new ComputeBuffer(sampleCount, sizeof(uint) * 1);

            uint[]    histogramData = new uint[sampleCount];
            Color32[] histogramCols = new Color32[sampleCount];

            Texture3D dataTexture = dataset.GetDataTexture();

            if (handleInitialize < 0 || handleMain < 0)
            {
                Debug.LogError("Histogram compute shader initialization failed.");
            }

            computeHistogram.SetFloat("ValueRange", (float)(numValues - 1));
            computeHistogram.SetTexture(handleMain, "VolumeTexture", dataTexture);
            computeHistogram.SetBuffer(handleMain, "HistogramBuffer", histogramBuffer);
            computeHistogram.SetBuffer(handleInitialize, "HistogramBuffer", histogramBuffer);

            computeHistogram.Dispatch(handleInitialize, sampleCount / 8, 1, 1);
            computeHistogram.Dispatch(handleMain, (dataTexture.width + 7) / 8, (dataTexture.height + 7) / 8, (dataTexture.depth + 7) / 8);

            histogramBuffer.GetData(histogramData);

            int maxValue = (int)histogramData.Max();

            Texture2D texture = new Texture2D(sampleCount, 1, TextureFormat.RGBA32, false);

            for (int iSample = 0; iSample < sampleCount; iSample++)
            {
                histogramCols[iSample] = new Color(Mathf.Log10((float)histogramData[iSample]) / Mathf.Log10((float)maxValue), 0.0f, 0.0f, 1.0f);
            }

            texture.SetPixels32(histogramCols);
            texture.Apply();

            return(texture);
        }
예제 #17
0
        static void ShowDICOMImporter()
        {
            string dir = EditorUtility.OpenFolderPanel("Select a folder to load", "", "");

            if (Directory.Exists(dir))
            {
                DICOMImporter importer = new DICOMImporter(dir, true);
                VolumeDataset dataset  = importer.Import();
                if (dataset != null)
                {
                    VolumeObjectFactory.CreateObject(dataset);
                }
            }
            else
            {
                Debug.LogError("Directory doesn't exist: " + dir);
            }
        }
        public VolumeDataset Import()
        {
            if (!Directory.Exists(directoryPath))
            {
                throw new NullReferenceException("No directory found: " + directoryPath);
            }

            List <string> imagePaths = GetSortedImagePaths();

            Vector3Int dimensions = GetVolumeDimensions(imagePaths);

            int[]         data    = FillSequentialData(dimensions, imagePaths);
            VolumeDataset dataset = FillVolumeDataset(data, dimensions);

            dataset.FixDimensions();

            return(dataset);
        }
        /// <summary>
        /// Wraps volume data into a VolumeDataset.
        /// </summary>
        /// <param name="data">Sequential value data for a volume.</param>
        /// <param name="dimensions">The XYZ dimensions of the volume.</param>
        /// <returns>The wrapped volume data.</returns>
        private VolumeDataset FillVolumeDataset(int[] data, Vector3Int dimensions)
        {
            string name = Path.GetFileName(directoryPath);

            VolumeDataset dataset = new VolumeDataset()
            {
                name        = name,
                datasetName = name,
                data        = Array.ConvertAll(data, new Converter <int, float>((int val) => { return(Convert.ToSingle(val)); })),
                dimX        = dimensions.x,
                dimY        = dimensions.y,
                dimZ        = dimensions.z,
                scaleX      = 1f, // Scale arbitrarily normalised around the x-axis
                scaleY      = (float)dimensions.y / (float)dimensions.x,
                scaleZ      = (float)dimensions.z / (float)dimensions.x
            };

            return(dataset);
        }
예제 #20
0
        /// <summary>
        /// Wraps volume data into a VolumeDataset.
        /// </summary>
        /// <param name="data">Sequential value data for a volume.</param>
        /// <param name="dimensions">The XYZ dimensions of the volume.</param>
        /// <returns>The wrapped volume data.</returns>
        private VolumeDataset FillVolumeDataset(int[] data, Vector3Int dimensions)
        {
            string name = Path.GetFileName(directoryPath);

            VolumeDataset dataset = new VolumeDataset()
            {
                name        = name,
                datasetName = name,
                data        = data,
                dimX        = dimensions.x,
                dimY        = dimensions.y,
                dimZ        = dimensions.z,
                scaleX      = 1f, // Scale arbitrarily normalised around the x-axis
                scaleY      = (float)dimensions.y / (float)dimensions.x,
                scaleZ      = (float)dimensions.z / (float)dimensions.x
            };

            return(dataset);
        }
        public static Texture2D Generate2DHistogramTexture(VolumeDataset dataset)
        {
            int numSamples         = dataset.GetMaxDataValue() + 1;
            int numGradientSamples = 256;

            Color[]   cols    = new Color[numSamples * numGradientSamples];
            Texture2D texture = new Texture2D(numSamples, numGradientSamples, TextureFormat.RGBAFloat, false);

            for (int iCol = 0; iCol < cols.Length; iCol++)
            {
                cols[iCol] = new Color(0.0f, 0.0f, 0.0f, 0.0f);
            }

            int         maxRange = dataset.GetMaxDataValue() - dataset.GetMinDataValue();
            const float maxNormalisedMagnitude = 1.75f; // sqrt(1^2 + 1^2 + 1^2) = swrt(3) = a bit less than 1.75

            for (int x = 1; x < dataset.dimX - 1; x++)
            {
                for (int y = 1; y < dataset.dimY - 1; y++)
                {
                    for (int z = 1; z < dataset.dimZ - 1; z++)
                    {
                        int iData   = x + y * dataset.dimX + z * (dataset.dimX * dataset.dimY);
                        int density = dataset.data[iData];

                        int x1 = dataset.data[(x + 1) + y * dataset.dimX + z * (dataset.dimX * dataset.dimY)];
                        int x2 = dataset.data[(x - 1) + y * dataset.dimX + z * (dataset.dimX * dataset.dimY)];
                        int y1 = dataset.data[x + (y + 1) * dataset.dimX + z * (dataset.dimX * dataset.dimY)];
                        int y2 = dataset.data[x + (y - 1) * dataset.dimX + z * (dataset.dimX * dataset.dimY)];
                        int z1 = dataset.data[x + y * dataset.dimX + (z + 1) * (dataset.dimX * dataset.dimY)];
                        int z2 = dataset.data[x + y * dataset.dimX + (z - 1) * (dataset.dimX * dataset.dimY)];

                        Vector3 grad = new Vector3((x2 - x1) / (float)maxRange, (y2 - y1) / (float)maxRange, (z2 - z1) / (float)maxRange);
                        cols[density + (int)(grad.magnitude * numGradientSamples / maxNormalisedMagnitude) * numSamples] = Color.white;
                    }
                }
            }

            texture.SetPixels(cols);
            texture.Apply();

            return(texture);
        }
예제 #22
0
        static void ShowDICOMImporter()
        {
            string dir = EditorUtility.OpenFolderPanel("Select a folder to load", "", "");

            if (Directory.Exists(dir))
            {
                bool recursive = true;

                // Read all files
                IEnumerable <string> fileCandidates = Directory.EnumerateFiles(dir, "*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                                                      .Where(p => p.EndsWith(".dcm", StringComparison.InvariantCultureIgnoreCase) || p.EndsWith(".dicom", StringComparison.InvariantCultureIgnoreCase) || p.EndsWith(".dicm", StringComparison.InvariantCultureIgnoreCase));

                if (!fileCandidates.Any())
                {
#if UNITY_EDITOR
                    if (UnityEditor.EditorUtility.DisplayDialog("Could not find any DICOM files",
                                                                $"Failed to find any files with DICOM file extension.{Environment.NewLine}Do you want to include files without DICOM file extension?", "Yes", "No"))
                    {
                        fileCandidates = Directory.EnumerateFiles(dir, "*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly);
                    }
#endif
                }

                if (fileCandidates.Any())
                {
                    DICOMImporter importer = new DICOMImporter(fileCandidates, Path.GetFileName(dir));
                    VolumeDataset dataset  = importer.Import();
                    if (dataset != null)
                    {
                        VolumeObjectFactory.CreateObject(dataset);
                    }
                }
                else
                {
                    Debug.LogError("Could not find any DICOM files to import.");
                }
            }
            else
            {
                Debug.LogError("Directory doesn't exist: " + dir);
            }
        }
예제 #23
0
        public override VolumeDataset Import()
        {
            if (!Directory.Exists(directoryPath))
            {
                throw new NullReferenceException("No directory found: " + directoryPath);
            }

            List <string> imagePaths = GetSortedImagePaths();

            if (!ImageSetHasUniformDimensions(imagePaths))
            {
                throw new IndexOutOfRangeException("Image sequence has non-uniform dimensions");
            }

            Vector3Int dimensions = GetVolumeDimensions(imagePaths);

            int[]         data    = FillSequentialData(dimensions, imagePaths);
            VolumeDataset dataset = FillVolumeDataset(data, dimensions);

            return(dataset);
        }
예제 #24
0
        public static void ImportDataset(string filePath)
        {
            DatasetType datasetType = DatasetImporterUtility.GetDatasetType(filePath);

            switch (datasetType)
            {
            case DatasetType.Raw:
            {
                RAWDatasetImporterEditorWindow wnd = (RAWDatasetImporterEditorWindow)EditorWindow.GetWindow(typeof(RAWDatasetImporterEditorWindow));
                if (wnd != null)
                {
                    wnd.Close();
                }

                wnd = new RAWDatasetImporterEditorWindow(filePath);
                wnd.Show();
                break;
            }

            case DatasetType.DICOM:
            {
                string directoryPath = new FileInfo(filePath).Directory.FullName;

                // Find all DICOM files in directory
                IEnumerable <string> fileCandidates = Directory.EnumerateFiles(directoryPath, "*.*", SearchOption.TopDirectoryOnly)
                                                      .Where(p => p.EndsWith(".dcm", StringComparison.InvariantCultureIgnoreCase) || p.EndsWith(".dicom", StringComparison.InvariantCultureIgnoreCase) || p.EndsWith(".dicm", StringComparison.InvariantCultureIgnoreCase));

                DatasetImporterBase importer = new DICOMImporter(fileCandidates, Path.GetFileName(directoryPath));
                VolumeDataset       dataset  = importer.Import();

                if (dataset != null)
                {
                    VolumeRenderedObject obj = VolumeObjectFactory.CreateObject(dataset);
                }
                break;
            }
            }
        }
예제 #25
0
        private void OnOpenDICOMDatasetResult(RuntimeFileBrowser.DialogResult result)
        {
            if (!result.cancelled)
            {
                // We'll only allow one dataset at a time in the runtime GUI (for simplicity)
                DespawnAllDatasets();

                bool recursive = true;

                // Read all files
                IEnumerable <string> fileCandidates = Directory.EnumerateFiles(result.path, "*.*", recursive ? SearchOption.AllDirectories : SearchOption.TopDirectoryOnly)
                                                      .Where(p => p.EndsWith(".dcm", StringComparison.InvariantCultureIgnoreCase) || p.EndsWith(".dicom", StringComparison.InvariantCultureIgnoreCase) || p.EndsWith(".dicm", StringComparison.InvariantCultureIgnoreCase));

                // Import the dataset
                DICOMImporter importer = new DICOMImporter(fileCandidates, Path.GetFileName(result.path));
                VolumeDataset dataset  = importer.Import();
                // Spawn the object
                if (dataset != null)
                {
                    VolumeObjectFactory.CreateObject(dataset);
                }
            }
        }
예제 #26
0
        private void ImportDataset()
        {
            DatasetImporterBase importer = null;

            switch (datasetType)
            {
            case DatasetType.Raw:
            {
                importer = new RawDatasetImporter(fileToImport, dimX, dimY, dimZ, dataFormat, bytesToSkip);
                break;
            }

            case DatasetType.DICOM:
            {
                importer = new DICOMImporter(new FileInfo(fileToImport).Directory.FullName, false);
                break;
            }
            }

            VolumeDataset dataset = null;

            if (importer != null)
            {
                dataset = importer.Import();
            }

            if (dataset != null)
            {
                VolumeRenderedObject obj = VolumeObjectFactory.CreateObject(dataset);
            }
            else
            {
                Debug.LogError("Failed to import datset");
            }

            this.Close();
        }
        /// <summary>
        /// Generates a histogram where:
        ///   X-axis = the data sample (density) value
        ///   Y-axis = the sample count (number of data samples with the specified density)
        /// </summary>
        /// <param name="dataset"></param>
        /// <returns></returns>
        public static Texture2D GenerateHistogramTexture(VolumeDataset dataset)
        {
            float minValue   = dataset.GetMinDataValue();
            float maxValue   = dataset.GetMaxDataValue();
            float valueRange = maxValue - minValue;

            int numFrequencies = Mathf.Min((int)valueRange, 1024);

            int[] frequencies = new int[numFrequencies];

            int   maxFreq       = 0;
            float valRangeRecip = 1.0f / (maxValue - minValue);

            for (int iData = 0; iData < dataset.data.Length; iData++)
            {
                float dataValue = dataset.data[iData];
                float tValue    = (dataValue - minValue) * valRangeRecip;
                int   freqIndex = (int)(tValue * (numFrequencies - 1));
                frequencies[freqIndex] += 1;
                maxFreq = System.Math.Max(frequencies[freqIndex], maxFreq);
            }

            Color[]   cols    = new Color[numFrequencies];
            Texture2D texture = new Texture2D(numFrequencies, 1, TextureFormat.RGBAFloat, false);

            for (int iSample = 0; iSample < numFrequencies; iSample++)
            {
                cols[iSample] = new Color(Mathf.Log10((float)frequencies[iSample]) / Mathf.Log10((float)maxFreq), 0.0f, 0.0f, 1.0f);
            }

            texture.SetPixels(cols);
            //texture.filterMode = FilterMode.Point;
            texture.Apply();

            return(texture);
        }
예제 #28
0
        public static VolumeRenderedObject CreateObject(VolumeDataset dataset)
        {
            GameObject           obj          = GameObject.Instantiate((GameObject)Resources.Load("VolumeRenderedObject"));
            VolumeRenderedObject volObj       = obj.GetComponent <VolumeRenderedObject>();
            MeshRenderer         meshRenderer = obj.GetComponent <MeshRenderer>();

            meshRenderer.material = new Material(meshRenderer.sharedMaterial);

            volObj.dataset = dataset;

            const int noiseDimX    = 512;
            const int noiseDimY    = 512;
            Texture2D noiseTexture = NoiseTextureGenerator.GenerateNoiseTexture(noiseDimX, noiseDimY);

            TransferFunction tf        = TransferFunctionDatabase.CreateTransferFunction();
            Texture2D        tfTexture = tf.GetTexture();

            volObj.transferFunction = tf;

            tf.histogramTexture = HistogramTextureGenerator.GenerateHistogramTexture(dataset);

            TransferFunction2D tf2D = TransferFunctionDatabase.CreateTransferFunction2D();

            volObj.transferFunction2D = tf2D;

            meshRenderer.sharedMaterial.SetTexture("_DataTex", dataset.GetDataTexture());
            meshRenderer.sharedMaterial.SetTexture("_GradientTex", null);
            meshRenderer.sharedMaterial.SetTexture("_NoiseTex", noiseTexture);
            meshRenderer.sharedMaterial.SetTexture("_TFTex", tfTexture);

            meshRenderer.sharedMaterial.EnableKeyword("MODE_DVR");
            meshRenderer.sharedMaterial.DisableKeyword("MODE_MIP");
            meshRenderer.sharedMaterial.DisableKeyword("MODE_SURF");

            return(volObj);
        }
        private void ImportDataset()
        {
            RawDatasetImporter importer = new RawDatasetImporter(fileToImport, dimX, dimY, dimZ, dataFormat, endianness, bytesToSkip);
            VolumeDataset      dataset  = importer.Import();

            if (dataset != null)
            {
                if (EditorPrefs.GetBool("DownscaleDatasetPrompt"))
                {
                    if (EditorUtility.DisplayDialog("Optional DownScaling",
                                                    $"Do you want to downscale the dataset? The dataset's dimension is: {dataset.dimX} x {dataset.dimY} x {dataset.dimZ}", "Yes", "No"))
                    {
                        dataset.DownScaleData();
                    }
                }
                VolumeRenderedObject obj = VolumeObjectFactory.CreateObject(dataset);
            }
            else
            {
                Debug.LogError("Failed to import datset");
            }

            this.Close();
        }
        private void ImportDataset()
        {
            DatasetImporterBase importer = null;

            switch (datasetType)
            {
            case DatasetType.Raw:
            {
                importer = new RawDatasetImporter(fileToImport, dimX, dimY, dimZ, dataFormat, bytesToSkip);
                break;
            }

            case DatasetType.DICOM:
            {
                throw new System.NotImplementedException("TODO: implement support for DICOM files");
            }
            }

            VolumeDataset dataset = null;

            if (importer != null)
            {
                dataset = importer.Import();
            }

            if (dataset != null)
            {
                VolumeRenderedObject obj = VolumeObjectFactory.CreateObject(dataset);
            }
            else
            {
                Debug.LogError("Failed to import datset");
            }

            this.Close();
        }