Skip to content

Commit 4c47e7d

Browse files
committed
ENH: Creating templateless region splitter classes
The end goal of this topic is to consolidate code, enabling re-use, and modularization to facilitate customization and experimentation with different splitting algorithms for multi-threading, streaming and IO. Creating a new virtual ImageRegionSplitterBase class which does not have a class template. This enables the same splitter to be used for the multi-threading, the streaming image filter, and the IO classes. Additionally, it allows for a global default splitter to use used and shared. The current default algorithm of splitting along the slowest dimension is not implemented in the ImageRegionSplittingSlowDimension class. There are some novel to ITK design patterns used here which should be considered. 1) Using a templatedless class with templated function which dispatches to a function which takes the dimension and arrays. This allow for compiled functions to be reused. 2) Multiple inheritance is used, to add common static members which access common data between all implemented instances of the class. That is it can provide common data and methods for all instantiations across template instantiations. Add GetModified IVAR accessors to ImageRegion class. Change-Id: Ia73a69a32cf5f543540809a466223f9456a9af06
1 parent dbacdbc commit 4c47e7d

12 files changed

+543
-58
lines changed

Modules/Core/Common/include/itkImageRegion.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -140,17 +140,17 @@ class ITK_EXPORT ImageRegion:public Region
140140
{ m_Index = index; }
141141

142142
/** Get index defining the corner of the region. */
143-
const IndexType & GetIndex() const
144-
{ return m_Index; }
143+
const IndexType & GetIndex() const { return m_Index; }
144+
IndexType & GetModifiableIndex() { return m_Index; }
145145

146146
/** Set the size of the region. This plus the index determines the
147147
* rectangular shape, or extent, of the region. */
148148
void SetSize(const SizeType & size)
149149
{ m_Size = size; }
150150

151151
/** Get the size of the region. */
152-
const SizeType & GetSize() const
153-
{ return m_Size; }
152+
const SizeType & GetSize() const { return m_Size; }
153+
SizeType & GetModifiableSize() { return m_Size; }
154154

