int main(int argc, char* argv[]) { CSimpleOpt::SOption specs[] = { { 0, "-o", SO_REQ_SEP }, SO_END_OF_OPTIONS }; Options argParser; StringVector args = argParser.ParseOptions(argc, argv, specs); if (args.size() < 1) { cout << argv[0] << " [input-vector] [output-rgb]" << endl; return 1; } ImageIO<DeformFieldImageType> io; DeformFieldImageType::Pointer img = io.ReadImage(args[0]); // itk::UnaryFunctorImageFilter<DeformFieldImageType,RGBImageType> CastFilter; typedef itk::UnaryFunctorImageFilter<DeformFieldImageType, RGBImageType, Vector2RGB> CastFilter; CastFilter::Pointer caster = CastFilter::New(); caster->SetInput(img); caster->Update(); RGBImageType::Pointer rgbImg = caster->GetOutput(); rgbImg->Print(cout); io.WriteImageS<RGBImageType>(args[1], rgbImg); return 0; }
//#################### PUBLIC METHODS #################### void CTIPFBuilder::execute() { typedef itk::Image<short,3> GradientMagnitudeImage; typedef itk::Image<int,3> HounsfieldImage; typedef itk::Image<float,3> RealImage; typedef itk::Image<unsigned char,3> WindowedImage; HounsfieldImage::Pointer hounsfieldImage = (*m_volume)->base_image(); //~~~~~~~ // STEP 1 //~~~~~~~ set_status("Preprocessing image..."); // Construct the windowed image. WindowedImage::Pointer windowedImage = (*m_volume)->windowed_image(m_segmentationOptions.windowSettings); if(is_aborted()) return; // Cast the input image (whether Hounsfield or windowed) to make its pixels real-valued. RealImage::Pointer realImage; switch(m_segmentationOptions.inputType) { case CTSegmentationOptions::INPUTTYPE_HOUNSFIELD: { typedef itk::CastImageFilter<HounsfieldImage,RealImage> CastFilter; CastFilter::Pointer castFilter = CastFilter::New(); castFilter->SetInput(hounsfieldImage); castFilter->Update(); realImage = castFilter->GetOutput(); break; } case CTSegmentationOptions::INPUTTYPE_WINDOWED: { typedef itk::CastImageFilter<WindowedImage,RealImage> CastFilter; CastFilter::Pointer castFilter = CastFilter::New(); castFilter->SetInput(windowedImage); castFilter->Update(); realImage = castFilter->GetOutput(); break; } default: { throw Exception("Unknown CT segmentation input type"); // this should never happen } } if(is_aborted()) return; // Smooth this real image using anisotropic diffusion filtering. typedef itk::GradientAnisotropicDiffusionImageFilter<RealImage,RealImage> ADFilter; for(int i=0; i<m_segmentationOptions.adfIterations; ++i) { ADFilter::Pointer adFilter = ADFilter::New(); adFilter->SetInput(realImage); adFilter->SetConductanceParameter(1.0); adFilter->SetNumberOfIterations(1); adFilter->SetTimeStep(0.0625); adFilter->Update(); realImage = adFilter->GetOutput(); if(is_aborted()) return; increment_progress(); } // Calculate the gradient magnitude of the smoothed image. typedef itk::GradientMagnitudeImageFilter<RealImage,GradientMagnitudeImage> GMFilter; GMFilter::Pointer gmFilter = GMFilter::New(); gmFilter->SetInput(realImage); gmFilter->SetUseImageSpacingOff(); gmFilter->Update(); GradientMagnitudeImage::Pointer gradientMagnitudeImage = gmFilter->GetOutput(); if(is_aborted()) return; increment_progress(); //~~~~~~~ // STEP 2 //~~~~~~~ set_status("Running watershed..."); // Run the watershed algorithm on the gradient magnitude image. typedef MeijsterRoerdinkWatershed<GradientMagnitudeImage::PixelType,3> WS; WS ws(gradientMagnitudeImage, ITKImageUtil::make_6_connected_offsets()); if(is_aborted()) return; increment_progress(); //~~~~~~~ // STEP 3 //~~~~~~~ set_status("Creating initial partition forest..."); boost::shared_ptr<CTImageLeafLayer> leafLayer(new CTImageLeafLayer(hounsfieldImage, windowedImage, gradientMagnitudeImage)); if(is_aborted()) return; boost::shared_ptr<CTImageBranchLayer> lowestBranchLayer = IPF::make_lowest_branch_layer(leafLayer, ws.calculate_groups()); if(is_aborted()) return; m_ipf.reset(new IPF(leafLayer, lowestBranchLayer)); increment_progress(); //~~~~~~~ // STEP 4 //~~~~~~~ set_status("Creating rooted MST for lowest branch layer..."); RootedMST<int> mst(*lowestBranchLayer); if(is_aborted()) return; increment_progress(); //~~~~~~~ // STEP 5 //~~~~~~~ set_status("Running waterfall..."); // Iteratively run a Nicholls waterfall pass on the MST until the forest is built. typedef WaterfallPass<int>::Listener WaterfallPassListener; NichollsWaterfallPass<int> waterfallPass; boost::shared_ptr<WaterfallPassListener> listener = make_forest_building_waterfall_pass_listener(m_ipf); waterfallPass.add_listener(listener); while(mst.node_count() != 1 && m_ipf->highest_layer() < m_segmentationOptions.waterfallLayerLimit) { m_ipf->clone_layer(m_ipf->highest_layer()); if(is_aborted()) return; waterfallPass.run(mst); if(is_aborted()) return; } set_finished(); }
void forest_test() { // Create the Hounsfield and 'windowed' images. typedef itk::Image<int,2> HounsfieldImage; typedef itk::Image<unsigned char,2> WindowedImage; typedef itk::Image<short,2> GradientMagnitudeImage; int pixels[] = { 2,2,2,9,9,3,3,3, 2,2,2,9,9,3,3,3, 2,2,2,9,9,3,3,3, 9,9,9,9,9,9,9,9, 9,9,9,9,9,9,9,9, 5,5,5,9,9,3,3,3, 5,5,5,9,9,3,3,3, 5,5,5,9,9,3,3,3, }; HounsfieldImage::Pointer hounsfieldImage = ITKImageUtil::make_filled_image(8, 8, pixels); ITKImageUtil::output_image(std::cout, hounsfieldImage); std::cout << '\n'; // This is not the proper way to do windowing - it's a hack for testing purposes. typedef itk::CastImageFilter<HounsfieldImage,WindowedImage> CastFilter; CastFilter::Pointer castFilter = CastFilter::New(); castFilter->SetInput(hounsfieldImage); castFilter->Update(); WindowedImage::Pointer windowedImage = castFilter->GetOutput(); // Calculate the gradient magnitude image. typedef itk::GradientMagnitudeImageFilter<WindowedImage,GradientMagnitudeImage> GradientMagnitudeFilter; GradientMagnitudeFilter::Pointer gradientMagnitudeFilter = GradientMagnitudeFilter::New(); gradientMagnitudeFilter->SetInput(windowedImage); gradientMagnitudeFilter->SetUseImageSpacingOff(); gradientMagnitudeFilter->Update(); GradientMagnitudeImage::Pointer gradientMagnitudeImage = gradientMagnitudeFilter->GetOutput(); ITKImageUtil::output_image(std::cout, gradientMagnitudeImage); std::cout << '\n'; // Run the watershed algorithm on the gradient magnitude image. typedef MeijsterRoerdinkWatershed<GradientMagnitudeImage::PixelType,2> WS; WS ws(gradientMagnitudeImage, ITKImageUtil::make_4_connected_offsets()); // Output the results. ITKImageUtil::output_image(std::cout, ws.lower_complete()); std::cout << '\n'; ITKImageUtil::output_image(std::cout, ws.arrows()); std::cout << '\n'; ITKImageUtil::output_image(std::cout, ws.labels()); std::cout << '\n'; // Create the initial partition forest. typedef PartitionForest<CTImageLeafLayer,CTImageBranchLayer> IPF; typedef shared_ptr<IPF> IPF_Ptr; shared_ptr<CTImageLeafLayer> leafLayer(new CTImageLeafLayer(hounsfieldImage, windowedImage, gradientMagnitudeImage)); shared_ptr<CTImageBranchLayer> lowestBranchLayer = IPF::make_lowest_branch_layer(leafLayer, ws.calculate_groups()); std::copy(lowestBranchLayer->edges_cbegin(), lowestBranchLayer->edges_cend(), std::ostream_iterator<WeightedEdge<int> >(std::cout, " ")); std::cout << '\n'; IPF_Ptr ipf(new IPF(leafLayer, lowestBranchLayer)); }
//#################### PUBLIC METHODS #################### void CTLowestLayersBuilder::execute() { typedef itk::Image<short,3> GradientMagnitudeImage; typedef itk::Image<int,3> HounsfieldImage; typedef itk::Image<float,3> RealImage; typedef itk::Image<unsigned char,3> WindowedImage; HounsfieldImage::Pointer hounsfieldImage = (*m_volume)->base_image(); //~~~~~~~ // STEP 1 //~~~~~~~ set_status("Preprocessing image..."); // Construct the windowed image. WindowedImage::Pointer windowedImage = (*m_volume)->windowed_image(m_segmentationOptions.windowSettings); if(is_aborted()) return; // Cast the input image (whether Hounsfield or windowed) to make its pixels real-valued. RealImage::Pointer realImage; switch(m_segmentationOptions.inputType) { case CTSegmentationOptions::INPUTTYPE_HOUNSFIELD: { typedef itk::CastImageFilter<HounsfieldImage,RealImage> CastFilter; CastFilter::Pointer castFilter = CastFilter::New(); castFilter->SetInput(hounsfieldImage); castFilter->Update(); realImage = castFilter->GetOutput(); break; } case CTSegmentationOptions::INPUTTYPE_WINDOWED: { typedef itk::CastImageFilter<WindowedImage,RealImage> CastFilter; CastFilter::Pointer castFilter = CastFilter::New(); castFilter->SetInput(windowedImage); castFilter->Update(); realImage = castFilter->GetOutput(); break; } default: { throw Exception("Unknown CT segmentation input type"); // this should never happen } } if(is_aborted()) return; // Smooth this real image using anisotropic diffusion filtering. typedef itk::GradientAnisotropicDiffusionImageFilter<RealImage,RealImage> ADFilter; for(int i=0; i<m_segmentationOptions.adfIterations; ++i) { ADFilter::Pointer adFilter = ADFilter::New(); adFilter->SetInput(realImage); adFilter->SetConductanceParameter(1.0); adFilter->SetNumberOfIterations(1); adFilter->SetTimeStep(0.0625); adFilter->Update(); realImage = adFilter->GetOutput(); if(is_aborted()) return; increment_progress(); } // Calculate the gradient magnitude of the smoothed image. typedef itk::GradientMagnitudeImageFilter<RealImage,GradientMagnitudeImage> GMFilter; GMFilter::Pointer gmFilter = GMFilter::New(); gmFilter->SetInput(realImage); gmFilter->SetUseImageSpacingOff(); gmFilter->Update(); GradientMagnitudeImage::Pointer gradientMagnitudeImage = gmFilter->GetOutput(); if(is_aborted()) return; increment_progress(); //~~~~~~~ // STEP 2 //~~~~~~~ set_status("Running watershed..."); // Run the watershed algorithm on the gradient magnitude image. typedef MeijsterRoerdinkWatershed<GradientMagnitudeImage::PixelType,3> WS; WS ws(gradientMagnitudeImage, ITKImageUtil::make_6_connected_offsets()); if(is_aborted()) return; increment_progress(); //~~~~~~~ // STEP 3 //~~~~~~~ set_status("Creating lowest forest layers..."); m_leafLayer.reset(new CTImageLeafLayer(hounsfieldImage, windowedImage, gradientMagnitudeImage)); if(is_aborted()) return; m_lowestBranchLayer = IPF::make_lowest_branch_layer(m_leafLayer, ws.calculate_groups()); if(is_aborted()) return; set_finished(); }