/*=========================================================================
 *
 *  Copyright NumFOCUS
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *         https://www.apache.org/licenses/LICENSE-2.0.txt
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 *
 *=========================================================================*/

//  Software Guide : BeginCommandLineArgs
//    INPUTS:  {BrainProtonDensitySlice.png}
//    OUTPUTS: {ImageAdaptorThresholdingA.png}
//    ARGUMENTS:    180
//  Software Guide : EndCommandLineArgs
//
//  Software Guide : BeginCommandLineArgs
//    INPUTS:  {BrainProtonDensitySlice.png}
//    OUTPUTS: {ImageAdaptorThresholdingB.png}
//    ARGUMENTS:    220
//  Software Guide : EndCommandLineArgs

// Software Guide : BeginLatex
//
// Image adaptors can also be used to perform simple pixel-wise computations
// on image data. The following example illustrates how to use the
// \doxygen{ImageAdaptor} for image thresholding.
//
// \index{itk::ImageAdaptor!Instantiation}
// \index{itk::ImageAdaptor!Header}
// \index{itk::ImageAdaptor!performing computation}
// \index{itk::PixelAccessor!with parameters}
// \index{itk::PixelAccessor!performing computation}
//
// Software Guide : EndLatex

#include "itkImageAdaptor.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkRescaleIntensityImageFilter.h"


//  Software Guide : BeginLatex
//
//  A pixel accessor for image thresholding requires that the accessor
//  maintain the threshold value. Therefore, it must also implement the
//  assignment operator to set this internal parameter.
//
//  Software Guide : EndLatex

namespace itk
{
// Software Guide : BeginCodeSnippet
class ThresholdingPixelAccessor
{
public:
  using InternalType = unsigned char;
  using ExternalType = unsigned char;

  ThresholdingPixelAccessor() = default;

  [[nodiscard]] ExternalType
  Get(const InternalType & input) const
  {
    return (input > m_Threshold) ? 1 : 0;
  }
  void
  SetThreshold(const InternalType threshold)
  {
    m_Threshold = threshold;
  }

  ThresholdingPixelAccessor &
  operator=(const ThresholdingPixelAccessor & vpa) = default;

private:
  InternalType m_Threshold{ 0 };
};
} // namespace itk

// Software Guide : EndCodeSnippet


//  Software Guide : BeginLatex
//
//  The \code{Get()} method returns one if the input pixel is above
//  the threshold and zero otherwise. The assignment operator transfers
//  the value of the threshold member
//  variable from one instance of the pixel accessor to another.
//
//  Software Guide : EndLatex


//-------------------------
//
//   Main code
//
//-------------------------

int
main(int argc, char * argv[])
{
  if (argc < 4)
  {
    std::cerr << "Usage: " << std::endl;
    std::cerr << "ImageAdaptor4   inputFileName outputBinaryFileName ";
    std::cerr << " thresholdValue" << std::endl;
    return EXIT_FAILURE;
  }


  //  Software Guide : BeginLatex
  //
  //  To create an image adaptor, we first instantiate an image type
  //  whose pixel type is the same as the internal pixel type of the pixel
  //  accessor.
  //
  //  Software Guide : EndLatex


  // Software Guide : BeginCodeSnippet
  using PixelType = itk::ThresholdingPixelAccessor::InternalType;
  constexpr unsigned int Dimension = 2;
  using ImageType = itk::Image<PixelType, Dimension>;
  // Software Guide : EndCodeSnippet


  //  Software Guide : BeginLatex
  //
  //  We instantiate the ImageAdaptor using the image type as the
  //  first template parameter and the pixel accessor as the second template
  //  parameter.
  //
  //  Software Guide : EndLatex


  // Software Guide : BeginCodeSnippet
  using ImageAdaptorType =
    itk::ImageAdaptor<ImageType, itk::ThresholdingPixelAccessor>;

  auto adaptor = ImageAdaptorType::New();
  // Software Guide : EndCodeSnippet


  //  Software Guide : BeginLatex
  //
  //  The threshold value is set from the command line. A threshold
  //  pixel accessor is created and connected to the image adaptor
  //  in the same manner as in the previous example.
  //
  //  Software Guide : EndLatex


  // Software Guide : BeginCodeSnippet
  itk::ThresholdingPixelAccessor accessor;
  accessor.SetThreshold(std::stoi(argv[3]));
  adaptor->SetPixelAccessor(accessor);
  // Software Guide : EndCodeSnippet


  //  Software Guide : BeginLatex
  //
  //  We create a reader to load the input image and connect the output
  //  of the reader as the input to the adaptor.
  //
  //  Software Guide : EndLatex


  // Software Guide : BeginCodeSnippet
  using ReaderType = itk::ImageFileReader<ImageType>;
  auto reader = ReaderType::New();
  reader->SetFileName(argv[1]);
  reader->Update();

  adaptor->SetImage(reader->GetOutput());
  //  Software Guide : EndCodeSnippet


  using RescalerType =
    itk::RescaleIntensityImageFilter<ImageAdaptorType, ImageType>;

  auto rescaler = RescalerType::New();
  using WriterType = itk::ImageFileWriter<ImageType>;
  auto writer = WriterType::New();


  writer->SetFileName(argv[2]);

  rescaler->SetOutputMinimum(0);
  rescaler->SetOutputMaximum(255);

  rescaler->SetInput(adaptor);
  writer->SetInput(rescaler->GetOutput());
  writer->Update();


  //  Software Guide : BeginLatex
  //
  // \begin{figure} \center
  // \includegraphics[width=0.32\textwidth]{BrainProtonDensitySlice}
  // \includegraphics[width=0.32\textwidth]{ImageAdaptorThresholdingA}
  // \includegraphics[width=0.32\textwidth]{ImageAdaptorThresholdingB}
  // \itkcaption[Image Adaptor for performing computations]{Using
  // ImageAdaptor to perform a simple image computation. An
  // ImageAdaptor is used to perform binary thresholding on
  // the input image on the  left. The center image was created using a
  // threshold of 180, while the
  // image on the right corresponds to a  threshold of 220.}
  // \label{fig:ImageAdaptorThresholding}
  // \end{figure}
  //
  //  As before, we rescale the emulated scalar image before writing it
  //  out to file.
  //  Figure~\ref{fig:ImageAdaptorThresholding} illustrates the result of
  //  applying the thresholding adaptor to a typical gray scale image using
  //  two different threshold values. Note that the same effect could have
  //  been achieved by using the \doxygen{BinaryThresholdImageFilter} but at
  //  the price of holding an extra copy of the image in memory.
  //
  // Software Guide : EndLatex


  return EXIT_SUCCESS;
}
