initial commit
This commit is contained in:
@@ -0,0 +1,14 @@
|
|||||||
|
cmake_minimum_required(VERSION 2.8)
|
||||||
|
|
||||||
|
project(FollicleSeparator)
|
||||||
|
|
||||||
|
find_package(ITK REQUIRED)
|
||||||
|
include(${ITK_USE_FILE})
|
||||||
|
|
||||||
|
file(GLOB_RECURSE HEADERS "src/*.h")
|
||||||
|
file(GLOB_RECURSE INLINES "src/*.inl")
|
||||||
|
file(GLOB_RECURSE SOURCES "src/*.cpp")
|
||||||
|
|
||||||
|
add_executable(FollicleSeparator ${HEADERS} ${INLINES} ${SOURCES})
|
||||||
|
|
||||||
|
target_link_libraries(FollicleSeparator ${ITK_LIBRARIES})
|
||||||
@@ -0,0 +1,157 @@
|
|||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable:4996)
|
||||||
|
#include <itkImageFileReader.h>
|
||||||
|
#include <itkImageFileWriter.h>
|
||||||
|
#include <itkBinaryThresholdImageFilter.h>
|
||||||
|
#include <itkMaskNegatedImageFilter.h>
|
||||||
|
#include <itkMinimumMaximumImageCalculator.h>
|
||||||
|
#include <itkIntensityWindowingImageFilter.h>
|
||||||
|
#include <itkSignedMaurerDistanceMapImageFilter.h>
|
||||||
|
#include <itkMorphologicalWatershedImageFilter.h>
|
||||||
|
#include <itkTimeProbe.h>
|
||||||
|
#pragma warning(pop)
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
///
|
||||||
|
/// Binary object splitting using
|
||||||
|
/// watershed segmentation applied to the distance transform
|
||||||
|
///
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
const int DIM = 3;
|
||||||
|
typedef itk::Image<unsigned char, DIM> UInt8Volume; // Binary Mask
|
||||||
|
typedef itk::Image<short, DIM> Int16Volume; // Input Volume
|
||||||
|
typedef itk::Image<unsigned short, DIM> UInt16Volume; // Label Volume
|
||||||
|
typedef itk::Image<float, DIM> Float32Volume; // Distance
|
||||||
|
|
||||||
|
// Read labeled volume
|
||||||
|
|
||||||
|
itk::ImageFileReader<Int16Volume>::Pointer pReader = itk::ImageFileReader<Int16Volume>::New();
|
||||||
|
{
|
||||||
|
itk::TimeProbe clock;
|
||||||
|
clock.Start();
|
||||||
|
|
||||||
|
cout << "Read input from labeledVolume.vtk" << endl;
|
||||||
|
pReader->SetFileName("labeledVolume.vtk");
|
||||||
|
pReader->Update();
|
||||||
|
|
||||||
|
clock.Stop();
|
||||||
|
cout << "ImageFileReader: " << clock.GetTotal() << "s" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Binarize input volume: Follicles = 0, Background = 255
|
||||||
|
|
||||||
|
itk::BinaryThresholdImageFilter<Int16Volume,UInt8Volume>::Pointer pBinarizationFilter =
|
||||||
|
itk::BinaryThresholdImageFilter<Int16Volume,UInt8Volume>::New();
|
||||||
|
{
|
||||||
|
itk::TimeProbe clock;
|
||||||
|
clock.Start();
|
||||||
|
|
||||||
|
pBinarizationFilter->SetInput(pReader->GetOutput());
|
||||||
|
pBinarizationFilter->SetLowerThreshold(0);
|
||||||
|
pBinarizationFilter->SetUpperThreshold(0);
|
||||||
|
pBinarizationFilter->SetInsideValue(255);
|
||||||
|
pBinarizationFilter->SetOutsideValue(0);
|
||||||
|
pBinarizationFilter->Update();
|
||||||
|
|
||||||
|
clock.Stop();
|
||||||
|
cout << "BinaryThresholdImageFilter: " << clock.GetTotal() << "s" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute signed distance from background pixels
|
||||||
|
// Inside the follicle: positive
|
||||||
|
// Outside of the follicle: negative
|
||||||
|
|
||||||
|
itk::SignedMaurerDistanceMapImageFilter<UInt8Volume,Float32Volume>::Pointer pSignedMaurer =
|
||||||
|
itk::SignedMaurerDistanceMapImageFilter<UInt8Volume,Float32Volume>::New();
|
||||||
|
{
|
||||||
|
itk::TimeProbe clock;
|
||||||
|
clock.Start();
|
||||||
|
|
||||||
|
pSignedMaurer->SetInput(pBinarizationFilter->GetOutput());
|
||||||
|
|
||||||
|
pSignedMaurer->Update();
|
||||||
|
|
||||||
|
clock.Stop();
|
||||||
|
cout << "SignedMaurerDistanceMapImageFilter: " << clock.GetTotal() << "s" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invert distance map: [0 ... max distance] -> [255 ... 0]
|
||||||
|
// background pixels will have intensity 255
|
||||||
|
// pixels inside the follicle far away from the border will have low intensities
|
||||||
|
itk::IntensityWindowingImageFilter<Float32Volume,UInt8Volume>::Pointer pConvertToUInt8 =
|
||||||
|
itk::IntensityWindowingImageFilter<Float32Volume,UInt8Volume>::New();
|
||||||
|
{
|
||||||
|
itk::TimeProbe clock;
|
||||||
|
clock.Start();
|
||||||
|
|
||||||
|
itk::MinimumMaximumImageCalculator<Float32Volume>::Pointer pMinMaxDistance =
|
||||||
|
itk::MinimumMaximumImageCalculator<Float32Volume>::New();
|
||||||
|
pMinMaxDistance->SetImage(pSignedMaurer->GetOutput());
|
||||||
|
pMinMaxDistance->ComputeMaximum();
|
||||||
|
float maxDistance = pMinMaxDistance->GetMaximum();
|
||||||
|
|
||||||
|
pConvertToUInt8->SetInput(pSignedMaurer->GetOutput());
|
||||||
|
pConvertToUInt8->SetWindowMinimum(0.0);
|
||||||
|
pConvertToUInt8->SetWindowMaximum(maxDistance);
|
||||||
|
pConvertToUInt8->SetOutputMinimum(255);
|
||||||
|
pConvertToUInt8->SetOutputMaximum(0);
|
||||||
|
pConvertToUInt8->Update();
|
||||||
|
|
||||||
|
clock.Stop();
|
||||||
|
cout << "ConvertToUInt8: " << clock.GetTotal() << "s" << endl;
|
||||||
|
|
||||||
|
itk::ImageFileWriter<UInt8Volume>::Pointer pWriter = itk::ImageFileWriter<UInt8Volume>::New();
|
||||||
|
pWriter->SetInput(pConvertToUInt8->GetOutput());
|
||||||
|
pWriter->SetFileName("labeledVolume.distanceMap.vtk");
|
||||||
|
pWriter->Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Watershed transformation of the distance map
|
||||||
|
itk::MorphologicalWatershedImageFilter<UInt8Volume,UInt16Volume>::Pointer pWatershed = itk::MorphologicalWatershedImageFilter<UInt8Volume,UInt16Volume>::New();
|
||||||
|
{
|
||||||
|
itk::TimeProbe clock;
|
||||||
|
clock.Start();
|
||||||
|
|
||||||
|
pWatershed->SetLevel(25); // high level -> low Number of regions
|
||||||
|
pWatershed->SetMarkWatershedLine(false);
|
||||||
|
pWatershed->SetInput(pConvertToUInt8->GetOutput());
|
||||||
|
pWatershed->Update();
|
||||||
|
|
||||||
|
clock.Stop();
|
||||||
|
cout << "WatershedImageFilter: " << clock.GetTotal() << "s" << endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mask out background voxels from the watershed result
|
||||||
|
itk::MaskNegatedImageFilter<UInt16Volume, UInt8Volume, UInt16Volume>::Pointer pMaskImageFilter =
|
||||||
|
itk::MaskNegatedImageFilter<UInt16Volume, UInt8Volume, UInt16Volume>::New();
|
||||||
|
{
|
||||||
|
pMaskImageFilter->SetInput(pWatershed->GetOutput());
|
||||||
|
pMaskImageFilter->SetMaskImage(pBinarizationFilter->GetOutput());
|
||||||
|
pMaskImageFilter->Update();
|
||||||
|
}
|
||||||
|
|
||||||
|
itk::MinimumMaximumImageCalculator<UInt16Volume>::Pointer pMaxLabelCalculator =
|
||||||
|
itk::MinimumMaximumImageCalculator<UInt16Volume>::New();
|
||||||
|
pMaxLabelCalculator->SetImage(pMaskImageFilter->GetOutput());
|
||||||
|
pMaxLabelCalculator->ComputeMaximum();
|
||||||
|
cout << "Number of labels: " << pMaxLabelCalculator->GetMaximum() << endl;
|
||||||
|
|
||||||
|
cout << "Write result to labeledVolume.watershed.vtk" << endl;
|
||||||
|
itk::ImageFileWriter<UInt16Volume>::Pointer pWriter = itk::ImageFileWriter<UInt16Volume>::New();
|
||||||
|
pWriter->SetInput(pMaskImageFilter->GetOutput());
|
||||||
|
pWriter->SetFileName("labeledVolume.watershed.vtk");
|
||||||
|
pWriter->Update();
|
||||||
|
}
|
||||||
|
catch (const itk::ExceptionObject& ex)
|
||||||
|
{
|
||||||
|
std::cerr << ex.GetDescription() << std::endl;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user