155155
/** Convenience methods to get and set the size of the particular dimension i.
156156
*/
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*=========================================================================
2+
*
3+
* Copyright Insight Software Consortium
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0.txt
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*=========================================================================*/
18+
#ifndef __itkImageRegionSplitterBase_h
19+
#define __itkImageRegionSplitterBase_h
20+
21+
#include "itkImageRegion.h"
22+
#include "itkObjectFactory.h"
23+
24+
namespace itk
25+
{
26+
27+
/** \class ImageRegionSplitterBase
28+
* \brief Divide an image region into several pieces.
29+
*
30+
* ImageRegionSplitterBase is an abstract interface to divides an
31+
* ImageRegion into smaller regions. ImageRegionSplitterBase is used
32+
* by the ImageSource, StreamingImageFilter, streaming ImageIO
33+
* classes to divide a region into a series of smaller subregions.
34+
*
35+
* This object has two basic methods: \c GetNumberOfSplits() and
36+
* \c GetSplit().
37+
*
38+
* \c GetNumberOfSplits() is used to determine how may subregions a given
39+
* region can be divided. You call GetNumberOfSplits with an argument
40+
* that is the number of subregions you want. If the image region can
41+
* support that number of subregions, that number is returned.
42+
* Otherwise, the maximum number of splits less then or equal to the
43+
* argumen be returned. For example, if a region splitter class only divides
44+
* a region into horizontal slabs, then the maximum number of splits
45+
* will be the number of rows in the region.
46+
*
47+
* \c GetSplit() returns the ith of N subregions (as an ImageRegion object).
48+
*
49+
* \sa ImageRegionSplitterDirection
50+
* \sa ImageRegionSplitterSlowDimension
51+
*
52+
* \ingroup ITKSystemObjects
53+
* \ingroup DataProcessing
54+
* \ingroup ITKCommon
55+
*/
56+
57+
class ITKCommon_EXPORT ImageRegionSplitterBase
58+
:public Object
59+
{
60+
public:
61+
/** Standard class typedefs. */
62+
typedef ImageRegionSplitterBase Self;
63+
typedef Object Superclass;
64+
typedef SmartPointer< Self > Pointer;
65+
typedef SmartPointer< const Self > ConstPointer;
66+
67+
/** Run-time type information (and related methods). */
68+
itkTypeMacro(ImageRegionSplitterBase, Object);
69+
70+
/** How many pieces can the specified region be split? A given region
71+
* cannot always be divided into the requested number of pieces. For
72+
* instance, if the \c numberOfPieces exceeds the number of pixels along
73+
* a certain dimensions, then some splits will not be possible. This
74+
* method returns a number less than or equal to the requested number
75+
* of pieces. */
76+
template <unsigned int VImageDimension>
77+
unsigned int GetNumberOfSplits(const ImageRegion<VImageDimension> & region,
78+
unsigned int requestedNumber) const
79+
{
80+
return this->GetNumberOfSplitsInternal( VImageDimension,
81+
region.GetIndex().m_Index,
82+
region.GetSize().m_Size,
83+
requestedNumber);
84+
}
85+
86+
87+
/** \brief Get a region definition that represents the ith piece a
88+
* specified region.
89+
*
90+
* The \c numberOfPieces must be equal to what \c GetNumberOfSplits()
91+
* returns. The return value is the maximum number of splits
92+
* available. If \c i is greater than or equal to the return value
93+
* the value of the region is undefined.
94+
*/
95+
template <unsigned int VImageDimension>
96+
unsigned int GetSplit( unsigned int i,
97+
unsigned int numberOfPieces,
98+
ImageRegion<VImageDimension> & region ) const
99+
{
100+
return this->GetSplitInternal( VImageDimension,
101+
i,
102+
numberOfPieces,
103+
region.GetModifiableIndex().m_Index,
104+
region.GetModifiableSize().m_Size );
105+
}
106+
107+
protected:
108+
ImageRegionSplitterBase();
109+
110+
/** Templetless method to compute the number of possible splits for
111+
* any number of dimensions. */
112+
virtual unsigned int GetNumberOfSplitsInternal( unsigned int dim,
113+
const IndexValueType regionIndex[],
114+
const SizeValueType regionSize[],
115+
unsigned int requestedNumber ) const = 0;
116+
117+
/** Templetless method to compute an actual split for any number of
118+
* dimensions. \c dim is the size of the \c regionIndex and \c
119+
* regionSize arrays.
120+
*/
121+
virtual unsigned int GetSplitInternal( unsigned int dim,
122+
unsigned int i,
123+
unsigned int numberOfPieces,
124+
IndexValueType regionIndex[],
125+
SizeValueType regionSize[] ) const = 0;
126+
127+
void PrintSelf(std::ostream & os, Indent indent) const;
128+
129+
private:
130+
ImageRegionSplitterBase(const ImageRegionSplitterBase &); //purposely not implemented
131+
void operator=(const ImageRegionSplitterBase &); //purposely not implemented
132+
};
133+
} // end namespace itk
134+
135+
#endif
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
/*=========================================================================
2+
*
3+
* Copyright Insight Software Consortium
4+
*
5+
* Licensed under the Apache License, Version 2.0 (the "License");
6+
* you may not use this file except in compliance with the License.
7+
* You may obtain a copy of the License at
8+
*
9+
* http://www.apache.org/licenses/LICENSE-2.0.txt
10+
*
11+
* Unless required by applicable law or agreed to in writing, software
12+
* distributed under the License is distributed on an "AS IS" BASIS,
13+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
* See the License for the specific language governing permissions and
15+
* limitations under the License.
16+
*
17+
*=========================================================================*/
18+
#ifndef __itkImageRegionSplitterSlowDimension_h
19+
#define __itkImageRegionSplitterSlowDimension_h
20+
21+
#include "itkImageRegionSplitterBase.h"
22+
23+
namespace itk
24+
{
25+
26+
/** \class ImageRegionSplitterSlowDimension
27+
* \brief Divide an image region along the slowest dimension
28+
*
29+
* ImageRegionSplitterSlowDimension divides an ImageRegion into smaller regions.
30+
* ImageRegionSplitterSlowDimension is the default splitter for many situations.
31+
*
32+
* This ImageRegionSplitterSlowDimension class divides a region along the
33+
* outermost or slowest dimension. If the outermost dimension has size
34+
* 1 (i.e. a volume with a single slice), the ImageRegionSplitter will
35+
* divide the region along the next outermost dimension. If that
36+
* dimension has size 1, the process continues with the next outermost
37+
* dimension.
38+
*
39+
* \sa ImageRegionSplitterDirection
40+
*
41+
* \ingroup ITKSystemObjects
42+
* \ingroup DataProcessing
43+
* \ingroup ITKCommon
44+
*/
45+
46+
class ITKCommon_EXPORT ImageRegionSplitterSlowDimension
47+
:public ImageRegionSplitterBase
48+
{
49+
public:
50+
/** Standard class typedefs. */
51+
typedef ImageRegionSplitterSlowDimension Self;
52+
typedef ImageRegionSplitterBase Superclass;
53+
typedef SmartPointer< Self > Pointer;
54+
typedef SmartPointer< const Self > ConstPointer;
55+
56+
/** Method for creation through the object factory. */
57+
itkNewMacro(Self);
58+
59+
/** Run-time type information (and related methods). */
60+
itkTypeMacro(ImageRegionSplitterSlowDimension, ImageRegionSplitterBase);
61+
62+
63+
protected:
64+
ImageRegionSplitterSlowDimension();
65+
66+
virtual unsigned int GetNumberOfSplitsInternal( unsigned int dim,
67+
const IndexValueType regionIndex[],
68+
const SizeValueType regionSize[],
69+
unsigned int requestedNumber ) const;
70+
71+
virtual unsigned int GetSplitInternal( unsigned int dim,
72+
unsigned int i,
73+
unsigned int numberOfPieces,
74+
IndexValueType regionIndex[],
75+
SizeValueType regionSize[] ) const;
76+
77+
private:
78+
ImageRegionSplitterSlowDimension(const ImageRegionSplitterSlowDimension &); //purposely not implemented
79+
void operator=(const ImageRegionSplitterSlowDimension &); //purposely not implemented
80+
};
81+
} // end namespace itk
82+
83+
#endif

