X-Git-Url: https://git.creatis.insa-lyon.fr/pubgit/?a=blobdiff_plain;f=itk%2FclitkSegmentationUtils.txx;h=dccfc35df72daee8087047b54757168e1909ed46;hb=c0274b5a8535f5ed75fe9939f3a12f86e8e1ef3c;hp=0f5ebfbd58b9f7a9888e906091129b48909737e2;hpb=48f513811d9b13e6c7df67d8dc16fa073aa0751a;p=clitk.git diff --git a/itk/clitkSegmentationUtils.txx b/itk/clitkSegmentationUtils.txx index 0f5ebfb..dccfc35 100644 --- a/itk/clitkSegmentationUtils.txx +++ b/itk/clitkSegmentationUtils.txx @@ -18,29 +18,37 @@ // clitk #include "clitkSetBackgroundImageFilter.h" +#include "clitkSliceBySliceRelativePositionFilter.h" +#include "clitkCropLikeImageFilter.h" +#include "clitkMemoryUsage.h" // itk #include #include #include #include +#include +#include +#include +#include +#include //-------------------------------------------------------------------- template void clitk::ComputeBBFromImageRegion(typename ImageType::Pointer image, typename ImageType::RegionType region, typename itk::BoundingBox::Pointer bb) { + ImageType::ImageDimension>::Pointer bb) { typedef typename ImageType::IndexType IndexType; IndexType firstIndex; IndexType lastIndex; for(unsigned int i=0; iGetImageDimension(); i++) { firstIndex[i] = region.GetIndex()[i]; - lastIndex[i] = region.GetSize()[i]; + lastIndex[i] = firstIndex[i]+region.GetSize()[i]; } typedef itk::BoundingBox BBType; + ImageType::ImageDimension> BBType; typedef typename BBType::PointType PointType; PointType lastPoint; PointType firstPoint; @@ -99,7 +107,11 @@ void clitk::ComputeRegionFromBB(typename ImageType::Pointer image, PointType maxs = bb->GetMaximum(); PointType mins = bb->GetMinimum(); for(unsigned int i=0; iGetSpacing()[i]); + // DD(maxs[i]); + // DD(mins[i]); + // DD((maxs[i] - mins[i])/image->GetSpacing()[i]); + regionSize[i] = lrint((maxs[i] - mins[i])/image->GetSpacing()[i]); + // DD(regionSize[i]); } // Create region @@ -111,12 +123,17 @@ void clitk::ComputeRegionFromBB(typename ImageType::Pointer image, //-------------------------------------------------------------------- template typename ImageType::Pointer -clitk::SetBackground(typename ImageType::ConstPointer input, - typename TMaskImageType::ConstPointer mask, +clitk::SetBackground(const ImageType * input, + const TMaskImageType * mask, typename TMaskImageType::PixelType maskBG, - typename ImageType::PixelType outValue) { - typedef clitk::SetBackgroundImageFilter SetBackgroundImageFilterType; - typename SetBackgroundImageFilterType::Pointer setBackgroundFilter = SetBackgroundImageFilterType::New(); + typename ImageType::PixelType outValue, + bool inPlace) { + typedef clitk::SetBackgroundImageFilter + SetBackgroundImageFilterType; + typename SetBackgroundImageFilterType::Pointer setBackgroundFilter + = SetBackgroundImageFilterType::New(); + // if (inPlace) setBackgroundFilter->ReleaseDataFlagOn(); // No seg fault + setBackgroundFilter->SetInPlace(inPlace); // This is important to keep memory low setBackgroundFilter->SetInput(input); setBackgroundFilter->SetInput2(mask); setBackgroundFilter->SetMaskValue(maskBG); @@ -129,28 +146,55 @@ clitk::SetBackground(typename ImageType::ConstPointer input, //-------------------------------------------------------------------- template +int clitk::GetNumberOfConnectedComponentLabels(typename ImageType::Pointer input, + typename ImageType::PixelType BG, + bool isFullyConnected) { + // Connected Component label + typedef itk::ConnectedComponentImageFilter ConnectFilterType; + typename ConnectFilterType::Pointer connectFilter = ConnectFilterType::New(); + connectFilter->SetInput(input); + connectFilter->SetBackgroundValue(BG); + connectFilter->SetFullyConnected(isFullyConnected); + connectFilter->Update(); + + // Return result + return connectFilter->GetObjectCount(); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +/* + Warning : in this cas, we consider outputType like inputType, not + InternalImageType. Be sure it fits. + */ +template typename ImageType::Pointer -clitk::Labelize(typename ImageType::Pointer input, +clitk::Labelize(const ImageType * input, typename ImageType::PixelType BG, bool isFullyConnected, int minimalComponentSize) { + // InternalImageType for storing large number of component + typedef itk::Image InternalImageType; + // Connected Component label - typedef itk::ConnectedComponentImageFilter ConnectFilterType; + typedef itk::ConnectedComponentImageFilter ConnectFilterType; typename ConnectFilterType::Pointer connectFilter = ConnectFilterType::New(); + // connectFilter->ReleaseDataFlagOn(); connectFilter->SetInput(input); connectFilter->SetBackgroundValue(BG); connectFilter->SetFullyConnected(isFullyConnected); // Sort by size and remove too small area. - typedef itk::RelabelComponentImageFilter RelabelFilterType; + typedef itk::RelabelComponentImageFilter RelabelFilterType; typename RelabelFilterType::Pointer relabelFilter = RelabelFilterType::New(); - relabelFilter->InPlaceOn(); + // relabelFilter->ReleaseDataFlagOn(); // if yes, fail when ExplosionControlledThresholdConnectedImageFilter ??? relabelFilter->SetInput(connectFilter->GetOutput()); relabelFilter->SetMinimumObjectSize(minimalComponentSize); relabelFilter->Update(); // Return result - return relabelFilter->GetOutput(); + typename ImageType::Pointer output = relabelFilter->GetOutput(); + return output; } //-------------------------------------------------------------------- @@ -180,7 +224,7 @@ clitk::RemoveLabels(typename ImageType::Pointer input, //-------------------------------------------------------------------- template typename ImageType::Pointer -clitk::KeepLabels(typename ImageType::Pointer input, +clitk::KeepLabels(const ImageType * input, typename ImageType::PixelType BG, typename ImageType::PixelType FG, typename ImageType::PixelType firstKeep, @@ -225,40 +269,477 @@ clitk::LabelizeAndSelectLabels(typename ImageType::Pointer input, //-------------------------------------------------------------------- template typename ImageType::Pointer -clitk::EnlargeImageLike(typename ImageType::Pointer input, - typename ImageType::Pointer like, - typename ImageType::PixelType backgroundValue) +clitk::ResizeImageLike(typename ImageType::Pointer input, + typename ImageType::Pointer like, + typename ImageType::PixelType backgroundValue) { - if (!HaveSameSpacing(input, like)) { - FATAL("Images must have the same spacing"); - } + typedef clitk::CropLikeImageFilter CropFilterType; + typename CropFilterType::Pointer cropFilter = CropFilterType::New(); + cropFilter->SetInput(input); + cropFilter->SetCropLikeImage(like); + cropFilter->SetBackgroundValue(backgroundValue); + cropFilter->Update(); + return cropFilter->GetOutput(); +} +//-------------------------------------------------------------------- - typename ImageType::Pointer output = ImageType::New(); - typename ImageType::SizeType size; - for(unsigned int i=0; iGetLargestPossibleRegion().GetSize()[i]*like->GetSpacing()[i])/ - (double)like->GetSpacing()[i]); + +//-------------------------------------------------------------------- +template +typename MaskImageType::Pointer +clitk::SliceBySliceRelativePosition(const MaskImageType * input, + const MaskImageType * object, + int direction, + double threshold, + std::string orientation, + bool uniqueConnectedComponent, + double spacing, + bool inverseflag) +{ + typedef clitk::SliceBySliceRelativePositionFilter SliceRelPosFilterType; + typename SliceRelPosFilterType::Pointer sliceRelPosFilter = SliceRelPosFilterType::New(); + sliceRelPosFilter->VerboseStepFlagOff(); + sliceRelPosFilter->WriteStepFlagOff(); + sliceRelPosFilter->SetInput(input); + sliceRelPosFilter->SetInputObject(object); + sliceRelPosFilter->SetDirection(direction); + sliceRelPosFilter->SetFuzzyThreshold(threshold); + sliceRelPosFilter->AddOrientationTypeString(orientation); + sliceRelPosFilter->SetResampleBeforeRelativePositionFilter((spacing != -1)); + sliceRelPosFilter->SetIntermediateSpacing(spacing); + sliceRelPosFilter->SetUniqueConnectedComponentBySlice(uniqueConnectedComponent); + sliceRelPosFilter->SetInverseOrientationFlag(inverseflag); + // sliceRelPosFilter->SetAutoCropFlag(true); ?? + sliceRelPosFilter->Update(); + return sliceRelPosFilter->GetOutput(); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +bool +clitk::FindExtremaPointInAGivenDirection(const ImageType * input, + typename ImageType::PixelType bg, + int direction, bool opposite, + typename ImageType::PointType & point) +{ + typename ImageType::PointType dummy; + return clitk::FindExtremaPointInAGivenDirection(input, bg, direction, + opposite, dummy, 0, point); +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +bool +clitk::FindExtremaPointInAGivenDirection(const ImageType * input, + typename ImageType::PixelType bg, + int direction, bool opposite, + typename ImageType::PointType refpoint, + double distanceMax, + typename ImageType::PointType & point) +{ + /* + loop over input pixels, store the index in the fg that is max + according to the given direction. + */ + typedef itk::ImageRegionConstIteratorWithIndex IteratorType; + IteratorType iter(input, input->GetLargestPossibleRegion()); + iter.GoToBegin(); + typename ImageType::IndexType max = input->GetLargestPossibleRegion().GetIndex(); + if (opposite) max = max+input->GetLargestPossibleRegion().GetSize(); + bool found=false; + while (!iter.IsAtEnd()) { + if (iter.Get() != bg) { + bool test = iter.GetIndex()[direction] > max[direction]; + if (opposite) test = !test; + if (test) { + typename ImageType::PointType p; + input->TransformIndexToPhysicalPoint(iter.GetIndex(), p); + if ((distanceMax==0) || (p.EuclideanDistanceTo(refpoint) < distanceMax)) { + max = iter.GetIndex(); + found = true; + } + } + } + ++iter; } - // DD(size); + if (!found) return false; + input->TransformIndexToPhysicalPoint(max, point); + return true; +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +typename ImageType::Pointer +clitk::CropImageAbove(typename ImageType::Pointer image, + int dim, double min, + bool autoCrop, + typename ImageType::PixelType BG) +{ + return clitk::CropImageAlongOneAxis(image, dim, + image->GetOrigin()[dim], + min, + autoCrop, BG); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +typename ImageType::Pointer +clitk::CropImageBelow(typename ImageType::Pointer image, + int dim, double max, + bool autoCrop, + typename ImageType::PixelType BG) +{ + typename ImageType::PointType p; + image->TransformIndexToPhysicalPoint(image->GetLargestPossibleRegion().GetIndex()+ + image->GetLargestPossibleRegion().GetSize(), p); + return clitk::CropImageAlongOneAxis(image, dim, max, p[dim], autoCrop, BG); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +typename ImageType::Pointer +clitk::CropImageAlongOneAxis(typename ImageType::Pointer image, + int dim, double min, double max, + bool autoCrop, + typename ImageType::PixelType BG) +{ + // Compute region size typename ImageType::RegionType region; + typename ImageType::SizeType size = image->GetLargestPossibleRegion().GetSize(); + typename ImageType::PointType p = image->GetOrigin(); + p[dim] = min; + typename ImageType::IndexType start; + image->TransformPhysicalPointToIndex(p, start); + p[dim] = max; + typename ImageType::IndexType end; + image->TransformPhysicalPointToIndex(p, end); + size[dim] = fabs(end[dim]-start[dim]); + region.SetIndex(start); region.SetSize(size); - output->SetRegions(region); - output->SetSpacing(like->GetSpacing()); - output->SetOrigin(like->GetOrigin()); - output->Allocate(); - output->FillBuffer(backgroundValue); - typedef itk::PasteImageFilter PasteFilterType; - typename PasteFilterType::Pointer pasteFilter = PasteFilterType::New(); - typename PasteFilterType::InputImageIndexType index; - for(unsigned int i=0; iGetOrigin()[i] - like->GetOrigin()[i])/(double)input->GetSpacing()[i]); + + // Perform Crop + typedef itk::RegionOfInterestImageFilter CropFilterType; + typename CropFilterType::Pointer cropFilter = CropFilterType::New(); + cropFilter->SetInput(image); + cropFilter->SetRegionOfInterest(region); + cropFilter->Update(); + typename ImageType::Pointer result = cropFilter->GetOutput(); + + // Auto Crop + if (autoCrop) { + result = clitk::AutoCrop(result, BG); } - // DD(index); - pasteFilter->SetSourceImage(input); - pasteFilter->SetDestinationImage(output); - pasteFilter->SetDestinationIndex(index); - pasteFilter->SetSourceRegion(input->GetLargestPossibleRegion()); - pasteFilter->Update(); - return pasteFilter->GetOutput(); + return result; +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ComputeCentroids(typename ImageType::Pointer image, + typename ImageType::PixelType BG, + std::vector & centroids) +{ + typedef long LabelType; + static const unsigned int Dim = ImageType::ImageDimension; + typedef itk::ShapeLabelObject< LabelType, Dim > LabelObjectType; + typedef itk::LabelMap< LabelObjectType > LabelMapType; + typedef itk::LabelImageToLabelMapFilter ImageToMapFilterType; + typename ImageToMapFilterType::Pointer imageToLabelFilter = ImageToMapFilterType::New(); + typedef itk::ShapeLabelMapFilter ShapeFilterType; + typename ShapeFilterType::Pointer statFilter = ShapeFilterType::New(); + imageToLabelFilter->SetBackgroundValue(BG); + imageToLabelFilter->SetInput(image); + statFilter->SetInput(imageToLabelFilter->GetOutput()); + statFilter->Update(); + typename LabelMapType::Pointer labelMap = statFilter->GetOutput(); + + centroids.clear(); + typename ImageType::PointType dummy; + centroids.push_back(dummy); // label 0 -> no centroid, use dummy point + for(uint i=1; iGetNumberOfLabelObjects()+1; i++) { + centroids.push_back(labelMap->GetLabelObject(i)->GetCentroid()); + } } //-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::ExtractSlices(typename ImageType::Pointer image, + int direction, + std::vector::Pointer > & slices) +{ + typedef clitk::ExtractSliceFilter ExtractSliceFilterType; + typedef typename ExtractSliceFilterType::SliceType SliceType; + typename ExtractSliceFilterType::Pointer + extractSliceFilter = ExtractSliceFilterType::New(); + extractSliceFilter->SetInput(image); + extractSliceFilter->SetDirection(direction); + extractSliceFilter->Update(); + extractSliceFilter->GetOutputSlices(slices); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +typename ImageType::Pointer +clitk::JoinSlices(std::vector::Pointer > & slices, + typename ImageType::Pointer input, + int direction) { + typedef typename itk::Image SliceType; + typedef itk::JoinSeriesImageFilter JoinSeriesFilterType; + typename JoinSeriesFilterType::Pointer joinFilter = JoinSeriesFilterType::New(); + joinFilter->SetOrigin(input->GetOrigin()[direction]); + joinFilter->SetSpacing(input->GetSpacing()[direction]); + for(unsigned int i=0; iPushBackInput(slices[i]); + } + joinFilter->Update(); + return joinFilter->GetOutput(); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::PointsUtils::Convert2DTo3D(const PointType2D & p, + ImagePointer image, + const int slice, + PointType3D & p3D) +{ + p3D[0] = p[0]; + p3D[1] = p[1]; + p3D[2] = (image->GetLargestPossibleRegion().GetIndex()[2]+slice)*image->GetSpacing()[2] + + image->GetOrigin()[2]; +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void +clitk::PointsUtils::Convert2DTo3DList(const MapPoint2DType & map, + ImagePointer image, + VectorPoint3DType & list) +{ + typename MapPoint2DType::const_iterator iter = map.begin(); + while (iter != map.end()) { + PointType3D p; + Convert2DTo3D(iter->second, image, iter->first, p); + list.push_back(p); + ++iter; + } +} +//-------------------------------------------------------------------- + +//-------------------------------------------------------------------- +template +void +clitk::WriteListOfLandmarks(std::vector points, + std::string filename) +{ + std::ofstream os; + openFileForWriting(os, filename); + os << "LANDMARKS1" << std::endl; + for(uint i=0; i +typename ImageType::Pointer +clitk::Dilate(typename ImageType::Pointer image, + double radiusInMM, + typename ImageType::PixelType BG, + typename ImageType::PixelType FG, + bool extendSupport) +{ + typename ImageType::SizeType r; + for(uint i=0; iGetSpacing()[i]); + return clitk::Dilate(image, r, BG, FG, extendSupport); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +typename ImageType::Pointer +clitk::Dilate(typename ImageType::Pointer image, + typename ImageType::PointType radiusInMM, + typename ImageType::PixelType BG, + typename ImageType::PixelType FG, + bool extendSupport) +{ + typename ImageType::SizeType r; + for(uint i=0; iGetSpacing()[i]); + return clitk::Dilate(image, r, BG, FG, extendSupport); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +typename ImageType::Pointer +clitk::Dilate(typename ImageType::Pointer image, + typename ImageType::SizeType radius, + typename ImageType::PixelType BG, + typename ImageType::PixelType FG, + bool extendSupport) +{ + // Create kernel for dilatation + typedef itk::BinaryBallStructuringElement KernelType; + KernelType structuringElement; + structuringElement.SetRadius(radius); + structuringElement.CreateStructuringElement(); + + if (extendSupport) { + typedef itk::ConstantPadImageFilter PadFilterType; + typename PadFilterType::Pointer padFilter = PadFilterType::New(); + padFilter->SetInput(image); + typename ImageType::SizeType lower; + typename ImageType::SizeType upper; + for(uint i=0; i<3; i++) { + lower[i] = upper[i] = 2*(radius[i]+1); + } + padFilter->SetPadLowerBound(lower); + padFilter->SetPadUpperBound(upper); + padFilter->Update(); + image = padFilter->GetOutput(); + } + + // Dilate filter + typedef itk::BinaryDilateImageFilter DilateFilterType; + typename DilateFilterType::Pointer dilateFilter = DilateFilterType::New(); + dilateFilter->SetBackgroundValue(BG); + dilateFilter->SetForegroundValue(FG); + dilateFilter->SetBoundaryToForeground(false); + dilateFilter->SetKernel(structuringElement); + dilateFilter->SetInput(image); + dilateFilter->Update(); + return image = dilateFilter->GetOutput(); +} +//-------------------------------------------------------------------- + + +//-------------------------------------------------------------------- +template +void clitk::ConvertOption(std::string optionName, uint given, + ValueType * values, VectorType & p, + uint dim, bool required) +{ + if (required && (given == 0)) { + clitkExceptionMacro("The option --" << optionName << " must be set and have 1 or " + << dim << " values."); + } + if (given == 1) { + for(uint i=0; i to accelerate, start with formula, when change sign -> stop and fill +*/ +template +void +clitk::SliceBySliceSetBackgroundFromLineSeparation(typename ImageType::Pointer input, + std::vector & lA, + std::vector & lB, + typename ImageType::PixelType BG, + int mainDirection, + double offsetToKeep) +{ + + typedef itk::ImageSliceIteratorWithIndex SliceIteratorType; + SliceIteratorType siter = SliceIteratorType(input, + input->GetLargestPossibleRegion()); + siter.SetFirstDirection(0); + siter.SetSecondDirection(1); + siter.GoToBegin(); + uint i=0; + typename ImageType::PointType A; + typename ImageType::PointType B; + typename ImageType::PointType C; + assert(lA.size() == B.size()); + // DD(lA.size()); + //DD(input->GetLargestPossibleRegion().GetSize()); + while ((iTransformIndexToPhysicalPoint(siter.GetIndex(), C); + if (C[2] != lA[i][2]) { + // DD(C); + // DD(lA[i]); + } + else { + // Define A,B,C points + A = lA[i]; + B = lB[i]; + C = A; + C[mainDirection] += offsetToKeep; // I know I must keep this point + double s = (B[0] - A[0]) * (C[1] - A[1]) - (B[1] - A[1]) * (C[0] - A[0]); + bool isPositive = s<0; + while (!siter.IsAtEndOfSlice()) { + while (!siter.IsAtEndOfLine()) { + // Very slow, I know ... but image should be very small + input->TransformIndexToPhysicalPoint(siter.GetIndex(), C); + double s = (B[0] - A[0]) * (C[1] - A[1]) - (B[1] - A[1]) * (C[0] - A[0]); + if (s == 0) siter.Set(BG); // on the line, we decide to remove + if (isPositive) { + if (s > 0) siter.Set(BG); + } + else { + if (s < 0) siter.Set(BG); + } + ++siter; + } + siter.NextLine(); + } + ++i; + } + siter.NextSlice(); + } +} +//--------------------------------------------------------------------