void Initialisation::setInputImage(ImageType::Pointer image) { OrientImage<ImageType> orientationFilter; orientationFilter.setInputImage(image); orientationFilter.orientation(itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_AIL); inputImage_ = orientationFilter.getOutputImage(); orientation_ = orientationFilter.getInitialImageOrientation(); }
Initialisation::Initialisation(ImageType::Pointer image, double imageFactor, double gap) { OrientImage<ImageType> orientationFilter; orientationFilter.setInputImage(image); orientationFilter.orientation(itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_AIL); inputImage_ = orientationFilter.getOutputImage(); orientation_ = orientationFilter.getInitialImageOrientation(); typeImageFactor_ = imageFactor; gap_ = gap; startSlice_ = -1.0; numberOfSlices_ = 5; radius_ = 4.0; verbose_ = false; }
void Image3D::TransformMeshToBinaryImage(Mesh* m, string filename, OrientationType orient, bool sub_segmentation, bool cropUpDown, CVector3* upperSlicePoint, CVector3* upperSliceNormal, CVector3* downSlicePoint, CVector3* downSliceNormal) { //m->subdivision(2); MeshTypeB::Pointer mesh; MeshFilterType::Pointer meshFilter = MeshFilterType::New(); if (cropUpDown) { mesh = MeshTypeB::New(); vtkSmartPointer<vtkPolyData> polyData; try { polyData = m->reduceMeshUpAndDown(*upperSlicePoint, *upperSliceNormal, *downSlicePoint, *downSliceNormal); } catch (const exception& e) { cout << e.what() << endl; } vtkSmartPointer<vtkFillHolesFilter> fillHolesFilter = vtkSmartPointer<vtkFillHolesFilter>::New(); fillHolesFilter->SetInputData(polyData); fillHolesFilter->SetHoleSize(1000.0); fillHolesFilter->Update(); // Make the triangle windong order consistent vtkSmartPointer<vtkPolyDataNormals> normals = vtkSmartPointer<vtkPolyDataNormals>::New(); normals->SetInputData(fillHolesFilter->GetOutput()); normals->ConsistencyOn(); normals->SplittingOff(); normals->Update(); // Restore the original normals normals->GetOutput()->GetPointData()->SetNormals(polyData->GetPointData()->GetNormals()); polyData = normals->GetOutput(); // // Transfer the points from the vtkPolyData into the itk::Mesh // const unsigned int numberOfPoints = polyData->GetNumberOfPoints(); vtkPoints * vtkpoints = polyData->GetPoints(); mesh->GetPoints()->Reserve( numberOfPoints ); for(unsigned int p =0; p < numberOfPoints; p++) { double * apoint = vtkpoints->GetPoint( p ); mesh->SetPoint( p, MeshTypeB::PointType( apoint )); } // // Transfer the cells from the vtkPolyData into the itk::Mesh // vtkCellArray * triangleStrips = polyData->GetStrips(); vtkIdType * cellPoints; vtkIdType numberOfCellPoints; // // First count the total number of triangles from all the triangle strips. // unsigned int numberOfTriangles = 0; triangleStrips->InitTraversal(); while( triangleStrips->GetNextCell( numberOfCellPoints, cellPoints ) ) { numberOfTriangles += numberOfCellPoints-2; } vtkCellArray * polygons = polyData->GetPolys(); polygons->InitTraversal(); while( polygons->GetNextCell( numberOfCellPoints, cellPoints ) ) { if( numberOfCellPoints == 3 ) { numberOfTriangles ++; } } // // Reserve memory in the itk::Mesh for all those triangles // mesh->GetCells()->Reserve( numberOfTriangles ); // // Copy the triangles from vtkPolyData into the itk::Mesh // // typedef MeshTypeB::CellType CellType; typedef itk::TriangleCell< CellType > TriangleCellType; int cellId = 0; // first copy the triangle strips triangleStrips->InitTraversal(); while( triangleStrips->GetNextCell( numberOfCellPoints, cellPoints ) ) { unsigned int numberOfTrianglesInStrip = numberOfCellPoints - 2; unsigned long pointIds[3]; pointIds[0] = cellPoints[0]; pointIds[1] = cellPoints[1]; pointIds[2] = cellPoints[2]; for( unsigned int t=0; t < numberOfTrianglesInStrip; t++ ) { MeshTypeB::CellAutoPointer c; TriangleCellType * tcell = new TriangleCellType; tcell->SetPointIds( pointIds ); c.TakeOwnership( tcell ); mesh->SetCell( cellId, c ); cellId++; pointIds[0] = pointIds[1]; pointIds[1] = pointIds[2]; pointIds[2] = cellPoints[t+3]; } } // then copy the normal triangles polygons->InitTraversal(); while( polygons->GetNextCell( numberOfCellPoints, cellPoints ) ) { if( numberOfCellPoints !=3 ) // skip any non-triangle. { continue; } MeshTypeB::CellAutoPointer c; TriangleCellType * t = new TriangleCellType; t->SetPointIds( (unsigned long*)cellPoints ); c.TakeOwnership( t ); mesh->SetCell( cellId, c ); cellId++; } meshFilter->SetInput(mesh); } else { mesh = MeshTypeB::New(); vector<Vertex*> points = m->getListPoints(); PointType pnt; CVector3 p, n; for (unsigned int i=0; i<points.size(); i++) { p = points[i]->getPosition(); n = points[i]->getNormal(); pnt[0] = p[0]; pnt[1] = p[1]; pnt[2] = p[2]; mesh->SetPoint(i,pnt); } vector<int> triangles = m->getListTriangles(); for (unsigned int i=0; i<triangles.size(); i+=3) { CellTypeB::CellAutoPointer triangle; triangle.TakeOwnership(new CellTypeB); triangle->SetPointId(0,triangles[i]); triangle->SetPointId(1,triangles[i+1]); triangle->SetPointId(2,triangles[i+2]); mesh->SetCell((int)(i+1)/3,triangle); } meshFilter->SetInput(mesh); } meshFilter->SetOrigin(imageOriginale_->GetOrigin()); meshFilter->SetSpacing(imageOriginale_->GetSpacing()); meshFilter->SetSize(imageOriginale_->GetLargestPossibleRegion().GetSize()); meshFilter->SetDirection(imageOriginale_->GetDirection()); meshFilter->SetIndex(imageOriginale_->GetLargestPossibleRegion().GetIndex()); //meshFilter->SetTolerance(1.0); meshFilter->SetInsideValue(1.0); meshFilter->SetOutsideValue(0.0); try { meshFilter->Update(); } catch( itk::ExceptionObject & e ) { cout << "Exception thrown ! " << endl; cout << "An error ocurred during creating binary image" << endl; cout << "Location = " << e.GetLocation() << endl; cout << "Description = " << e.GetDescription() << endl; } BinaryImageType::Pointer im = meshFilter->GetOutput(); if (!sub_segmentation) { imageSegmentation_ = im; } else { BinaryImageType::RegionType region = im->GetLargestPossibleRegion(); itk::ImageRegionConstIterator<BinaryImageType> imageIterator(im,region); unsigned char pixel, pixel_seg; BinaryIndexType index; while(!imageIterator.IsAtEnd()) { index = imageIterator.GetIndex(); pixel = imageIterator.Get(); pixel_seg = imageSegmentation_->GetPixel(index); im->SetPixel(index,pixel && !pixel_seg); ++imageIterator; } } OrientImage<BinaryImageType> orientationFilter; orientationFilter.setInputImage(im); orientationFilter.orientation(orient); im = orientationFilter.getOutputImage(); // Write the image typedef itk::ImageFileWriter< BinaryImageType > WriterType; WriterType::Pointer writer = WriterType::New(); itk::NiftiImageIO::Pointer io = itk::NiftiImageIO::New(); writer->SetImageIO(io); writer->SetFileName(filename); writer->SetInput(im); try { writer->Update(); } catch( itk::ExceptionObject & e ) { cout << "Exception thrown ! " << endl; cout << "An error ocurred during Writing" << endl; cout << "Location = " << e.GetLocation() << endl; cout << "Description = " << e.GetDescription() << endl; } }
vector<CVector3> extractCenterline(string filename) { vector<CVector3> result; string nii=".nii", niigz=".nii.gz", txt=".txt", suffix=""; size_t pos_niigz = filename.find(niigz), pos_nii = filename.find(nii), pos_txt = filename.find(txt); if (pos_niigz != string::npos || pos_nii != string::npos) { ReaderType::Pointer reader = ReaderType::New(); itk::NiftiImageIO::Pointer io = itk::NiftiImageIO::New(); reader->SetImageIO(io); reader->SetFileName(filename); try { reader->Update(); } catch( itk::ExceptionObject & e ) { cerr << "Exception caught while reading centerline input image " << endl; cerr << e << endl; } ImageType::Pointer image_centerline = reader->GetOutput(); OrientImage<ImageType> orientationFilter; orientationFilter.setInputImage(image_centerline); orientationFilter.orientation(itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_AIL); image_centerline = orientationFilter.getOutputImage(); ImageType::IndexType ind; itk::Point<double,3> point; ImageIterator it( image_centerline, image_centerline->GetRequestedRegion() ); it.GoToBegin(); while(!it.IsAtEnd()) { if (it.Get()!=0) { ind = it.GetIndex(); image_centerline->TransformIndexToPhysicalPoint(ind, point); bool added = false; if (result.size() == 0) { result.push_back(CVector3(point[0],point[1],point[2])); added = true; } else { for (vector<CVector3>::iterator it=result.begin(); it!=result.end(); it++) { if (point[2] < (*it)[2]) { result.insert(it, CVector3(point[0],point[1],point[2])); added = true; break; } } } if (!added) result.push_back(CVector3(point[0],point[1],point[2])); } ++it; } /*// spline approximation to produce correct centerline double range = result.size()/4.0 ; const unsigned int ParametricDimension = 1; const unsigned int DataDimension = 3; typedef double RealType; typedef itk::Vector<RealType, DataDimension> VectorType; typedef itk::Image<VectorType, ParametricDimension> ImageType; typedef itk::PointSet <VectorType , ParametricDimension > PointSetType; PointSetType::Pointer pointSet = PointSetType::New(); // Sample the helix. int nb = result.size(); for (unsigned long i=0; i<nb; i++) { PointSetType::PointType point; point[0] = (double)i/(double)(nb-1); pointSet ->SetPoint( i, point ); VectorType V; V[0] = result[i][0]; V[1] = result[i][1]; V[2] = result[i][2]; pointSet ->SetPointData( i, V ); } typedef itk::BSplineScatteredDataPointSetToImageFilter <PointSetType , ImageType > FilterType; FilterType::Pointer filter = FilterType::New(); ImageType::SpacingType spacing; spacing.Fill( 1.0 ); ImageType::SizeType size; size.Fill( 2.0); ImageType::PointType origin; origin.Fill( 0.0 ); ImageType::RegionType region(size); FilterType::ArrayType closedim; closedim.Fill(0); filter->SetSize( size ); filter->SetOrigin( origin ); filter->SetSpacing( spacing ); filter->SetInput( pointSet ); int splineOrder = 3; filter->SetSplineOrder( splineOrder ); FilterType::ArrayType ncps; ncps.Fill( splineOrder + 1 ); filter->SetNumberOfControlPoints( ncps ); filter->SetNumberOfLevels( 5 ); filter->SetGenerateOutputImage( false ); try { filter->Update(); } catch( itk::ExceptionObject & e ) { std::cerr << "Exception caught while reading input image " << std::endl; std::cerr << e << std::endl; } typedef itk::BSplineControlPointImageFunction < ImageType, double > BSplineType; BSplineType::Pointer bspline = BSplineType::New(); bspline->SetSplineOrder(filter->GetSplineOrder()); bspline->SetOrigin(origin); bspline->SetSpacing(spacing); bspline->SetSize(size); bspline->SetInputImage(filter->GetPhiLattice()); result.clear(); for (double i=0; i<=2.0*range; i++) { PointSetType::PointType point; point[0] = i/(2.0*range); VectorType V = bspline->Evaluate( point ); result.push_back(CVector3(V[0],V[1],V[2])); }*/ } else if (pos_txt != string::npos) { ifstream myfile; string l; double x, y, z; CVector3 point, pointPrecedent; int i = 0; myfile.open(filename.c_str()); if (myfile.is_open()) { while (myfile.good()) { getline(myfile,l); stringstream ss(l); ss >> x >> z >> y; point = CVector3(x,y,z); if ((point-pointPrecedent).Norm() > 0) { pointPrecedent = point; //point[1] = -point[1]; result.push_back(point); } i++; } } myfile.close(); }
int main(int argc, char *argv[]) { srand (time(NULL)); if (argc == 1) { help(); return EXIT_FAILURE; } string inputFilename = "", outputPath = "", outputFilenameBinary = "", outputFilenameMesh = "", outputFilenameBinaryCSF = "", outputFilenameMeshCSF = "", outputFilenameAreas = "", outputFilenameAreasCSF = "", outputFilenameCenterline = "", outputFilenameCenterlineBinary = "", inputCenterlineFilename = "", initMaskFilename = ""; double typeImageFactor = 0.0, initialisation = 0.5; int downSlice = -10000, upSlice = 10000; string suffix; bool input_dicom = false, output_detection = false, output_mesh = false, output_centerline_binary = false, output_centerline_coord = false, output_cross = false, init_with_centerline = false, init_with_mask = false, verbose = false, output_init_tube = false, completeCenterline = false, init_validation = false, low_res_mesh = false, CSF_segmentation = false; int gapInterSlices = 4, nbSlicesInitialisation = 5; double radius = 4.0; int numberOfPropagationIteration = 200; double maxDeformation = 0.0, maxArea = 0.0, minContrast = 50.0, tradeoff_d; bool tradeoff_d_bool = false; for (int i = 0; i < argc; ++i) { if (strcmp(argv[i],"-i")==0) { i++; inputFilename = argv[i]; } else if (strcmp(argv[i],"-i-dicom")==0) { i++; //inputFilename = argv[i]; //input_dicom = true; } else if (strcmp(argv[i],"-o")==0) { i++; outputPath = argv[i]; } else if (strcmp(argv[i],"-t")==0) { i++; if (strcmp(argv[i],"t1")==0) { typeImageFactor = -1.0; if (verbose) cout << endl << "WARNING: be sure your image is a T1-weighted image." << endl << endl; } else if (strcmp(argv[i],"t2")==0) { typeImageFactor = 1.0; if (verbose) cout << endl << "WARNING: be sure your image is a T2-weighted image." << endl << endl; } else { cout << "Error: Invalid type or image (need to be \"t1\" or \"t2\")" << endl << endl; help(); return EXIT_FAILURE; } } else if (strcmp(argv[i],"-init")==0) { i++; initialisation = atof(argv[i]); } else if (strcmp(argv[i],"-down")==0) { i++; downSlice = atoi(argv[i]); } else if (strcmp(argv[i],"-up")==0) { i++; upSlice = atoi(argv[i]); } else if (strcmp(argv[i],"-detect-display")==0) { output_detection = true; } else if (strcmp(argv[i],"-mesh")==0) { output_mesh = true; } else if (strcmp(argv[i],"-centerline-binary")==0) { output_centerline_binary = true; } else if (strcmp(argv[i],"-centerline-coord")==0) { output_centerline_coord = true; } else if (strcmp(argv[i],"-cross")==0) { output_cross = true; } else if (strcmp(argv[i],"-detect-n")==0) { i++; nbSlicesInitialisation = atoi(argv[i]); } else if (strcmp(argv[i],"-detect-gap")==0) { i++; gapInterSlices = atoi(argv[i]); } else if (strcmp(argv[i],"-detect-radius")==0) { i++; radius = atof(argv[i]); } else if (strcmp(argv[i],"-init-centerline")==0) { i++; inputCenterlineFilename = argv[i]; init_with_centerline = true; } else if (strcmp(argv[i],"-nbiter")==0) { i++; numberOfPropagationIteration = atoi(argv[i]); } else if (strcmp(argv[i],"-init-mask")==0) { i++; initMaskFilename = argv[i]; init_with_mask = true; } else if (strcmp(argv[i],"-init-tube")==0) { output_init_tube = true; } else if (strcmp(argv[i],"-init-validation")==0) { init_validation = true; } else if (strcmp(argv[i],"-low-resolution-mesh")==0) { low_res_mesh = true; } else if (strcmp(argv[i],"-max-deformation")==0) { i++; maxDeformation = atof(argv[i]); } else if (strcmp(argv[i],"-max-area")==0) { i++; maxArea = atof(argv[i]); } else if (strcmp(argv[i],"-min-contrast")==0) { i++; minContrast = atof(argv[i]); } else if (strcmp(argv[i],"-d")==0) { i++; tradeoff_d = atof(argv[i]); tradeoff_d_bool = true; } else if (strcmp(argv[i],"-CSF")==0) { CSF_segmentation = true; if (maxArea == 0.0) maxArea = 120; if (maxDeformation == 0.0) maxDeformation = 2.5; } else if (strcmp(argv[i],"-verbose")==0) { verbose = true; } else if (strcmp(argv[i],"-help")==0) { help(); return EXIT_FAILURE; } } if (inputFilename == "") { cerr << "Input filename or folder (if DICOM) not provided" << endl; help(); return EXIT_FAILURE; } if (typeImageFactor == 0) { cerr << "Error: The type of contrast not provided (option -t)" << endl; help(); return EXIT_FAILURE; } // output files must have the same extension as input file string nii=".nii", niigz=".nii.gz"; suffix=niigz; size_t pos = inputFilename.find(niigz); if (pos == string::npos) { pos = inputFilename.find(nii); suffix = nii; } if (outputPath!="" && outputPath.compare(outputPath.length()-1,1,"/")) outputPath += "/"; // add "/" if missing outputFilenameBinary = outputPath+"segmentation_binary"+suffix; outputFilenameMesh = outputPath+"segmentation_mesh.vtk"; outputFilenameBinaryCSF = outputPath+"segmentation_CSF_binary"+suffix; outputFilenameMeshCSF = outputPath+"segmentation_CSF_mesh.vtk"; outputFilenameAreas = outputPath+"cross_sectional_areas.txt"; outputFilenameAreasCSF = outputPath+"cross_sectional_areas_CSF.txt"; outputFilenameCenterline = outputPath+"segmentation_centerline.txt"; outputFilenameCenterlineBinary = outputPath+"segmentation_centerline_binary"+suffix; // if output path doesn't exist, we create it if (outputPath!="") itk::FileTools::CreateDirectory(outputPath.c_str()); // Image reading - image can be T1 or T2 (or Tx-like) depending on contrast between spinal cord and CSF // typeImageFactor depend of contrast type and is equal to +1 when CSF is brighter than spinal cord and equal to -1 inversely ImageType::Pointer initialImage, image = ImageType::New(); if (input_dicom) { /*ImageIOType::Pointer gdcmIO = ImageIOType::New(); InputNamesGeneratorType::Pointer inputNames = InputNamesGeneratorType::New(); inputNames->SetInputDirectory( inputFilename ); const DICOMReaderType::FileNamesContainer & filenames = inputNames->GetInputFileNames(); DICOMReaderType::Pointer reader = DICOMReaderType::New(); reader->SetImageIO( gdcmIO ); reader->SetFileNames( filenames ); try { reader->Update(); } catch (itk::ExceptionObject &excp) { std::cerr << "Exception thrown while reading the DICOM series" << std::endl; std::cerr << excp << std::endl; return EXIT_FAILURE; } initialImage = reader->GetOutput();*/ } else { ReaderType::Pointer reader = ReaderType::New(); itk::NiftiImageIO::Pointer io = itk::NiftiImageIO::New(); reader->SetImageIO(io); reader->SetFileName(inputFilename); try { reader->Update(); } catch( itk::ExceptionObject & e ) { cerr << "Exception caught while reading input image" << endl; cerr << e << endl; return EXIT_FAILURE; } initialImage = reader->GetOutput(); } // Change orientation of input image to AIL. Output images will have the same orientation as input image OrientImage<ImageType> orientationFilter; orientationFilter.setInputImage(initialImage); orientationFilter.orientation(itk::SpatialOrientation::ITK_COORDINATE_ORIENTATION_AIL); initialImage = orientationFilter.getOutputImage(); // Crop image if it is too large in left-right direction. No need to compute the initialization on the whole image. We assume the spinal cord is included in a 5cm large region. ImageType::SizeType desiredSize = initialImage->GetLargestPossibleRegion().GetSize(); ImageType::SpacingType spacingI = initialImage->GetSpacing(); if (desiredSize[2]*spacingI[2] > 60 && !init_with_mask && !init_with_centerline) { SymmetricalCropping symCroppingFilter; symCroppingFilter.setInputImage(initialImage); symCroppingFilter.setInitSlice(initialisation); int crop_slice = -1; try { crop_slice = symCroppingFilter.symmetryDetection(); } catch(exception & e) { cerr << "Exception caught while computing symmetry" << endl; cerr << e.what() << endl; return EXIT_FAILURE; } if (crop_slice != -1) { if (verbose) cout << "Cropping input image in left-right direction around slice = " << crop_slice << endl; image = symCroppingFilter.cropping(); } else { if (verbose) cout << "Image non cropped for symmetry" << endl; image = initialImage; } } else image = initialImage; // Intensity normalization RescaleFilterType::Pointer rescaleFilter = RescaleFilterType::New(); rescaleFilter->SetInput(image); rescaleFilter->SetOutputMinimum(0); rescaleFilter->SetOutputMaximum(1000); try { rescaleFilter->Update(); } catch( itk::ExceptionObject & e ) { cerr << "Exception caught while normalizing input image " << endl; cerr << e << endl; return EXIT_FAILURE; } image = rescaleFilter->GetOutput(); // computing magnitude and direction of gradient image GradientMFilterType::Pointer gradientMagnitudeFilter = GradientMFilterType::New(); gradientMagnitudeFilter->SetInput(image); try { gradientMagnitudeFilter->Update(); } catch( itk::ExceptionObject & e ) { cerr << "Exception caught while updating gradientMagnitudeFilter " << endl; cerr << e << endl; return EXIT_FAILURE; } ImageType::Pointer imageGradient = gradientMagnitudeFilter->GetOutput(); VectorGradientFilterType::Pointer gradientMapFilter = VectorGradientFilterType::New(); gradientMapFilter->SetInput( image ); try { gradientMapFilter->Update(); } catch( itk::ExceptionObject & e ) { cerr << "Exception caught while updating gradientMapFilter " << endl; cerr << e << endl; return EXIT_FAILURE; } GradientImageType::Pointer imageVectorGradient = gradientMapFilter->GetOutput(); // Creation of 3D image with origin, orientation and scaling, containing original image, gradient image, vector gradient image ImageType::SizeType regionSize = image->GetLargestPossibleRegion().GetSize(); ImageType::PointType origineI = image->GetOrigin(); CVector3 origine = CVector3(origineI[0],origineI[1],origineI[2]); ImageType::DirectionType directionI = image->GetInverseDirection(); CVector3 directionX = CVector3(directionI[0][0],directionI[0][1],directionI[0][2]), directionY = CVector3(directionI[1][0],directionI[1][1],directionI[1][2]), directionZ = CVector3(directionI[2][0],directionI[2][1],directionI[2][2]); CVector3 spacing = CVector3(spacingI[0],spacingI[1],spacingI[2]); Image3D* image3DGrad = new Image3D(imageVectorGradient,regionSize[0],regionSize[1],regionSize[2],origine,directionX,directionY,directionZ,spacing,typeImageFactor); image3DGrad->setImageOriginale(initialImage); image3DGrad->setCroppedImageOriginale(image); image3DGrad->setImageMagnitudeGradient(imageGradient); /****************************************** // Initialization of Propagated Deformable Model of Spinal Cord ******************************************/ int radialResolution, axialResolution, numberOfDeformIteration = 3; double axialStep, propagationLength = 800.0; // Definition of parameters for T1 and T2 images. T1 need better resolution to provide accurate segmentation. if (typeImageFactor == 1.0) { // T2 radialResolution = 15; axialResolution = 3; axialStep = 6.0; } else { // T1 radialResolution = 20; //30 axialResolution = 3; //5 axialStep = 6.0; //8 } CVector3 point, normal1, normal2; // normal1 and normal2 and normals in both direction from initial point double stretchingFactor = 1.0; vector<CVector3> centerline; if (init_with_centerline) { if (verbose) cout << "Initialization - using given centerline" << endl; centerline = extractCenterline(inputCenterlineFilename); if (centerline.size() == 0) return EXIT_FAILURE; } else if (init_with_mask) { if (verbose) cout << "Initialization - using given mask" << endl; bool result_init = extractPointAndNormalFromMask(initMaskFilename, point, normal1, normal2); if (!result_init) return EXIT_FAILURE; if (verbose) { cout << "Point = " << point << endl; cout << "Normal 1 = " << normal1 << endl; cout << "Normal 2 = " << normal2 << endl; } } else { bool isSpinalCordDetected = false; int countFailure = 0; double step = 0.025; // step of displacement in pourcentage of the image do { if (verbose) cout << "Initialization - spinal cord detection on axial slices" << endl; Initialisation init(image,typeImageFactor); init.setVerbose(verbose); init.setGap(gapInterSlices); // gap between slices is necessary to provide good normals init.setRadius(radius); // approximate radius of spinal cord. This parameter is used to initiate Hough transform init.setNumberOfSlices(nbSlicesInitialisation); // if the initialization fails at the first position in the image, an other spinal cord detection process is launch higher. int d = rand() % 2; if (d==0) d = -1; isSpinalCordDetected = init.computeInitialParameters(initialisation+(double)countFailure*step*(double)d); //if (!isSpinalCordDetected) isSpinalCordDetected = init.computeInitialParameters(0.7); if(isSpinalCordDetected) { if (output_detection) init.savePointAsAxialImage(image,outputPath+"result_detection.png"); init.getPoints(point,normal1,normal2,radius,stretchingFactor); if (normal2 == CVector3::ZERO) normal2 = -normal1; if (verbose) { cout << "Initialization - Spinal Cord Detection:" << endl; cout << "Point = " << point << endl; cout << "Normal 1 = " << normal1 << endl; cout << "Normal 2 = " << normal2 << endl; cout << "Radius = " << radius << endl; } if(init_validation) { // Definition of discrimination surface for the validation of the spinal cord detection module double K_T1 = 15.7528, K_T2 = 3.2854; CVector3 L_T1 = CVector3(-0.0762,-2.5921,0.3472), L_T2 = CVector3(-0.0022,-1.2995,0.4909); CMatrix3x3 Q_T1, Q_T2; Q_T1[0] = 0.0; Q_T1[1] = 0.0; Q_T1[2] = 0.0; Q_T1[3] = 0.0; Q_T1[4] = 0.1476; Q_T1[5] = 0.0; Q_T1[6] = 0.0; Q_T1[7] = 0.0; Q_T1[8] = 0.6082; Q_T2[0] = 0.0; Q_T2[1] = 0.0; Q_T2[2] = 0.0; Q_T2[3] = 0.0; Q_T2[4] = 0.0687; Q_T2[5] = 0.0; Q_T2[6] = 0.0; Q_T2[7] = 0.0; Q_T2[8] = 0.3388; double contrast = 0.0, mean_distance = 0.0, std_distance = 0.0; // validation of the spinal cord detetion int *sizeDesired = new int[3]; double *spacingDesired = new double[3]; sizeDesired[0] = 61; sizeDesired[1] = 61; sizeDesired[2] = 11; spacingDesired[0] = 0.5; spacingDesired[1] = 0.5; spacingDesired[2] = 0.5; SCRegion* spinal_cord_verif = new SCRegion(); spinal_cord_verif->setSize(sizeDesired); spinal_cord_verif->setSpacing(spacingDesired); spinal_cord_verif->setOrigin(point[0],point[1],point[2]); spinal_cord_verif->setNormal(normal1[0],normal1[1],normal1[2]); spinal_cord_verif->setFactor(typeImageFactor); try { spinal_cord_verif->readImage(initialImage); spinal_cord_verif->createImage(); contrast = spinal_cord_verif->computeContrast(mean_distance,std_distance,15); } catch (string const& e) { cerr << e << endl; contrast = -1.0; } CVector3 vec = CVector3(contrast,mean_distance,std_distance); double discrim = 0.0; if (typeImageFactor == -1) // if T1 { CVector3 temp = vec*Q_T1; double quad = 0.0; for(int r=0; r<3; r++) { quad += temp[r]*vec[r]; } discrim = K_T1 + vec*L_T1 + quad; } else{ CVector3 temp = vec*Q_T2; double quad = 0.0; for(int r=0; r<3; r++) { quad += temp[r]*vec[r]; } discrim = K_T2 + vec*L_T2 + quad; } if (discrim > 0.0) { countFailure++; isSpinalCordDetected = false; if (verbose) cout << "WARNING: Bad initialization. Attempt to locate spinal cord at an other level." << endl << endl; } else { isSpinalCordDetected = true; } delete sizeDesired, spacingDesired, spinal_cord_verif; } else { isSpinalCordDetected = true; } } else { countFailure++; } } while (!isSpinalCordDetected && countFailure<10); if (!isSpinalCordDetected) { cerr << "Error: Enable to detect the spinal cord. Please provide the initial position and orientation of the spinal cord (-init, -init-mask)" << endl; return EXIT_FAILURE; } } /****************************************** // Launch of Propagated Deformable Model of Spinal Cord. Propagation have to be done in both direction ******************************************/ PropagatedDeformableModel* prop = new PropagatedDeformableModel(radialResolution,axialResolution,radius,numberOfDeformIteration,numberOfPropagationIteration,axialStep,propagationLength); if (maxDeformation != 0.0) prop->setMaxDeformation(maxDeformation); if (maxArea != 0.0) prop->setMaxArea(maxArea); prop->setMinContrast(minContrast); prop->setInitialPointAndNormals(point,normal1,normal2); prop->setStretchingFactor(stretchingFactor); prop->setUpAndDownLimits(downSlice,upSlice); prop->setImage3D(image3DGrad); if (init_with_centerline) { prop->propagationWithCenterline(); for (unsigned int k=0; k<centerline.size(); k++) prop->addPointToCenterline(centerline[k]); if (initialisation <= 1) prop->setInitPosition(initialisation); } if (tradeoff_d_bool) { prop->setTradeOffDistanceFeature(tradeoff_d); } prop->setVerbose(verbose); prop->computeMeshInitial(); if (output_init_tube) { SpinalCord *tube1 = prop->getInitialMesh(), *tube2 = prop->getInverseInitialMesh(); tube1->save(outputPath+"InitialTube1.vtk"); tube2->save(outputPath+"InitialTube2.vtk"); } prop->adaptationGlobale(); // Propagation // Saving low resolution mesh if (low_res_mesh) { SpinalCord *meshOutputLowResolution = prop->getOutput(); meshOutputLowResolution->save(outputPath+"segmentation_mesh_low_resolution.vtk",initialImage); //meshOutput->computeCenterline(true,path+"LowResolution"); //meshOutput->computeCrossSectionalArea(true,path+"LowResolution"); //image3DGrad->TransformMeshToBinaryImage(meshOutput,path+"LowResolution",orientationFilter.getInitialImageOrientation()); //meshOutput->saveCenterlineAsBinaryImage(initialImage,path+"LowResolution",orientationFilter.getInitialImageOrientation()); } /****************************************** // High Resolution Deformation ******************************************/ prop->rafinementGlobal(); SpinalCord* meshOutputFinal = prop->getOutputFinal(); if (output_mesh) meshOutputFinal->save(outputFilenameMesh,initialImage); if (output_centerline_coord) meshOutputFinal->computeCenterline(true,outputFilenameCenterline,true); if (output_cross) meshOutputFinal->computeCrossSectionalArea(true,outputFilenameAreas,true,image3DGrad); image3DGrad->TransformMeshToBinaryImage(meshOutputFinal,outputFilenameBinary,orientationFilter.getInitialImageOrientation()); if (output_centerline_binary) meshOutputFinal->saveCenterlineAsBinaryImage(initialImage,outputFilenameCenterlineBinary,orientationFilter.getInitialImageOrientation()); if (verbose) { double lengthPropagation = meshOutputFinal->getLength(); cout << "Total propagation length = " << lengthPropagation << " mm" << endl; } if (CSF_segmentation) { /****************************************** // Launch of Propagated Deformable Model on the CSF. Propagation have to be done in both direction ******************************************/ double factor_CSF = 2; PropagatedDeformableModel* prop_CSF = new PropagatedDeformableModel(radialResolution,axialResolution,radius*factor_CSF,numberOfDeformIteration,numberOfPropagationIteration,axialStep,propagationLength); if (maxDeformation != 0.0) prop_CSF->setMaxDeformation(maxDeformation*factor_CSF); if (maxArea != 0.0) prop_CSF->setMaxArea(maxArea*factor_CSF*2); prop->setMinContrast(minContrast); prop_CSF->setInitialPointAndNormals(point,normal1,normal2); prop_CSF->setStretchingFactor(stretchingFactor); prop_CSF->setUpAndDownLimits(downSlice,upSlice); image3DGrad->setTypeImageFactor(-image3DGrad->getTypeImageFactor()); prop_CSF->setImage3D(image3DGrad); if (init_with_centerline) { prop_CSF->propagationWithCenterline(); for (unsigned int k=0; k<centerline.size(); k++) prop->addPointToCenterline(centerline[k]); if (initialisation <= 1) prop->setInitPosition(initialisation); } prop_CSF->setVerbose(verbose); prop_CSF->computeMeshInitial(); if (output_init_tube) { SpinalCord *tube1 = prop_CSF->getInitialMesh(), *tube2 = prop_CSF->getInverseInitialMesh(); tube1->save(outputPath+"InitialTubeCSF1.vtk"); tube2->save(outputPath+"InitialTubeCSF2.vtk"); } prop_CSF->adaptationGlobale(); // Propagation // Saving low resolution mesh if (low_res_mesh) { SpinalCord *meshOutputLowResolution = prop_CSF->getOutput(); meshOutputLowResolution->save(outputPath+"segmentation_CSF_mesh_low_resolution.vtk",initialImage); //meshOutput->computeCenterline(true,path+"LowResolution"); //meshOutput->computeCrossSectionalArea(true,path+"LowResolution"); //image3DGrad->TransformMeshToBinaryImage(meshOutput,path+"LowResolution",orientationFilter.getInitialImageOrientation()); //meshOutput->saveCenterlineAsBinaryImage(initialImage,path+"LowResolution",orientationFilter.getInitialImageOrientation()); } /****************************************** // High Resolution Deformation ******************************************/ prop_CSF->rafinementGlobal(); SpinalCord* meshOutputFinal = prop_CSF->getOutputFinal(); if (output_mesh) meshOutputFinal->save(outputFilenameMeshCSF,initialImage); if (output_cross) meshOutputFinal->computeCrossSectionalArea(true,outputFilenameAreasCSF,true,image3DGrad); image3DGrad->TransformMeshToBinaryImage(meshOutputFinal,outputFilenameBinaryCSF,orientationFilter.getInitialImageOrientation()); if (verbose) { double lengthPropagation = meshOutputFinal->getLength(); cout << "Total propagation length = " << lengthPropagation << " mm" << endl; } delete prop_CSF; } delete image3DGrad, prop; return EXIT_SUCCESS; }
int changeOrientationMethod(string inputFilename, string outputFilename, OrientationType orientation, bool changeOrientation, bool displayInitialOrientation, bool displayAvailableOrientation) { typedef itk::Image< TPixelType, N > ImageType; typedef itk::ImageFileReader<ImageType> ReaderType; typedef itk::ImageFileWriter<ImageType> WriterType; typename ReaderType::Pointer reader = ReaderType::New(); itk::NiftiImageIO::Pointer io = itk::NiftiImageIO::New(); reader->SetImageIO(io); reader->SetFileName(inputFilename); OrientImage<ImageType> orientationFilter; orientationFilter.setInputImage(reader->GetOutput()); if (displayInitialOrientation) { try { io->SetFileName(inputFilename); io->ReadImageInformation(); //reader->Update(); } catch( itk::ExceptionObject & e ) { std::cerr << "Exception caught while reading input image " << std::endl; std::cerr << e << std::endl; } typename ImageType::DirectionType direction; vector<double> dir0 = io->GetDirection(0); for (int i=0; i<dir0.size(); i++) direction(i,0) = dir0[i]; vector<double> dir1 = io->GetDirection(1); for (int i=0; i<dir1.size(); i++) direction(i,1) = dir1[i]; vector<double> dir2 = io->GetDirection(2); for (int i=0; i<dir2.size(); i++) direction(i,2) = dir2[i]; cout << direction << endl; cout << "Input image orientation : " << FlagToString(orientationFilter.getOrientationFromDirection(direction)) << endl; } if (changeOrientation) { try { io->SetFileName(inputFilename); io->ReadImageInformation(); //reader->Update(); } catch( itk::ExceptionObject & e ) { std::cerr << "Exception caught while reading input image " << std::endl; std::cerr << e << std::endl; } orientationFilter.orientation(orientation); typename WriterType::Pointer writer = WriterType::New(); writer->SetImageIO(io); writer->SetFileName(outputFilename); writer->SetInput(orientationFilter.getOutputImage()); try { writer->Write(); } catch( itk::ExceptionObject & e ) { std::cerr << "Exception caught while writing output image " << std::endl; std::cerr << e << std::endl; } } return EXIT_SUCCESS; }
void Initialisation::savePointAsBinaryImage(ImageType::Pointer initialImage, string filename, OrientationType orientation) { if (points_.size() > 0) { typedef itk::Image< unsigned char, 3 > BinaryImageType; BinaryImageType::Pointer binary = BinaryImageType::New(); ImageType::RegionType region; ImageType::IndexType start; start[0] = 0; start[1] = 0; start[2] = 0; ImageType::SizeType size, imSize = initialImage->GetLargestPossibleRegion().GetSize(); size[0] = imSize[0]; size[1] = imSize[1]; size[2] = imSize[2]; region.SetSize(size); region.SetIndex(start); binary->CopyInformation(initialImage); binary->SetRegions(region); binary->Allocate(); binary->FillBuffer(false); typedef ImageType::IndexType IndexType; ContinuousIndex ind; IndexType ind2; unsigned int pSize = points_.size(); unsigned int indexMiddle = 0; for (unsigned int i=0; i<pSize; i++) { if (points_[i][1] == startSlice_) indexMiddle = i; } ind[0] = points_[indexMiddle][0]; ind[1] = points_[indexMiddle][1]; ind[2] = points_[indexMiddle][2]; PointType pt; inputImage_->TransformContinuousIndexToPhysicalPoint(ind, pt); initialImage->TransformPhysicalPointToIndex(pt, ind2); binary->SetPixel(ind2,true); OrientImage<BinaryImageType> orientationFilter; orientationFilter.setInputImage(binary); orientationFilter.orientation(orientation); binary = orientationFilter.getOutputImage(); ImageIterator it( binary, binary->GetRequestedRegion() ); it.GoToBegin(); while(!it.IsAtEnd()) { if (it.Get()==true) { ind2 = it.GetIndex(); break; } ++it; } if (verbose_) cout << "Center of spinal cord saved on pixel : " << ind2 << endl; WriterBinaryType::Pointer writer = WriterBinaryType::New(); itk::NiftiImageIO::Pointer io = itk::NiftiImageIO::New(); writer->SetImageIO(io); writer->SetFileName(filename); writer->SetInput(binary); try { writer->Write(); } catch( itk::ExceptionObject & e ) { std::cerr << "Exception caught while writing image " << std::endl; std::cerr << e << std::endl; } } else cout << "Error: Spinal cord center not detected" << endl; }