189 lines
5.0 KiB
C++
189 lines
5.0 KiB
C++
/*=========================================================================
|
|
|
|
Program: Visualization Toolkit
|
|
Module: vtkLabelMapLookup.h
|
|
|
|
Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
|
|
All rights reserved.
|
|
See Copyright.txt or http://www.kitware.com/Copyright.htm for details.
|
|
|
|
This software is distributed WITHOUT ANY WARRANTY; without even
|
|
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
PURPOSE. See the above copyright notice for more information.
|
|
|
|
=========================================================================*/
|
|
/**
|
|
* @class vtkLabelMapLookup
|
|
* @brief provide an efficient numeric label lookup
|
|
*
|
|
*
|
|
* vtkLabelMapLookup is a helper object that enables faster lookup of
|
|
* a segmentation label from a set of labels. It uses caching, and
|
|
* different strategies depending on the size of the set of labels.
|
|
*
|
|
* @sa
|
|
* vtkSurfaceNets2D vtkSurfaceNets3D vtkDiscreteFlyingEdgesClipper2D
|
|
*/
|
|
|
|
#ifndef vtkLabelMapLookup_h
|
|
#define vtkLabelMapLookup_h
|
|
|
|
#include <unordered_set>
|
|
#include <vector>
|
|
|
|
// Determine whether an image label/object has been specified for output.
|
|
// This requires looking up an image pixel/scalar value and determining
|
|
// whether it's part of a segmented object. Since this can be relatively
|
|
// expensive when performed many times, different lookup classes are used
|
|
// depending on the number of labels specified. A cache is used for the
|
|
// common case of repeated queries for the same label value.
|
|
template <typename T>
|
|
struct vtkLabelMapLookup
|
|
{
|
|
T CachedValue;
|
|
T CachedOutValue;
|
|
bool CachedOutValueInitialized;
|
|
|
|
vtkLabelMapLookup(const double* values, int vtkNotUsed(numValues))
|
|
{
|
|
this->CachedValue = static_cast<T>(values[0]);
|
|
this->CachedOutValue = static_cast<T>(values[0]);
|
|
this->CachedOutValueInitialized = false;
|
|
}
|
|
virtual ~vtkLabelMapLookup() = default;
|
|
virtual bool IsLabelValue(T label) = 0;
|
|
bool IsLabelValueInCache(T label, bool& inLabelSet)
|
|
{
|
|
if (label == this->CachedValue)
|
|
{
|
|
inLabelSet = true;
|
|
return true;
|
|
}
|
|
else if (this->CachedOutValueInitialized && label == this->CachedOutValue)
|
|
{
|
|
inLabelSet = false;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
// A little factor for creating the right type of label map based on the
|
|
// number of labels in the set.
|
|
static vtkLabelMapLookup<T>* CreateLabelLookup(const double* values, vtkIdType numLabels);
|
|
}; // vtkLabelMapLookup
|
|
|
|
// Cache a single contour value
|
|
template <typename T>
|
|
struct SingleLabelValue : public vtkLabelMapLookup<T>
|
|
{
|
|
SingleLabelValue(const double* values)
|
|
: vtkLabelMapLookup<T>(values, 1)
|
|
{
|
|
}
|
|
bool IsLabelValue(T label) override { return label == this->CachedValue; }
|
|
}; // SingleLabelValue
|
|
|
|
// Represent a few contour values with a std::vector<>
|
|
template <typename T>
|
|
struct LabelVector : public vtkLabelMapLookup<T>
|
|
{
|
|
std::vector<T> Map;
|
|
|
|
LabelVector(const double* values, int numValues)
|
|
: vtkLabelMapLookup<T>(values, numValues)
|
|
{
|
|
for (int vidx = 0; vidx < numValues; vidx++)
|
|
{
|
|
Map.push_back(static_cast<T>(values[vidx]));
|
|
}
|
|
}
|
|
bool IsLabelValue(T label) override
|
|
{
|
|
bool inLabelSet;
|
|
// Check the cache
|
|
if (this->IsLabelValueInCache(label, inLabelSet))
|
|
{
|
|
return inLabelSet;
|
|
}
|
|
|
|
// Not in the cache, check the vector
|
|
if (std::find(this->Map.begin(), this->Map.end(), label) != this->Map.end())
|
|
{
|
|
this->CachedValue = label;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
this->CachedOutValue = label;
|
|
this->CachedOutValueInitialized = true;
|
|
return false;
|
|
}
|
|
}
|
|
}; // LabelVector
|
|
|
|
// Represent many contour values with a std::set<>
|
|
template <typename T>
|
|
struct LabelSet : public vtkLabelMapLookup<T>
|
|
{
|
|
std::unordered_set<T> Map;
|
|
|
|
LabelSet(const double* values, int numValues)
|
|
: vtkLabelMapLookup<T>(values, numValues)
|
|
{
|
|
for (int vidx = 0; vidx < numValues; vidx++)
|
|
{
|
|
Map.insert(static_cast<T>(values[vidx]));
|
|
}
|
|
}
|
|
bool IsLabelValue(T label) override
|
|
{
|
|
bool inLabelSet;
|
|
// Check the cache
|
|
if (this->IsLabelValueInCache(label, inLabelSet))
|
|
{
|
|
return inLabelSet;
|
|
}
|
|
|
|
// Not in cache, check the map
|
|
if (this->Map.find(label) != this->Map.end())
|
|
{
|
|
this->CachedValue = label;
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
this->CachedOutValue = label;
|
|
this->CachedOutValueInitialized = true;
|
|
return false;
|
|
}
|
|
}
|
|
}; // LabelSet
|
|
|
|
// Given a list of label values (represented generically as doubles),
|
|
// create the appropriate lookup class and add the label values to
|
|
// the collection of labels.
|
|
template <typename T>
|
|
vtkLabelMapLookup<T>* vtkLabelMapLookup<T>::CreateLabelLookup(
|
|
const double* values, vtkIdType numLabels)
|
|
{
|
|
// These cutoffs are empirical and can be changed.
|
|
if (numLabels == 1)
|
|
{
|
|
return new SingleLabelValue<T>(values);
|
|
}
|
|
else if (numLabels < 20)
|
|
{
|
|
return new LabelVector<T>(values, numLabels);
|
|
}
|
|
else
|
|
{
|
|
return new LabelSet<T>(values, numLabels);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
// VTK-HeaderTest-Exclude: vtkLabelMapLookup.h
|