int main() { typedef itk::Image<itk::CovariantVector<float, 3>, 2> ImageType; // typedef FloatVectorImageType ImageType; ImageType::Pointer image = ImageType::New(); Testing::GetBlankImage(image.GetPointer(), 4); Mask::Pointer mask = Mask::New(); Testing::GetFullyValidMask(mask.GetPointer()); unsigned int patchRadius = 5; PriorityCriminisi<ImageType> priority(image.GetPointer(), mask.GetPointer(), patchRadius); itk::Index<2> sourcePixel; sourcePixel.Fill(0); itk::Index<2> targetPixel; targetPixel.Fill(1); priority.Update(sourcePixel, targetPixel); itk::Index<2> queryPixel = {{0,0}}; priority.ComputePriority(queryPixel); return EXIT_SUCCESS; }
int main() { FloatVectorImageType::Pointer image = FloatVectorImageType::New(); Testing::GetBlankImage(image.GetPointer(), 4); Mask::Pointer mask = Mask::New(); Testing::GetFullyValidMask(mask.GetPointer()); UnsignedCharScalarImageType::Pointer manualPriorityImage = UnsignedCharScalarImageType::New(); Testing::GetBlankImage(manualPriorityImage.GetPointer()); unsigned int patchRadius = 5; typedef PriorityConfidence ConfidencePriorityType; ConfidencePriorityType priorityConfidence(mask, patchRadius); PriorityManual<itk::Index<2>, UnsignedCharScalarImageType, ConfidencePriorityType> priority(manualPriorityImage, &priorityConfidence); itk::Index<2> filledPixel = {{0,0}}; priority.Update(filledPixel); priority.SetManualPriorityImage(manualPriorityImage); itk::Index<2> queryPixel = {{0,0}}; priority.ComputePriority(queryPixel); return EXIT_SUCCESS; }
int main(int argc, char*argv[]) { Mask::Pointer mask = Mask::New(); CreateMask(mask); OutputHelpers::WriteImage(mask.GetPointer(), "mask.png"); UnsignedCharScalarImageType::Pointer image = UnsignedCharScalarImageType::New(); CreateImage(image); OutputHelpers::WriteImage(image.GetPointer(), "image.png"); FloatScalarImageType::Pointer output = FloatScalarImageType::New(); MaskOperations::MaskedLaplacian(image.GetPointer(), mask.GetPointer(), output.GetPointer()); OutputHelpers::WriteImage(output.GetPointer(), "laplacian.mha"); return EXIT_SUCCESS; }
void Mask::CreateBoundaryImageInRegion(const itk::ImageRegion<2>& region, BoundaryImageType* const boundaryImage, const HoleMaskPixelTypeEnum& whichSideOfBoundary) const { // Create a binary image of the mask unsigned char holeColor = 255; unsigned char validColor = 0; UnsignedCharImageType::Pointer fullBinaryImage = UnsignedCharImageType::New(); CreateBinaryImageInRegion(region, fullBinaryImage, holeColor, validColor); // Extract the relevant region from the binary image UnsignedCharImageType::Pointer binaryImage = UnsignedCharImageType::New(); binaryImage->SetRegions(region); binaryImage->Allocate(); CopyRegion(fullBinaryImage.GetPointer(), binaryImage.GetPointer(), region, region); // Extract the relevant region from the mask Mask::Pointer extractedRegionMask = Mask::New(); extractedRegionMask->SetRegions(region); extractedRegionMask->Allocate(); CopyRegion(this, extractedRegionMask.GetPointer(), region, region); // Since the hole is white (we have specified this at the beginning of this function), // we want the foreground value of the contour filter to be black. // This means that the boundary will be detected in the black pixel region, // which is on the outside edge of the hole like we want. However, // The BinaryContourImageFilter will change all non-boundary pixels to the background color, // so the resulting output will be inverted - the boundary pixels will be black and the // non-boundary pixels will be white. // Find the boundary typedef itk::BinaryContourImageFilter<UnsignedCharImageType, UnsignedCharImageType> binaryContourImageFilterType; binaryContourImageFilterType::Pointer binaryContourFilter = binaryContourImageFilterType::New(); binaryContourFilter->SetInput(binaryImage); binaryContourFilter->SetFullyConnected(true); if(whichSideOfBoundary == HoleMaskPixelTypeEnum::VALID) { // we want the boundary pixels to be in the valid region. binaryContourFilter->SetForegroundValue(validColor); binaryContourFilter->SetBackgroundValue(holeColor); } else if(whichSideOfBoundary == HoleMaskPixelTypeEnum::HOLE) { // we want the boundary pixels to be in the hole region. binaryContourFilter->SetForegroundValue(holeColor); binaryContourFilter->SetBackgroundValue(validColor); } else { throw std::runtime_error("An invalid side of the boundary was requested."); } binaryContourFilter->Update(); DeepCopy(binaryContourFilter->GetOutput(), boundaryImage); }
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; }
void Vector() { typedef itk::Image<unsigned char, 2 > ChannelType; const unsigned int NumberOfChannels = 3; typedef itk::Image<itk::CovariantVector<unsigned char, NumberOfChannels>, 2 > ImageType; ImageType::Pointer image = ImageType::New(); itk::Index<2> corner = {{0,0}}; itk::Size<2> imageSize = {{500,500}}; itk::ImageRegion<2> fullRegion(corner, imageSize); image->SetRegions(fullRegion); image->Allocate(); for(unsigned int i = 0; i < NumberOfChannels; ++i) { itk::RandomImageSource<ChannelType>::Pointer randomImageSource = itk::RandomImageSource<ChannelType>::New(); randomImageSource->SetNumberOfThreads(1); // to produce non-random results randomImageSource->SetSize(imageSize); randomImageSource->Update(); ITKHelpers::SetChannel(image.GetPointer(), i, randomImageSource->GetOutput()); } itk::Size<2> patchSize = {{21,21}}; // There is nothing magic about these particular patches itk::Index<2> targetCorner = {{319, 302}}; itk::ImageRegion<2> targetRegion(targetCorner, patchSize); itk::Index<2> sourceCorner = {{341, 300}}; itk::ImageRegion<2> sourceRegion(sourceCorner, patchSize); Mask::Pointer mask = Mask::New(); mask->SetRegions(fullRegion); mask->Allocate(); ITKHelpers::SetImageToConstant(mask.GetPointer(), mask->GetValidValue()); typedef SumSquaredPixelDifference<ImageType::PixelType> PixelDifferenceType; typedef ImagePatchPixelDescriptor<ImageType> PatchType; ImagePatchDifference<PatchType, PixelDifferenceType> imagePatchDifference; PatchType targetPatch(image, mask, targetRegion); PatchType sourcePatch(image, mask, sourceRegion); float difference = imagePatchDifference(targetPatch, sourcePatch); std::cout << "GMHDifference: " << difference << std::endl; }
int main() { FloatVectorImageType::Pointer image = FloatVectorImageType::New(); Testing::GetBlankImage(image.GetPointer(), 4); Mask::Pointer mask = Mask::New(); Testing::GetFullyValidMask(mask.GetPointer()); unsigned int patchRadius = 5; PriorityDepth<FloatVectorImageType> priority(image, mask, patchRadius); itk::Index<2> filledPixel = {{0,0}}; priority.Update(filledPixel); itk::Index<2> queryPixel = {{0,0}}; priority.ComputePriority(queryPixel); return EXIT_SUCCESS; }
void Scalar() { typedef itk::Image< unsigned char, 2 > ImageType; itk::Size<2> imageSize = {{500,500}}; itk::RandomImageSource<ImageType>::Pointer randomImageSource = itk::RandomImageSource<ImageType>::New(); randomImageSource->SetNumberOfThreads(1); // to produce non-random results randomImageSource->SetSize(imageSize); randomImageSource->Update(); ImageType* image = randomImageSource->GetOutput(); itk::Size<2> patchSize = {{21,21}}; // There is nothing magic about these particular patches itk::Index<2> targetCorner = {{319, 302}}; itk::ImageRegion<2> targetRegion(targetCorner, patchSize); itk::Index<2> sourceCorner = {{341, 300}}; itk::ImageRegion<2> sourceRegion(sourceCorner, patchSize); Mask::Pointer mask = Mask::New(); mask->SetRegions(randomImageSource->GetOutput()->GetLargestPossibleRegion()); mask->Allocate(); ITKHelpers::SetImageToConstant(mask.GetPointer(), mask->GetValidValue()); typedef SumSquaredPixelDifference<ImageType::PixelType> PixelDifferenceType; typedef ImagePatchPixelDescriptor<ImageType> PatchType; ImagePatchDifference<PatchType, PixelDifferenceType> imagePatchDifference; PatchType targetPatch(image, mask, targetRegion); PatchType sourcePatch(image, mask, sourceRegion); float difference = imagePatchDifference(targetPatch, sourcePatch); std::cout << "Difference: " << difference << std::endl; }
int main() { typedef itk::Image<itk::CovariantVector<float, 3>, 2> ImageType; ImageType::Pointer image = ImageType::New(); Testing::GetBlankImage(image.GetPointer(), 4); Mask::Pointer mask = Mask::New(); Testing::GetFullyValidMask(mask.GetPointer()); vtkSmartPointer<vtkStructuredGrid> structuredGrid = vtkSmartPointer<vtkStructuredGrid>::New(); unsigned int patchRadius = 5; PriorityCurvature<itk::Index<2> > priority(structuredGrid, patchRadius); itk::Index<2> filledPixel = {{0,0}}; itk::Index<2> sourcePixel = {{0,0}}; priority.Update(sourcePixel, filledPixel); itk::Index<2> queryPixel = {{0,0}}; priority.ComputePriority(queryPixel); return EXIT_SUCCESS; }
void TestComputeMaskedImage1DHistogram() { // // Single channel // { // typedef itk::Image<unsigned char, 2> ImageType; // ImageType::Pointer image = ImageType::New(); // ImageType::IndexType corner = {{0,0}}; // ImageType::SizeType size = {{100,100}}; // ImageType::RegionType region(corner, size); // image->SetRegions(region); // image->Allocate(); // itk::ImageRegionIterator<ImageType> imageIterator(image,region); // while(!imageIterator.IsAtEnd()) // { // if(imageIterator.GetIndex()[0] < 70) // { // imageIterator.Set(255); // } // else // { // imageIterator.Set(0); // } // ++imageIterator; // } // ImageType::PixelType rangeMin = 0; // ImageType::PixelType rangeMax = 255; // unsigned int numberOfBins = 10; // typedef int BinValueType; // typedef Histogram<BinValueType>::HistogramType HistogramType; // HistogramType histogram = Histogram<BinValueType>::ComputeImageHistogram1D(image.GetPointer(), // image->GetLargestPossibleRegion(), // numberOfBins, rangeMin, rangeMax); // Histogram<BinValueType>::OutputHistogram(histogram); // std::cout << std::endl; // } // Multi channel VectorImage { typedef itk::VectorImage<unsigned char, 2> ImageType; ImageType::Pointer image = ImageType::New(); ImageType::IndexType corner = {{0,0}}; ImageType::SizeType size = {{100,100}}; ImageType::RegionType region(corner, size); image->SetRegions(region); image->SetNumberOfComponentsPerPixel(3); image->Allocate(); Mask::Pointer mask = Mask::New(); mask->SetRegions(region); mask->Allocate(); itk::ImageRegionIterator<ImageType> imageIterator(image,region); while(!imageIterator.IsAtEnd()) { ImageType::PixelType pixel(image->GetNumberOfComponentsPerPixel()); if(imageIterator.GetIndex()[0] < 70) { for(unsigned int i = 0; i < pixel.GetSize(); ++i) { pixel[i] = 255; } } else { for(unsigned int i = 0; i < pixel.GetSize(); ++i) { pixel[i] = 0; } } imageIterator.Set(pixel); ++imageIterator; } // TypeTraits<ImageType::PixelType>::ComponentType rangeMin = 0; // TypeTraits<ImageType::PixelType>::ComponentType rangeMax = 255; ImageType::PixelType rangeMins; rangeMins.SetSize(image->GetNumberOfComponentsPerPixel()); rangeMins.Fill(0); ImageType::PixelType rangeMaxs; rangeMaxs.SetSize(image->GetNumberOfComponentsPerPixel()); rangeMaxs.Fill(255); unsigned int numberOfBinsPerComponent = 10; typedef int BinValueType; itk::ImageRegion<2> imageRegion = image->GetLargestPossibleRegion(); itk::ImageRegion<2> maskRegion = image->GetLargestPossibleRegion(); typedef MaskedHistogramGenerator<BinValueType> HistogramGeneratorType; typedef HistogramGeneratorType::HistogramType HistogramType; bool allowOutside = false; HistogramType histogram = HistogramGeneratorType::ComputeMaskedImage1DHistogram(image.GetPointer(), imageRegion, mask.GetPointer(), maskRegion, numberOfBinsPerComponent, rangeMins, rangeMaxs, allowOutside, HoleMaskPixelTypeEnum::VALID); histogram.Print(); std::cout << std::endl; } // // Multi channel Image<CovariantVector> // { // typedef itk::Image<itk::CovariantVector<unsigned char, 3>, 2> ImageType; // ImageType::Pointer image = ImageType::New(); // ImageType::IndexType corner = {{0,0}}; // ImageType::SizeType size = {{100,100}}; // ImageType::RegionType region(corner, size); // image->SetRegions(region); // image->Allocate(); // itk::ImageRegionIterator<ImageType> imageIterator(image,region); // while(!imageIterator.IsAtEnd()) // { // ImageType::PixelType pixel(image->GetNumberOfComponentsPerPixel()); // if(imageIterator.GetIndex()[0] < 70) // { // for(unsigned int i = 0; i < pixel.GetNumberOfComponents(); ++i) // { // pixel[i] = 255; // } // } // else // { // for(unsigned int i = 0; i < pixel.GetNumberOfComponents(); ++i) // { // pixel[i] = 0; // } // } // imageIterator.Set(pixel); // ++imageIterator; // } // TypeTraits<ImageType::PixelType>::ComponentType rangeMin = 0; // TypeTraits<ImageType::PixelType>::ComponentType rangeMax = 255; // unsigned int numberOfBinsPerComponent = 10; // typedef int BinValueType; // Histogram<BinValueType>::HistogramType histogram = Histogram<BinValueType>::ComputeImageHistogram1D(image.GetPointer(), // image->GetLargestPossibleRegion(), // numberOfBinsPerComponent, rangeMin, rangeMax); // Histogram<BinValueType>::OutputHistogram(histogram); // std::cout << std::endl; // } }
int main(int argc, char* argv[]) { // Verify arguments if(argc < 5) { std::cout << "Usage: PatchImage repeatX repeatY outputImage" << std::endl; return EXIT_FAILURE; } // Parse arguments std::string patchImageFilename = argv[1]; std::stringstream ssRepeatX; ssRepeatX << argv[2]; unsigned int repeatX = 0; ssRepeatX >> repeatX; std::stringstream ssRepeatY; ssRepeatY << argv[3]; unsigned int repeatY = 0; ssRepeatY >> repeatY; std::string outputFilename = argv[4]; // Output arguments std::cout << "Patch image: " << patchImageFilename << std::endl << "Repeat X: " << repeatX << std::endl << "Repeat Y: " << repeatY << std::endl << "Output image: " << outputFilename << std::endl; //typedef itk::VectorImage<float, 2> ImageType; typedef itk::Image<itk::CovariantVector<float, 3>, 2> ImageType; // Read patch image typedef itk::ImageFileReader<ImageType> ImageReaderType; ImageReaderType::Pointer patchImageReader = ImageReaderType::New(); patchImageReader->SetFileName(patchImageFilename); patchImageReader->Update(); Mask::Pointer mask = Mask::New(); itk::ImageRegion<2> patchRegion = patchImageReader->GetOutput()->GetLargestPossibleRegion(); mask->SetRegions(patchRegion); mask->Allocate(); itk::Index<2> holeCorner = {{1,1}}; itk::Size<2> holeSize = patchRegion.GetSize(); holeSize[0] -= 2; // Missing one row on the top, and one row on the bottom holeSize[1] -= 2; // Missing one column on the left, and one column on the right itk::ImageRegion<2> holeRegion(holeCorner, holeSize); mask->SetValid(patchRegion); mask->SetHole(holeRegion); ImageType::Pointer seamlessPatch = ImageType::New(); ITKHelpers::DeepCopy(patchImageReader->GetOutput(), seamlessPatch.GetPointer()); // Enforce periodic boundary conditions // Top and bottom for(int i = 0; i < static_cast<int>(patchRegion.GetSize()[1]); ++i) { itk::Index<2> topPixelIndex = {{0, i}}; itk::Index<2> bottomPixelIndex = {{static_cast<int>(patchRegion.GetSize()[0])-1, i}}; ImageType::PixelType topPixelValue = seamlessPatch->GetPixel(topPixelIndex); ImageType::PixelType bottomPixelValue = seamlessPatch->GetPixel(bottomPixelIndex); ImageType::PixelType averageValue = (topPixelValue + bottomPixelValue)/2.0f; seamlessPatch->SetPixel(topPixelIndex, averageValue); seamlessPatch->SetPixel(bottomPixelIndex, averageValue); } // Left and right for(int i = 0; i < static_cast<int>(patchRegion.GetSize()[0]); ++i) { itk::Index<2> leftPixelIndex = {{i, 0}}; itk::Index<2> rightPixelIndex = {{i, static_cast<int>(patchRegion.GetSize()[1])-1}}; ImageType::PixelType leftPixelValue = seamlessPatch->GetPixel(leftPixelIndex); ImageType::PixelType rightPixelValue = seamlessPatch->GetPixel(rightPixelIndex); ImageType::PixelType averageValue = (leftPixelValue + rightPixelValue)/2.0f; seamlessPatch->SetPixel(leftPixelIndex, averageValue); seamlessPatch->SetPixel(rightPixelIndex, averageValue); } typedef PoissonEditingParent::GuidanceFieldType GuidanceFieldType; std::vector<GuidanceFieldType::Pointer> guidanceFields = PoissonEditingParent::ComputeGuidanceField(patchImageReader->GetOutput()); ImageType::Pointer output = ImageType::New(); FillImage(seamlessPatch.GetPointer(), mask.GetPointer(), guidanceFields, output.GetPointer(), patchRegion, seamlessPatch.GetPointer()); // Write output ITKHelpers::WriteRGBImage(output.GetPointer(), outputFilename); // Original tiled ImageType::Pointer originalTiled = ImageType::New(); TilePatch(patchImageReader->GetOutput(), repeatX, repeatY, originalTiled.GetPointer()); ITKHelpers::WriteRGBImage(originalTiled.GetPointer(), "original_tiled.png"); // Seamless tiled ImageType::Pointer seamlessTiled = ImageType::New(); TilePatch(output.GetPointer(), repeatX, repeatY, seamlessTiled.GetPointer()); ITKHelpers::WriteRGBImage(seamlessTiled.GetPointer(), "seamless_tiled.png"); return EXIT_SUCCESS; }
int main(int, char*[]) { // typedef itk::Image<itk::CovariantVector<int, 3>, 2> ImageType; typedef itk::Image<itk::CovariantVector<unsigned char, 3>, 2> ImageType; ImageType::PixelType red; red.Fill(0); red[0] = 255; ImageType::PixelType black; black.Fill(0); ImageType::PixelType white; white.Fill(255); ImageType::PixelType green; // Note this is not 255 because then the magnitude of red and green would be the same, // which makes debugging hard since the gradient of the magnitude image is used internally (in IntroducedEnergy). green.Fill(0); green[1] = 122; ImageType::PixelType blue; blue.Fill(0); blue[2] = 255; ImageType::Pointer image = ImageType::New(); itk::Index<2> imageCorner = {{0,0}}; itk::Size<2> imageSize = {{100,100}}; itk::ImageRegion<2> region(imageCorner,imageSize); image->SetRegions(region); image->Allocate(); Mask::Pointer mask = Mask::New(); mask->SetRegions(region); mask->Allocate(); itk::ImageRegionIteratorWithIndex<Mask> initializeMaskIterator(mask, mask->GetLargestPossibleRegion()); while(!initializeMaskIterator.IsAtEnd()) { if(initializeMaskIterator.GetIndex()[0] < 55) { initializeMaskIterator.Set(mask->GetHoleValue()); } else { initializeMaskIterator.Set(mask->GetValidValue()); } ++initializeMaskIterator; } ITKHelpers::WriteImage(mask.GetPointer(), "mask.png"); // Create a red image itk::ImageRegionIterator<ImageType> initializeIterator(image, image->GetLargestPossibleRegion()); while(!initializeIterator.IsAtEnd()) { initializeIterator.Set(red); ++initializeIterator; } // Setup source and target patch itk::Size<2> patchSize = {{10,10}}; itk::Index<2> sourceCorner = {{10,10}}; itk::ImageRegion<2> sourceRegion(sourceCorner, patchSize); itk::Index<2> targetCorner = {{50,50}}; itk::ImageRegion<2> targetRegion(targetCorner, patchSize); itk::Index<2> perfectSourceCorner = {{75,75}}; itk::ImageRegion<2> perfectSourceRegion(perfectSourceCorner, patchSize); // Make the source patch green itk::ImageRegionIterator<ImageType> sourceRegionIterator(image, sourceRegion); while(!sourceRegionIterator.IsAtEnd()) { sourceRegionIterator.Set(green); ++sourceRegionIterator; } ITKHelpers::WriteImage(image.GetPointer(), "image.png"); { ImageType::Pointer regionHighlightImage = ImageType::New(); ITKHelpers::DeepCopy(image.GetPointer(), regionHighlightImage.GetPointer()); ITKHelpers::OutlineRegion(regionHighlightImage.GetPointer(), sourceRegion, white); ITKHelpers::OutlineRegion(regionHighlightImage.GetPointer(), targetRegion, black); ITKHelpers::OutlineRegion(regionHighlightImage.GetPointer(), perfectSourceRegion, blue); ITKHelpers::WriteImage(regionHighlightImage.GetPointer(), "regions.png"); } IntroducedEnergy<ImageType> introducedEnergy; introducedEnergy.SetDebugImages(true); // Bad match { std::cout << "Bad match:" << std::endl; float patchBoundaryEnergy = introducedEnergy.ComputeIntroducedEnergyPatchBoundary(image, mask, sourceRegion, targetRegion); std::cout << "patchBoundaryEnergy: " << patchBoundaryEnergy << std::endl; float maskBoundaryEnergy = introducedEnergy.ComputeIntroducedEnergyMaskBoundary(image, mask, sourceRegion, targetRegion); std::cout << "maskBoundaryEnergy: " << maskBoundaryEnergy << std::endl; float totalEnergy = introducedEnergy.ComputeIntroducedEnergy(image, mask, sourceRegion, targetRegion); std::cout << "totalEnergy: " << totalEnergy << std::endl; } // Perfect match { std::cout << "Perfect match:" << std::endl; // IntroducedEnergy<ImageType> introducedEnergy; typedef IntroducedEnergy<ImageType> IntroducedEnergyType; float patchBoundaryEnergy = introducedEnergy.ComputeIntroducedEnergyPatchBoundary(image, mask, perfectSourceRegion, targetRegion); std::cout << "patchBoundaryEnergy: " << patchBoundaryEnergy << std::endl; float maskBoundaryEnergy = introducedEnergy.ComputeIntroducedEnergyMaskBoundary(image, mask, perfectSourceRegion, targetRegion); std::cout << "maskBoundaryEnergy: " << maskBoundaryEnergy << std::endl; float totalEnergy = introducedEnergy.ComputeIntroducedEnergy(image, mask, perfectSourceRegion, targetRegion); std::cout << "totalEnergy: " << totalEnergy << std::endl; } return EXIT_SUCCESS; }
int main(int argc, char*argv[]) { if(argc != 6) { std::cerr << "Required arguments: image output R G B" << std::endl; return EXIT_FAILURE; } std::vector<int> values(3,0); std::stringstream ss; unsigned int counter = 0; for(int i = 3; i < argc; ++i) { ss << argv[i] << " "; counter++; } for(int i = 0; i < 3; ++i) { ss >> values[i]; } // itk::RGBPixel<unsigned char> color; // color.SetRed(values[0]); // color.SetGreen(values[1]); // color.SetBlue(values[2]); Color color; color.r = values[0]; color.g = values[1]; color.b = values[2]; std::string imageFilename = argv[1]; std::string outputMaskFilename = argv[2]; std::cout << "Reading image: " << imageFilename << std::endl; std::cout << "outputMaskFilename: " << outputMaskFilename << std::endl; std::cout << "Color: " << static_cast<int>(values[0]) << " " << static_cast<int>(values[1]) << " " << static_cast<int>(values[2]) << std::endl; //typedef itk::Image<float, 2> ImageType; typedef itk::Image<itk::CovariantVector<unsigned char, 3>, 2> ImageType; ImageType::PixelType pixelColor; pixelColor[0] = color.r; pixelColor[1] = color.g; pixelColor[2] = color.b; typedef itk::ImageFileReader<ImageType> ImageReaderType; ImageReaderType::Pointer imageReader = ImageReaderType::New(); imageReader->SetFileName(imageFilename.c_str()); imageReader->Update(); Mask::Pointer mask = Mask::New(); mask->SetRegions(imageReader->GetOutput()->GetLargestPossibleRegion()); mask->Allocate(); mask->CreateFromImage(imageReader->GetOutput(), pixelColor); OutputHelpers::WriteImage(mask.GetPointer(), outputMaskFilename); return EXIT_SUCCESS; }
bool AcceptMatch(VertexDescriptorType target, VertexDescriptorType source, float& computedEnergy) const { //std::cout << "DilatedVarianceDifferenceAcceptanceVisitor::AcceptMatch" << std::endl; itk::Index<2> targetPixel = ITKHelpers::CreateIndex(target); itk::ImageRegion<2> targetRegion = ITKHelpers::GetRegionInRadiusAroundPixel(targetPixel, HalfWidth); itk::Index<2> sourcePixel = ITKHelpers::CreateIndex(source); itk::ImageRegion<2> sourceRegion = ITKHelpers::GetRegionInRadiusAroundPixel(sourcePixel, HalfWidth); // Compute the functor on the pixels in the region just inside the hole in the source patch typename TypeTraits<typename TImage::PixelType>::LargerType sourceValue; { Mask::Pointer originalHole = Mask::New(); ITKHelpers::ExtractRegion(MaskImage, targetRegion, originalHole.GetPointer()); Mask::Pointer shrunkHole = Mask::New(); shrunkHole->DeepCopyFrom(originalHole); shrunkHole->ShrinkHole(5); typedef itk::Image<bool, 2> BoolImage; BoolImage::Pointer holeRindImage = BoolImage::New(); // "rind" like an "orange rind" ITKHelpers::XORRegions(originalHole.GetPointer(), originalHole->GetLargestPossibleRegion(), shrunkHole.GetPointer(), shrunkHole->GetLargestPossibleRegion(), holeRindImage.GetPointer()); std::vector<itk::Index<2> > holeRindPixels = ITKHelpers::GetPixelsWithValue(holeRindImage.GetPointer(), holeRindImage->GetLargestPossibleRegion(), true); itk::Index<2> zeroIndex = {{0,0}}; std::vector<itk::Offset<2> > holeRindOffsets = ITKHelpers::IndicesToOffsets(holeRindPixels, zeroIndex); std::vector<itk::Index<2> > sourceRindPixelIndices = ITKHelpers::OffsetsToIndices(holeRindOffsets, sourceRegion.GetIndex()); std::vector<typename TImage::PixelType> sourceRindPixels = ITKHelpers::GetPixelValues(Image, sourceRindPixelIndices); sourceValue = Functor(sourceRindPixels); } // Compute the functor on the pixels in the region just outside the hole in the target patch typename TypeTraits<typename TImage::PixelType>::LargerType targetValue; { Mask::Pointer originalHole = Mask::New(); ITKHelpers::ExtractRegion(MaskImage, targetRegion, originalHole.GetPointer()); Mask::Pointer expandedHole = Mask::New(); expandedHole->DeepCopyFrom(originalHole); expandedHole->ExpandHole(5); typedef itk::Image<bool, 2> BoolImage; BoolImage::Pointer validRindImage = BoolImage::New(); // "rind" like an "orange rind" ITKHelpers::XORRegions(originalHole.GetPointer(), originalHole->GetLargestPossibleRegion(), expandedHole.GetPointer(), expandedHole->GetLargestPossibleRegion(), validRindImage.GetPointer()); std::vector<itk::Index<2> > validRindPixels = ITKHelpers::GetPixelsWithValue(validRindImage.GetPointer(), validRindImage->GetLargestPossibleRegion(), true); itk::Index<2> zeroIndex = {{0,0}}; std::vector<itk::Offset<2> > validRindOffsets = ITKHelpers::IndicesToOffsets(validRindPixels, zeroIndex); std::vector<itk::Index<2> > targetRindPixelIndices = ITKHelpers::OffsetsToIndices(validRindOffsets, targetRegion.GetIndex()); std::vector<typename TImage::PixelType> targetRindPixels = ITKHelpers::GetPixelValues(Image, targetRindPixelIndices); targetValue = Functor(targetRindPixels); } // Compute the difference computedEnergy = (targetValue - sourceValue).GetNorm(); //std::cout << this->VisitorName << " Energy: " << computedEnergy << std::endl; if(computedEnergy < DifferenceThreshold) { std::cout << this->VisitorName << ": Match accepted (" << computedEnergy << " is less than " << DifferenceThreshold << ")" << std::endl << std::endl; return true; } else { std::cout << this->VisitorName << ": Match rejected (" << computedEnergy << " is greater than " << DifferenceThreshold << ")" << std::endl << std::endl; return false; } };
// 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(); }
void LidarSegmentationWidget::GenerateNeighborSinks() { Mask::Pointer sourcesImage = Mask::New(); sourcesImage->SetRegions(this->ImageRegion); ITKHelpers::IndicesToBinaryImage(this->Sources, sourcesImage); ITKHelpers::WriteImage(sourcesImage.GetPointer(), "sourcesImage.png"); // Dilate the mask std::cout << "Dilating mask..." << std::endl; typedef itk::BinaryBallStructuringElement<Mask::PixelType, 2> StructuringElementType; StructuringElementType structuringElement; structuringElement.SetRadius(1); structuringElement.CreateStructuringElement(); typedef itk::BinaryDilateImageFilter<Mask, Mask, StructuringElementType> BinaryDilateImageFilterType; BinaryDilateImageFilterType::Pointer dilateFilter = BinaryDilateImageFilterType::New(); dilateFilter->SetInput(sourcesImage); dilateFilter->SetKernel(structuringElement); dilateFilter->Update(); // Binary XOR the images to get the difference image //std::cout << "XORing masks..." << std::endl; typedef itk::XorImageFilter<Mask> XorImageFilterType; XorImageFilterType::Pointer xorFilter = XorImageFilterType::New(); xorFilter->SetInput1(dilateFilter->GetOutput()); xorFilter->SetInput2(sourcesImage); xorFilter->Update(); ITKHelpers::WriteImage(xorFilter->GetOutput(), "boundaryOfSegmentation.png"); // Iterate over the border pixels. If the closest pixel in the original segmentation has // a depth greater than a threshold, mark it as a new sink. Else, do not. std::cout << "Determining which boundary pixels should be declared background..." << std::endl; //std::cout << "There should be " << Helpers::CountNonZeroPixels(xorFilter->GetOutput()) // << " considered." << std::endl; typedef std::vector<itk::Index<2> > VectorOfPixelsType; VectorOfPixelsType newSinks; typedef itk::VectorIndexSelectionCastImageFilter<ImageType, FloatScalarImageType> IndexSelectionType; IndexSelectionType::Pointer indexSelectionFilter = IndexSelectionType::New(); indexSelectionFilter->SetIndex(3); indexSelectionFilter->SetInput(this->Image); indexSelectionFilter->Update(); FloatScalarImageType::Pointer depthImage = indexSelectionFilter->GetOutput(); //float sameObjectThreshold = 0.1f; VectorOfPixelsType consideredPixels; itk::ImageRegionIterator<Mask> imageIterator(xorFilter->GetOutput(), xorFilter->GetOutput()->GetLargestPossibleRegion()); while(!imageIterator.IsAtEnd()) { if(imageIterator.Get()) // If the current pixel is in question { consideredPixels.push_back(imageIterator.GetIndex()); } ++imageIterator; } std::cout << "There are " << consideredPixels.size() << " potential new sink pixels." << std::endl; for(VectorOfPixelsType::const_iterator iter = consideredPixels.begin(); iter != consideredPixels.end(); ++iter) { //std::cout << "Considering pixel " << consideredCounter << " (index " // << imageIterator.GetIndex() << ")" << std::endl; ImageType::PixelType currentPixel = this->Image->GetPixel(*iter); unsigned int radius = this->txtBackgroundCheckRadius->text().toUInt(); ImageType::RegionType desiredRegion = ITKHelpers::GetRegionInRadiusAroundPixel(*iter, radius); //std::cout << "desiredRegion: " << desiredRegion << std::endl; itk::ImageRegionIterator<Mask> sourcesImageIterator(sourcesImage, desiredRegion); std::vector<float> nonForegroundDepths; std::vector<float> foregroundDepths; while(!sourcesImageIterator.IsAtEnd()) { if(sourcesImageIterator.Get()) { foregroundDepths.push_back(depthImage->GetPixel(sourcesImageIterator.GetIndex())); } else { nonForegroundDepths.push_back(depthImage->GetPixel(sourcesImageIterator.GetIndex())); } ++sourcesImageIterator; } if(nonForegroundDepths.size() < 1) { } float nonForegroundMedian = Helpers::VectorMedian(nonForegroundDepths); float foregroundMedian = Helpers::VectorMedian(foregroundDepths); float difference = fabs(foregroundMedian - nonForegroundMedian); if(difference > this->txtBackgroundThreshold->text().toFloat()) { //std::cout << "Difference was " << difference << " so this is a sink pixel." << std::endl; newSinks.push_back(*iter); } else { //std::cout << "Difference was " << difference << " so this is NOT a sink pixel." << std::endl; } } // end loop over considered pixels unsigned char blue[3] = {0, 0, 255}; // ImageType::PixelType blue(3); // blue[0] = 0; // blue[1] = 0; // blue[2] = 255; ITKVTKHelpers::SetPixels(this->SourceSinkImageData.GetPointer(), consideredPixels, blue); this->SourceSinkImageData->Modified(); this->Refresh(); // Save the new sink pixels for inspection UnsignedCharScalarImageType::Pointer newSinksImage = UnsignedCharScalarImageType::New(); newSinksImage->SetRegions(this->Image->GetLargestPossibleRegion()); newSinksImage->Allocate(); ITKHelpers::IndicesToBinaryImage(newSinks, newSinksImage); ITKHelpers::WriteImage(newSinksImage.GetPointer(), "newSinks.png"); //std::cout << "Out of " << consideredCounter << " pixels considered, " // << backgroundCounter << " were declared background." << std::endl; // Set the new sinks std::cout << "Setting " << newSinks.size() << " new sinks." << std::endl; // Modify the list of sinks so it can be retrieved by the MainWindow after the segmentation is finished this->Sinks.insert(this->Sinks.end(), newSinks.begin(), newSinks.end()); UpdateSelections(); }