Histogram Creation And Bin Access

Synopsis

This example shows how to create a Histogram object and use it.

We call an instance in a Histogram object a bin. The Histogram differs from the itk::Statistics::ListSample, itk::Statistics::ImageToListSampleAdaptor, or itk::Statistics::PointSetToListSampleAdaptor in significant ways. Histograms can have a variable number of values (unsigned long type) for each measurement vector, while the three other classes have a fixed value (one) for all measurement vectors. Also those array-type containers can have multiple instances (data elements) with identical measurement vector values. However, in a Histogram object, there is one unique instance for any given measurement vector.

Here we create a histogram with dense frequency containers. In this example we will not have any zero-frequency measurements, so the dense frequency container is the appropriate choice. If the histogram is expected to have many empty (zero) bins, a sparse frequency container would be the better option. Note that this is not configurable in Python. Here we also set the size of the measurement vectors to be 2 components.

Output from the code below:

Frequency of the bin at index [0, 2] is 5 and the bin's instance identifier is 6

Code

C++

#include "itkHistogram.h"
#include "itkDenseFrequencyContainer2.h"

int
main()
{
  using MeasurementType = float;
  using FrequencyContainerType = itk::Statistics::DenseFrequencyContainer2;

  constexpr unsigned int numberOfComponents = 2;
  using HistogramType = itk::Statistics::Histogram<MeasurementType, FrequencyContainerType>;

  HistogramType::Pointer histogram = HistogramType::New();
  histogram->SetMeasurementVectorSize(numberOfComponents);

  // We initialize it as a 3x3 histogram with equal size intervals.

  HistogramType::SizeType size(numberOfComponents);
  size.Fill(3);
  HistogramType::MeasurementVectorType lowerBound(numberOfComponents);
  HistogramType::MeasurementVectorType upperBound(numberOfComponents);
  lowerBound[0] = 1.1;
  lowerBound[1] = 2.6;
  upperBound[0] = 7.1;
  upperBound[1] = 8.6;

  histogram->Initialize(size, lowerBound, upperBound);

  // Now the histogram is ready for storing frequency values. There
  // are three ways of accessing data elements in the histogram:
  // - using instance identifiers---just like any other Sample object;
  // - using n-dimensional indices---just like an Image object;
  // - using an iterator---just like any other Sample object.
  //
  // In this example, the index (0, 0) refers the same bin as the instance
  // identifier (0) refers to. The instance identifier of the index (0,
  // 1) is (3), (0, 2) is (6), (2, 2) is (8), and so on.

  histogram->SetFrequency(0, 0);
  histogram->SetFrequency(1, 2);
  histogram->SetFrequency(2, 3);
  histogram->SetFrequency(3, 2);
  histogram->SetFrequency(4, 1);
  histogram->SetFrequency(5, 1);
  histogram->SetFrequency(6, 5);
  histogram->SetFrequency(7, 4);
  histogram->SetFrequency(8, 0);

  // Let us examine if the frequency is set correctly by calling the
  // GetFrequency(index) method. We can use the
  // GetFrequency(instance identifier) method for the same purpose.

  HistogramType::IndexType index(numberOfComponents);
  index[0] = 0;
  index[1] = 2;
  std::cout << "Frequency of the bin at index " << index << " is " << histogram->GetFrequency(index)
            << " and the bin's instance identifier is " << histogram->GetInstanceIdentifier(index) << std::endl;

  return EXIT_SUCCESS;
}

Python

#!/usr/bin/env python

import itk

numberOfComponents = 2

histogram = itk.Histogram.New(MeasurementVectorSize=numberOfComponents)

# We initialize it as a 3x3 histogram with equal size intervals.
size = itk.Array.UL(numberOfComponents)
size.Fill(3)

lowerBound = 1.1, 2.6
upperBound = 7.1, 8.6
histogram.Initialize(size, lowerBound, upperBound)

# Now the histogram is ready for storing frequency values. There
# are three ways of accessing data elements in the histogram:
# - using instance identifiers---just like any other Sample object;
# - using n-dimensional indices---just like an Image object;
# - using an iterator---just like any other Sample object.
#
# In this example, the index (0, 0) refers the same bin as the instance
# identifier (0) refers to. The instance identifier of the index (0,
# 1) is (3), (0, 2) is (6), (2, 2) is (8), and so on.

frequencies = [
    (0, 0),
    (1, 2),
    (2, 3),
    (3, 2),
    (4, 1),
    (5, 1),
    (6, 5),
    (7, 4),
    (8, 0)
]

for instance_identifier, frequency in frequencies:
    histogram.SetFrequency(instance_identifier, frequency)

# Let us examine if the frequency is set correctly by calling the
# GetFrequency(index) method. We can use the
# GetFrequency(instance identifier) method for the same purpose.

index = [0, 2]
print("Frequency of the bin at index", index,
      "is", histogram.GetFrequency(index),
      "and the bin's instance identifier is",
      histogram.GetInstanceIdentifier(index))

Classes demonstrated

template<typename TMeasurement = float, typename TFrequencyContainer = DenseFrequencyContainer2>
class Histogram : public itk::Statistics::Sample<Array<TMeasurement>>

This class stores measurement vectors in the context of n-dimensional histogram.

Histogram represents an ND histogram. Histogram bins can be regularly or irregularly spaced. The storage for the histogram is managed via the FrequencyContainer specified by the template argument. The default frequency container is a DenseFrequencyContainer. A SparseFrequencyContainer can be used as an alternative.

Frequencies of a bin (SetFrequency(), IncreaseFrequency()) can be specified by measurement, index, or instance identifier.

Measurements can be queried by bin index or instance identifier. In this case, the measurement returned is the centroid of the histogram bin.

The Initialize() method is used to specify the number of bins for each dimension of the histogram. An overloaded version also allows for regularly spaced bins to defined. To define irregularly sized bins, use the SetBinMin()/SetBinMax() methods.

If you do not know the length of the measurement vector at compile time, you should use the VariableDimensionHistogram class, instead of the Histogram class.

If you know the length of the measurement vector at compile time, it can conveniently be obtained from MeasurementVectorTraits. For instance, instantiate a histogram as below:

using HistogramType = Histogram< THistogramMeasurement, typename TFrequencyContainer >;

See

Sample, DenseFrequencyContainer, SparseFrequencyContainer, VariableDimensionHistogram

ITK Sphinx Examples:

See itk::Statistics::Histogram for additional documentation.