1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
|
#ifndef RLEImage_h
#define RLEImage_h
#include <utility> //std::pair
#include <vector>
#include <itkImageBase.h>
#include <itkImage.h>
/** Run-Length Encoded image.
* It saves memory for label images at the expense of processing times.
* Unsuitable for ordinary images (in which case it is counterproductive).
*
* BufferedRegion must include complete run-length lines (along X index axis).
* BufferedRegion can be smaller than LargestPossibleRegion along other axes.
*
* It is best if pixel type and counter type have the same byte size
* (for memory alignment purposes).
*
* Copied and adapted from itk::Image.
*/
template< typename TPixel, unsigned int VImageDimension = 3, typename CounterType = unsigned short >
class RLEImage : public itk::ImageBase < VImageDimension >
{
public:
/** Standard class typedefs */
typedef RLEImage Self;
typedef itk::ImageBase < VImageDimension > Superclass;
typedef itk::SmartPointer< Self > Pointer;
typedef itk::SmartPointer< const Self > ConstPointer;
typedef itk::WeakPointer< const Self > ConstWeakPointer;
/** Method for creation through the object factory. */
itkNewMacro(Self);
/** Run-time type information (and related methods). */
itkTypeMacro(RLEImage, ImageBase);
/** Pixel typedef support. Used to declare pixel type in filters
* or other operations. */
typedef TPixel PixelType;
/** Typedef alias for PixelType */
typedef TPixel ValueType;
/** First element is count of repetitions,
* second element is the pixel value. */
typedef std::pair<CounterType, PixelType> RLSegment;
/** A Run-Length encoded line of pixels. */
typedef std::vector<RLSegment> RLLine;
/** Internal Pixel representation. Used to maintain a uniform API
* with Image Adaptors and allow to keep a particular internal
* representation of data while showing a different external
* representation. */
typedef RLLine InternalPixelType;
//typedef PixelType IOPixelType;
/** Dimension of the image. This constant is used by functions that are
* templated over image type (as opposed to being templated over pixel type
* and dimension) when they need compile time access to the dimension of
* the image. */
itkStaticConstMacro(ImageDimension, unsigned int, VImageDimension);
/** Index typedef support. An index is used to access pixel values. */
typedef typename Superclass::IndexType IndexType;
typedef typename Superclass::IndexValueType IndexValueType;
/** Offset typedef support. An offset is used to access pixel values. */
typedef typename Superclass::OffsetType OffsetType;
/** Size typedef support. A size is used to define region bounds. */
typedef typename Superclass::SizeType SizeType;
typedef typename Superclass::SizeValueType SizeValueType;
/** Direction typedef support. A matrix of direction cosines. */
typedef typename Superclass::DirectionType DirectionType;
/** Region typedef support. A region is used to specify a subset of an image.
*/
typedef typename Superclass::RegionType RegionType;
/** Spacing typedef support. Spacing holds the size of a pixel. The
* spacing is the geometric distance between image samples. */
typedef typename Superclass::SpacingType SpacingType;
typedef typename Superclass::SpacingValueType SpacingValueType;
/** Origin typedef support. The origin is the geometric coordinates
* of the index (0,0). */
typedef typename Superclass::PointType PointType;
/** Offset typedef (relative position between indices) */
typedef typename Superclass::OffsetValueType OffsetValueType;
/** Allocate the image memory. The size of the image must
* already be set, e.g. by calling SetRegions().
* Pixel values are initialized using default constructor. */
virtual void Allocate(bool initialize = false);
/** Restore the data object to its initial state. This means releasing
* memory. */
virtual void Initialize()
{
// Call the superclass which should initialize the BufferedRegion ivar.
Superclass::Initialize();
m_OnTheFlyCleanup = true;
myBuffer = BufferType::New();
}
/** Fill the image buffer with a value. Be sure to call Allocate()
* first. */
void FillBuffer(const TPixel & value);
virtual void SetLargestPossibleRegion(const RegionType & region)
{
Superclass::SetLargestPossibleRegion(region);
myBuffer->SetLargestPossibleRegion(truncateRegion(region));
}
virtual void SetBufferedRegion(const RegionType & region)
{
Superclass::SetBufferedRegion(region);
myBuffer->SetBufferedRegion(truncateRegion(region));
}
virtual void SetRequestedRegion(const RegionType & region)
{
Superclass::SetRequestedRegion(region);
myBuffer->SetRequestedRegion(truncateRegion(region));
}
/** \brief Set a pixel value.
*
* Allocate() needs to have been called first -- for efficiency,
* this function does not check that the image has actually been
* allocated yet. SLOW -> Use iterators instead. */
void SetPixel(const IndexType & index, const TPixel & value);
/** Set a pixel value in the given line and updates segmentRemainder
* and realIndex to refer to the same pixel.
* Returns difference in line length which happens due to merging or splitting segments.
* This method is used by iterators directly. */
int SetPixel(RLLine & line, IndexValueType & segmentRemainder, IndexValueType & realIndex, const TPixel & value);
/** \brief Get a pixel. SLOW! Better use iterators for pixel access. */
const TPixel & GetPixel(const IndexType & index) const;
///** Get a reference to a pixel. Chaning it changes the whole RLE segment! */
//TPixel & GetPixel(const IndexType & index);
///** \brief Access a pixel. Chaning it changes the whole RLE segment! */
//TPixel & operator[](const IndexType & index)
//{
// return this->GetPixel(index);
//}
/** \brief Access a pixel. This version can only be an rvalue.
* SLOW -> Use iterators instead. */
const TPixel & operator[](const IndexType & index) const
{
return this->GetPixel(index);
}
virtual unsigned int GetNumberOfComponentsPerPixel() const
{
// use the GetLength() method which works with variable length arrays,
// to make it work with as much pixel types as possible
PixelType p;
return itk::NumericTraits< PixelType >::GetLength(p);
}
/** Typedef for the internally used buffer. */
typedef typename itk::Image<RLLine, VImageDimension - 1> BufferType;
/** We need to allow itk-style iterators to be constructed. */
typename BufferType::Pointer GetBuffer() { return myBuffer; }
/** We need to allow itk-style const iterators to be constructed. */
typename BufferType::Pointer GetBuffer() const { return myBuffer; }
/** Returns N-1-dimensional index, the remainder after 0-index is removed. */
static inline typename BufferType::IndexType
truncateIndex(const IndexType & index);
/** Returns N-1-dimensional size, the remainder after 0-size is removed. */
static inline typename BufferType::SizeType
truncateSize(const SizeType & size);
/** Returns N-1-dimensional region, the remainder after 0-index and size are removed. */
static typename BufferType::RegionType
truncateRegion(const RegionType & region);
/** Merges adjacent segments with duplicate values.
* Automatically called when turning on OnTheFlyCleanup. */
void CleanUp() const;
/** Should same-valued segments be merged on the fly?
* On the fly merging usually provides better performance. */
bool GetOnTheFlyCleanup() const { return m_OnTheFlyCleanup; }
/** Should same-valued segments be merged on the fly?
* On the fly merging usually provides better performance. */
void SetOnTheFlyCleanup(bool value)
{
if (value == m_OnTheFlyCleanup)
return;
m_OnTheFlyCleanup = value;
if (m_OnTheFlyCleanup)
CleanUp(); //put the image into a clean state
}
protected:
RLEImage() : itk::ImageBase < VImageDimension >()
{
m_OnTheFlyCleanup = true;
myBuffer = BufferType::New();
}
void PrintSelf(std::ostream & os, itk::Indent indent) const;
virtual ~RLEImage() {}
/** Compute helper matrices used to transform Index coordinates to
* PhysicalPoint coordinates and back. This method is virtual and will be
* overloaded in derived classes in order to provide backward compatibility
* behavior in classes that did not used to take image orientation into
* account. */
virtual void ComputeIndexToPhysicalPointMatrices()
{
this->Superclass::ComputeIndexToPhysicalPointMatrices();
}
/** Merges adjacent segments with duplicate values in a single line. */
void CleanUpLine(RLLine & line) const;
private:
bool m_OnTheFlyCleanup; //should same-valued segments be merged on the fly
RLEImage(const Self &); //purposely not implemented
void operator=(const Self &); //purposely not implemented
/** Memory for the current buffer. */
mutable typename BufferType::Pointer myBuffer;
};
#ifndef ITK_MANUAL_INSTANTIATION
#include "RLEImage.txx"
#endif
#endif //RLEImage_h
|