Modules/Core/Common/include/itkImageSource.h

Lines changed: 59 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,31 @@
3030

3131
#include "itkProcessObject.h"
3232
#include "itkImage.h"
33+
#include "itkImageRegionSplitterBase.h"
3334

3435
namespace itk
3536
{
37+
38+
/** \class ImageSourceCommon
39+
* \brief Secondary bass class of ImageSource common between templates
40+
*
41+
* This class provides common non-templated code which can be compiled
42+
* and used by all templated versions of ImageSource.
43+
*
44+
* This class must be inherited privately, and light-weight adapting
45+
* of methods is required for virtual methods or non-private methods
46+
* for the ImageSource interface.
47+
*
48+
* \ingroup ITKCommon
49+
*/
50+
struct ITKCommon_EXPORT ImageSourceCommon
51+
{
52+
/**
53+
* Provide access to a common static object for image region splitting
54+
*/
55+
static const ImageRegionSplitterBase* GetGlobalDefaultSplitter(void);
56+
};
57+
3658
/** \class ImageSource
3759
* \brief Base class for all process objects that output image data.
3860
*
@@ -61,7 +83,8 @@ namespace itk
6183
* \endwiki
6284
*/
6385
template< class TOutputImage >
64-
class ITK_EXPORT ImageSource:public ProcessObject
86+
class ITK_EXPORT ImageSource
87+
: public ProcessObject, private ImageSourceCommon
6588
{
6689
public:
6790
/** Standard class typedefs. */
@@ -232,7 +255,7 @@ class ITK_EXPORT ImageSource:public ProcessObject
232255

233256
/** If an imaging filter can be implemented as a multithreaded
234257
* algorithm, the filter will provide an implementation of
235-
* ThreadedGenerateData(). This superclass will automatically split
258+
* ThreadedGenerateData(). This superclass will automatically split
236259
* the output image into a number of pieces, spawn multiple threads,
237260
* and call ThreadedGenerateData() in each thread. Prior to spawning
238261
* threads, the BeforeThreadedGenerateData() method is called. After
@@ -287,11 +310,42 @@ class ITK_EXPORT ImageSource:public ProcessObject
287310
* a ThreadedGenerateData() method and NOT a GenerateData() method. */
288311
virtual void AfterThreadedGenerateData() {}
289312

313+
/** \brief Returns the default image region splitter
314+
*
315+
* This is an adapter function from the private common base class to
316+
* the interface of this class.
317+
*/
318+
static const ImageRegionSplitterBase* GetGlobalDefaultSplitter()
319+
{
320+
return ImageSourceCommon::GetGlobalDefaultSplitter();
321+
}
322+
323+
/** \brief Get the image splitter to split the image for multi-threading.
324+
*
325+
* The Splitter object divides the image into regions for threading
326+
* or streaming. The algorithms on how to split an images are
327+
* separated into class so that they can be easily be reused. When
328+
* deriving from this class to write a filter consideration to the
329+
* algorithm used to divide the image should be made. If a change is
330+
* desired this method should be overridden to return the
331+
* appropriate object.
332+
*/
333+
virtual const ImageRegionSplitterBase* GetImageRegionSplitter(void) const;
334+
290335
/** Split the output's RequestedRegion into "num" pieces, returning
291-
* region "i" as "splitRegion". This method is called "num" times. The
292-
* regions must not overlap. The method returns the number of pieces that
336+
* region "i" as "splitRegion". This method is called concurrently
337+
* "num" times. The regions must not overlap. The method returns the number of pieces that
293338
* the routine is capable of splitting the output RequestedRegion,
294-
* i.e. return value is less than or equal to "num". */
339+
* i.e. return value is less than or equal to "num".
340+
*
341+
* To override the algorithm used split the image this method should
342+
* no longer be overridden. It stead the algorithm should be
343+
* implemented in a ImageRegionSplitter class, and the
344+
* GetImageRegionSplitter should overridden to return the splitter
345+
* object with the desired algorithm.
346+
*
347+
* \sa GetImageRegionSplitter
348+
**/
295349
virtual
296350
unsigned int SplitRequestedRegion(unsigned int i, unsigned int num, OutputImageRegionType & splitRegion);
297351

0 commit comments

Comments
 (0)