Authors belong to:
- University of LYON http://www.universite-lyon.fr/
- - Léon Bérard cancer center http://oncora1.lyon.fnclcc.fr
+ - Léon Bérard cancer center http://www.centreleonberard.fr
- CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
This software is distributed WITHOUT ANY WARRANTY; without even
- BSD See included LICENSE.txt file
- CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
- ======================================================================-====*/
+ ===========================================================================**/
// clitk
#include "clitkCommon.h"
#include "clitkAutoCropFilter.h"
#include "clitkResampleImageWithOptionsFilter.h"
#include "clitkBooleanOperatorLabelImageFilter.h"
+#include "clitkCropLikeImageFilter.h"
// itk
#include <deque>
#include <itkBinaryErodeImageFilter.h>
#include <itkBinaryBallStructuringElement.h>
#include <itkAddImageFilter.h>
-#include <itkDivideByConstantImageFilter.h>
+#include <itkDivideImageFilter.h>
// itk [Bloch et al]
#include "RelativePositionPropImageFilter.h"
SetBackgroundValue(0);
SetObjectBackgroundValue(0);
ClearOrientationType();
- ResampleBeforeRelativePositionFilterOn();
+ IntermediateSpacingFlagOn();
SetIntermediateSpacing(10);
AutoCropFlagOn();
InverseOrientationFlagOff();
RemoveObjectFlagOn();
CombineWithOrFlagOff();
+ VerboseStepFlagOff();
+ WriteStepFlagOff();
+ FuzzyMapOnlyFlagOff();
+ FastFlagOff();
+ SetRadius(2.0);
+ SetK1(std::acos(-1.0)/2);
}
//--------------------------------------------------------------------
AddOrientationTypeString(std::string t)
{
m_OrientationTypeString.push_back(t);
- switch (t[0]) {
- case 'L' : AddOrientationType(LeftTo); break;
- case 'R' : AddOrientationType(RightTo);break;
- case 'A' : AddOrientationType(AntTo);break;
- case 'P' : AddOrientationType(PostTo);break;
- case 'S' : AddOrientationType(SupTo);break;
- case 'I' : AddOrientationType(InfTo);break;
- default: clitkExceptionMacro("Error, you must provide L,R or A,P or S,I");
- }
+
+ if (t == "LeftTo") { AddOrientationType(LeftTo); return; }
+ if (t == "RightTo") { AddOrientationType(RightTo); return; }
+ if (t == "AntTo") { AddOrientationType(AntTo); return; }
+ if (t == "PostTo") { AddOrientationType(PostTo); return; }
+ if (t == "SupTo") { AddOrientationType(SupTo); return; }
+ if (t == "InfTo") { AddOrientationType(InfTo); return; }
+
+ if (t == "NotLeftTo") { AddOrientationType(LeftTo); InverseOrientationFlagOn(); return; }
+ if (t == "NotRightTo") { AddOrientationType(RightTo); InverseOrientationFlagOn(); return; }
+ if (t == "NotAntTo") { AddOrientationType(AntTo); InverseOrientationFlagOn(); return; }
+ if (t == "NotPostTo") { AddOrientationType(PostTo); InverseOrientationFlagOn(); return; }
+ if (t == "NotSupTo") { AddOrientationType(SupTo); InverseOrientationFlagOn(); return; }
+ if (t == "NotInfTo") { AddOrientationType(InfTo); InverseOrientationFlagOn(); return; }
+
+ if (t == "Angle") return;
+
+ clitkExceptionMacro("Error, you must provide LeftTo,RightTo or AntTo,PostTo or SupTo,InfTo (or NotLeftTo, NotRightTo etc) but you give " << t);
}
//--------------------------------------------------------------------
template <class ImageType>
void
clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
-AddAngles(double a, double b)
+AddAnglesInRad(double a, double b)
{
- AddOrientationTypeString("Angle");
+ m_OrientationTypeString.push_back("Angle");
+ m_OrientationType.push_back(Angle);
m_Angle1.push_back(a);
m_Angle2.push_back(b);
}
//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
+AddAnglesInDeg(double a, double b)
+{
+ AddAnglesInRad(clitk::deg2rad(a), clitk::deg2rad(b));
+}
+//--------------------------------------------------------------------
+
+
//--------------------------------------------------------------------
template <class ImageType>
void
{
m_OrientationType.push_back(orientation);
switch (orientation) {
- case LeftTo:
+ case RightTo:
m_Angle1.push_back(clitk::deg2rad(0));
m_Angle2.push_back(clitk::deg2rad(0));
break;
- case RightTo:
+ case LeftTo:
m_Angle1.push_back(clitk::deg2rad(180));
m_Angle2.push_back(clitk::deg2rad(0));
break;
//--------------------------------------------------------------------
+//--------------------------------------------------------------------
+template <class ImageType>
+void
+clitk::AddRelativePositionConstraintToLabelImageFilter<ImageType>::
+PrintOptions()
+{
+ DD((int)this->GetBackgroundValue());
+ DD((int)this->GetObjectBackgroundValue());
+ DDV(this->GetOrientationTypeString(), (uint)this->GetNumberOfAngles());
+ DD(this->GetIntermediateSpacingFlag());
+ DD(this->GetIntermediateSpacing());
+ DD(this->GetFuzzyThreshold());
+ DD(this->GetAutoCropFlag());
+ DD(this->GetInverseOrientationFlag());
+ DD(this->GetRemoveObjectFlag());
+ DD(this->GetCombineWithOrFlag());
+}
+//--------------------------------------------------------------------
+
+
//--------------------------------------------------------------------
template <class ImageType>
void
clitkExceptionMacro("Add at least one orientation type");
}
+ if (GetVerboseOptionFlag()) {
+ for(int i=0; i<GetNumberOfAngles(); i++) {
+ std::cout << "Orientation \t:" << GetOrientationTypeString(i) << std::endl;
+ }
+ std::cout << "Interm Spacing \t:" << GetIntermediateSpacingFlag() << " " << GetIntermediateSpacing() << "mm" << std::endl;
+ std::cout << "Fuzzy threshold\t:" << GetFuzzyThreshold() << std::endl;
+ std::cout << "AutoCrop \t:" << GetAutoCropFlag() << std::endl;
+ std::cout << "InverseOrient \t:" << GetInverseOrientationFlag() << std::endl;
+ std::cout << "RemoveObject \t:" << GetRemoveObjectFlag() << std::endl;
+ std::cout << "CombineWithOr \t:" << GetCombineWithOrFlag() << std::endl;
+ }
+
// Get input pointer
input = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(0));
object = dynamic_cast<ImageType*>(itk::ProcessObject::GetInput(1));
-
- //--------------------------------------------------------------------
- //--------------------------------------------------------------------
static const unsigned int dim = ImageType::ImageDimension;
- StartNewStep("Initial resample");
- // Step 1 : resample
- if (m_ResampleBeforeRelativePositionFilter) {
- typedef clitk::ResampleImageWithOptionsFilter<ImageType> ResampleFilterType;
- typename ResampleFilterType::Pointer resampleFilter = ResampleFilterType::New();
- resampleFilter->SetInput(object);
- resampleFilter->SetOutputIsoSpacing(m_IntermediateSpacing);
- resampleFilter->SetGaussianFilteringEnabled(false);
- // resampleFilter->SetVerboseOptions(true);
- resampleFilter->Update();
- working_image = resampleFilter->GetOutput();
- }
- else {
- working_image = object;
- }
- StopCurrentStep<ImageType>(working_image);
// Step 2: object pad to input image -> we want to compute the
// relative position for each point belonging to the input image
// domain, so we have to extend (pad) the object image to fit the
// domain size
+ working_image = object;
if (!clitk::HaveSameSizeAndSpacing<ImageType, ImageType>(input, working_image)) {
- StartNewStep("Pad object to image size");
- typename ImageType::Pointer output = ImageType::New();
- SizeType size;
- for(unsigned int i=0; i<dim; i++) {
- size[i] = lrint((input->GetLargestPossibleRegion().GetSize()[i]*
- input->GetSpacing()[i])/(double)working_image->GetSpacing()[i]);
- }
+ StartNewStep("Pad (resize) object to input size");
+
+ if (0) { // OLD VERSION (TO REMOVE)
+ StartNewStep("Pad object to image size");
+ typename ImageType::Pointer output = ImageType::New();
+ SizeType size;
+ for(unsigned int i=0; i<dim; i++) {
+ size[i] = lrint((input->GetLargestPossibleRegion().GetSize()[i]*
+ input->GetSpacing()[i])/(double)working_image->GetSpacing()[i]);
+ }
- // The index of the input is not necessarily zero, so we have to
- // take it into account (not done)
- RegionType region;
- IndexType index = input->GetLargestPossibleRegion().GetIndex();
- region.SetSize(size);
- for(unsigned int i=0; i<dim; i++) {
- if (index[i] != 0) {
- std::cerr << "Index diff from zero : " << index << ". not done yet !" << std::endl;
- exit(0);
+ // The index of the input is not necessarily zero, so we have to
+ // take it into account (not done)
+ RegionType region;
+ IndexType index = input->GetLargestPossibleRegion().GetIndex();
+ region.SetSize(size);
+ for(unsigned int i=0; i<dim; i++) {
+ if (index[i] != 0) {
+ std::cerr << "Index diff from zero : " << index << ". not done yet !" << std::endl;
+ exit(0);
+ }
}
+ // output->SetLargestPossibleRegion(region);
+ output->SetRegions(region);
+ output->SetSpacing(working_image->GetSpacing());
+ PointType origin = input->GetOrigin();
+ for(unsigned int i=0; i<dim; i++) {
+ origin[i] = index[i]*input->GetSpacing()[i] + input->GetOrigin()[i];
+ }
+ output->SetOrigin(origin);
+ // output->SetOrigin(input->GetOrigin());
+
+ output->Allocate();
+ output->FillBuffer(m_BackgroundValue);
+ typename PasteFilterType::Pointer padFilter = PasteFilterType::New();
+ // typename PasteFilterType::InputImageIndexType index;
+ for(unsigned int i=0; i<dim; i++) {
+ index[i] = -index[i]*input->GetSpacing()[i]/(double)working_image->GetSpacing()[i]
+ + lrint((working_image->GetOrigin()[i] - input->GetOrigin()[i])/working_image->GetSpacing()[i]);
+ }
+ padFilter->SetSourceImage(working_image);
+ padFilter->SetDestinationImage(output);
+ padFilter->SetDestinationIndex(index);
+ padFilter->SetSourceRegion(working_image->GetLargestPossibleRegion());
+ padFilter->Update();
+ working_image = padFilter->GetOutput();
}
- // output->SetLargestPossibleRegion(region);
- output->SetRegions(region);
- output->SetSpacing(working_image->GetSpacing());
- PointType origin = input->GetOrigin();
- for(unsigned int i=0; i<dim; i++) {
- origin[i] = index[i]*input->GetSpacing()[i] + input->GetOrigin()[i];
- }
- output->SetOrigin(origin);
- // output->SetOrigin(input->GetOrigin());
-
- output->Allocate();
- output->FillBuffer(m_BackgroundValue);
- typename PadFilterType::Pointer padFilter = PadFilterType::New();
- // typename PadFilterType::InputImageIndexType index;
- for(unsigned int i=0; i<dim; i++) {
- index[i] = -index[i]*input->GetSpacing()[i]/(double)working_image->GetSpacing()[i]
- + lrint((working_image->GetOrigin()[i] - input->GetOrigin()[i])/working_image->GetSpacing()[i]);
- }
- padFilter->SetSourceImage(working_image);
- padFilter->SetDestinationImage(output);
- padFilter->SetDestinationIndex(index);
- padFilter->SetSourceRegion(working_image->GetLargestPossibleRegion());
- padFilter->Update();
- working_image = padFilter->GetOutput();
+
+ // Resize object like input
+ working_image = clitk::ResizeImageLike<ImageType>(working_image, input, GetBackgroundValue());
StopCurrentStep<ImageType>(working_image);
}
- else {
- // DD("[debug] RelPos : same size and spacing : no padding");
+
+ //--------------------------------------------------------------------
+ //--------------------------------------------------------------------
+ // Step 1 : resample
+ if (m_IntermediateSpacingFlag) {
+ StartNewStep("Resample object to intermediate spacing (" + toString(m_IntermediateSpacing) + ")");
+ typedef clitk::ResampleImageWithOptionsFilter<ImageType> ResampleFilterType;
+ typename ResampleFilterType::Pointer resampleFilter = ResampleFilterType::New();
+ resampleFilter->SetInput(working_image);
+ resampleFilter->SetDefaultPixelValue(0);
+ resampleFilter->SetOutputIsoSpacing(m_IntermediateSpacing);
+ resampleFilter->SetGaussianFilteringEnabled(false);
+ //resampleFilter->SetVerboseOptions(true);
+ resampleFilter->Update();
+ working_image = resampleFilter->GetOutput();
+ StopCurrentStep<ImageType>(working_image);
}
+
// Keep object image (with resampline and pad)
object_resampled = working_image;
- // StopCurrentStep<ImageType>(working_image);
// Step 3: compute rel pos in object
StartNewStep("Relative Position Map");
typedef itk::RelativePositionPropImageFilter<ImageType, FloatImageType> RelPosFilterType;
typename RelPosFilterType::Pointer relPosFilter;
- typename FloatImageType::Pointer m_FuzzyMap;
for(int i=0; i<GetNumberOfAngles(); i++) {
// Compute fuzzy map
relPosFilter = RelPosFilterType::New();
+ relPosFilter->SetFast(GetFastFlag());
+ relPosFilter->SetRadius(GetRadius());
relPosFilter->SetInput(working_image);
relPosFilter->SetAlpha1(m_Angle1[i]); // xy plane
relPosFilter->SetAlpha2(m_Angle2[i]);
- relPosFilter->SetK1(M_PI/2.0); // Opening parameter, default = pi/2
- relPosFilter->SetFast(true);
- relPosFilter->SetRadius(1); // seems sufficient in this case
+ relPosFilter->SetK1(GetK1());// M_PI/2.0); // Opening parameter, default = pi/2
// relPosFilter->SetVerboseProgress(true);
+
relPosFilter->Update();
relPos = relPosFilter->GetOutput();
// Divide by the number of relpos
if (GetNumberOfAngles() != 1) {
- typedef itk::DivideByConstantImageFilter<FloatImageType, float, FloatImageType> DivideFilter;
+ typedef itk::DivideImageFilter<FloatImageType, FloatImageType, FloatImageType> DivideFilter;
typename DivideFilter::Pointer divideFilter = DivideFilter::New();
+ divideFilter->SetConstant2(GetNumberOfAngles());
divideFilter->SetInput(m_FuzzyMap);
- divideFilter->SetConstant(GetNumberOfAngles());
divideFilter->Update();
m_FuzzyMap = divideFilter->GetOutput();
}
relPos = m_FuzzyMap;
StopCurrentStep<FloatImageType>(relPos);
+ if (GetFuzzyMapOnlyFlag()) {
+ // If the spacing is used, recompute fuzzy map with the input size/spacing
+ if (m_IntermediateSpacingFlag) {
+ StartNewStep("Resample FuzzyMap to come back to the same sampling than input");
+ typedef clitk::ResampleImageWithOptionsFilter<FloatImageType> ResampleFilterType;
+ typename ResampleFilterType::Pointer resampleFilter = ResampleFilterType::New();
+ resampleFilter->SetDefaultPixelValue(0.0); //Default fuzzymap value FIXME
+ resampleFilter->SetInput(relPos);
+ resampleFilter->SetOutputSpacing(input->GetSpacing());
+ resampleFilter->SetGaussianFilteringEnabled(false);
+ resampleFilter->Update();
+ relPos = m_FuzzyMap = resampleFilter->GetOutput();
+ StopCurrentStep<FloatImageType>(relPos);
+
+ // Need to put exactly the same size
+ if (relPos->GetLargestPossibleRegion() != input->GetLargestPossibleRegion()) {
+ StartNewStep("Pad to get the same size than input");
+ typename FloatImageType::Pointer temp = FloatImageType::New();
+ temp->CopyInformation(input);
+ temp->SetRegions(input->GetLargestPossibleRegion()); // Do not forget !!
+ temp->Allocate();
+ temp->FillBuffer(0.0); // Default fuzzymap value FIXME
+ typename PasteFloatFilterType::Pointer padFilter2 = PasteFloatFilterType::New();
+ padFilter2->SetSourceImage(relPos);
+ padFilter2->SetDestinationImage(temp);
+ padFilter2->SetDestinationIndex(input->GetLargestPossibleRegion().GetIndex());
+ padFilter2->SetSourceRegion(relPos->GetLargestPossibleRegion());
+ padFilter2->Update();
+ relPos = padFilter2->GetOutput();
+ StopCurrentStep<FloatImageType>(relPos);
+ m_FuzzyMap = relPos;
+ }
+ }
+ else {
+ StopCurrentStep<FloatImageType>(relPos);
+ }
+ return;
+ }
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//--------------------------------------------------------------------
//--------------------------------------------------------------------
// Step 5: resample to initial spacing
- if (m_ResampleBeforeRelativePositionFilter) {
- StartNewStep("Resample to get the same sampling than input");
+ if (m_IntermediateSpacingFlag) {
+ StartNewStep("Resample to come back to the same sampling than input");
typedef clitk::ResampleImageWithOptionsFilter<ImageType> ResampleFilterType;
typename ResampleFilterType::Pointer resampleFilter = ResampleFilterType::New();
resampleFilter->SetDefaultPixelValue(m_BackgroundValue);
temp->SetRegions(input->GetLargestPossibleRegion()); // Do not forget !!
temp->Allocate();
temp->FillBuffer(m_BackgroundValue);
- typename PadFilterType::Pointer padFilter2 = PadFilterType::New();
+ typename PasteFilterType::Pointer padFilter2 = PasteFilterType::New();
padFilter2->SetSourceImage(working_image);
padFilter2->SetDestinationImage(temp);
- // DD(input->GetLargestPossibleRegion().GetIndex());
padFilter2->SetDestinationIndex(input->GetLargestPossibleRegion().GetIndex());
padFilter2->SetSourceRegion(working_image->GetLargestPossibleRegion());
padFilter2->Update();