3 #include <itkConnectedComponentImageFilter.h> 4 #include <itkRelabelComponentImageFilter.h> 5 #include <itkImageRegionIterator.h> 6 #include <itkMultiThreaderBase.h> 7 #include <vnl/vnl_matrix.h> 9 #include <tclap/CmdLine.h> 13 int main(
int argc,
char **argv)
15 TCLAP::CmdLine cmd(
"Computes from two segmentations the connected components that grew (L=3), were already there (L=1), or are new (L=2).\n INRIA / IRISA - VisAGeS/Empenn Team",
' ', ANIMA_VERSION);
28 TCLAP::ValueArg <std::string> refArg(
"r",
"ref",
"Reference binary segmentation",
true,
"",
"reference segmentation", cmd);
29 TCLAP::ValueArg <std::string> testArg(
"t",
"test",
"Test binary segmentation",
true,
"",
"test segmentation", cmd);
30 TCLAP::ValueArg <std::string> outArg(
"o",
"out",
"output image with labeled lesions",
true,
"",
"output labeled lesions", cmd);
32 TCLAP::ValueArg <double> alphaArg(
"a",
"alpha",
"Alpha threshold (in between 0 and 1, default: 0)",
false, 0,
"alpha threshold", cmd);
33 TCLAP::ValueArg <double> gammaArg(
"g",
"gamma",
"Gamma threshold (*100 %, default: 0.5)",
false, 0.5,
"gamma threshold", cmd);
34 TCLAP::ValueArg <double> gammaAbsoluteArg(
"G",
"gamma-abs",
"Gamma threshold (in mm3, default: 12)",
false, 12,
"gamma absolute threshold", cmd);
35 TCLAP::ValueArg <double> betaArg(
"b",
"beta",
"Beta threshold (in between 0 and 1, default: 0.05)",
false, 0.05,
"beta threshold", cmd);
37 TCLAP::ValueArg <unsigned int> minVolumeArg(
"m",
"min-vol",
"Minimal volume for the component to be considered (default: 6 mm3)",
false, 6,
"minimal volume", cmd);
38 TCLAP::ValueArg <unsigned int> nbpArg(
"T",
"numberofthreads",
"Number of threads to run on (default : all cores)",
false,itk::MultiThreaderBase::GetGlobalDefaultNumberOfThreads(),
"number of threads",cmd);
40 TCLAP::SwitchArg fullConnectArg(
"F",
"full-connect",
"Use 26-connectivity instead of 6-connectivity",cmd,
false);
44 cmd.parse(argc, argv);
46 catch (TCLAP::ArgException& e)
48 std::cerr <<
"Error: " << e.error() <<
"for argument " << e.argId() << std::endl;
52 typedef itk::Image <unsigned short, 3> ImageType;
53 typedef itk::ImageRegionIterator <ImageType> ImageIteratorType;
55 ImageType::Pointer refSegmentation = anima::readImage <ImageType> (refArg.getValue());
56 ImageType::Pointer testSegmentation = anima::readImage <ImageType> (testArg.getValue());
58 typedef itk::ConnectedComponentImageFilter <ImageType, ImageType> CCFilterType;
59 typedef itk::RelabelComponentImageFilter <ImageType, ImageType> RelabelComponentFilterType;
61 CCFilterType::Pointer refCCFilter = CCFilterType::New();
62 refCCFilter->SetInput(refSegmentation);
63 refCCFilter->SetFullyConnected(fullConnectArg.isSet());
64 refCCFilter->SetNumberOfWorkUnits(nbpArg.getValue());
65 refCCFilter->Update();
67 ImageType::SpacingType spacing = refSegmentation->GetSpacing();
68 ImageType::SpacingValueType spacingTot = spacing[0];
69 for (
unsigned int i = 1;i < 3;++i)
70 spacingTot *= spacing[i];
73 unsigned int minSizeInVoxel = static_cast <
unsigned int> (std::ceil(minVolumeArg.getValue() / spacingTot));
76 RelabelComponentFilterType::Pointer relabelRefFilter = RelabelComponentFilterType::New();
77 relabelRefFilter->SetInput(refCCFilter->GetOutput());
78 relabelRefFilter->SetMinimumObjectSize(minSizeInVoxel);
79 relabelRefFilter->SetNumberOfWorkUnits(nbpArg.getValue());
80 relabelRefFilter->Update();
83 refSegmentation = relabelRefFilter->GetOutput();
84 refSegmentation->DisconnectPipeline();
86 CCFilterType::Pointer testCCFilter = CCFilterType::New();
87 testCCFilter->SetInput(testSegmentation);
88 testCCFilter->SetFullyConnected(fullConnectArg.isSet());
89 testCCFilter->SetNumberOfWorkUnits(nbpArg.getValue());
90 testCCFilter->Update();
93 RelabelComponentFilterType::Pointer relabelTestFilter = RelabelComponentFilterType::New();
94 relabelTestFilter->SetInput(testCCFilter->GetOutput());
95 relabelTestFilter->SetMinimumObjectSize(minSizeInVoxel);
96 relabelTestFilter->SetNumberOfWorkUnits(nbpArg.getValue());
97 relabelTestFilter->Update();
100 testSegmentation = relabelTestFilter->GetOutput();
101 testSegmentation->DisconnectPipeline();
103 ImageIteratorType testItr(testSegmentation, testSegmentation->GetLargestPossibleRegion());
105 unsigned short maxTestLabel = 0;
106 while (!testItr.IsAtEnd())
108 if (testItr.Get() > maxTestLabel)
109 maxTestLabel = testItr.Get();
116 ImageIteratorType refItr(refSegmentation, refSegmentation->GetLargestPossibleRegion());
117 std::vector <unsigned int> labelsOverlap(maxTestLabel,0);
118 std::vector <unsigned int> labelsNonOverlapping(maxTestLabel,0);
119 std::vector <unsigned int> labelsSizes(maxTestLabel,0);
121 ImageType::Pointer subImage = ImageType::New();
122 subImage->Initialize();
123 subImage->SetRegions(testSegmentation->GetLargestPossibleRegion());
124 subImage->SetSpacing (testSegmentation->GetSpacing());
125 subImage->SetOrigin (testSegmentation->GetOrigin());
126 subImage->SetDirection (testSegmentation->GetDirection());
127 subImage->Allocate();
128 ImageIteratorType subItr(subImage,testSegmentation->GetLargestPossibleRegion());
131 while (!refItr.IsAtEnd())
133 if (refItr.Get() != 0)
134 labelsOverlap[testItr.Get()]++;
136 labelsNonOverlapping[testItr.Get()]++;
138 labelsSizes[testItr.Get()]++;
144 std::cout <<
"Processing " << maxTestLabel <<
" lesions in second timepoint..." << std::endl;
145 for (
unsigned int i = 1;i < maxTestLabel;++i)
148 double ratioNonOverlapOverlap = static_cast <
double> (labelsNonOverlapping[i]) / labelsOverlap[i];
150 if ((labelsNonOverlapping[i] <= minSizeInVoxel) || (ratioNonOverlapOverlap <= betaArg.getValue()))
152 while (!testItr.IsAtEnd())
154 if (testItr.Get() == i)
155 testItr.Set(maxTestLabel + 1);
164 double ratioOverlapSizes = static_cast <
double> (labelsOverlap[i]) / labelsSizes[i];
165 if (ratioOverlapSizes <= alphaArg.getValue())
167 while (!testItr.IsAtEnd())
169 if (testItr.Get() == i)
170 testItr.Set(maxTestLabel + 2);
179 if ((ratioNonOverlapOverlap > gammaArg.getValue()) && (labelsNonOverlapping[i] * spacingTot > gammaAbsoluteArg.getValue()))
182 while (!testItr.IsAtEnd())
184 if (testItr.Get() == i)
185 testItr.Set(maxTestLabel + 2);
194 subImage->FillBuffer(0);
197 while (!testItr.IsAtEnd())
199 if ((testItr.Get() == i)&&(refItr.Get() == 0))
207 CCFilterType::Pointer tmpCCFilter = CCFilterType::New();
208 tmpCCFilter->SetInput(subImage);
209 tmpCCFilter->SetFullyConnected(fullConnectArg.isSet());
210 tmpCCFilter->SetNumberOfWorkUnits(nbpArg.getValue());
211 tmpCCFilter->Update();
214 RelabelComponentFilterType::Pointer relabelTmpCCFilter = RelabelComponentFilterType::New();
215 relabelTmpCCFilter->SetInput(tmpCCFilter->GetOutput());
216 relabelTmpCCFilter->SetMinimumObjectSize(0);
217 relabelTmpCCFilter->SetNumberOfWorkUnits(nbpArg.getValue());
218 relabelTmpCCFilter->Update();
220 ImageIteratorType subCCItr(relabelTmpCCFilter->GetOutput(),testSegmentation->GetLargestPossibleRegion());
221 std::vector <unsigned int> numVoxelsCCSub(1);
222 while (!subCCItr.IsAtEnd())
224 unsigned int currentSize = numVoxelsCCSub.size();
225 unsigned int value = subCCItr.Get();
227 if (value >= currentSize)
229 numVoxelsCCSub.resize(value + 1);
230 for (
unsigned int j = currentSize;j <= value;++j)
231 numVoxelsCCSub[j] = 0;
234 numVoxelsCCSub[value]++;
238 unsigned int numSubLabels = numVoxelsCCSub.size() - 1;
239 double ratioOverlap = static_cast <
double> (numVoxelsCCSub[numSubLabels]) / labelsOverlap[i];
240 bool okGrowing = (ratioOverlap > betaArg.getValue());
246 while (!refItr.IsAtEnd())
248 if (testItr.Get() == i)
250 if (refItr.Get() == 0)
251 testItr.Set(maxTestLabel + 3);
253 testItr.Set(maxTestLabel + 1);
263 while (!testItr.IsAtEnd())
265 if (testItr.Get() == i)
266 testItr.Set(maxTestLabel + 1);
274 while (!testItr.IsAtEnd())
276 unsigned int value = testItr.Get();
278 testItr.Set(value - maxTestLabel);
283 std::cout <<
"Writing output to " << outArg.getValue() << std::endl;
285 anima::writeImage <ImageType> (outArg.getValue(),testSegmentation);
int main(int argc, char **argv)