From aef8b1742e673931c1b4a59b286cbe477c8713dd Mon Sep 17 00:00:00 2001 From: alexandergetka Date: Tue, 22 Feb 2022 06:51:18 -0500 Subject: [PATCH 01/10] correct 4D check conditions Check needed to be done for loading 4D and having 4D loaded. --- src/view/gui/fMainWindow.cpp | 46 ++++++++++++++++++++++++++++++------ 1 file changed, 39 insertions(+), 7 deletions(-) diff --git a/src/view/gui/fMainWindow.cpp b/src/view/gui/fMainWindow.cpp index a1b31dda6..335289fc7 100644 --- a/src/view/gui/fMainWindow.cpp +++ b/src/view/gui/fMainWindow.cpp @@ -1824,9 +1824,25 @@ void fMainWindow::LoadSlicerImages(const std::string &fileName, const int &image image4DSlider->setEnabled(true); image4DSlider->setRange(0, imageInfo.GetImageSize()[3] - 1); ImageTypeFloat4D::Pointer imagePerf = cbica::ReadImage(fname); - imageManager->SetPerfImage(imagePerf); + imageManager->mImageSubType = CAPTK::ImageModalityType::IMAGE_TYPE_PERFUSION; - //return; + imageManager->SetOriginalOrigin(imageInfo.GetImageOrigins()); // Fix missing (3D) origins for 4D + /*auto originalDirection = imageInfo.GetImageDirections(); + ImageTypeFloat3D::DirectionType originalDirectionIn3D; + for (int i = 0; i < 3; i++) + { + for (int j = 0; j < 3; j++) + { + originalDirectionIn3D[i][j] = originalDirection[i][j]; + } + } + imageManager->SetOriginalDirection(originalDirectionIn3D); + */ + //auto tempImage = cbica::GetImageOrientation< ImageTypeFloat4D >(imagePerf); + //imageManager->SetOriginalOrientation(tempImage.first); + //imagePerf = ChangeImageDirectionToIdentity< ImageTypeFloat4D >(tempImage.second); + imageManager->SetPerfImage(imagePerf); + //return; } else { @@ -5816,18 +5832,34 @@ void fMainWindow::openImages(QStringList files, bool callingFromCmd) } else { + if (!((extension == ".ima") || (extension == ".nii") || (extension == ".nii.gz"))) { unsupportedExtension += fileName + "\n"; } - else if (!cbica::ImageSanityCheck(fileForSanityCheck, files[i].toStdString())) - { - erroredFiles += fileName + "\n"; - } else { - basicSanityChecksPassedFiles.push_back(files[i].toStdString()); + // This 4D check is duplicated here from LoadSlicerImages, + // because it has to be for us to correctly know to use 4D sanity checks below. + // TBD: This needs a refactor for clarity. + auto imageInfo = cbica::ImageInfo(fileName); + bool fourDImage = false; + int dimsOfImage0 = cbica::ImageInfo(fileForSanityCheck).GetImageDimensions(); + if ((imageInfo.GetImageDimensions() == 4) || (dimsOfImage0 == 4)) + { + fourDImage = true; + } + if (!cbica::ImageSanityCheck(fileForSanityCheck, files[i].toStdString(), fourDImage)) + { + erroredFiles += fileName + "\n"; + } + else + { + basicSanityChecksPassedFiles.push_back(files[i].toStdString()); + } + } + } } From 825dbdac98b76b8c0d8921193cae4788d95b64f4 Mon Sep 17 00:00:00 2001 From: alexandergetka Date: Tue, 22 Feb 2022 10:35:19 -0500 Subject: [PATCH 02/10] Time points (current/max) on 4D-scroll-bar --- src/view/gui/fMainWindow.cpp | 4 ++++ src/view/gui/ui_fMainWindow.h | 18 +++++++++++++++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/view/gui/fMainWindow.cpp b/src/view/gui/fMainWindow.cpp index 335289fc7..6012e31f8 100644 --- a/src/view/gui/fMainWindow.cpp +++ b/src/view/gui/fMainWindow.cpp @@ -1823,8 +1823,11 @@ void fMainWindow::LoadSlicerImages(const std::string &fileName, const int &image { image4DSlider->setEnabled(true); image4DSlider->setRange(0, imageInfo.GetImageSize()[3] - 1); + image4DMaxSliceIndicator->setText(QString::fromStdString(" / " + std::to_string(imageInfo.GetImageSize()[3]))); + //Update4DSliderInfo(); ImageTypeFloat4D::Pointer imagePerf = cbica::ReadImage(fname); + imageManager->mImageSubType = CAPTK::ImageModalityType::IMAGE_TYPE_PERFUSION; imageManager->SetOriginalOrigin(imageInfo.GetImageOrigins()); // Fix missing (3D) origins for 4D /*auto originalDirection = imageInfo.GetImageDirections(); @@ -5644,6 +5647,7 @@ void fMainWindow::imageSliderChanged() if (mSlicerManagers[index]->mImageSubType == CAPTK::ImageModalityType::IMAGE_TYPE_PERFUSION) { mSlicerManagers[index]->Get3DImageAtCurrentPerfusionIndex(value); + image4DCurrentSliceIndicator->setText(QString::fromStdString(std::to_string(value+1))); } AxialViewSliderChanged(); mSlicerManagers[index]->Picked(); diff --git a/src/view/gui/ui_fMainWindow.h b/src/view/gui/ui_fMainWindow.h index 72c2a85eb..cc43b5ddf 100644 --- a/src/view/gui/ui_fMainWindow.h +++ b/src/view/gui/ui_fMainWindow.h @@ -44,6 +44,10 @@ class Ui_fMainWindow public: QSlider *image4DSlider; + QLabel* image4DTimeLabel; + QLabel* image4DCurrentSliceIndicator; + QLabel* image4DMaxSliceIndicator; + QHBoxLayout* image4DBarLayout; QGroupBox *preferencesGroupBox; QWidget *centralwidget; @@ -146,7 +150,19 @@ class Ui_fMainWindow image4DSlider->setPageStep(1); image4DSlider->setSliderPosition(5); image4DSlider->setOrientation(Qt::Horizontal); - overallGridLayout->addWidget(image4DSlider, 1, 0, 1, 3); + image4DTimeLabel = new QLabel(centralwidget); + image4DTimeLabel->setText("Time: "); + image4DCurrentSliceIndicator = new QLabel(centralwidget); + image4DCurrentSliceIndicator->setText("1"); + image4DMaxSliceIndicator = new QLabel(centralwidget); + image4DMaxSliceIndicator->setText(" / 1"); + image4DBarLayout = new QHBoxLayout(centralwidget); + image4DBarLayout->addWidget(image4DTimeLabel, 0); + image4DBarLayout->addWidget(image4DCurrentSliceIndicator, 0); + image4DBarLayout->addWidget(image4DMaxSliceIndicator, 0); + image4DBarLayout->addWidget(image4DSlider, 0); + overallGridLayout->addLayout(image4DBarLayout, 1, 0, 1, 3); + //overallGridLayout->addWidget(image4DSlider, 1, 0, 1, 3); //--------------------------------------------------------------------------------------- preferencesGroupBox = new QGroupBox(centralwidget); //-------------------preferences related objects---------------------- From 822b4198c3732b0d5e8d91a3fb2a6ee27cc4eb08 Mon Sep 17 00:00:00 2001 From: alexandergetka Date: Tue, 22 Feb 2022 11:19:17 -0500 Subject: [PATCH 03/10] Add time-point message on GUI --- src/view/gui/fMainWindow.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/view/gui/fMainWindow.cpp b/src/view/gui/fMainWindow.cpp index 6012e31f8..f71061ee9 100644 --- a/src/view/gui/fMainWindow.cpp +++ b/src/view/gui/fMainWindow.cpp @@ -1824,7 +1824,6 @@ void fMainWindow::LoadSlicerImages(const std::string &fileName, const int &image image4DSlider->setEnabled(true); image4DSlider->setRange(0, imageInfo.GetImageSize()[3] - 1); image4DMaxSliceIndicator->setText(QString::fromStdString(" / " + std::to_string(imageInfo.GetImageSize()[3]))); - //Update4DSliderInfo(); ImageTypeFloat4D::Pointer imagePerf = cbica::ReadImage(fname); @@ -6738,6 +6737,12 @@ void fMainWindow::ApplicationEGFR() QString::number(EGFRStatusParams[4]) + "/" + QString::number(farIndices.size()) + "\n\n\n----------\n\nPHI Threshold = 0.1377\n[based on 142 UPenn brain tumor scans]"; + msg = msg + "\n\nNote that processing was conducted on all detected time points (" + + QString::number(perfusionImage->GetLargestPossibleRegion().GetSize()[3])+ + ") of the given DSC-MRI image." + + "\nUPenn scans used for analysis typically contain 45 time points." + + "\nIn order to select a number of time points to use, or to do batch processing, please use the command-line interface."; + updateProgress(0); ShowMessage(msg.toStdString(), this); } From 64308f2f92b282d51b49387d32d5096a94e9219b Mon Sep 17 00:00:00 2001 From: alexandergetka Date: Tue, 22 Feb 2022 21:45:09 -0500 Subject: [PATCH 04/10] Add batch processing and time point selection to PHI --- 3_HowToGuides.txt | 4 + src/applications/EGFRvIIISurrogateIndex.cxx | 338 +++++++++++++++++--- 2 files changed, 295 insertions(+), 47 deletions(-) diff --git a/3_HowToGuides.txt b/3_HowToGuides.txt index 4cddb728b..816c999a5 100644 --- a/3_HowToGuides.txt +++ b/3_HowToGuides.txt @@ -560,6 +560,10 @@ This application evaluates the Epidermal Growth Factor Receptor splice variant I - This application is also available as with a stand-alone CLI for data analysts to build pipelines around, using the following example command: \verbatim ${CaPTk_InstallDir}/bin/EGFRvIIISurrogateIndex.exe -i C:/inputDSCImage.nii.gz -m C:/maskWithNearAndFarLabels.nii.gz +\endverbatim + - Additionally, you can process a batch directory (subdirectories are subjects, and each must have a perfusion and mask image). Pass "--help" to the CLI application for more details. +\verbatim +${CaPTk_InstallDir}/bin/EGFRvIIISurrogateIndex.exe -b C:/inputDirectory/ -o C:/output.csv \endverbatim RULES FOR ROI ANNOTATION: diff --git a/src/applications/EGFRvIIISurrogateIndex.cxx b/src/applications/EGFRvIIISurrogateIndex.cxx index 0dc7c7727..d77537b34 100644 --- a/src/applications/EGFRvIIISurrogateIndex.cxx +++ b/src/applications/EGFRvIIISurrogateIndex.cxx @@ -2,70 +2,314 @@ #include "cbicaCmdParser.h" #include "cbicaUtilities.h" #include "cbicaITKSafeImageIO.h" +#include + +//returns pair of int (return code) and vector (EGFRStatus) +std::pair> RunForSingleSubject(const std::string inputFile, const std::string drawingFile, + const int userTimePoints = -1) +{ + // returns EXIT_SUCCESS (0) if all good, EXIT_FAILURE(1) otherwise + + if (!cbica::fileExists(inputFile)) + { + std::cerr << "Input image file not found :'" << inputFile << "'\n"; + return std::make_pair(EXIT_FAILURE, std::vector()); + } + + if (!cbica::fileExists(drawingFile)) + { + std::cerr << "Input mask file not found :'" << drawingFile << "'\n"; + return std::make_pair(EXIT_FAILURE, std::vector()); + } + + + std::cout << "Reading inputs.\n"; + using ImageType = itk::Image< float, 3 >; + using ImageTypePerfusion = itk::Image< float, 4 >; + auto perfusionImage = cbica::ReadImage< ImageTypePerfusion >(inputFile); + auto mask = cbica::ReadImage< ImageType >(drawingFile); + int timePointsInImage = perfusionImage->GetLargestPossibleRegion().GetSize()[3]; + + int timePointsToUse = 0; + + if (userTimePoints == -1) + { + timePointsToUse = timePointsInImage; + std::cout << "Found " << std::to_string(timePointsInImage) << " time points in image." << std::endl; + std::cout << "If you wish to process fewer time points, specify the -t parameter." << std::endl; + } + + if (userTimePoints > timePointsInImage) + { + std::cerr << "Error: Requested number of time points is greater than those present in the image." << std::endl; + std::cerr << "To resolve, specify a value within bounds." << std::endl; + return std::make_pair(EXIT_FAILURE, std::vector()); + } + + // Handle case where time points are specified and valid (within image bounds) + auto finalPerfusionImage = ImageTypePerfusion::New(); + if (userTimePoints > 1 && userTimePoints <= timePointsInImage) + { + std::cout << "Using " + std::to_string(userTimePoints) + " time points from perfusion image." << std::endl; + typedef itk::ExtractImageFilter ExtractFilterType; + ExtractFilterType::Pointer extractFilter = ExtractFilterType::New(); + extractFilter->SetDirectionCollapseToSubmatrix(); + ImageTypePerfusion::RegionType inputRegion = perfusionImage->GetLargestPossibleRegion(); + ImageTypePerfusion::SizeType size = inputRegion.GetSize(); + size[3] = userTimePoints; + ImageTypePerfusion::IndexType start = inputRegion.GetIndex(); + ImageTypePerfusion::RegionType desiredRegion; + desiredRegion.SetSize(size); + desiredRegion.SetIndex(start); + extractFilter->SetExtractionRegion(desiredRegion); + extractFilter->SetInput(perfusionImage); + extractFilter->Update(); + finalPerfusionImage = extractFilter->GetOutput(); + finalPerfusionImage->DisconnectPipeline(); + + } + else // Use all time points instead, no extraction needed + { + finalPerfusionImage = perfusionImage; + } + + + std::vector nearIndices, farIndices; + + itk::ImageRegionIteratorWithIndex< ImageType > maskIt(mask, mask->GetLargestPossibleRegion()); + for (maskIt.GoToBegin(); !maskIt.IsAtEnd(); ++maskIt) + { + if (maskIt.Get() == 1) + nearIndices.push_back(maskIt.GetIndex()); + else if (maskIt.Get() == 2) + farIndices.push_back(maskIt.GetIndex()); + } + if (nearIndices.size() == 0) + { + std::cerr << "Mask file does not have near indices with label=1. \n"; + return std::make_pair(EXIT_FAILURE, std::vector()); + } + if (farIndices.size() == 0) + { + std::cerr << "Mask file does not have far indices with label=2. \n"; + return std::make_pair(EXIT_FAILURE, std::vector()); + } + EGFRStatusPredictor egfrEstimator; + auto extension = cbica::getFilenameExtension(inputFile); + std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); + auto EGFRStatusParams = egfrEstimator.PredictEGFRStatus< ImageType, ImageTypePerfusion >(finalPerfusionImage, nearIndices, farIndices); + + std::cout << "Printing results...\n\n"; + std::cout << "PHI Value = " << EGFRStatusParams[0] << "\n"; + std::cout << "Peak Height Ratio = " << EGFRStatusParams[1] / EGFRStatusParams[2] << "\n"; + std::cout << "Number of near voxels used = " << EGFRStatusParams[3] << "\n"; + std::cout << "Number of far voxels used = " << EGFRStatusParams[4] << "\n"; + + return std::make_pair(EXIT_SUCCESS, EGFRStatusParams); +} int main(int argc, char **argv) { auto parser = cbica::CmdParser(argc, argv, "EGFRvIIISurrogateIndex"); - parser.addRequiredParameter("i", "image", cbica::Parameter::FILE, "NIfTI", "Input Perfusion image on which computation is done"); - parser.addRequiredParameter("m", "mask", cbica::Parameter::FILE, "NIfTI", "Mask containing near (1) and far (2) labels"); + parser.addOptionalParameter("i", "image", cbica::Parameter::FILE, "NIfTI", "Input Perfusion image on which computation is done"); + parser.addOptionalParameter("m", "mask", cbica::Parameter::FILE, "NIfTI", "Mask containing near (1) and far (2) labels"); + parser.addOptionalParameter("t", "timePoints", cbica::Parameter::INTEGER, ">1", "Number of time points to use for computation.", "Useful for using a uniform number of points across batch subjects.", "(Defaults to the number of time points present in the image)"); + parser.addOptionalParameter("b", "batchDir", cbica::Parameter::DIRECTORY, "", "Directory of subjects (subdirectories) to run PHI on.", "Each subject subdirectory must have a file with 'DSC' or 'perf' in the basename and a mask with 'mask' in the basename."); + parser.addOptionalParameter("o", "batchOutputFile", cbica::Parameter::FILE, "", "File to place output in for batch processing, csv"); parser.addExampleUsage("-i DSC-MRI_data.nii.gz -m Near_Far_masks.nii.gz", "Based on the near-far mask and input DSC MRI data, the PHI index is calculated"); + parser.addExampleUsage("-b C:/PHI_Subjects -o C:/PHI_Output.csv -t 45", + "For each subject dir in C:/PHI_Subjects, like C:/PHI_Subjects/AAAA/, calculate PHI based on 45 time points and place in C:/PHI_Output.csv ."); parser.addApplicationDescription("Peritumoral Heterogeneity Index calculator"); - std::string inputFile, drawingFile; - - parser.getParameterValue("i", inputFile); - parser.getParameterValue("m", drawingFile); - - if (!cbica::fileExists(inputFile)) + bool singleSubjectMode = false; + bool batchMode = false; + if (parser.isPresent("i") || parser.isPresent("m")) { - std::cerr << "Input image file not found :'" << inputFile << "'\n"; - return EXIT_FAILURE; + singleSubjectMode = true; } - - if (!cbica::fileExists(drawingFile)) + if (parser.isPresent("b") || parser.isPresent("o")) { - std::cerr << "Input mask file not found :'" << drawingFile << "'\n"; - return EXIT_FAILURE; + batchMode = true; + } + if (singleSubjectMode && batchMode) + { + std::cerr << "Inconsistent options provided. -i and -m parameters are for single-subject, -b and -o are for batch processing." << std::endl; + std::cerr << "Please check parameters and try again." << std::endl; + return EXIT_FAILURE; + } + if (!singleSubjectMode && !batchMode) + { + std::cerr << "You must specify options for either single-subject mode (-i, -m) or batch mode (-b, -o)." << std::endl; + std::cerr << "Please check parameters and try again." << std::endl; + return EXIT_FAILURE; } - std::cout << "Reading inputs.\n"; - using ImageType = itk::Image< float, 3 >; - using ImageTypePerfusion = itk::Image< float, 4 >; - auto perfusionImage = cbica::ReadImage< ImageTypePerfusion >(inputFile); - auto mask = cbica::ReadImage< ImageType >(drawingFile); - - std::vector nearIndices, farIndices; - - itk::ImageRegionIteratorWithIndex< ImageType > maskIt(mask, mask->GetLargestPossibleRegion()); - for (maskIt.GoToBegin(); !maskIt.IsAtEnd(); ++maskIt) + bool bRequestedTimePoints = false; + int userSpecifiedTimePoints = 0; + if (parser.isPresent("t")) { - if (maskIt.Get() == 1) - nearIndices.push_back(maskIt.GetIndex()); - else if (maskIt.Get() == 2) - farIndices.push_back(maskIt.GetIndex()); + bRequestedTimePoints = true; + std::string timePointsString; + parser.getParameterValue("t", userSpecifiedTimePoints); + + if(userSpecifiedTimePoints <= 1) + { + std::cerr << "The number of provided time points is too low. Specify a value greater than 1." << std::endl; + return EXIT_FAILURE; + } } - if (nearIndices.size()==0) + + if (singleSubjectMode) { - std::cerr << "Mask file does not have near indices with label=1. \n"; - return EXIT_FAILURE; + std::string inputFile, drawingFile; + parser.getParameterValue("i", inputFile); + parser.getParameterValue("m", drawingFile); + + bool singleSubjectRunFailed; + if (bRequestedTimePoints) + { + singleSubjectRunFailed = RunForSingleSubject(inputFile, drawingFile, userSpecifiedTimePoints).first; + } + else + { + singleSubjectRunFailed = RunForSingleSubject(inputFile, drawingFile).first; + } + + if (singleSubjectRunFailed) + { + return EXIT_FAILURE; + } + } - if (farIndices.size() == 0) + else if (batchMode) { - std::cerr << "Mask file does not have far indices with label=2. \n"; - return EXIT_FAILURE; + std::string inputDirStr, outputFileStr; + parser.getParameterValue("b", inputDirStr); + parser.getParameterValue("o", outputFileStr); + std::cout << "Searching in dir " + inputDirStr + " for subject subdirectories." << std::endl; + if (!cbica::directoryExists(inputDirStr)) + { + std::cerr << "Could not read directory " + inputDirStr + ". Check existence and permissions and try again." << std::endl; + return EXIT_FAILURE; + } + + // Write header + std::ofstream outFile; + outFile.open(outputFileStr, ios::trunc); + if (outFile.is_open()) + { + outFile << "Subject Name, PHI Value, Peak Height Ratio, Num Near Voxels Used, Num Far Voxels Used\n"; + outFile.close(); + } + else + { + std::cerr << "Couldn't write to output file. Check permissions." << std::endl; + return EXIT_FAILURE; + } + + auto subjectDirs = cbica::subdirectoriesInDirectory(inputDirStr, false, true); + //QStringList subjectDirs = inputDir.entryList(); + bool anySubjectsFailed = false; + for (int i = 0; i < subjectDirs.size(); i++) + { + // Subject-specific loop -- in here, don't outright return failure, but flag any failures. + std::string currentSubjectDir = subjectDirs[i]; + std::string dirpath, dirbase, dirext; // + cbica::splitFileName(currentSubjectDir, dirpath, dirbase, dirext); + std::string currentSubjectName = dirbase; + std::cout << "Processing subject " + currentSubjectName + " ..." << std::endl; + + std::string possibleInputFile, possibleDrawingFile; + //currentSubjectDir.setFilter(QDir::Files | QDir::Readable); + //QStringList perfNameFilters, drawingNameFilters; + //perfNameFilters << "*perf*.nii.gz" << "*DSC*.nii.gz"; + //auto possibleInputFiles = currentSubjectDir.entryList(perfNameFilters); + //drawingNameFilters << "*mask*.nii.gz" << "*labels*.nii.gz"; + //auto possibleDrawingFiles = currentSubjectDir.entryList(); + auto filesInDir = cbica::filesInDirectory(currentSubjectDir, true); + std::regex perfRegex("(perf|DSC|PERF|dsc)"); + std::regex drawingRegex("(mask|MASK|label|LABEL|near|NEAR|far|FAR)"); + for (int file = 0; file < filesInDir.size(); file++) + { + std::string path, base, ext; + cbica::splitFileName(filesInDir[file], path, base, ext); + if (std::regex_search(base, perfRegex)) + { + possibleInputFile = filesInDir[file]; + continue; + } + if (std::regex_search(base, drawingRegex)) + { + possibleDrawingFile = filesInDir[file]; + continue; + } + } + if (possibleInputFile.empty()) + { + std::cerr << "No input DSC/perfusion NIFTIs found for subject " + currentSubjectName + " , skipping..." << std::endl; + anySubjectsFailed = true; + continue; + } + if (possibleDrawingFile.empty()) + { + std::cerr << "No near/far label NIFTIs found for subject " + currentSubjectName + " , skipping..." << std::endl; + anySubjectsFailed = true; + continue; + } + + bool singleSubjectRunFailed; + std::pair resultFromRun; + if (bRequestedTimePoints) + { + resultFromRun = RunForSingleSubject(possibleInputFile, possibleDrawingFile, userSpecifiedTimePoints); + } + else + { + resultFromRun = RunForSingleSubject(possibleInputFile, possibleDrawingFile); + } + singleSubjectRunFailed = resultFromRun.first > 0; + if (singleSubjectRunFailed) + { + anySubjectsFailed = true; + std::cerr << "Algorithm failed for subject " + currentSubjectName + " . Check logs for details. Skipping..." << std::endl; + continue; + } + else + { + std::vector egfrStatus = resultFromRun.second; + outFile.open(outputFileStr, ios::app); + if (outFile.is_open()) + { + outFile << std::fixed << std::setprecision(4) << currentSubjectName << "," << egfrStatus[0] << "," + << egfrStatus[1] / egfrStatus[2] << "," << egfrStatus[3] << "," << egfrStatus[4] << "\n"; + outFile.close(); + } + else + { + std::cerr << "Couldn't write to file. Check permissions." << std::endl; + return EXIT_FAILURE; + } + + } + + + std::cout << "Finished processing subject " + currentSubjectName + " ." << std::endl; + } + + if (anySubjectsFailed) + { + std::cerr << "Failed to process one or more subjects. Check the console logs for more details." << std::endl; + return EXIT_FAILURE; + } + else + { + std::cout << "Finished processing all subjects successfully." << std::endl; + } + } - EGFRStatusPredictor egfrEstimator; - auto extension = cbica::getFilenameExtension(inputFile); - std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); - auto EGFRStatusParams = egfrEstimator.PredictEGFRStatus< ImageType, ImageTypePerfusion >(perfusionImage, nearIndices, farIndices); - - std::cout << "Printing results...\n\n"; - std::cout << "PHI Value = " << EGFRStatusParams[0] << "\n"; - std::cout << "Peak Height Ratio = " << EGFRStatusParams[1] / EGFRStatusParams[2] << "\n"; - std::cout << "Number of near voxels used = " << EGFRStatusParams[3] << "\n"; - std::cout << "Number of far voxels used = " << EGFRStatusParams[4] << "\n"; - - std::cout << "Finished successfully.\n"; + + // If we get here without failing... return EXIT_SUCCESS; -} \ No newline at end of file +} + From 01e2501ebe7a59350949e571c14086627bcd0372 Mon Sep 17 00:00:00 2001 From: alexandergetka Date: Wed, 23 Feb 2022 09:17:32 -0500 Subject: [PATCH 05/10] Add PerfusionPCA message to clarify requirements --- src/applications/PerfusionPCA.cxx | 3 +++ src/view/gui/fMainWindow.cpp | 7 ++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/applications/PerfusionPCA.cxx b/src/applications/PerfusionPCA.cxx index e5c594061..96b6fb68a 100644 --- a/src/applications/PerfusionPCA.cxx +++ b/src/applications/PerfusionPCA.cxx @@ -146,6 +146,9 @@ int main(int argc, char **argv) if(!object_pca.HasValidSubjects()) { std::cout << "There is no subject with the required input in the given directory." << std::endl; + std::cout << "Make sure that the input directory has subdirectories (each one is one subject), and that each subdirectory two images: " << std::endl; + std::cout << "The perfusion image .nii.gz file must contain '_perf_' in the basename, and" << std::endl; + std::cout << "The segmentation .nii.gz file must contain '_segmentation' in the basename." << std::endl; return EXIT_FAILURE; } diff --git a/src/view/gui/fMainWindow.cpp b/src/view/gui/fMainWindow.cpp index f71061ee9..ebaed3676 100644 --- a/src/view/gui/fMainWindow.cpp +++ b/src/view/gui/fMainWindow.cpp @@ -4594,7 +4594,12 @@ void fMainWindow::PCAEstimateOnExistingModel(QString &inputdirectory, QString &o //check if input has valid subjects if (mPCAEstimator.HasValidSubjects() == 0) { - ShowErrorMessage("The specified directory does not have any subject with all the required imaging sequences."); + std::string msg = "The specified directory does not have any subject with all the required imaging sequences.\n"; + msg += "Make sure that the input directory has subdirectories (each one is one subject), and that each subdirectory two images : \n"; + msg += "The perfusion image .nii.gz file must contain '_perf_' in the basename, and "; + msg += "the segmentation .nii.gz file must end with '_segmentation.nii.gz'."; + + ShowErrorMessage(msg); return; } From 507f85b382d1bf09251011c29de7dc46bde56f2a Mon Sep 17 00:00:00 2001 From: alexandergetka Date: Wed, 23 Feb 2022 09:20:49 -0500 Subject: [PATCH 06/10] Disable mac builds on azure --- azure-pipelines.yml | 300 ++++++++++++++++++++++---------------------- 1 file changed, 150 insertions(+), 150 deletions(-) diff --git a/azure-pipelines.yml b/azure-pipelines.yml index 0a11df9f5..f6b60f83a 100644 --- a/azure-pipelines.yml +++ b/azure-pipelines.yml @@ -561,193 +561,193 @@ jobs: displayName: Uploading to NITRC condition: and( eq(variables['Build.DefinitionName'], 'CBICA.CaPTk'), or( eq(variables['Build.Reason'], 'Manual'), eq(variables['Build.Reason'], 'Schedule')) ) -- job: 'macOS_SelfHost_1014' - displayName: "Self-hosted agent on macOS 10.14" - timeoutInMinutes: 0 - cancelTimeoutInMinutes: 300 +# - job: 'macOS_SelfHost_1014' + # displayName: "Self-hosted agent on macOS 10.14" + # timeoutInMinutes: 0 + # cancelTimeoutInMinutes: 300 - pool: 'macOS_10.14_alt' # Change to alt pool to try running this outside of Phuc's account -- possible permissions problems + # pool: 'macOS_10.14_alt' # Change to alt pool to try running this outside of Phuc's account -- possible permissions problems - steps: - - checkout: self # self represents the repo where the initial Pipelines YAML file was found + # steps: + # - checkout: self # self represents the repo where the initial Pipelines YAML file was found - # submodule - - bash: | - export GIT_LFS_SKIP_SMUDGE=1 - git submodule update --init --recursive + # # submodule + # - bash: | + # export GIT_LFS_SKIP_SMUDGE=1 + # git submodule update --init --recursive - displayName: 'Git Submodule Init and Update' - - # Moving LFS Files - - bash: | - rm -rf bin - mkdir -p bin - cd bin - wget https://github.com/CBICA/CaPTk/raw/master/binaries/precompiledApps/macos.zip -O binaries_macos.zip - wget https://github.com/CBICA/CaPTk/raw/master/binaries/qt_5.12.1/macos.zip -O qt.zip - # mv ../binaries/precompiledApps/macos.zip ./binaries_macos.zip - # mv ../binaries/qt_5.12.1/macos.zip ./qt.zip - ls -lt - displayName: 'Downloading & Moving LFS files to the appropriate location under bin' + # displayName: 'Git Submodule Init and Update' + # # Moving LFS Files # - bash: | - # cd bin + # rm -rf bin + # mkdir -p bin + # cd bin + # wget https://github.com/CBICA/CaPTk/raw/master/binaries/precompiledApps/macos.zip -O binaries_macos.zip + # wget https://github.com/CBICA/CaPTk/raw/master/binaries/qt_5.12.1/macos.zip -O qt.zip + # # mv ../binaries/precompiledApps/macos.zip ./binaries_macos.zip + # # mv ../binaries/qt_5.12.1/macos.zip ./qt.zip + # ls -lt + # displayName: 'Downloading & Moving LFS files to the appropriate location under bin' - # export CMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE - # export CMAKE_PREFIX_PATH="/Library/TeX/texbin" + # # - bash: | + # # cd bin - # cmake ../ -DCMAKE_INSTALL_PREFIX="./install" + # # export CMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE + # # export CMAKE_PREFIX_PATH="/Library/TeX/texbin" - # make -j 2 + # # cmake ../ -DCMAKE_INSTALL_PREFIX="./install" - # displayName: 'Configure and compile Superbuild' + # # make -j 2 - # - bash: | - # # mkdir $(Build.SourcesDirectory)/../superbuild - # # cd bin - # # mv ./* $(Build.SourcesDirectory)/../superbuild - # # cd $(Build.SourcesDirectory)/.. - # # ls - # # echo "Done cd" - # # tar cvfz superbuild.tar.gz superbuild - # # ls - # # echo "done tar" - # # rm -rf superbuild - # # ls - # # cd $(Build.SourcesDirectory) + # # displayName: 'Configure and compile Superbuild' - # pwd + # # - bash: | + # # # mkdir $(Build.SourcesDirectory)/../superbuild + # # # cd bin + # # # mv ./* $(Build.SourcesDirectory)/../superbuild + # # # cd $(Build.SourcesDirectory)/.. + # # # ls + # # # echo "Done cd" + # # # tar cvfz superbuild.tar.gz superbuild + # # # ls + # # # echo "done tar" + # # # rm -rf superbuild + # # # ls + # # # cd $(Build.SourcesDirectory) - # cd $(Build.SourcesDirectory)/../../ - # ls - # tar xvfz superbuild.tar.gz - # rm -rf superbuild.tar.gz - # cd $(Build.SourcesDirectory)/../../superbuild/bin - # ls - # echo "Done tar" - # displayName: 'Move superbuild and qt and compiled apps' + # # pwd - - bash: | - git pull origin master - git log -1 - cat CMakeLists.txt | grep -i "PROJECT_VERSION" - displayName: 'Testing git pull and version' + # # cd $(Build.SourcesDirectory)/../../ + # # ls + # # tar xvfz superbuild.tar.gz + # # rm -rf superbuild.tar.gz + # # cd $(Build.SourcesDirectory)/../../superbuild/bin + # # ls + # # echo "Done tar" + # # displayName: 'Move superbuild and qt and compiled apps' - - bash: | - cd bin - pwd + # - bash: | + # git pull origin master + # git log -1 + # cat CMakeLists.txt | grep -i "PROJECT_VERSION" + # displayName: 'Testing git pull and version' - rm -rf CaPTk_* + # - bash: | + # cd bin + # pwd - export CMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE - export CMAKE_PREFIX_PATH=/Users/Shared/superbuild/ITK-build:/Users/Shared/superbuild/DCMTK-build:/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5:/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5Core:$(pwd)/qt/5.12.1/clang_64/lib/cmake/Qt5:$(pwd)/qt/5.12.1/clang_64/lib/cmake/Qt5Core:$CMAKE_PREFIX_PATH - echo "[DEBUG] CMAKE_PREFIX_PATH: " $CMAKE_PREFIX_PATH - #cmake ../ - #rm -f CMakeCache.txt + # rm -rf CaPTk_* + + # export CMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE + # export CMAKE_PREFIX_PATH=/Users/Shared/superbuild/ITK-build:/Users/Shared/superbuild/DCMTK-build:/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5:/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5Core:$(pwd)/qt/5.12.1/clang_64/lib/cmake/Qt5:$(pwd)/qt/5.12.1/clang_64/lib/cmake/Qt5Core:$CMAKE_PREFIX_PATH + # echo "[DEBUG] CMAKE_PREFIX_PATH: " $CMAKE_PREFIX_PATH + # #cmake ../ + # #rm -f CMakeCache.txt - cmake -DITK_DIR="/Users/Shared/superbuild/ITK-build" -DDCMTK_DIR="/Users/Shared/superbuild/DCMTK-build" -DVTK_DIR="/Users/Shared/superbuild/VTK-build" -DCMAKE_INSTALL_PREFIX="./install" -DQt5_DIR=/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5 -DQt5Core_DIR=/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5Core ../ + # cmake -DITK_DIR="/Users/Shared/superbuild/ITK-build" -DDCMTK_DIR="/Users/Shared/superbuild/DCMTK-build" -DVTK_DIR="/Users/Shared/superbuild/VTK-build" -DCMAKE_INSTALL_PREFIX="./install" -DQt5_DIR=/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5 -DQt5Core_DIR=/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5Core ../ - # Debug using vsts' cache - cp CMakeCache.txt /Users/Shared/debug-vsts-getkaa-cmakecache.txt - make -j 2 + # # Debug using vsts' cache + # cp CMakeCache.txt /Users/Shared/debug-vsts-getkaa-cmakecache.txt + # make -j 2 - displayName: 'Configure and compile CaPTk' + # displayName: 'Configure and compile CaPTk' - - bash: | - cd bin + # - bash: | + # cd bin - version=$(grep -i -e "project_version:*" CMakeCache.txt | cut -c24-) + # version=$(grep -i -e "project_version:*" CMakeCache.txt | cut -c24-) - rm -rf CaPTk_$version.app/Contents/Resources/bin/ITK-SNAP.app + # rm -rf CaPTk_$version.app/Contents/Resources/bin/ITK-SNAP.app - rm -rf CaPTk*.app + # rm -rf CaPTk*.app - cmake ../ - rm -f CMakeCache.txt - export CMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE - export CMAKE_PREFIX_PATH=/Users/Shared/superbuild/ITK-build:/Users/Shared/superbuild/DCMTK-build:/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5:/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5Core:/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5:/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5Core:$CMAKE_PREFIX_PATH + # cmake ../ + # rm -f CMakeCache.txt + # export CMAKE_INSTALL_RPATH_USE_LINK_PATH=TRUE + # export CMAKE_PREFIX_PATH=/Users/Shared/superbuild/ITK-build:/Users/Shared/superbuild/DCMTK-build:/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5:/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5Core:/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5:/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5Core:$CMAKE_PREFIX_PATH - cmake -DITK_DIR="/Users/Shared/superbuild/ITK-build" -DDCMTK_DIR="/Users/Shared/superbuild/DCMTK-build" -DCMAKE_INSTALL_PREFIX="./install" -DQt5_DIR=/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5 -DQt5Core_DIR=/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5Core ../ + # cmake -DITK_DIR="/Users/Shared/superbuild/ITK-build" -DDCMTK_DIR="/Users/Shared/superbuild/DCMTK-build" -DCMAKE_INSTALL_PREFIX="./install" -DQt5_DIR=/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5 -DQt5Core_DIR=/Users/Shared/superbuild/qt/5.12.1/clang_64/lib/cmake/Qt5Core ../ - make -j 2 + # make -j 2 - displayName: 'Ensure documentation is picked up properly' + # displayName: 'Ensure documentation is picked up properly' - - bash: | - cd bin + # - bash: | + # cd bin - version=$(grep -i -e "project_version:*" CMakeCache.txt | cut -c24-) - pkgname="_Installer" - pkgname="$version$pkgname" + # version=$(grep -i -e "project_version:*" CMakeCache.txt | cut -c24-) + # pkgname="_Installer" + # pkgname="$version$pkgname" - rm -rf *.pkg - rm -rf install_manifest.txt - make package + # rm -rf *.pkg + # rm -rf install_manifest.txt + # make package - # print dir tree for debug - ls -R _CPack_Packages + # # print dir tree for debug + # ls -R _CPack_Packages - pkgpath="" - if [ -d "$(Build.SourcesDirectory)/bin/_CPack_Packages/OSX/DragNDrop/CaPTk_$version/ALL_IN_ONE/CaPTk_$version.app/" ]; then pkgpath="$(Build.SourcesDirectory)/bin/_CPack_Packages/OSX/DragNDrop/CaPTk_$version/ALL_IN_ONE/CaPTk_$version.app/"; else pkgpath="$(Build.SourcesDirectory)/bin/_CPack_Packages/OSX/DragNDrop/CaPTk_$version/CaPTk_$version.app/"; fi + # pkgpath="" + # if [ -d "$(Build.SourcesDirectory)/bin/_CPack_Packages/OSX/DragNDrop/CaPTk_$version/ALL_IN_ONE/CaPTk_$version.app/" ]; then pkgpath="$(Build.SourcesDirectory)/bin/_CPack_Packages/OSX/DragNDrop/CaPTk_$version/ALL_IN_ONE/CaPTk_$version.app/"; else pkgpath="$(Build.SourcesDirectory)/bin/_CPack_Packages/OSX/DragNDrop/CaPTk_$version/CaPTk_$version.app/"; fi - # Try patching Utilities as late as possible. Seems to be necessary for Utilities specifically. - install_name_tool -change /usr/local/opt/libomp/lib/libomp.dylib @rpath/libomp.dylib $pkgpath/Contents/Resources/bin/Utilities + # # Try patching Utilities as late as possible. Seems to be necessary for Utilities specifically. + # install_name_tool -change /usr/local/opt/libomp/lib/libomp.dylib @rpath/libomp.dylib $pkgpath/Contents/Resources/bin/Utilities - pkgbuild --version $version --identifier com.cbica.captk --install-location /Applications --component $pkgpath ./CaPTk_$version.pkg - - productbuild --synthesize --package CaPTk_$version.pkg ./distribution.xml - - xml=' - - CaPTk_'"$version"' - - - - - - - - - - - - - CaPTk_'"$version"'.pkg - ' - - echo $xml > "./distribution.xml" - - productbuild --distribution ./distribution.xml --resources $(Build.SourcesDirectory)/bin/_CPack_Packages/OSX/DragNDrop/CaPTk_$version/ALL_IN_ONE/CaPTk_$version.app/Contents/Resources/license/ --package-path . ./CaPTk_$pkgname.pkg - - mv *_Installer* $(Build.ArtifactStagingDirectory) - - displayName: 'Package CaPTk (.dmg and .pkg)' - - - task: PublishBuildArtifacts@1 - inputs: - pathtoPublish: '$(Build.ArtifactStagingDirectory)' - artifactName: '$(Build.DefinitionName)_installer_macOS' - - - task: DownloadBuildArtifacts@0 - inputs: - buildType: 'current' - downloadType: 'single' - artifactName: '$(Build.DefinitionName)_installer_macOS' - downloadPath: '$(System.ArtifactsDirectory)' - - - task: CopyFilesOverSSH@0 - inputs: - sshEndpoint: cbicaNITRC - sourceFolder: $(Build.ArtifactStagingDirectory) - contents: '*_Installer.*' - targetFolder: /var/home/groups/captk/htdocs # previously /mnt/gforge-data/gforge/home/groups/captk/downloads - cleanTargetFolder: false - overwrite: true - continueOnError: true - displayName: Uploading to NITRC - condition: and( eq(variables['Build.DefinitionName'], 'CBICA.CaPTk'), or( eq(variables['Build.Reason'], 'Manual'), eq(variables['Build.Reason'], 'Schedule')) ) + # pkgbuild --version $version --identifier com.cbica.captk --install-location /Applications --component $pkgpath ./CaPTk_$version.pkg + + # productbuild --synthesize --package CaPTk_$version.pkg ./distribution.xml + + # xml=' + # + # CaPTk_'"$version"' + # + # + # + # + # + # + # + # + # + # + # + # + # CaPTk_'"$version"'.pkg + # ' + + # echo $xml > "./distribution.xml" + + # productbuild --distribution ./distribution.xml --resources $(Build.SourcesDirectory)/bin/_CPack_Packages/OSX/DragNDrop/CaPTk_$version/ALL_IN_ONE/CaPTk_$version.app/Contents/Resources/license/ --package-path . ./CaPTk_$pkgname.pkg + + # mv *_Installer* $(Build.ArtifactStagingDirectory) + + # displayName: 'Package CaPTk (.dmg and .pkg)' + + # - task: PublishBuildArtifacts@1 + # inputs: + # pathtoPublish: '$(Build.ArtifactStagingDirectory)' + # artifactName: '$(Build.DefinitionName)_installer_macOS' + + # - task: DownloadBuildArtifacts@0 + # inputs: + # buildType: 'current' + # downloadType: 'single' + # artifactName: '$(Build.DefinitionName)_installer_macOS' + # downloadPath: '$(System.ArtifactsDirectory)' + + # - task: CopyFilesOverSSH@0 + # inputs: + # sshEndpoint: cbicaNITRC + # sourceFolder: $(Build.ArtifactStagingDirectory) + # contents: '*_Installer.*' + # targetFolder: /var/home/groups/captk/htdocs # previously /mnt/gforge-data/gforge/home/groups/captk/downloads + # cleanTargetFolder: false + # overwrite: true + # continueOnError: true + # displayName: Uploading to NITRC + # condition: and( eq(variables['Build.DefinitionName'], 'CBICA.CaPTk'), or( eq(variables['Build.Reason'], 'Manual'), eq(variables['Build.Reason'], 'Schedule')) ) # - job: 'Linux_SelfHost_CentOS7' # displayName: "Self-hosted agent on CentOS 7" From b1c14025dadbbc608c1e21df9c488765fbe4b0f0 Mon Sep 17 00:00:00 2001 From: alexandergetka Date: Wed, 23 Feb 2022 09:37:40 -0500 Subject: [PATCH 07/10] Update 3_HowToGuides.txt --- 3_HowToGuides.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/3_HowToGuides.txt b/3_HowToGuides.txt index 816c999a5..f4515d76e 100644 --- a/3_HowToGuides.txt +++ b/3_HowToGuides.txt @@ -1078,11 +1078,11 @@ This application extracts the principal components from DSC-MRI scans as mention REQUIREMENTS: Directory containing the following images in a sub-folder: -# A single DSC-MRI image (filename must contain the text 'perf' or 'PERF' or 'DSC' to be correctly detected e.g. AAAA_perf.nii.gz ) - -# Its corresponding mask for which the measurements need to be extracted (filename must contain the text 'label' or 'segmentation' + -# Its corresponding mask for which the measurements need to be extracted (filename must contain the text 'label' or 'segmentation') to be correctly detected e.g. AAA_label.nii.gz) -# An example directory structure for the input data is as follows: \verbatim - - RootFolder + - RootFolder (this is the one you select for input) - Subject_AAAA - AAAA_perf.nii.gz - AAAA_label.nii.gz From 3e13786dd363e7e52bd892f37ff7492611bbb729 Mon Sep 17 00:00:00 2001 From: Alexander Getka <59709326+AlexanderGetka-cbica@users.noreply.github.com> Date: Tue, 8 Mar 2022 15:55:45 -0500 Subject: [PATCH 08/10] Update 3_HowToGuides.txt --- 3_HowToGuides.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/3_HowToGuides.txt b/3_HowToGuides.txt index f4515d76e..85b2289e9 100644 --- a/3_HowToGuides.txt +++ b/3_HowToGuides.txt @@ -93,7 +93,7 @@ ${CaPTk_InstallDir}/bin/Utilities.exe -i C:/test/dicomFolderWithSingleSubject -o /** \page preprocessing_reg Image Co-registration -This tool registers multiple moving images to a single target image using the Greedy Registration technique [1]. +This tool registers multiple moving images to a single target image using the Greedy Registration technique [1]. This tool is also available from the web on the [CBICA Image Processing Portal](https://ipp.cbica.upenn.edu/). Please see the experiment on the portal for details. REQUIREMENTS: -# A Target image. From c5e02fe1c14eafc6c8b34348da3770bad6dcf4e0 Mon Sep 17 00:00:00 2001 From: Alexander Getka <59709326+AlexanderGetka-cbica@users.noreply.github.com> Date: Tue, 8 Mar 2022 21:41:16 -0500 Subject: [PATCH 09/10] Update EGFRvIIISurrogateIndex.cxx --- src/applications/EGFRvIIISurrogateIndex.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/EGFRvIIISurrogateIndex.cxx b/src/applications/EGFRvIIISurrogateIndex.cxx index d77537b34..2d6e16247 100644 --- a/src/applications/EGFRvIIISurrogateIndex.cxx +++ b/src/applications/EGFRvIIISurrogateIndex.cxx @@ -5,7 +5,7 @@ #include //returns pair of int (return code) and vector (EGFRStatus) -std::pair> RunForSingleSubject(const std::string inputFile, const std::string drawingFile, +std::pair> RunForSingleSubject(const std::string& inputFile, const std::string drawingFile, const int userTimePoints = -1) { // returns EXIT_SUCCESS (0) if all good, EXIT_FAILURE(1) otherwise From 10440164abb9d4726938db1eea289f3ce1d47447 Mon Sep 17 00:00:00 2001 From: Alexander Getka <59709326+AlexanderGetka-cbica@users.noreply.github.com> Date: Thu, 10 Mar 2022 22:47:25 -0500 Subject: [PATCH 10/10] Update EGFRvIIISurrogateIndex.cxx --- src/applications/EGFRvIIISurrogateIndex.cxx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/applications/EGFRvIIISurrogateIndex.cxx b/src/applications/EGFRvIIISurrogateIndex.cxx index 2d6e16247..6ff6be0ea 100644 --- a/src/applications/EGFRvIIISurrogateIndex.cxx +++ b/src/applications/EGFRvIIISurrogateIndex.cxx @@ -5,7 +5,7 @@ #include //returns pair of int (return code) and vector (EGFRStatus) -std::pair> RunForSingleSubject(const std::string& inputFile, const std::string drawingFile, +std::pair> RunForSingleSubject(const std::string& inputFile, const std::string& drawingFile, const int userTimePoints = -1) { // returns EXIT_SUCCESS (0) if all good, EXIT_FAILURE(1) otherwise