Statistical Properties of Labeled Regions

Synopsis

Get statistical properties of labeled regions in an image.

Results

image.png

image.png

Output:

Number of labels: 2

min: 255
max: 255
median: 0
mean: 255
sigma: 0
variance: 0
sum: 4080
count: 16
region: ImageRegion (0x7ffedfd04a28)
Dimension: 2
Index: [6, 6]
Size: [4, 4]

min: 0
max: 0
median: 0
mean: 0
sigma: 0
variance: 0
sum: 0
count: 384
region: ImageRegion (0x7ffedfd04a28)
Dimension: 2
Index: [0, 0]
Size: [20, 20]

Code

C++

#include "itkImage.h"
#include "itkImageFileWriter.h"
#include "itkImageRegionIterator.h"
#include "itkBinaryImageToLabelMapFilter.h"
#include "itkLabelMapToLabelImageFilter.h"
#include "itkLabelStatisticsImageFilter.h"

using ImageType = itk::Image<unsigned char, 2>;
static void
CreateImage(ImageType::Pointer image);

int
main(int, char *[])
{
  ImageType::Pointer image = ImageType::New();
  CreateImage(image);

  using BinaryImageToLabelMapFilterType = itk::BinaryImageToLabelMapFilter<ImageType>;
  BinaryImageToLabelMapFilterType::Pointer binaryImageToLabelMapFilter = BinaryImageToLabelMapFilterType::New();
  binaryImageToLabelMapFilter->SetInput(image);
  binaryImageToLabelMapFilter->Update();

  using LabelMapToLabelImageFilterType =
    itk::LabelMapToLabelImageFilter<BinaryImageToLabelMapFilterType::OutputImageType, ImageType>;
  LabelMapToLabelImageFilterType::Pointer labelMapToLabelImageFilter = LabelMapToLabelImageFilterType::New();
  labelMapToLabelImageFilter->SetInput(binaryImageToLabelMapFilter->GetOutput());
  labelMapToLabelImageFilter->Update();

  using LabelStatisticsImageFilterType = itk::LabelStatisticsImageFilter<ImageType, ImageType>;
  LabelStatisticsImageFilterType::Pointer labelStatisticsImageFilter = LabelStatisticsImageFilterType::New();
  labelStatisticsImageFilter->SetLabelInput(labelMapToLabelImageFilter->GetOutput());
  labelStatisticsImageFilter->SetInput(image);
  labelStatisticsImageFilter->Update();

  std::cout << "Number of labels: " << labelStatisticsImageFilter->GetNumberOfLabels() << std::endl;
  std::cout << std::endl;

  using LabelPixelType = LabelStatisticsImageFilterType::LabelPixelType;

  for (auto vIt = labelStatisticsImageFilter->GetValidLabelValues().begin();
       vIt != labelStatisticsImageFilter->GetValidLabelValues().end();
       ++vIt)
  {
    if (labelStatisticsImageFilter->HasLabel(*vIt))
    {
      LabelPixelType labelValue = *vIt;
      std::cout << "min: " << labelStatisticsImageFilter->GetMinimum(labelValue) << std::endl;
      std::cout << "max: " << labelStatisticsImageFilter->GetMaximum(labelValue) << std::endl;
      std::cout << "median: " << labelStatisticsImageFilter->GetMedian(labelValue) << std::endl;
      std::cout << "mean: " << labelStatisticsImageFilter->GetMean(labelValue) << std::endl;
      std::cout << "sigma: " << labelStatisticsImageFilter->GetSigma(labelValue) << std::endl;
      std::cout << "variance: " << labelStatisticsImageFilter->GetVariance(labelValue) << std::endl;
      std::cout << "sum: " << labelStatisticsImageFilter->GetSum(labelValue) << std::endl;
      std::cout << "count: " << labelStatisticsImageFilter->GetCount(labelValue) << std::endl;
      // std::cout << "box: " << labelStatisticsImageFilter->GetBoundingBox( labelValue ) << std::endl; // can't output
      // a box
      std::cout << "region: " << labelStatisticsImageFilter->GetRegion(labelValue) << std::endl;
      std::cout << std::endl << std::endl;
    }
  }

  return EXIT_SUCCESS;
}

void
CreateImage(ImageType::Pointer image)
{
  // Create a black image with a white square
  ImageType::IndexType start;
  start.Fill(0);

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

  ImageType::RegionType region;
  region.SetSize(size);
  region.SetIndex(start);
  image->SetRegions(region);
  image->Allocate();

  itk::ImageRegionIterator<ImageType> imageIterator(image, image->GetLargestPossibleRegion());

  // Make a square
  while (!imageIterator.IsAtEnd())
  {
    if ((imageIterator.GetIndex()[0] > 5 && imageIterator.GetIndex()[0] < 10) &&
        (imageIterator.GetIndex()[1] > 5 && imageIterator.GetIndex()[1] < 10))
    {
      imageIterator.Set(255);
    }
    else
    {
      imageIterator.Set(0);
    }

    ++imageIterator;
  }

  using WriterType = itk::ImageFileWriter<ImageType>;
  WriterType::Pointer writer = WriterType::New();
  writer->SetFileName("image.png");
  writer->SetInput(image);
  writer->Update();
}

Classes demonstrated

template<typename TInputImage, typename TLabelImage>
class LabelStatisticsImageFilter : public itk::ImageSink<TInputImage>

Given an intensity image and a label map, compute min, max, variance and mean of the pixels associated with each label or segment.

LabelStatisticsImageFilter computes the minimum, maximum, sum, mean, median, variance and sigma of regions of an intensity image, where the regions are defined via a label map (a second input). The label image should be integral type. The filter needs all of its input image. It behaves as a filter with an input and output. Thus it can be inserted in a pipeline with other filters and the statistics will only be recomputed if a downstream filter changes.

Optionally, the filter also computes intensity histograms on each object. If histograms are enabled, a median intensity value can also be computed, although its accuracy is limited to the bin width of the histogram. If histograms are not enabled, the median returns zero.

This filter is automatically multi-threaded and can stream its input when NumberOfStreamDivisions is set to more than

  1. Statistics are independently computed for each streamed and threaded region then merged.

ITK Sphinx Examples:

See itk::LabelStatisticsImageFilter for additional documentation.