Detect Edges With Canny Edge Detection Filter

Synopsis

Apply CannyEdgeDetectionImageFilter to an image

Results

Input image

Input image

Rescaled Output image

Rescaled Output image (values are in [0, 255])

Code

C++

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

int
main(int argc, char * argv[])
{
  if (argc != 6)
  {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0];
    std::cerr << "<InputImage> <OutputImage> ";
    std::cerr << "<Variance> <LowerThreshold> <UpperThreshold>";
    std::cerr << std::endl;
    return EXIT_FAILURE;
  }

  constexpr unsigned int Dimension = 2;
  using InputPixelType = float;
  using OutputPixelType = unsigned char;

  const char *         inputImage = argv[1];
  const char *         outputImage = argv[2];
  const InputPixelType variance = std::stod(argv[3]);
  const InputPixelType lowerThreshold = std::stod(argv[4]);
  const InputPixelType upperThreshold = std::stod(argv[5]);

  using InputImageType = itk::Image<InputPixelType, Dimension>;
  using OutputImageType = itk::Image<OutputPixelType, Dimension>;

  using ReaderType = itk::ImageFileReader<InputImageType>;
  ReaderType::Pointer reader = ReaderType::New();
  reader->SetFileName(inputImage);

  using FilterType = itk::CannyEdgeDetectionImageFilter<InputImageType, InputImageType>;
  FilterType::Pointer filter = FilterType::New();
  filter->SetInput(reader->GetOutput());
  filter->SetVariance(variance);
  filter->SetLowerThreshold(lowerThreshold);
  filter->SetUpperThreshold(upperThreshold);

  using RescaleType = itk::RescaleIntensityImageFilter<InputImageType, OutputImageType>;
  RescaleType::Pointer rescaler = RescaleType::New();
  rescaler->SetInput(filter->GetOutput());
  rescaler->SetOutputMinimum(0);
  rescaler->SetOutputMaximum(255);

  using WriterType = itk::ImageFileWriter<OutputImageType>;
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName(outputImage);
  writer->SetInput(rescaler->GetOutput());

  try
  {
    writer->Update();
  }
  catch (itk::ExceptionObject & e)
  {
    std::cerr << "Error: " << e << std::endl;
    return EXIT_FAILURE;
  }

  return EXIT_SUCCESS;
}

Python

#!/usr/bin/env python

import sys
import itk

if len(sys.argv) != 6:
    print("Usage: " + sys.argv[0] + " <InputImage> <OutputImage> "
          "<Variance> <LowerThreshold> <UpperThreshold>")
    sys.exit(1)

inputImage = sys.argv[1]
outputImage = sys.argv[2]
variance = float(sys.argv[3])
lowerThreshold = float(sys.argv[4])
upperThreshold = float(sys.argv[5])

InputPixelType = itk.F
OutputPixelType = itk.UC
Dimension = 2

InputImageType = itk.Image[InputPixelType, Dimension]
OutputImageType = itk.Image[OutputPixelType, Dimension]

reader = itk.ImageFileReader[InputImageType].New()
reader.SetFileName(inputImage)

cannyFilter = itk.CannyEdgeDetectionImageFilter[
    InputImageType,
    InputImageType].New()
cannyFilter.SetInput(reader.GetOutput())
cannyFilter.SetVariance(variance)
cannyFilter.SetLowerThreshold(lowerThreshold)
cannyFilter.SetUpperThreshold(upperThreshold)

rescaler = itk.RescaleIntensityImageFilter[
    InputImageType,
    OutputImageType].New()
rescaler.SetInput(cannyFilter.GetOutput())
rescaler.SetOutputMinimum(0)
rescaler.SetOutputMaximum(255)

writer = itk.ImageFileWriter[OutputImageType].New()
writer.SetFileName(outputImage)
writer.SetInput(rescaler.GetOutput())

writer.Update()

Classes demonstrated

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

This filter is an implementation of a Canny edge detector for scalar-valued images.

Based on John Canny’s paper “A Computational Approach

to Edge Detection”(IEEE Transactions on Pattern Analysis and Machine Intelligence, Vol. PAMI-8, No.6, November 1986), there are four major steps used in the edge-detection scheme: (1) Smooth the input image with Gaussian filter. (2) Calculate the second directional derivatives of the smoothed image. (3) Non-Maximum Suppression: the zero-crossings of 2nd derivative are found, and the sign of third derivative is used to find the correct extrema. (4) The hysteresis thresholding is applied to the gradient magnitude (multiplied with zero-crossings) of the smoothed image to find and link edges.

Inputs and Outputs

The input to this filter should be a scalar, real-valued Itk image of arbitrary dimension. The output should also be a scalar, real-value Itk image of the same dimensionality.

Parameters

There are four parameters for this filter that control the sub-filters used by the algorithm.

Variance and Maximum error are used in the Gaussian smoothing of the input image. See itkDiscreteGaussianImageFilter for information on these parameters.

Threshold is the lowest allowed value in the output image. Its data type is the same as the data type of the output image. Any values below the Threshold level will be replaced with the OutsideValue parameter value, whose default is zero.

See

DiscreteGaussianImageFilter

See

ZeroCrossingImageFilter

See

ThresholdImageFilter

See itk::CannyEdgeDetectionImageFilter for additional documentation.