int main(int argc, char*argv[]) { if(argc != 3) { std::cerr << "Required arguments: mask output" << std::endl; return EXIT_FAILURE; } std::string maskFilename = argv[1]; std::string outputFilename = argv[2]; std::cout << "Reading mask: " << maskFilename << std::endl; std::cout << "Output: " << outputFilename << std::endl; Mask::Pointer mask = Mask::New(); mask->Read(maskFilename.c_str()); Mask::BoundaryImageType::Pointer boundaryImage = Mask::BoundaryImageType::New(); boundaryImage->SetRegions(mask->GetLargestPossibleRegion()); boundaryImage->Allocate(); // mask->CreateBoundaryImage(boundaryImage.GetPointer(), mask->GetValidValue()); mask->CreateBoundaryImage(boundaryImage.GetPointer(), Mask::VALID); ITKHelpers::WriteImage(boundaryImage.GetPointer(), outputFilename); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { if(argc != 4) { std::cerr << "Required arguments: image mask output" << std::endl; return EXIT_FAILURE; } std::string imageFilename = argv[1]; std::string maskFilename = argv[2]; std::string outputFilename = argv[3]; Mask::Pointer mask = Mask::New(); mask->Read(maskFilename); typedef itk::Image<unsigned char, 2> ImageType; ImageType::Pointer image = ImageType::New(); ITKHelpers::ReadImage(imageFilename, image.GetPointer()); FastDigitalInpainting fastDigitalInpainting; fastDigitalInpainting.SetImage(image); fastDigitalInpainting.SetMask(mask); fastDigitalInpainting.SetNumberOfIterations(100); fastDigitalInpainting.Inpaint(); ITKHelpers::WriteImage(fastDigitalInpainting.GetOutput(), outputFilename); return EXIT_SUCCESS; }
// Run with: image.png image.mask 15 filled.png int main(int argc, char *argv[]) { // Verify arguments if(argc != 5) { std::cerr << "Required arguments: image.png image.mask patchHalfWidth output.png" << std::endl; std::cerr << "Input arguments: "; for(int i = 1; i < argc; ++i) { std::cerr << argv[i] << " "; } return EXIT_FAILURE; } // Parse arguments std::string imageFilename = argv[1]; std::string maskFilename = argv[2]; std::stringstream ssPatchRadius; ssPatchRadius << argv[3]; unsigned int patchHalfWidth = 0; ssPatchRadius >> patchHalfWidth; std::string outputFilename = argv[4]; // Output arguments std::cout << "Reading image: " << imageFilename << std::endl; std::cout << "Reading mask: " << maskFilename << std::endl; std::cout << "Patch half width: " << patchHalfWidth << std::endl; std::cout << "Output: " << outputFilename << std::endl; typedef itk::Image<itk::CovariantVector<float, 3>, 2> ImageType; typedef itk::ImageFileReader<ImageType> ImageReaderType; ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(imageFilename); imageReader->Update(); ImageType::Pointer image = ImageType::New(); ITKHelpers::DeepCopy(imageReader->GetOutput(), image.GetPointer()); Mask::Pointer mask = Mask::New(); mask->Read(maskFilename); std::cout << "Mask size: " << mask->GetLargestPossibleRegion().GetSize() << std::endl; std::cout << "hole pixels: " << mask->CountHolePixels() << std::endl; std::cout << "valid pixels: " << mask->CountValidPixels() << std::endl; // Setup the GUI system QApplication app( argc, argv ); // Without this, after we close the first dialog // (after the first iteration that is not accepted automatically), the event loop quits. app.setQuitOnLastWindowClosed(false); DummyPatchesDriver(image, mask, patchHalfWidth); return app.exec(); }
int main(int argc, char*argv[]) { if(argc < 4) { std::cerr << "Required arguments: image mask output" << std::endl; return EXIT_FAILURE; } std::string imageFilename = argv[1]; std::string maskFilename = argv[2]; std::string outputFilename = argv[3]; std::cout << "imageFilename: " << imageFilename << std::endl; std::cout << "maskFilename: " << maskFilename << std::endl; std::cout << "outputFilename: " << outputFilename << std::endl; typedef itk::ImageFileReader<ImageType> ImageReaderType; ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(imageFilename); imageReader->Update(); Mask::Pointer sourceMask = Mask::New(); sourceMask->Read(maskFilename); Mask::Pointer targetMask = Mask::New(); targetMask->SetRegions(sourceMask->GetLargestPossibleRegion()); targetMask->Allocate(); ITKHelpers::SetImageToConstant(targetMask.GetPointer(), HoleMaskPixelTypeEnum::VALID); typedef SSD<ImageType> DistanceFunctorType; DistanceFunctorType* patchDistanceFunctor = new DistanceFunctorType; patchDistanceFunctor->SetImage(imageReader->GetOutput()); typedef Propagator<DistanceFunctorType> PropagatorType; PropagatorType* propagationFunctor = new PropagatorType; typedef RandomSearch<ImageType, DistanceFunctorType> RandomSearchType; RandomSearchType* randomSearchFunctor = new RandomSearchType; typedef PatchMatch<ImageType, PropagatorType, RandomSearchType> PatchMatchType; PatchMatchType patchMatch; patchMatch.SetImage(imageReader->GetOutput()); patchMatch.SetPatchRadius(3); patchMatch.SetPropagationFunctor(propagationFunctor); patchMatch.SetRandomSearchFunctor(randomSearchFunctor); patchMatch.Compute(); NNFieldType::Pointer output = patchMatch.GetNNField(); PatchMatchHelpers::WriteNNField(output.GetPointer(), "nnfield.mha"); return EXIT_SUCCESS; }
int main(int argc, char*argv[]) { if(argc != 4) { std::cerr << "Required arguments: image mask output" << std::endl; return EXIT_FAILURE; } std::string imageFilename = argv[1]; std::string maskFilename = argv[2]; std::string outputFilename = argv[3]; std::cout << "Reading image: " << imageFilename << std::endl; std::cout << "Reading mask: " << maskFilename << std::endl; std::cout << "Output: " << outputFilename << std::endl; //typedef itk::Image<float, 2> ImageType; //typedef itk::Image<itk::CovariantVector<unsigned char, 3>, 2> ImageType; // ImageType::PixelType color; // color[0] = 0; // color[1] = 255; // color[2] = 0; typedef itk::VectorImage<float, 2> ImageType; // ImageType::PixelType color; // color.SetRed(0); // color.SetGreen(255); // color.SetBlue(0); typedef itk::ImageFileReader<ImageType> ImageReaderType; ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(imageFilename.c_str()); imageReader->Update(); ImageType::PixelType value(imageReader->GetOutput()->GetNumberOfComponentsPerPixel()); value.Fill(0); Mask::Pointer mask = Mask::New(); mask->Read(maskFilename.c_str()); mask->ApplyToImage(imageReader->GetOutput(), value); OutputHelpers::WriteImage(imageReader->GetOutput(), outputFilename); return EXIT_SUCCESS; }
int main(int argc, char*argv[]) { if(argc != 2) { std::cerr << "Required arguments: mask" << std::endl; return EXIT_FAILURE; } std::string maskFilename = argv[1]; std::cout << "Reading mask: " << maskFilename << std::endl; Mask::Pointer mask = Mask::New(); mask->Read(maskFilename.c_str()); std::cout << "There are " << mask->CountBoundaryPixels() << " boundary pixels." << std::endl; return EXIT_SUCCESS; }
int main(int argc, char*argv[]) { if(argc != 5) { std::cerr << "Required arguments: image mask kernelRadius output" << std::endl; return EXIT_FAILURE; } std::string imageFilename = argv[1]; std::string maskFilename = argv[2]; std::stringstream ssRadius; ssRadius << argv[3]; unsigned int kernelRadius = 0; ssRadius >> kernelRadius; std::string outputFilename = argv[4]; std::cout << "Reading image: " << imageFilename << std::endl; std::cout << "Reading mask: " << maskFilename << std::endl; std::cout << "Kernel radius: " << kernelRadius << std::endl; std::cout << "Output: " << outputFilename << std::endl; typedef itk::Image<float, 2> ImageType; typedef itk::ImageFileReader<ImageType> ImageReaderType; ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(imageFilename.c_str()); imageReader->Update(); Mask::Pointer mask = Mask::New(); mask->Read(maskFilename.c_str()); MaskOperations::MedianFilterInHole(imageReader->GetOutput(), mask, kernelRadius); OutputHelpers::WriteImage(imageReader->GetOutput(), outputFilename); return EXIT_SUCCESS; }
int main(int argc, char *argv[]) { // Verify arguments if(argc != 5) { std::cerr << "Required arguments: image.png imageMask.mask patchHalfWidth targetPatch.png" << std::endl; std::cerr << "Input arguments: "; for(int i = 1; i < argc; ++i) { std::cerr << argv[i] << " "; } return EXIT_FAILURE; } // Parse arguments std::string imageFilename = argv[1]; std::string maskFilename = argv[2]; std::stringstream ssPatchHalfWidth; ssPatchHalfWidth << argv[3]; unsigned int patchHalfWidth = 0; ssPatchHalfWidth >> patchHalfWidth; std::string targetPatchFileName = argv[4]; // Output arguments std::cout << "Reading image: " << imageFilename << std::endl; std::cout << "Reading mask: " << maskFilename << std::endl; std::cout << "Patch half width: " << patchHalfWidth << std::endl; std::cout << "targetPatchFileName: " << targetPatchFileName << std::endl; typedef itk::Image<itk::CovariantVector<int, 3>, 2> OriginalImageType; typedef itk::ImageFileReader<OriginalImageType> ImageReaderType; ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(imageFilename); imageReader->Update(); OriginalImageType* originalImage = imageReader->GetOutput(); Mask::Pointer mask = Mask::New(); mask->Read(maskFilename); itk::ImageRegion<2> fullRegion = originalImage->GetLargestPossibleRegion(); // Blur the image // typedef TImage BlurredImageType; // Usually the blurred image is the same type as the original image. // typename BlurredImageType::Pointer blurredImage = BlurredImageType::New(); // float blurVariance = 2.0f; //// float blurVariance = 1.2f; // MaskOperations::MaskedBlur(originalImage.GetPointer(), mask, blurVariance, blurredImage.GetPointer()); // ITKHelpers::WriteRGBImage(blurredImage.GetPointer(), "BlurredImage.png"); typedef ImagePatchPixelDescriptor<OriginalImageType> ImagePatchPixelDescriptorType; // Create the graph typedef boost::grid_graph<2> VertexListGraphType; boost::array<std::size_t, 2> graphSideLengths = { { fullRegion.GetSize()[0], fullRegion.GetSize()[1] } }; std::shared_ptr<VertexListGraphType> graph(new VertexListGraphType(graphSideLengths)); typedef boost::graph_traits<VertexListGraphType>::vertex_descriptor VertexDescriptorType; typedef boost::graph_traits<VertexListGraphType>::vertex_iterator VertexIteratorType; // Queue typedef IndirectPriorityQueue<VertexListGraphType> BoundaryNodeQueueType; std::shared_ptr<BoundaryNodeQueueType> boundaryNodeQueue(new BoundaryNodeQueueType(*graph)); // Create the descriptor map. This is where the data for each pixel is stored. typedef boost::vector_property_map<ImagePatchPixelDescriptorType, BoundaryNodeQueueType::IndexMapType> ImagePatchDescriptorMapType; std::shared_ptr<ImagePatchDescriptorMapType> imagePatchDescriptorMap(new ImagePatchDescriptorMapType(num_vertices(*graph), *(boundaryNodeQueue->GetIndexMap()))); // Create the descriptor visitor typedef ImagePatchDescriptorVisitor<VertexListGraphType, OriginalImageType, ImagePatchDescriptorMapType> ImagePatchDescriptorVisitorType; std::shared_ptr<ImagePatchDescriptorVisitorType> imagePatchDescriptorVisitor(new ImagePatchDescriptorVisitorType(originalImage, mask, // ImagePatchDescriptorVisitorType(blurredImage.GetPointer(), mask, imagePatchDescriptorMap, patchHalfWidth)); // Create the inpainting visitor // typedef InpaintingVisitor<VertexListGraphType, BoundaryNodeQueueType, // ImagePatchDescriptorVisitorType, AcceptanceVisitorType, PriorityType> // InpaintingVisitorType; // std::shared_ptr<InpaintingVisitorType> inpaintingVisitor(new InpaintingVisitorType(mask, boundaryNodeQueue, // imagePatchDescriptorVisitor, acceptanceVisitor, // priorityFunction, patchHalfWidth, "InpaintingVisitor")); // inpaintingVisitor->SetAllowNewPatches(false); // // Initialize the boundary node queue from the user provided mask image. // InitializeFromMaskImage<InpaintingVisitorType, VertexDescriptorType>(mask, inpaintingVisitor.get()); // // Create the nearest neighbor finder // typedef ImagePatchDifference<ImagePatchPixelDescriptorType, // SumSquaredPixelDifference<typename TImage::PixelType> > PatchDifferenceType; // // Write top patch grid at each iteration. To do this, we need a KNNSearcher // // to pass a list of valid patches to the FirstAndWrite class. // typedef LinearSearchKNNProperty<ImagePatchDescriptorMapType, // PatchDifferenceType > KNNSearchType; // unsigned int knn = 100; // std::shared_ptr<KNNSearchType> knnSearch(new KNNSearchType(imagePatchDescriptorMap, knn)); // typedef LinearSearchBestFirstAndWrite<ImagePatchDescriptorMapType, TImage, // PatchDifferenceType> BestSearchType; // std::shared_ptr<BestSearchType> linearSearchBest( // new BestSearchType(*imagePatchDescriptorMap, originalImage, mask)); //// typedef KNNBestWrapper<KNNSearchType, BestSearchType> KNNWrapperType; //// std::shared_ptr<KNNWrapperType> knnWrapper(new KNNWrapperType(knnSearch, //// linearSearchBest)); return EXIT_SUCCESS; }
// Run with: Data/trashcan.mha Data/trashcan_mask.mha 15 Data/trashcan.vtp Intensity filled.mha int main(int argc, char *argv[]) { // Verify arguments if(argc != 6) { std::cerr << "Required arguments: image.mha imageMask.mha patch_half_width normals.vts output.mha" << std::endl; std::cerr << "Input arguments: "; for(int i = 1; i < argc; ++i) { std::cerr << argv[i] << " "; } return EXIT_FAILURE; } // Parse arguments std::string imageFilename = argv[1]; std::string maskFilename = argv[2]; std::stringstream ssPatchRadius; ssPatchRadius << argv[3]; unsigned int patch_half_width = 0; ssPatchRadius >> patch_half_width; std::string normalsFileName = argv[4]; std::string outputFilename = argv[5]; // Output arguments std::cout << "Reading image: " << imageFilename << std::endl; std::cout << "Reading mask: " << maskFilename << std::endl; std::cout << "Patch half width: " << patch_half_width << std::endl; std::cout << "Reading normals: " << normalsFileName << std::endl; std::cout << "Output: " << outputFilename << std::endl; vtkSmartPointer<vtkXMLStructuredGridReader> structuredGridReader = vtkSmartPointer<vtkXMLStructuredGridReader>::New(); structuredGridReader->SetFileName(normalsFileName.c_str()); structuredGridReader->Update(); typedef FloatVectorImageType ImageType; typedef itk::ImageFileReader<ImageType> ImageReaderType; ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(imageFilename); imageReader->Update(); ImageType::Pointer image = ImageType::New(); ITKHelpers::DeepCopy(imageReader->GetOutput(), image.GetPointer()); Mask::Pointer mask = Mask::New(); mask->Read(maskFilename); std::cout << "hole pixels: " << mask->CountHolePixels() << std::endl; std::cout << "valid pixels: " << mask->CountValidPixels() << std::endl; typedef ImagePatchPixelDescriptor<ImageType> ImagePatchPixelDescriptorType; typedef FeatureVectorPixelDescriptor FeatureVectorPixelDescriptorType; // Create the graph typedef boost::grid_graph<2> VertexListGraphType; boost::array<std::size_t, 2> graphSideLengths = { { imageReader->GetOutput()->GetLargestPossibleRegion().GetSize()[0], imageReader->GetOutput()->GetLargestPossibleRegion().GetSize()[1] } }; VertexListGraphType graph(graphSideLengths); typedef boost::graph_traits<VertexListGraphType>::vertex_descriptor VertexDescriptorType; // Get the index map typedef boost::property_map<VertexListGraphType, boost::vertex_index_t>::const_type IndexMapType; IndexMapType indexMap(get(boost::vertex_index, graph)); // Create the priority map typedef boost::vector_property_map<float, IndexMapType> PriorityMapType; PriorityMapType priorityMap(num_vertices(graph), indexMap); // Create the node fill status map. Each pixel is either filled (true) or not filled (false). typedef boost::vector_property_map<bool, IndexMapType> FillStatusMapType; FillStatusMapType fillStatusMap(num_vertices(graph), indexMap); // Create the boundary status map. A node is on the current boundary if this property is true. // This property helps the boundaryNodeQueue because we can mark here if a node has become no longer // part of the boundary, so when the queue is popped we can check this property to see if it should // actually be processed. typedef boost::vector_property_map<bool, IndexMapType> BoundaryStatusMapType; BoundaryStatusMapType boundaryStatusMap(num_vertices(graph), indexMap); // Create the descriptor map. This is where the data for each pixel is stored. typedef boost::vector_property_map<ImagePatchPixelDescriptorType, IndexMapType> ImagePatchDescriptorMapType; ImagePatchDescriptorMapType imagePatchDescriptorMap(num_vertices(graph), indexMap); // Create the descriptor map. This is where the data for each pixel is stored. typedef boost::vector_property_map<FeatureVectorPixelDescriptorType, IndexMapType> FeatureVectorDescriptorMapType; FeatureVectorDescriptorMapType featureVectorDescriptorMap(num_vertices(graph), indexMap); // Create the patch inpainter. The inpainter needs to know the status of each pixel to determine if they should be inpainted. typedef MaskedGridPatchInpainter<FillStatusMapType> InpainterType; InpainterType patchInpainter(patch_half_width, fillStatusMap); // Create the priority function typedef PriorityRandom PriorityType; PriorityType priorityFunction; // Create the boundary node queue. The priority of each node is used to order the queue. typedef boost::vector_property_map<std::size_t, IndexMapType> IndexInHeapMap; IndexInHeapMap index_in_heap(indexMap); // Create the priority compare functor typedef std::less<float> PriorityCompareType; PriorityCompareType lessThanFunctor; typedef boost::d_ary_heap_indirect<VertexDescriptorType, 4, IndexInHeapMap, PriorityMapType, PriorityCompareType> BoundaryNodeQueueType; BoundaryNodeQueueType boundaryNodeQueue(priorityMap, index_in_heap, lessThanFunctor); // Create the descriptor visitors typedef FeatureVectorPrecomputedStructuredGridNormalsDescriptorVisitor<VertexListGraphType, FeatureVectorDescriptorMapType> FeatureVectorPrecomputedStructuredGridNormalsDescriptorVisitorType; FeatureVectorPrecomputedStructuredGridNormalsDescriptorVisitorType featureVectorPrecomputedStructuredGridNormalsDescriptorVisitor(featureVectorDescriptorMap, structuredGridReader->GetOutput()); typedef ImagePatchDescriptorVisitor<VertexListGraphType, ImageType, ImagePatchDescriptorMapType> ImagePatchDescriptorVisitorType; ImagePatchDescriptorVisitorType imagePatchDescriptorVisitor(image, mask, imagePatchDescriptorMap, patch_half_width); typedef CompositeDescriptorVisitor<VertexListGraphType> CompositeDescriptorVisitorType; CompositeDescriptorVisitorType compositeDescriptorVisitor; compositeDescriptorVisitor.AddVisitor(&imagePatchDescriptorVisitor); compositeDescriptorVisitor.AddVisitor(&featureVectorPrecomputedStructuredGridNormalsDescriptorVisitor); // Create the inpainting visitor typedef InpaintingVisitor<VertexListGraphType, ImageType, BoundaryNodeQueueType, FillStatusMapType, CompositeDescriptorVisitorType, PriorityType, PriorityMapType, BoundaryStatusMapType> InpaintingVisitorType; InpaintingVisitorType inpaintingVisitor(image, mask, boundaryNodeQueue, fillStatusMap, compositeDescriptorVisitor, priorityMap, &priorityFunction, patch_half_width, boundaryStatusMap); InitializePriority(mask, boundaryNodeQueue, priorityMap, &priorityFunction, boundaryStatusMap); // Initialize the boundary node queue from the user provided mask image. InitializeFromMaskImage(mask, &inpaintingVisitor, graph, fillStatusMap); std::cout << "PatchBasedInpaintingNonInteractive: There are " << boundaryNodeQueue.size() << " nodes in the boundaryNodeQueue" << std::endl; // Create the nearest neighbor finder // typedef LinearSearchKNNProperty<FeatureVectorDescriptorMapType, FeatureVectorAngleDifference> KNNSearchType; // KNNSearchType linearSearchKNN(featureVectorDescriptorMap); typedef LinearSearchCriteriaProperty<FeatureVectorDescriptorMapType, FeatureVectorAngleDifference> ThresholdSearchType; //float maximumAngle = 0.34906585; // ~ 20 degrees float maximumAngle = 0.15; // ~ 10 degrees //float maximumAngle = 0.08; // ~ 5 degrees (this seems to be too strict) ThresholdSearchType thresholdSearchType(featureVectorDescriptorMap, maximumAngle); typedef LinearSearchBestProperty<ImagePatchDescriptorMapType, ImagePatchDifference<ImagePatchPixelDescriptorType> > BestSearchType; BestSearchType linearSearchBest(imagePatchDescriptorMap); TwoStepNearestNeighbor<ThresholdSearchType, BestSearchType> twoStepNearestNeighbor(thresholdSearchType, linearSearchBest); // Perform the inpainting std::cout << "Performing inpainting...: " << std::endl; inpainting_loop(graph, inpaintingVisitor, boundaryStatusMap, boundaryNodeQueue, twoStepNearestNeighbor, patchInpainter); HelpersOutput::WriteImage<ImageType>(image, outputFilename); return EXIT_SUCCESS; }
// Run with: Data/trashcan.mha Data/trashcan_mask.mha 15 filled.mha int main(int argc, char *argv[]) { // Verify arguments if(argc != 6) { std::cerr << "Required arguments: image.mha imageMask.mha patchHalfWidth neighborhoodRadius output.mha" << std::endl; std::cerr << "Input arguments: "; for(int i = 1; i < argc; ++i) { std::cerr << argv[i] << " "; } return EXIT_FAILURE; } // Parse arguments std::string imageFileName = argv[1]; std::string maskFileName = argv[2]; std::stringstream ssPatchRadius; ssPatchRadius << argv[3]; unsigned int patchHalfWidth = 0; ssPatchRadius >> patchHalfWidth; // The percent of the image size to use as the neighborhood (0 - 1) std::stringstream ssNeighborhoodPercent; ssNeighborhoodPercent << argv[4]; float neighborhoodPercent = 0; ssNeighborhoodPercent >> neighborhoodPercent; std::string outputFileName = argv[5]; // Output arguments std::cout << "Reading image: " << imageFileName << std::endl; std::cout << "Reading mask: " << maskFileName << std::endl; std::cout << "Patch half width: " << patchHalfWidth << std::endl; std::cout << "Neighborhood percent: " << neighborhoodPercent << std::endl; std::cout << "Output: " << outputFileName << std::endl; typedef itk::Image<itk::CovariantVector<int, 3>, 2> ImageType; typedef itk::ImageFileReader<ImageType> ImageReaderType; ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(imageFileName); imageReader->Update(); ImageType::Pointer image = ImageType::New(); ITKHelpers::DeepCopy(imageReader->GetOutput(), image.GetPointer()); Mask::Pointer mask = Mask::New(); mask->Read(maskFileName); std::cout << "hole pixels: " << mask->CountHolePixels() << std::endl; std::cout << "valid pixels: " << mask->CountValidPixels() << std::endl; typedef ImagePatchPixelDescriptor<ImageType> ImagePatchPixelDescriptorType; // Create the graph typedef boost::grid_graph<2> VertexListGraphType; boost::array<std::size_t, 2> graphSideLengths = { { imageReader->GetOutput()->GetLargestPossibleRegion().GetSize()[0], imageReader->GetOutput()->GetLargestPossibleRegion().GetSize()[1] } }; // VertexListGraphType graph(graphSideLengths); std::shared_ptr<VertexListGraphType> graph(new VertexListGraphType(graphSideLengths)); typedef boost::graph_traits<VertexListGraphType>::vertex_descriptor VertexDescriptorType; //ImagePatchDescriptorMapType smallImagePatchDescriptorMap(num_vertices(graph), indexMap); // Create the patch inpainter. The inpainter needs to know the status of each pixel to determine if they should be inpainted. typedef PatchInpainter<ImageType> ImageInpainterType; std::shared_ptr<ImageInpainterType> imagePatchInpainter(new ImageInpainterType(patchHalfWidth, image, mask)); // Create the priority function typedef PriorityRandom PriorityType; std::shared_ptr<PriorityType> priorityFunction(new PriorityType); // typedef PriorityCriminisi<ImageType> PriorityType; // std::shared_ptr<PriorityType> priorityFunction(new PriorityType(image, mask, patchHalfWidth)); typedef IndirectPriorityQueue<VertexListGraphType> BoundaryNodeQueueType; std::shared_ptr<BoundaryNodeQueueType> boundaryNodeQueue(new BoundaryNodeQueueType(*graph)); // Create the descriptor map. This is where the data for each pixel is stored. typedef boost::vector_property_map<ImagePatchPixelDescriptorType, BoundaryNodeQueueType::IndexMapType> ImagePatchDescriptorMapType; // ImagePatchDescriptorMapType imagePatchDescriptorMap(num_vertices(graph), indexMap); std::shared_ptr<ImagePatchDescriptorMapType> imagePatchDescriptorMap(new ImagePatchDescriptorMapType(num_vertices(*graph), *(boundaryNodeQueue->GetIndexMap()))); // Create the descriptor visitor typedef ImagePatchDescriptorVisitor<VertexListGraphType, ImageType, ImagePatchDescriptorMapType> ImagePatchDescriptorVisitorType; // ImagePatchDescriptorVisitorType imagePatchDescriptorVisitor(image, mask, imagePatchDescriptorMap, patchHalfWidth); std::shared_ptr<ImagePatchDescriptorVisitorType> imagePatchDescriptorVisitor(new ImagePatchDescriptorVisitorType(image.GetPointer(), mask, imagePatchDescriptorMap, patchHalfWidth)); /* ImagePatchDescriptorVisitor(TImage* const in_image, Mask* const in_mask, std::shared_ptr<TDescriptorMap> in_descriptorMap, const unsigned int in_half_width) : */ typedef ImagePatchDifference<ImagePatchPixelDescriptorType, SumAbsolutePixelDifference<ImageType::PixelType> > ImagePatchDifferenceType; // typedef CompositeDescriptorVisitor<VertexListGraphType> CompositeDescriptorVisitorType; // CompositeDescriptorVisitorType compositeDescriptorVisitor; // compositeDescriptorVisitor.AddVisitor(imagePatchDescriptorVisitor); // Create the descriptor visitor // typedef CompositeAcceptanceVisitor<VertexListGraphType> CompositeAcceptanceVisitorType; // CompositeAcceptanceVisitorType compositeAcceptanceVisitor; typedef DefaultAcceptanceVisitor<VertexListGraphType> AcceptanceVisitorType; std::shared_ptr<AcceptanceVisitorType> acceptanceVisitor(new AcceptanceVisitorType); // typedef AlwaysAccept<VertexListGraphType> AcceptanceVisitorType; // AcceptanceVisitorType acceptanceVisitor; // If the hole is less than 15% of the patch, always accept the initial best match // HoleSizeAcceptanceVisitor<VertexListGraphType> holeSizeAcceptanceVisitor(mask, patchHalfWidth, .15); // compositeAcceptanceVisitor.AddOverrideVisitor(&holeSizeAcceptanceVisitor); // AllQuadrantHistogramCompareAcceptanceVisitor<VertexListGraphType, ImageType> // allQuadrantHistogramCompareAcceptanceVisitor(image, mask, patchHalfWidth, 8.0f); // Crazy low // compositeAcceptanceVisitor.AddRequiredPassVisitor(&allQuadrantHistogramCompareAcceptanceVisitor); // template <typename TGraph, typename TBoundaryNodeQueue, // typename TDescriptorVisitor, typename TAcceptanceVisitor, typename TPriority> typedef InpaintingVisitor<VertexListGraphType, BoundaryNodeQueueType, ImagePatchDescriptorVisitorType, AcceptanceVisitorType, PriorityType> InpaintingVisitorType; std::shared_ptr<InpaintingVisitorType> inpaintingVisitor(new InpaintingVisitorType(mask, boundaryNodeQueue, imagePatchDescriptorVisitor, acceptanceVisitor, priorityFunction, patchHalfWidth, "InpaintingVisitor")); // typedef InpaintingVisitor<VertexListGraphType, BoundaryNodeQueueType, // ImagePatchDescriptorVisitorType, AcceptanceVisitorType, PriorityType> // InpaintingVisitorType; // std::shared_ptr<InpaintingVisitorType> inpaintingVisitor(new InpaintingVisitorType(mask, boundaryNodeQueue, // imagePatchDescriptorVisitor, acceptanceVisitor, // priorityFunction, patchHalfWidth, "InpaintingVisitor")); // typedef DebugVisitor<VertexListGraphType, ImageType, BoundaryStatusMapType, BoundaryNodeQueueType> DebugVisitorType; // DebugVisitorType debugVisitor(image, mask, patchHalfWidth, boundaryStatusMap, boundaryNodeQueue); LoggerVisitor<VertexListGraphType> loggerVisitor("log.txt"); InitializePriority(mask, boundaryNodeQueue.get(), priorityFunction.get()); // Initialize the boundary node queue from the user provided mask image. InitializeFromMaskImage<InpaintingVisitorType, VertexDescriptorType>(mask, inpaintingVisitor.get()); // For debugging we use LinearSearchBestProperty instead of DefaultSearchBest because it can output the difference value. typedef LinearSearchBestProperty<ImagePatchDescriptorMapType, ImagePatchDifferenceType > BestSearchType; std::shared_ptr<BestSearchType> linearSearchBest(new BestSearchType(*imagePatchDescriptorMap)); typedef NeighborhoodSearch<VertexDescriptorType, ImagePatchDescriptorMapType> NeighborhoodSearchType; NeighborhoodSearchType neighborhoodSearch(image->GetLargestPossibleRegion(), image->GetLargestPossibleRegion().GetSize()[0] * neighborhoodPercent, *imagePatchDescriptorMap); InpaintingAlgorithmWithLocalSearch<VertexListGraphType, InpaintingVisitorType, BoundaryNodeQueueType, NeighborhoodSearchType, ImageInpainterType, BestSearchType>(graph, inpaintingVisitor, boundaryNodeQueue, linearSearchBest, imagePatchInpainter, neighborhoodSearch); // If the output filename is a png file, then use the RGBImage writer so that it is first // casted to unsigned char. Otherwise, write the file directly. if(Helpers::GetFileExtension(outputFileName) == "png") { ITKHelpers::WriteRGBImage(image.GetPointer(), outputFileName); } else { ITKHelpers::WriteImage(image.GetPointer(), outputFileName); } return EXIT_SUCCESS; }
int main(int argc, char*argv[]) { // Parse the input if(argc < 6) { std::cerr << "Required arguments: image sourceMask.mask targetMask.mask patchRadius output" << std::endl; return EXIT_FAILURE; } std::stringstream ss; for(int i = 1; i < argc; ++i) { ss << argv[i] << " "; } std::string imageFilename; std::string sourceMaskFilename; std::string targetMaskFilename; unsigned int patchRadius; std::string outputFilename; ss >> imageFilename >> sourceMaskFilename >> targetMaskFilename >> patchRadius >> outputFilename; // Output the parsed values std::cout << "imageFilename: " << imageFilename << std::endl << "sourceMaskFilename: " << sourceMaskFilename << std::endl << "targetMaskFilename: " << targetMaskFilename << std::endl << "patchRadius: " << patchRadius << std::endl << "outputFilename: " << outputFilename << std::endl; typedef itk::Image<itk::CovariantVector<unsigned char, 3>, 2> ImageType; // Read the image and the masks typedef itk::ImageFileReader<ImageType> ImageReaderType; ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(imageFilename); imageReader->Update(); ImageType* image = imageReader->GetOutput(); Mask::Pointer sourceMask = Mask::New(); sourceMask->Read(sourceMaskFilename); Mask::Pointer targetMask = Mask::New(); targetMask->Read(targetMaskFilename); //std::cout << "target mask has " << targetMask->CountHolePixels() << " hole pixels." << std::endl; // Poisson fill the input image typedef PoissonEditing<typename TypeTraits<ImageType::PixelType>::ComponentType> PoissonEditingType; typename PoissonEditingType::GuidanceFieldType::Pointer zeroGuidanceField = PoissonEditingType::GuidanceFieldType::New(); zeroGuidanceField->SetRegions(image->GetLargestPossibleRegion()); zeroGuidanceField->Allocate(); typename PoissonEditingType::GuidanceFieldType::PixelType zeroPixel; zeroPixel.Fill(0); ITKHelpers::SetImageToConstant(zeroGuidanceField.GetPointer(), zeroPixel); PoissonEditingType::FillImage(image, targetMask, zeroGuidanceField.GetPointer(), image); ITKHelpers::WriteRGBImage(image, "PoissonFilled.png"); // PatchMatch requires that the target region be specified by valid pixels targetMask->InvertData(); // Setup the patch distance functor SSD<ImageType> ssdFunctor; ssdFunctor.SetImage(image); // Setup the PatchMatch functor //PatchMatch<ImageType> patchMatchFunctor; PatchMatchRings<ImageType> patchMatchFunctor; patchMatchFunctor.SetPatchRadius(patchRadius); patchMatchFunctor.SetPatchDistanceFunctor(&ssdFunctor); patchMatchFunctor.SetIterations(1); InitializerRandom<ImageType> initializer; initializer.SetImage(image); initializer.SetTargetMask(targetMask); initializer.SetSourceMask(sourceMask); initializer.SetPatchDistanceFunctor(&ssdFunctor); initializer.SetPatchRadius(patchRadius); patchMatchFunctor.SetInitializer(&initializer); // Test the result of PatchMatch here patchMatchFunctor.SetRandom(false); // Here, the source match and target match are the same, specifying the classicial // "use pixels outside the hole to fill the pixels inside the hole". // In an interactive algorith, the user could manually specify a source region, // improving the resulting inpainting. BDSInpaintingMultiRes<ImageType> bdsInpainting; bdsInpainting.SetPatchRadius(patchRadius); bdsInpainting.SetImage(image); bdsInpainting.SetSourceMask(sourceMask); bdsInpainting.SetTargetMask(targetMask); bdsInpainting.SetIterations(1); //bdsInpainting.SetIterations(4); Compositor<ImageType> compositor; compositor.SetCompositingMethod(Compositor<ImageType>::AVERAGE); bdsInpainting.SetCompositor(&compositor); bdsInpainting.SetPatchMatchFunctor(&patchMatchFunctor); bdsInpainting.Inpaint(); ITKHelpers::WriteRGBImage(bdsInpainting.GetOutput(), outputFilename); return EXIT_SUCCESS; }
// Run with: Data/trashcan.png Data/trashcan.mask 15 filled.png int main(int argc, char *argv[]) { // Verify arguments if(argc != 5) { std::cerr << "Required arguments: image.png imageMask.mask patchHalfWidth output.png" << std::endl; std::cerr << "Input arguments: "; for(int i = 1; i < argc; ++i) { std::cerr << argv[i] << " "; } return EXIT_FAILURE; } // Parse arguments std::string imageFilename = argv[1]; std::string maskFilename = argv[2]; std::stringstream ssPatchHalfWidth; ssPatchHalfWidth << argv[3]; unsigned int patchHalfWidth = 0; ssPatchHalfWidth >> patchHalfWidth; std::string outputFileName = argv[4]; // Output arguments std::cout << "Reading image: " << imageFilename << std::endl; std::cout << "Reading mask: " << maskFilename << std::endl; std::cout << "Patch half width: " << patchHalfWidth << std::endl; std::cout << "Output: " << outputFileName << std::endl; typedef itk::Image<itk::CovariantVector<int, 3>, 2> OriginalImageType; typedef itk::ImageFileReader<OriginalImageType> ImageReaderType; ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(imageFilename); imageReader->Update(); // OriginalImageType* originalImage = imageReader->GetOutput(); OriginalImageType::Pointer originalImage = OriginalImageType::New(); ITKHelpers::DeepCopy(imageReader->GetOutput(), originalImage.GetPointer()); Mask::Pointer mask = Mask::New(); mask->Read(maskFilename); ClassicalImageInpaintingDebug(originalImage, mask, patchHalfWidth); // If the output filename is a png file, then use the RGBImage writer so that it is first // casted to unsigned char. Otherwise, write the file directly. if(Helpers::GetFileExtension(outputFileName) == "png") { ITKHelpers::WriteRGBImage(originalImage.GetPointer(), outputFileName); } else { ITKHelpers::WriteImage(originalImage.GetPointer(), outputFileName); } return EXIT_SUCCESS; }
int main(int argc, char*argv[]) { // Parse the input if(argc < 6) { std::cerr << "Required arguments: image sourceMask.mask targetMask.mask patchRadius output" << std::endl; return EXIT_FAILURE; } std::stringstream ss; for(int i = 1; i < argc; ++i) { ss << argv[i] << " "; } std::string imageFilename; std::string sourceMaskFilename; std::string targetMaskFilename; unsigned int patchRadius; std::string outputFilename; ss >> imageFilename >> sourceMaskFilename >> targetMaskFilename >> patchRadius >> outputFilename; // Output the parsed values std::cout << "imageFilename: " << imageFilename << std::endl << "sourceMaskFilename: " << sourceMaskFilename << std::endl << "targetMaskFilename: " << targetMaskFilename << std::endl << "patchRadius: " << patchRadius << std::endl << "outputFilename: " << outputFilename << std::endl; typedef itk::Image<itk::CovariantVector<unsigned char, 3>, 2> ImageType; // Read the image and the masks typedef itk::ImageFileReader<ImageType> ImageReaderType; ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(imageFilename); imageReader->Update(); ImageType* image = imageReader->GetOutput(); Mask::Pointer sourceMask = Mask::New(); sourceMask->Read(sourceMaskFilename); Mask::Pointer targetMask = Mask::New(); targetMask->Read(targetMaskFilename); // Poisson fill the input image in HSV space typedef itk::Image<itk::CovariantVector<float, 3>, 2> HSVImageType; HSVImageType::Pointer hsvImage = HSVImageType::New(); ITKVTKHelpers::ConvertRGBtoHSV(image, hsvImage.GetPointer()); ITKHelpers::WriteImage(image, "HSV.mha"); typedef PoissonEditing<typename TypeTraits<HSVImageType::PixelType>::ComponentType> PoissonEditingType; typename PoissonEditingType::GuidanceFieldType::Pointer zeroGuidanceField = PoissonEditingType::GuidanceFieldType::New(); zeroGuidanceField->SetRegions(hsvImage->GetLargestPossibleRegion()); zeroGuidanceField->Allocate(); typename PoissonEditingType::GuidanceFieldType::PixelType zeroPixel; zeroPixel.Fill(0); ITKHelpers::SetImageToConstant(zeroGuidanceField.GetPointer(), zeroPixel); PoissonEditingType::FillImage(hsvImage.GetPointer(), targetMask, zeroGuidanceField.GetPointer(), hsvImage.GetPointer()); ITKHelpers::WriteImage(image, "PoissonFilled_HSV.mha"); ITKVTKHelpers::ConvertHSVtoRGB(hsvImage.GetPointer(), image); ITKHelpers::WriteRGBImage(image, "PoissonFilled_HSV.png"); // PatchMatch requires that the target region be specified by valid pixels targetMask->InvertData(); // Here, the source mask and target mask are the same, specifying the classicial // "use pixels outside the hole to fill the pixels inside the hole". // In an interactive algorith, the user could manually specify a source region, // improving the resulting inpainting. BDSInpaintingRings<ImageType> bdsInpainting; bdsInpainting.SetPatchRadius(patchRadius); bdsInpainting.SetImage(image); bdsInpainting.SetSourceMask(sourceMask); bdsInpainting.SetTargetMask(targetMask); bdsInpainting.SetIterations(1); //bdsInpainting.SetIterations(4); Compositor<ImageType, PixelCompositorAverage> compositor; bdsInpainting.Inpaint(); ITKHelpers::WriteRGBImage(bdsInpainting.GetOutput(), outputFilename); return EXIT_SUCCESS; }
// Run with: Data/trashcan.mha Data/trashcan_mask.mha 15 filled.mha int main(int argc, char *argv[]) { // Verify arguments if(argc != 5) { std::cerr << "Required arguments: image.mha imageMask.mha patchHalfWidth output.mha" << std::endl; std::cerr << "Input arguments: "; for(int i = 1; i < argc; ++i) { std::cerr << argv[i] << " "; } return EXIT_FAILURE; } // Setup the GUI system QApplication app( argc, argv ); // Parse arguments std::string imageFilename = argv[1]; std::string maskFilename = argv[2]; std::stringstream ssPatchRadius; ssPatchRadius << argv[3]; unsigned int patchHalfWidth = 0; ssPatchRadius >> patchHalfWidth; std::string outputFilename = argv[4]; // Output arguments std::cout << "Reading image: " << imageFilename << std::endl; std::cout << "Reading mask: " << maskFilename << std::endl; std::cout << "Patch half width: " << patchHalfWidth << std::endl; std::cout << "Output: " << outputFilename << std::endl; typedef FloatVectorImageType ImageType; typedef itk::ImageFileReader<ImageType> ImageReaderType; ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(imageFilename); imageReader->Update(); ImageType* image = imageReader->GetOutput(); itk::ImageRegion<2> fullRegion = imageReader->GetOutput()->GetLargestPossibleRegion(); Mask::Pointer mask = Mask::New(); mask->Read(maskFilename); std::cout << "hole pixels: " << mask->CountHolePixels() << std::endl; std::cout << "valid pixels: " << mask->CountValidPixels() << std::endl; std::cout << "image has " << image->GetNumberOfComponentsPerPixel() << " components." << std::endl; typedef ImagePatchPixelDescriptor<ImageType> ImagePatchPixelDescriptorType; // Create the graph typedef boost::grid_graph<2> VertexListGraphType; boost::array<std::size_t, 2> graphSideLengths = { { fullRegion.GetSize()[0], fullRegion.GetSize()[1] } }; VertexListGraphType graph(graphSideLengths); typedef boost::graph_traits<VertexListGraphType>::vertex_descriptor VertexDescriptorType; // Get the index map typedef boost::property_map<VertexListGraphType, boost::vertex_index_t>::const_type IndexMapType; IndexMapType indexMap(get(boost::vertex_index, graph)); // Create the priority map typedef boost::vector_property_map<float, IndexMapType> PriorityMapType; PriorityMapType priorityMap(num_vertices(graph), indexMap); // Create the boundary status map. A node is on the current boundary if this property is true. // This property helps the boundaryNodeQueue because we can mark here if a node has become no longer // part of the boundary, so when the queue is popped we can check this property to see if it should // actually be processed. typedef boost::vector_property_map<bool, IndexMapType> BoundaryStatusMapType; BoundaryStatusMapType boundaryStatusMap(num_vertices(graph), indexMap); // Create the descriptor map. This is where the data for each pixel is stored. typedef boost::vector_property_map<ImagePatchPixelDescriptorType, IndexMapType> ImagePatchDescriptorMapType; ImagePatchDescriptorMapType imagePatchDescriptorMap(num_vertices(graph), indexMap); //ImagePatchDescriptorMapType smallImagePatchDescriptorMap(num_vertices(graph), indexMap); // Create the patch inpainter. The inpainter needs to know the status of each // pixel to determine if they should be inpainted. typedef MaskImagePatchInpainter InpainterType; MaskImagePatchInpainter patchInpainter(patchHalfWidth, mask); // Create the priority function // typedef PriorityRandom PriorityType; // PriorityType priorityFunction; typedef PriorityOnionPeel PriorityType; PriorityType priorityFunction(mask, patchHalfWidth); // Create the boundary node queue. The priority of each node is used to order the queue. typedef boost::vector_property_map<std::size_t, IndexMapType> IndexInHeapMap; IndexInHeapMap index_in_heap(indexMap); // Create the priority compare functor (we want the highest priority nodes to be first in the queue) typedef std::greater<float> PriorityCompareType; PriorityCompareType lessThanFunctor; typedef boost::d_ary_heap_indirect<VertexDescriptorType, 4, IndexInHeapMap, PriorityMapType, PriorityCompareType> BoundaryNodeQueueType; BoundaryNodeQueueType boundaryNodeQueue(priorityMap, index_in_heap, lessThanFunctor); // Create the descriptor visitor typedef ImagePatchDescriptorVisitor<VertexListGraphType, ImageType, ImagePatchDescriptorMapType> ImagePatchDescriptorVisitorType; ImagePatchDescriptorVisitorType imagePatchDescriptorVisitor(image, mask, imagePatchDescriptorMap, patchHalfWidth); //ImagePatchDescriptorVisitorType imagePatchDescriptorVisitor(cielabImage, // mask, imagePatchDescriptorMap, patchHalfWidth); typedef ImagePatchDifference<ImagePatchPixelDescriptorType, SumAbsolutePixelDifference<ImageType::PixelType> > ImagePatchDifferenceType; ImagePatchDifferenceType imagePatchDifferenceFunction; // typedef WeightedSumAbsolutePixelDifference<ImageType::PixelType> PixelDifferenceFunctorType; // PixelDifferenceFunctorType pixelDifferenceFunctor; // std::vector<float> weights; // weights.push_back(1.0f); // weights.push_back(1.0f); // weights.push_back(1.0f); // float gradientWeight = 500.0f; // weights.push_back(gradientWeight); // weights.push_back(gradientWeight); // pixelDifferenceFunctor.Weights = weights; // std::cout << "Weights: "; // OutputHelpers::OutputVector(pixelDifferenceFunctor.Weights); // typedef ImagePatchDifference<ImagePatchPixelDescriptorType, PixelDifferenceFunctorType > // ImagePatchDifferenceType; // // ImagePatchDifferenceType imagePatchDifferenceFunction(pixelDifferenceFunctor); typedef CompositeDescriptorVisitor<VertexListGraphType> CompositeDescriptorVisitorType; CompositeDescriptorVisitorType compositeDescriptorVisitor; compositeDescriptorVisitor.AddVisitor(&imagePatchDescriptorVisitor); typedef CompositeAcceptanceVisitor<VertexListGraphType> CompositeAcceptanceVisitorType; CompositeAcceptanceVisitorType compositeAcceptanceVisitor; typedef InpaintingVisitor<VertexListGraphType, ImageType, BoundaryNodeQueueType, CompositeDescriptorVisitorType, CompositeAcceptanceVisitorType, PriorityType, PriorityMapType, BoundaryStatusMapType> InpaintingVisitorType; InpaintingVisitorType inpaintingVisitor(image, mask, boundaryNodeQueue, compositeDescriptorVisitor, compositeAcceptanceVisitor, priorityMap, &priorityFunction, patchHalfWidth, boundaryStatusMap, outputFilename); typedef DisplayVisitor<VertexListGraphType, ImageType> DisplayVisitorType; DisplayVisitorType displayVisitor(image, mask, patchHalfWidth); typedef DebugVisitor<VertexListGraphType, ImageType, BoundaryStatusMapType, BoundaryNodeQueueType> DebugVisitorType; DebugVisitorType debugVisitor(image, mask, patchHalfWidth, boundaryStatusMap, boundaryNodeQueue); LoggerVisitor<VertexListGraphType> loggerVisitor("log.txt"); PaintPatchVisitor<VertexListGraphType, ImageType> inpaintRGBVisitor(image, mask.GetPointer(), patchHalfWidth); typedef CompositeInpaintingVisitor<VertexListGraphType> CompositeInpaintingVisitorType; CompositeInpaintingVisitorType compositeInpaintingVisitor; compositeInpaintingVisitor.AddVisitor(&inpaintingVisitor); //compositeInpaintingVisitor.AddVisitor(&inpaintRGBVisitor); compositeInpaintingVisitor.AddVisitor(&displayVisitor); compositeInpaintingVisitor.AddVisitor(&debugVisitor); //compositeInpaintingVisitor.AddVisitor(&loggerVisitor); InitializePriority(mask, boundaryNodeQueue, priorityMap, &priorityFunction, boundaryStatusMap); // Initialize the boundary node queue from the user provided mask image. InitializeFromMaskImage<CompositeInpaintingVisitorType, VertexDescriptorType>(mask, &compositeInpaintingVisitor); // Create the nearest neighbor finders typedef LinearSearchKNNProperty<ImagePatchDescriptorMapType, ImagePatchDifferenceType > KNNSearchType; KNNSearchType knnSearch(imagePatchDescriptorMap, 50000, 1, imagePatchDifferenceFunction); // For debugging we use LinearSearchBestProperty instead of DefaultSearchBest // because it can output the difference value. typedef LinearSearchBestProperty<ImagePatchDescriptorMapType, ImagePatchDifferenceType > BestSearchType; BestSearchType bestSearch(imagePatchDescriptorMap, imagePatchDifferenceFunction); BasicViewerWidget<ImageType> basicViewerWidget(image, mask); basicViewerWidget.show(); // These connections are Qt::BlockingQueuedConnection because the algorithm quickly // goes on to fill the hole, and since we are sharing the image memory, we want to make sure these things are // refreshed at the right time, not after the hole has already been filled // (this actually happens, it is not just a theoretical thing). QObject::connect(&displayVisitor, SIGNAL(signal_RefreshImage()), &basicViewerWidget, SLOT(slot_UpdateImage()), Qt::BlockingQueuedConnection); QObject::connect(&displayVisitor, SIGNAL(signal_RefreshSource(const itk::ImageRegion<2>&, const itk::ImageRegion<2>&)), &basicViewerWidget, SLOT(slot_UpdateSource(const itk::ImageRegion<2>&, const itk::ImageRegion<2>&)), Qt::BlockingQueuedConnection); QObject::connect(&displayVisitor, SIGNAL(signal_RefreshTarget(const itk::ImageRegion<2>&)), &basicViewerWidget, SLOT(slot_UpdateTarget(const itk::ImageRegion<2>&)), Qt::BlockingQueuedConnection); QObject::connect(&displayVisitor, SIGNAL(signal_RefreshResult(const itk::ImageRegion<2>&, const itk::ImageRegion<2>&)), &basicViewerWidget, SLOT(slot_UpdateResult(const itk::ImageRegion<2>&, const itk::ImageRegion<2>&)), Qt::BlockingQueuedConnection); // TopPatchesDialog<ImageType> topPatchesDialog(image, mask, patchHalfWidth, &basicViewerWidget); // typedef VisualSelectionBest<ImageType> ManualSearchType; // ManualSearchType manualSearchBest(image, mask, patchHalfWidth, &topPatchesDialog); typedef DefaultSearchBest ManualSearchType; DefaultSearchBest manualSearchBest; // By specifying the radius as the image size/8, we are searching up to 1/4 of the image each time typedef NeighborhoodSearch<VertexDescriptorType> NeighborhoodSearchType; NeighborhoodSearchType neighborhoodSearch(fullRegion, fullRegion.GetSize()[0]/8); // Run the remaining inpainting QtConcurrent::run(boost::bind(InpaintingAlgorithmWithLocalSearch< VertexListGraphType, CompositeInpaintingVisitorType, BoundaryStatusMapType, BoundaryNodeQueueType, NeighborhoodSearchType, KNNSearchType, BestSearchType, ManualSearchType, InpainterType>, graph, compositeInpaintingVisitor, &boundaryStatusMap, &boundaryNodeQueue, neighborhoodSearch, knnSearch, bestSearch, boost::ref(manualSearchBest), patchInpainter)); return app.exec(); }
int main(int argc, char* argv[]) { // Verify arguments if(argc < 5) { std::cout << "Usage: ImageToFill mask guidanceField outputImage" << std::endl; return EXIT_FAILURE; } // Parse arguments std::string targetImageFilename = argv[1]; std::string maskFilename = argv[2]; std::string guidanceFieldFilename = argv[3]; std::string outputFilename = argv[4]; // Output arguments std::cout << "Target image: " << targetImageFilename << std::endl << "Mask image: " << maskFilename << std::endl << "Guidance field: " << guidanceFieldFilename << std::endl << "Output image: " << outputFilename << std::endl; //typedef itk::VectorImage<float, 2> FloatVectorImageType; typedef itk::Image<float, 2> ImageType; // Read images typedef itk::ImageFileReader<ImageType> ImageReaderType; ImageReaderType::Pointer targetImageReader = ImageReaderType::New(); targetImageReader->SetFileName(targetImageFilename); targetImageReader->Update(); std::cout << "Read target image." << std::endl; // Read mask Mask::Pointer mask = Mask::New(); mask->Read(maskFilename); std::cout << "Read mask." << std::endl; typedef itk::CovariantVector<float, 2> Vector2Type; typedef itk::Image<Vector2Type, 2> Vector2ImageType; typedef itk::ImageFileReader<Vector2ImageType> GuidanceFieldReaderType; GuidanceFieldReaderType::Pointer guidanceFieldReader = GuidanceFieldReaderType::New(); guidanceFieldReader->SetFileName(guidanceFieldFilename); guidanceFieldReader->Update(); std::cout << "Read guidance field." << std::endl; typedef PoissonEditing<float> PoissonEditingFilterType; PoissonEditingFilterType poissonFilter; poissonFilter.SetTargetImage(targetImageReader->GetOutput()); poissonFilter.SetGuidanceField(guidanceFieldReader->GetOutput()); poissonFilter.SetMask(mask); poissonFilter.FillMaskedRegion(); // Write output ITKHelpers::WriteImage(poissonFilter.GetOutput(), outputFilename); // Helpers::WriteVectorImageAsPNG(output.GetPointer(), outputFilename); return EXIT_SUCCESS; }