Exemple #1
0
void Mask::FindBoundary(UnsignedCharScalarImageType* boundaryImage) const
{
  // Compute the "outer" boundary of the region to fill. That is, we want the boundary pixels to be in the source region.

  //HelpersOutput::WriteImageConditional<Mask>(this->CurrentMask, "Debug/FindBoundary.CurrentMask.mha", this->DebugImages);
  //HelpersOutput::WriteImageConditional<Mask>(this->CurrentMask, "Debug/FindBoundary.CurrentMask.png", this->DebugImages);

  // Create a binary image (throw away the "dont use" pixels)
  Mask::Pointer holeOnly = Mask::New();
  holeOnly->DeepCopyFrom(this);

  itk::ImageRegionIterator<Mask> maskIterator(holeOnly, holeOnly->GetLargestPossibleRegion());
  // This should result in a white hole on a black background
  while(!maskIterator.IsAtEnd())
    {
    itk::Index<2> currentPixel = maskIterator.GetIndex();
    if(!holeOnly->IsHole(currentPixel))
      {
      holeOnly->SetPixel(currentPixel, holeOnly->GetValidValue());
      }
    ++maskIterator;
    }

  //HelpersOutput::WriteImageConditional<Mask>(holeOnly, "Debug/FindBoundary.HoleOnly.mha", this->DebugImages);
  //HelpersOutput::WriteImageConditional<Mask>(holeOnly, "Debug/FindBoundary.HoleOnly.png", this->DebugImages);

  // Since the hole is white, 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 <Mask, Mask> binaryContourImageFilterType;
  binaryContourImageFilterType::Pointer binaryContourFilter = binaryContourImageFilterType::New();
  binaryContourFilter->SetInput(holeOnly);
  binaryContourFilter->SetFullyConnected(true);
  binaryContourFilter->SetForegroundValue(holeOnly->GetValidValue());
  binaryContourFilter->SetBackgroundValue(holeOnly->GetHoleValue());
  binaryContourFilter->Update();

  //HelpersOutput::WriteImageConditional<Mask>(binaryContourFilter->GetOutput(), "Debug/FindBoundary.Boundary.mha", this->DebugImages);
  //HelpersOutput::WriteImageConditional<Mask>(binaryContourFilter->GetOutput(), "Debug/FindBoundary.Boundary.png", this->DebugImages);

  // Since we want to interpret non-zero pixels as boundary pixels, we must invert the image.
  typedef itk::InvertIntensityImageFilter <Mask> InvertIntensityImageFilterType;
  InvertIntensityImageFilterType::Pointer invertIntensityFilter = InvertIntensityImageFilterType::New();
  invertIntensityFilter->SetInput(binaryContourFilter->GetOutput());
  invertIntensityFilter->SetMaximum(255);
  invertIntensityFilter->Update();

  //this->BoundaryImage = binaryContourFilter->GetOutput();
  //this->BoundaryImage->Graft(binaryContourFilter->GetOutput());
  ITKHelpers::DeepCopy<UnsignedCharScalarImageType>(invertIntensityFilter->GetOutput(), boundaryImage);

  //HelpersOutput::WriteImageConditional<UnsignedCharScalarImageType>(this->BoundaryImage, "Debug/FindBoundary.BoundaryImage.mha", this->DebugImages);

}
int main(int argc, char *argv[])
{
  // Verify arguments
  if(argc != 5)
    {
    std::cerr << "Required arguments: image imageMask patchRadius outputPrefix" << std::endl;
    return EXIT_FAILURE;
    }

  // Parse arguments
  std::string imageFilename = argv[1];
  std::string maskFilename = argv[2];

  std::stringstream ssPatchRadius;
  ssPatchRadius << argv[3];
  int patchRadius = 0;
  ssPatchRadius >> patchRadius;

  std::string outputPrefix = argv[4];

  // Output arguments
  std::cout << "Reading image: " << imageFilename << std::endl;
  std::cout << "Reading mask: " << maskFilename << std::endl;
  std::cout << "Patch radius: " << patchRadius << std::endl;
  //std::cout << "Output: " << outputFilename << std::endl;

  typedef  itk::ImageFileReader< FloatVectorImageType > ImageReaderType;
  ImageReaderType::Pointer imageReader = ImageReaderType::New();
  imageReader->SetFileName(imageFilename.c_str());
  imageReader->Update();

  FloatVectorImageType::Pointer scaledImage = FloatVectorImageType::New();
  // Initialize
  Helpers::DeepCopy<FloatVectorImageType>(imageReader->GetOutput(), scaledImage);

  std::vector<float> maxValues = Helpers::MaxValuesVectorImage<float>(imageReader->GetOutput());

  // Scale all channels the same
//   for(unsigned int channel = 0; channel < imageReader->GetOutput()->GetNumberOfComponentsPerPixel(); ++channel)
//     {
//     Helpers::ScaleChannel<float>(imageReader->GetOutput(), channel, 1.0f, scaledImage);
//     }

  // Scale color channels
  for(unsigned int channel = 0; channel < 3; ++channel)
    {
    Helpers::ScaleChannel<float>(scaledImage, channel, 0.33f, scaledImage);
    }

  // Scale depth channel
  Helpers::ScaleChannel<float>(scaledImage, 3, 1.0f, scaledImage);

  Helpers::WriteImage<FloatVectorImageType>(scaledImage, "scaled.mha");

  typedef  itk::ImageFileReader< Mask > MaskReaderType;
  MaskReaderType::Pointer maskReader = MaskReaderType::New();
  maskReader->SetFileName(maskFilename.c_str());
  maskReader->Update();

  Mask::Pointer finalMask = Mask::New();
  ModifyMask(maskReader->GetOutput(), patchRadius, finalMask);

  cout.setf(ios::showpoint);

  std::vector<float> lambdas;
  for(unsigned int i = 0; i <= 10; ++i)
    {
    lambdas.push_back(0.1f * static_cast<float>(i));
    std::cout << "Using lambda " << lambdas[i] << std::endl;
    }

  std::shared_ptr<SelfPatchCompare> patchCompare(new SelfPatchCompare);
  patchCompare->SetNumberOfComponentsPerPixel(imageReader->GetOutput()->GetNumberOfComponentsPerPixel());
  //patchCompare->FunctionsToCompute.push_back(boost::bind(&SelfPatchCompare::SetPatchAverageAbsoluteSourceDifference,patchCompare,_1));
  patchCompare->FunctionsToCompute.push_back(boost::bind(&SelfPatchCompare::SetPatchColorDifference,patchCompare,_1));
  patchCompare->FunctionsToCompute.push_back(boost::bind(&SelfPatchCompare::SetPatchDepthDifference,patchCompare,_1));

  std::ofstream fout("scores.txt");

  fout.setf(ios::showpoint);
  for(unsigned int lambdaId = 0; lambdaId < lambdas.size(); ++lambdaId)
    {
    // Inpaint
    std::cout << "Inpainting with lambda = " << lambdas[lambdaId] << std::endl;

    PatchPair::DepthColorLambda = lambdas[lambdaId];

    CriminisiInpainting inpainting;
    //inpainting.SetDebugFunctionEnterLeave(true);
    inpainting.SetPatchRadius(patchRadius);
    inpainting.SetImage(scaledImage);
    inpainting.SetMask(finalMask);
    inpainting.SetMaxForwardLookPatches(3);
    inpainting.SetPatchCompare(patchCompare);

    inpainting.PatchSortFunction = &SortByDepthAndColor;
    //inpainting.PatchSortFunction = &SortByAverageAbsoluteDifference;

    //DepthAndColorDifference = ColorDifference * Lambda + (1.0 - Lambda) * DepthDifference;
    // When lambda = 0, only the depth is used
    // When lambda = 1, only the color is used

    inpainting.Initialize();
    inpainting.Inpaint();

    // Compute error
    itk::ImageRegionIterator<Mask> iterator(finalMask, finalMask->GetLargestPossibleRegion());
    float depthError = 0.0f;
    float colorError = 0.0f;

    while(!iterator.IsAtEnd())
      {
      if(finalMask->IsHole(iterator.GetIndex()))
	{
	colorError += ColorPixelDifference::Difference(scaledImage->GetPixel(iterator.GetIndex()), inpainting.GetCurrentOutputImage()->GetPixel(iterator.GetIndex()));
	depthError += DepthPixelDifference::Difference(scaledImage->GetPixel(iterator.GetIndex()), inpainting.GetCurrentOutputImage()->GetPixel(iterator.GetIndex()));
	}
      ++iterator;
      }
    std::cout << "colorError: " << colorError << std::endl;
    std::cout << "depthError: " << depthError << std::endl;

    fout << colorError << " " << depthError << std::endl;

    // Unscale all channels
    for(unsigned int channel = 0; channel < imageReader->GetOutput()->GetNumberOfComponentsPerPixel(); ++channel)
      {
      Helpers::ScaleChannel<float>(inpainting.GetCurrentOutputImage(), channel, maxValues[channel], inpainting.GetCurrentOutputImage());
      }

    std::stringstream ssFloat;
    ssFloat.setf(ios::showpoint);
    ssFloat << outputPrefix << "_float_lambda_" << lambdas[lambdaId] << ".mha";
    Helpers::WriteImage<FloatVectorImageType>(inpainting.GetCurrentOutputImage(), ssFloat.str());

    std::stringstream ssRGB;
    ssRGB.setf(ios::showpoint);
    ssRGB << outputPrefix << "_RGB_lambda_" << lambdas[lambdaId] << ".mha";
    Helpers::WriteVectorImageAsRGB(inpainting.GetCurrentOutputImage(), ssRGB.str());
    //Helpers::WriteVectorImageAsRGB(inpainting.GetCurrentOutputImage(), Helpers::ReplaceFileExtension(ss.str(), "png"));
    }

  fout.close();

  return EXIT_SUCCESS;
}