/// <summary> /// Uses the ANTS implementation of the N4 bias correction algorithm to correct the given file. /// </summary> /// <param name="inputFile">Path to input nifti file.</param> /// <param name="updates">Event handler for updates from the process</param> /// <returns>Path for output nifti file.</returns> public static string AntsN4(string inputFile, DataReceivedEventHandler updates = null) { string niftiInPath = Path.GetFullPath(inputFile); string niftiOutPath = Path.GetFullPath(inputFile + ".antsN4.out.nii"); var args = $"-i \"{niftiInPath}\" -o \"{niftiOutPath}\""; Log.GetLogger().Info(" --Starting AntsN4.."); ProcessBuilder.CallExecutableFile(CapiConfig.GetConfig().Binaries.N4BiasFieldCorrection, args, outputDataReceived: updates, errorOccuredInProcess: updates); return(niftiOutPath); }
public static void ConvertBmpToDicom(string bmpFilepath, string dicomFilePath, string dicomHeadersFilePath = "") { var arguments = string.Empty; if (!string.IsNullOrEmpty(dicomHeadersFilePath)) { arguments = $"-df \"{dicomHeadersFilePath}\" "; // Copy dicom headers from dicom file: -df = dataset file } arguments += $"-i BMP \"{bmpFilepath}\" \"{dicomFilePath}\""; ProcessBuilder.CallExecutableFile(CapiConfig.GetConfig().Binaries.img2dcm, arguments); }
/// <summary> /// Uses the BrainSuite BSE tool to extract the brain from the given Nifti file path. /// </summary> /// <param name="inputFile">Path to .nii file which needs a brain extractin'</param> /// <param name="updates">Event handler to accept progress updates from the tool.</param> /// <returns>The path of the output file.</returns> public static string BrainSuiteBSE(string inputFile, DataReceivedEventHandler updates = null) { string niftiInPath = Path.GetFullPath(inputFile); string niftiOutPath = Path.GetFullPath(inputFile + ".bse.out.nii"); var args = $"--auto --trim -i \"{niftiInPath}\" -o \"{niftiOutPath}\""; ProcessBuilder.CallExecutableFile(CapiConfig.GetConfig().Binaries.bse, args, outputDataReceived: updates); return(niftiOutPath); }
public static string CMTKResliceUsingPrevious(string floatingFile, string niftiRefPath, DataReceivedEventHandler updates = null) { Environment.SetEnvironmentVariable("CMTK_WRITE_UNCOMPRESSED", "1"); string niftiOutPath = floatingFile + ".cmtkrego.out.nii"; string regOutPath = "reg"; var args = $"-o \"{niftiOutPath}\" --floating \"{floatingFile}\" \"{niftiRefPath}\" \"{regOutPath}\""; ProcessBuilder.CallExecutableFile(CapiConfig.GetConfig().Binaries.reformatx, args, outputDataReceived: updates); return(niftiOutPath); }
public static string ANTSApplyTransforms(string floatingFile, string referenceFile, DataReceivedEventHandler updates = null) { floatingFile = Path.GetFullPath(floatingFile); referenceFile = Path.GetFullPath(referenceFile); string niftiOutPath = Path.Combine("warped.nii"); string args = $"-d 3 --float 1 -i \"{floatingFile}\" -r \"{referenceFile}\" -o \"{niftiOutPath}\" -n Linear -t \"{niftiOutPath}0GenericAffine.mat\""; ProcessBuilder.CallExecutableFile(CapiConfig.GetConfig().Binaries.antsApplyTransforms, args, outputDataReceived: updates); return(niftiOutPath); }
/// <summary> /// Uses the BrainSuite BSE tool to extract the brain from a given INifti. /// </summary> /// <param name="input">Nifti which contains the brain to be extracted</param> /// <param name="updates">Data handler for updates from the BSE tool.</param> /// <returns>The INifti containing the extracted brain.</returns> public static INifti <float> BrainSuiteBSE(INifti <float> input, DataReceivedEventHandler updates = null) { // Setup our temp file names. string niftiInPath = Path.GetFullPath(Tools.TEMPDIR + input.GetHashCode() + ".bse.in.nii"); string niftiOutPath = Path.GetFullPath(Tools.TEMPDIR + input.GetHashCode() + ".bse.out.nii"); // Write nifti to temp directory. input.WriteNifti(niftiInPath); var args = $"--auto --trim -i \"{niftiInPath}\" -o \"{niftiOutPath}\""; ProcessBuilder.CallExecutableFile(CapiConfig.GetConfig().Binaries.bse, args, outputDataReceived: updates); var output = input.DeepCopy(); // Sometimes this messes with the header and gives us a 4-up??? output.ReadNifti(niftiOutPath); return(output); }
/// <summary> /// Uses the ANTS implementation of the N4 bias correction algorithm. /// </summary> /// <param name="input">The input nifti to be corrected</param> /// <param name="updates">Event handler for updates from the process</param> /// <returns>New, corrected nifti</returns> public static INifti <float> AntsN4(INifti <float> input, DataReceivedEventHandler updates = null) { // Setup our temp file names. string niftiInPath = Path.GetFullPath(Tools.TEMPDIR + input.GetHashCode() + ".antsN4.in.nii"); string niftiOutPath = Path.GetFullPath(Tools.TEMPDIR + input.GetHashCode() + ".antsN4.out.nii"); // Write nifti to temp directory. input.WriteNifti(niftiInPath); var args = $"-i \"{niftiInPath}\" -o \"{niftiOutPath}\""; ProcessBuilder.CallExecutableFile(CapiConfig.GetConfig().Binaries.N4BiasFieldCorrection, args, outputDataReceived: updates); var output = input.DeepCopy(); output.ReadNifti(niftiOutPath); output.RecalcHeaderMinMax(); return(output); }
public static string ANTSRegistration(string floatingFile, string fixedFile, DataReceivedEventHandler updates = null) { string niftiOutPath = floatingFile + "warped.nii"; // ANTS didn't like me splitting args into a nicely tabbed string so it's all one big line. // --dimensionality 3 :: we have a 3-d image // --float 1 :: we want to keep things floating point // --interpolation Linear :: using linear interpolation for the warped image // --use-histogram-matching 0 :: histogram matching is pre-normalisation (we're avoiding this in case we have hyper-intense fat on one and not the other) // --initial-moving-transform [{fixedFile},{floatingFile}, 1] :: inputs // --transform Rigid[0.1] :: using an rigid transform (6 degrees of freedom, linear) // --metric MI[{fixedFile},{floatingFile},1,32,Regular,0.25] :: metric is mutual information, although we could use cross correlation so long as we're registering the same sequence type // --convergence [1000x500x250x100,1e-6,10] :: convergence is the iterations at each level and the threashold for imporovement in the metric // --shrink-factors 8x4x2x1 :: shrink factors control the resolution at each level // --smoothing-sigmas 3x2x1x0vox :: not really sure what smoothing sigmas do but the values should be fine // --output [_, {niftiOutPath}] :: output the transform value + our sweet nifti file. var args = $" --dimensionality 3 --float 1 --interpolation Linear --use-histogram-matching 0 --initial-moving-transform [\"{fixedFile}\",\"{floatingFile}\", 1] --transform Affine[0.1] --metric MI[\"{fixedFile}\",\"{floatingFile}\",1,32,Regular,0.25] --convergence [1000x500x250x100,1e-6,10] --shrink-factors 8x4x2x1 --smoothing-sigmas 3x2x1x0vox --output [\"{niftiOutPath}\", \"{niftiOutPath}\"]"; ProcessBuilder.CallExecutableFile(CapiConfig.GetConfig().Binaries.antsRegistration, args, outputDataReceived: updates); return(niftiOutPath); }
/// <summary> /// Converts the given Dicom path to a nifti file which is loaded and returned as a nifti object. /// </summary> /// <param name="dicomPath">Path to the DICOM</param> /// <param name="updates">Event handler to handle updates.</param> /// <returns></returns> public static string Dcm2Nii(string dicomPath, string name, DataReceivedEventHandler updates = null) { if (!FileSystem.DirectoryIsValidAndNotEmpty(dicomPath)) { Log.GetLogger().Error("Directory " + dicomPath + " does not seem to exist, or is empty."); return(null); } var niftiPath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(dicomPath), name)); var tmpDir = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(niftiPath), "tmp")); if (Directory.Exists(tmpDir)) { Directory.Delete(tmpDir, true); } FileSystem.DirectoryExistsIfNotCreate(tmpDir); var args = $" -o \"{tmpDir}\" \"{dicomPath}\""; ProcessBuilder.CallExecutableFile(CapiConfig.GetConfig().Binaries.dcm2niix, args, outputDataReceived: updates); if (!Directory.Exists(tmpDir)) { throw new DirectoryNotFoundException("dcm2niix output folder does not exist!"); } var outFiles = Directory.GetFiles(tmpDir); // Rather than cracking a tanty when we have more than one nii in the stack, we're just going to use the biggest one. // This is in case we have a reference slide at the front or end of the dicom stack, which can happen. var nims = outFiles.Where(f => Path.GetExtension(f) == ".nii").OrderByDescending(f => new FileInfo(f)?.Length); var nim = nims.FirstOrDefault(); if (nim == null) { if (!File.Exists(CapiConfig.GetConfig().Binaries.dcm2niix)) { Log.GetLogger().Error("Could not find dcm2niix at: " + CapiConfig.GetConfig().Binaries.dcm2niix); } var log = Log.GetLogger(); log.Error("Could not find valid output for dcm2niix. Files output were: "); foreach (var of in outFiles) { log.Error($"[{of}]"); } throw new FileNotFoundException("Could not find output of dcm2niix"); } if (File.Exists(niftiPath)) { File.Delete(niftiPath); } File.Move(nim, niftiPath); Directory.Delete(tmpDir, true); return(niftiPath); }