//RENDER FIRST DICOM FILE FROM DICOMDIR TO TEXTURE2D public static Texture2D CreateTextureFromFirstDicom(string path, bool anonymize, ref dicomInfoTools info) { string stream = null; DirectoryInfo dicomDirectoryInfo = new DirectoryInfo(path); foreach (var dicom in dicomDirectoryInfo.GetFiles(".", SearchOption.AllDirectories)) { if (DicomFile.HasValidHeader(dicom.FullName)) { stream = dicom.FullName; break; } } Debug.Log(stream); var file = DicomFile.Open(stream); Debug.Log($"Dicom File at {path} loaded"); info = new dicomInfoTools(file, anonymize); Texture2D texture = new DicomImage(file.Dataset).RenderImage().As <Texture2D>(); Debug.Log($"Single 2D Texture loaded"); return(texture); }
//CREATE A COMPLETE TEXTURE3D FROM A DICOMDIR public static Texture3D createTexture3DAsAssetScript(List <string> fileNameList, dicomInfoTools dicomInformation, int textureWidth, int textureHeight, int textureDepth) { /////Copy pixel data of 2D Textures in array into color array var colorsForCubeTexture = CreateColorArrayFromDicomdir(fileNameList, dicomInformation, textureWidth, textureHeight, textureDepth); //Debug.Log($" Color: {colorsForCubeTexture[15000000]}"); /////Map 2D Texture color pixels to 3D Texture var cubeTexture = CreateTexture3D(colorsForCubeTexture, textureWidth, textureHeight, textureDepth); //Debug.Log($"3D Texture created."); return(cubeTexture); }
//RENDER DICOM FILE TO TEXTURE2D public static Texture2D CreateTextureFromDicom(string path, bool anonymize, ref dicomInfoTools info) { var stream = File.OpenRead(path); var file = DicomFile.Open(stream); Debug.Log($"Dicom File at {path} loaded"); info = new dicomInfoTools(file, anonymize); Texture2D texture = new DicomImage(file.Dataset).RenderImage().As <Texture2D>(); Debug.Log($"Single 2D Texture loaded"); return(texture); }
//IMPORT DICOM SLICES public void CreateTexture3DAssets() { try { savedTextureDestinationPath = Path.Combine(rootPath, savedTextureDestinationDirectory); bool exists = Directory.Exists(savedTextureDestinationPath); // Create/Check for Folder: Saved Slices if (!exists) { Directory.CreateDirectory(savedTextureDestinationPath); } ressourceDestinationPath = Path.Combine("Assets/Resources/MediVR/Textures", assetDestinationDirectory); //Set some paths thisRessourceDestinationPath = Path.Combine(ressourceDestinationPath, userDefinedFolderName); exists = Directory.Exists(ressourceDestinationPath); // Create/Check for Folder: Dicom 3D Textures if (!exists) { Directory.CreateDirectory(ressourceDestinationPath); } exists = Directory.Exists(thisRessourceDestinationPath); // Create/Check for Folder: Dicom 3D Textures/dicomFileDirecory (CT_Series) if (!exists) { Directory.CreateDirectory(thisRessourceDestinationPath); } //Debug.Log($"Path to Directory: {dirPath}"); Debug.Log($"Path to Directory: {userDefinedDicomPath}"); Debug.Log($"Path to 3D Textures folder in Ressources Directory: {ressourceDestinationPath}"); //Debug.Log($"Path to {dicomFileDirectory} folder in Ressources Directory: {thisRessourceDestinationPath}"); Debug.Log($"Path to {userDefinedFolderName} folder in Ressources Directory: {thisRessourceDestinationPath}"); string pathTo3DTextures = "MediVR/Textures/" + assetDestinationDirectory + "/" + userDefinedFolderName; //dicomFileDirectory; //Debug.Log($"Initializing 3D Texture from {dirPath}."); Debug.Log($"Initializing 3D Texture from {userDefinedDicomPath}."); //var dicomDirectoryInfo = new DirectoryInfo(dirPath); var dicomDirectoryInfo = new DirectoryInfo(userDefinedDicomPath); int dicomFileCount = dicomDirectoryInfo.GetFiles().Length; Debug.Log($"Files found in Directory: {dicomFileCount}"); //Debug.Log($"Loading Dicom files from Directory {dirPath} into Array"); Debug.Log($"Loading Dicom files from Directory {userDefinedDicomPath} into Array"); //READ FILE NAMES List <string> dicomFileNameList = new List <string>(); foreach (var dicomFile in dicomDirectoryInfo.GetFiles(".", SearchOption.AllDirectories)) { if (DicomFile.HasValidHeader(dicomFile.FullName)) { dicomFileNameList.Add(dicomFile.FullName); } } if (dicomFileNameList.Count != 0) { Debug.Log($"Valid Dicom files found in Directory: {dicomFileNameList.Count}. File names loaded onto list."); if (reverseSliceOrder) { dicomFileNameList.Reverse(); } textureDepth = dicomImageTools.NextPow2(dicomFileNameList.Count); var file = DicomFile.Open(dicomFileNameList[0]); dicomInformation = new dicomInfoTools(file, anonymizeDicomMetaData); Debug.Log($"Metadata loaded from file: {dicomFileNameList[0]}."); //////// SAVE METADATA metadataRessourceName = thisRessourceDestinationPath + "/" + userDefinedFolderName + "_3DTexture_" + textureWidth + "x" + textureHeight + "x" + textureDepth + "_MetaData.XML"; XmlSerializer serializer = new XmlSerializer(typeof(dicomInfoTools)); using (TextWriter writer = new StreamWriter(metadataRessourceName)) { serializer.Serialize(writer, dicomInformation); } Debug.Log($"Metadata saved to file: {metadataRessourceName}."); //////// SAVE SINGLE SLICES sliceRessourceName = userDefinedFolderName + "_3DTexture_" + textureWidth + "x" + textureHeight + "x" + textureDepth + "_Slice"; dicomSlices = dicomImageTools.CreateNumberedTextureArrayFromDicomdir(dicomFileNameList, 5); dicomImageTools.SaveTextureArrayAsAssets(dicomSlices, thisRessourceDestinationPath, sliceRessourceName); //////// SAVE 3D TEXTURE textureRessourceName = userDefinedFolderName + "_3DTexture_" + textureWidth + "x" + textureHeight + "x" + textureDepth; threeDimTexture = dicomImageTools.createTexture3DAsAssetScript(dicomFileNameList, dicomInformation, textureWidth, textureHeight, textureDepth); dicomImageTools.exportTexture3DToAsset(threeDimTexture, thisRessourceDestinationPath, textureRessourceName); //////// SAVE IMPORTED DIRECTORY NAMES SaveImportedTextureDirectoryNames(); } else { Debug.Log($"Valid Dicom files found in Directory: {dicomFileNameList.Count}. Import failed. Try with valid directory."); } } catch (ArgumentException aE)//else { Debug.Log($"Exception: {aE.ToString()} thrown. Path to directory invalid. Try with valid directory."); } }
// Start is called before the first frame update void Start() { //////// PATHS dirName = setCurrentDirectory.currentDirectory; destinationTextureDirName = initialImportDicom.assetDestinationDirectory; textureDestinationPath = initialImportDicom.savedTextureDestinationPath; //////// LOAD 3D TEXTURE if (dirName != null) { pathTo3DTextures = "MediVR/Textures/" + destinationTextureDirName + "/" + dirName; loadedTextures = Resources.LoadAll(pathTo3DTextures, typeof(Texture3D)); //TRY TO LOAD 3D TEXTURE FROM FOLDER } if (loadedTextures != null) { if (loadedTextures.Length > 0) { threeDimTexture = (Texture3D)loadedTextures[0]; //Debug.Log($"{loadedTextures[0].name}"); //////// LOAD METADATA metadataName = pathTo3DTextures + "/" + loadedTextures[0].name + "_MetaData"; var resource = Resources.Load <TextAsset>(metadataName); if (resource != null) { metaData = resource.text; } //Debug.Log($"{metaData}"); if (metaData != null) { metaData = metaData.Replace("�", ""); XmlSerializer deserializer = new XmlSerializer(typeof(dicomInfoTools)); using (StringReader reader = new StringReader(metaData)) { object obj = deserializer.Deserialize(reader); dicomInformation = (dicomInfoTools)obj; dicomInformation.GetDicomInfoString(); } } //Debug.Log($"{dicomInformation.PatientId}"); //Debug.Log($"{metaData}"); //////// LOAD SINGLE SLICES loaded2DTextures = Resources.LoadAll(pathTo3DTextures, typeof(Texture2D)); //TRY TO LOAD 2D TEXTURES FROM FOLDER if (loaded2DTextures != null) { if (loaded2DTextures.Length == 5) { dicomSlices = new Texture2D[5]; for (int i = 0; i < loaded2DTextures.Length; i++) { dicomSlices[i] = (Texture2D)loaded2DTextures[i]; } } } } } }
/////CREATE COLOR ARRAY FROM LIST OF FILES IN DICOMDIR. COLOR ARRAY IS USED TO SET PIXELS OF TEXTURE3D public static Color[] CreateColorArrayFromDicomdir(List <string> fileNameList, dicomInfoTools dicomInformation, int textureWidth, int textureHeight, int textureDepth) { //Debug.Log($"Preparing stuff for color array creation."); var w = textureWidth; var h = textureHeight; var d = textureDepth; var textureCount = 0; Color[] colors = new Color[w * h * d]; Debug.Log($"Populating color array for 3D Texture"); var slicesCount = -1; //CENTRE SLICES IN TEXTURE3D var sliceCountOffset = Mathf.FloorToInt(d - fileNameList.Count) / 2; var invSliceCountOffset = sliceCountOffset + fileNameList.Count; //SET INITIAL HOUNSFIELD VALUES short hounsfieldUnitMaximumIntenisty = 3071; short hounsfieldUnitMinimumIntenisty = -1024; short hounsfieldUnitRange = (short)(hounsfieldUnitMaximumIntenisty - hounsfieldUnitMinimumIntenisty); //GET FRAME SIZE int dicomFrameWidth = dicomInformation.ImageWidth; int dicomFrameHeight = dicomInformation.ImageHeight; Texture2D newDicomTex = null; Color[] dicomOriginalTextureRescaledHU = new Color[dicomFrameWidth * dicomFrameHeight]; //SET COMPRESSION TYPE DicomTransferSyntax defaultDicomTransferSyntax = DicomTransferSyntax.ImplicitVRLittleEndian; bool rescale = false; //GET RESCALE PARAMETERS short rescaleSlope = (short)dicomInformation.ImageRescaleSlope; short rescaleIntercept = (short)dicomInformation.ImageRescaleIntercept; string modality = dicomInformation.Modality; //APPLY RESCALE PARAMETERS ONLY FOR CT IMAGES if (modality == "CT") { rescale = true; } Debug.Log($"Image frame width: {dicomFrameWidth} pixels and frame height: {dicomFrameHeight} pixels."); Debug.Log($"Image Transfer Syntax: {dicomInformation.ImageTransferSyntax}. Applying Decompression Transfer Syntax: {defaultDicomTransferSyntax}."); Debug.Log($"Image Rescale Slope: {rescaleSlope} and Rescale Intercept: {rescaleIntercept}."); Debug.Log($"Modality is: {modality} and Rescale is set to: {rescale}."); //Debug.Log($"Done peparing stuff for color array creation."); for (int z = 0; z < d; z++) { textureCount++; if (z > sliceCountOffset && z < invSliceCountOffset) { slicesCount++; //Debug.Log($"Opening Dicom File Nr. {z - sliceCountOffset}."); //DECOMPRESS DICOM FILE var dicomFileCompressed = DicomFile.Open(fileNameList[slicesCount]); var dicomFileUncompressed = new DicomFile(); if (dicomFileCompressed.Dataset.InternalTransferSyntax.IsEncapsulated) { dicomFileUncompressed = dicomFileCompressed.Clone(defaultDicomTransferSyntax); } else { dicomFileUncompressed = dicomFileCompressed; } dicomFileUncompressed = dicomFileCompressed.Clone(defaultDicomTransferSyntax); //GET RAW PIXEL DATA var dicomFramePixelData = DicomPixelData.Create(dicomFileUncompressed.Dataset); var dicomFrame = dicomFramePixelData.GetFrame(0); //Debug.Log($"Copying Bytes into Array."); byte[] dicomFrameByteArray = dicomFrame.Data; //Debug.Log($"Transforming Bytes to Shorts."); //CONVERT BYTES TO SHORTS short[] dicomFrameShortArray = new short[(int)Math.Ceiling((double)(dicomFrameByteArray.Length / 2))]; Buffer.BlockCopy(dicomFrameByteArray, 0, dicomFrameShortArray, 0, dicomFrameByteArray.Length); //Debug.Log($"Transforming complete."); //ITERATE THROUGH PIXEL DATA, PARALLELIZED FOR SPEED Parallel.For(0, dicomFramePixelData.Width * dicomFramePixelData.Height, x => { int dicomFileHUPixel = 0; //APPLY RESCALE PARAMETERS IF IMAGE COMES FROM CT if (rescale) { dicomFileHUPixel = (dicomFrameShortArray[x] * rescaleSlope) + rescaleIntercept; } else { dicomFileHUPixel = dicomFrameShortArray[x]; } //CONVERT RAW PIXEL VALUES INTO HOUSFIELD UNITS AND THEN INTO COLOR FLOAT VALUES BETWEEN 0 AND 1 float dicomFileRescaledHUIntensity = ((float)dicomFileHUPixel - (float)hounsfieldUnitMinimumIntenisty) / hounsfieldUnitRange; Color readyRescaledHUColor = new Color(dicomFileRescaledHUIntensity, dicomFileRescaledHUIntensity, dicomFileRescaledHUIntensity); dicomOriginalTextureRescaledHU[x] = readyRescaledHUColor; }); //SET COLOR ARRAY TO TEXTURE2D newDicomTex = new Texture2D(dicomFramePixelData.Width, dicomFramePixelData.Height, TextureFormat.ARGB32, true, true); newDicomTex.SetPixels(dicomOriginalTextureRescaledHU); newDicomTex.Apply(); //Debug.Log($"Texture created. Rescaling texture."); //RESCALE IMAGE, TYPICALLY IF LARGER THAN 256X256 if (w < dicomFramePixelData.Width || h < dicomFramePixelData.Height) { TextureScale.Bilinear(newDicomTex, w, h); } } //Debug.Log($"Building color slice from texture."); //BUILD COLOR ARRAY FOR 3D TEXTURE for (int x = 0; x < w; x++) { for (int y = 0; y < h; y++) { //INDEX FOR PIXEL VALUE IN COLOR ARRAY var idx = x + (y * w) + (z * (w * h)); Color c = Color.clear; if (z > sliceCountOffset && z < invSliceCountOffset) { c = newDicomTex.GetPixel(x, (h - y)); } colors [idx] = c; } } //Debug.Log($"Slice added to color array."); } Debug.Log($"Textures loaded into color array: {textureCount}"); return(colors); }