Thin Image#

Synopsis#

Skeletonix/thin an image.

Results#

Input.png

input.png#

OutputBaseline.png

OutputBaseline.png#

Code#

Python#

#!/usr/bin/env python

import itk
import argparse

parser = argparse.ArgumentParser(description="Thin Image.")
parser.add_argument("input_image", nargs="?")
args = parser.parse_args()

PixelType = itk.UC
Dimension = 2
ImageType = itk.Image[PixelType, Dimension]

if args.input_image:
    image = itk.imread(args.input_image)

else:
    # Create an image
    start = itk.Index[Dimension]()
    start.Fill(0)

    size = itk.Size[Dimension]()
    size.Fill(100)

    region = itk.ImageRegion[Dimension]()
    region.SetIndex(start)
    region.SetSize(size)

    image = ImageType.New(Regions=region)
    image.Allocate()
    image.FillBuffer(0)

    # Draw a 5 pixel wide line
    image[50:55, 20:80] = 255

    # Write Image
    itk.imwrite(image, "Input.png")

image = itk.binary_thinning_image_filter(image)

# Rescale the image so that it can be seen (the output is 0 and 1, we want 0 and 255)
image = itk.rescale_intensity_image_filter(image, output_minimum=0, output_maximum=255)

# Write Image
itk.imwrite(image, "OutputPython.png")

C++#

#include "itkBinaryThinningImageFilter.h"
#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkRescaleIntensityImageFilter.h"

using ImageType = itk::Image<unsigned char, 2>;

static void
CreateImage(ImageType::Pointer image);

int
main(int argc, char * argv[])
{
  auto image = ImageType::New();
  if (argc == 2)
  {
    image = itk::ReadImage<ImageType>(argv[1]);
  }
  else
  {
    CreateImage(image);
    itk::WriteImage(image, "Input.png");
  }

  using BinaryThinningImageFilterType = itk::BinaryThinningImageFilter<ImageType, ImageType>;
  auto binaryThinningImageFilter = BinaryThinningImageFilterType::New();
  binaryThinningImageFilter->SetInput(image);
  binaryThinningImageFilter->Update();

  // Rescale the image so that it can be seen (the output is 0 and 1, we want 0 and 255)
  using RescaleType = itk::RescaleIntensityImageFilter<ImageType, ImageType>;
  auto rescaler = RescaleType::New();
  rescaler->SetInput(binaryThinningImageFilter->GetOutput());
  rescaler->SetOutputMinimum(0);
  rescaler->SetOutputMaximum(255);
  rescaler->Update();

  itk::WriteImage(rescaler->GetOutput(), "Output.png");

  return EXIT_SUCCESS;
}

void
CreateImage(ImageType::Pointer image)
{
  // Create an image
  ImageType::IndexType start;
  start.Fill(0);

  ImageType::SizeType size;
  size.Fill(100);

  ImageType::RegionType region(start, size);

  image->SetRegions(region);
  image->Allocate();
  image->FillBuffer(0);

  // Draw a 5 pixel wide line
  for (unsigned int i = 20; i < 80; ++i)
  {
    for (unsigned int j = 50; j < 55; ++j)
    {
      itk::Index<2> index;
      index[0] = i;
      index[1] = j;
      image->SetPixel(index, 255);
    }
  }
}

Classes demonstrated#

template<typename TInputImage, typename TOutputImage>
class BinaryThinningImageFilter : public itk::ImageToImageFilter<TInputImage, TOutputImage>

This filter computes one-pixel-wide edges of the input image.

This class is parameterized over the type of the input image and the type of the output image.

The input is assumed to be a binary image. If the foreground pixels of the input image do not have a value of 1, they are rescaled to 1 internally to simplify the computation.

The filter will produce a skeleton of the object. The output background values are 0, and the foreground values are 1.

This filter is a sequential thinning algorithm and known to be computational time dependable on the image size. The algorithm corresponds with the 2D implementation described in:

Rafael C. Gonzales and Richard E. Woods. Digital Image Processing. Addison Wesley, 491-494, (1993).

To do: Make this filter ND.

See

MorphologyImageFilter

ITK Sphinx Examples:

See itk::BinaryThinningImageFilter for additional documentation.