OTB  7.1.0
Orfeo Toolbox
otbImageRegionAdaptativeSplitter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
3  *
4  * This file is part of Orfeo Toolbox
5  *
6  * https://www.orfeo-toolbox.org/
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #ifndef otbImageRegionAdaptativeSplitter_hxx
22 #define otbImageRegionAdaptativeSplitter_hxx
23 
25 #include "otbMath.h"
26 #include "otbMacro.h"
27 
28 // Default when no tile hint available
30 
31 namespace otb
32 {
33 
34 template <unsigned int VImageDimension>
35 unsigned int ImageRegionAdaptativeSplitter<VImageDimension>::GetNumberOfSplits(const RegionType& region, unsigned int requestedNumber)
36 {
37  // Set parameters
38  this->SetImageRegion(region);
39  this->SetRequestedNumberOfSplits(requestedNumber);
40 
41  // Check if we need to compute split map agagin
42  m_Lock.Lock();
43  if (!m_IsUpToDate)
44  {
45  // Do so if we need to
46  this->EstimateSplitMap();
47  }
48  m_Lock.Unlock();
49 
50  // Return the size of the split map
51  return m_StreamVector.size();
52 }
53 
54 template <unsigned int VImageDimension>
55 itk::ImageRegion<VImageDimension> ImageRegionAdaptativeSplitter<VImageDimension>::GetSplit(unsigned int i, unsigned int itkNotUsed(numberOfPieces),
56  const RegionType& region)
57 {
58  // Set parameters
59  this->SetImageRegion(region);
60 
61  // Check if we need to compute split map agagin
62  m_Lock.Lock();
63  if (!m_IsUpToDate)
64  {
65  // Do so if we need to
66  this->EstimateSplitMap();
67  }
68  m_Lock.Unlock();
69 
70  // Return the requested split
71  return m_StreamVector.at(i);
72 }
73 
74 template <unsigned int VImageDimension>
76 {
77  // Clear previous split map
78  m_StreamVector.clear();
79 
80  // Handle trivial case
81  if (m_RequestedNumberOfSplits == 1 || m_RequestedNumberOfSplits == 0)
82  {
83  m_StreamVector.push_back(m_ImageRegion);
84  m_IsUpToDate = true;
85  return;
86  }
87  // Handle the empty hint case and the case where VImageDimension != 2
88  if (m_TileHint[0] == 0 || m_TileHint[1] == 0 || VImageDimension != 2)
89  {
90  // In this case we fallback to the classical tile splitter
92 
93  // Retrieve nb splits
94  unsigned int nbSplits = splitter->GetNumberOfSplits(m_ImageRegion, m_RequestedNumberOfSplits);
95 
96  for (unsigned int i = 0; i < nbSplits; ++i)
97  {
98  m_StreamVector.push_back(splitter->GetSplit(i, m_RequestedNumberOfSplits, m_ImageRegion));
99  }
100  m_IsUpToDate = true;
101  return;
102  }
103 
104  // Now we can handle the case where we have a tile hint and a
105  // non-trivial requested number of splits
106  SizeType tilesPerDim, splitsPerDim;
107  IndexType firstTileCovered;
108 
109  // First, we need to get which tiles are covered by ROI
110  firstTileCovered[0] = m_ImageRegion.GetIndex()[0] / m_TileHint[0];
111  firstTileCovered[1] = m_ImageRegion.GetIndex()[1] / m_TileHint[1];
112  tilesPerDim[0] = (m_ImageRegion.GetIndex()[0] + m_ImageRegion.GetSize()[0] + m_TileHint[0] - 1) / m_TileHint[0] - firstTileCovered[0];
113  tilesPerDim[1] = (m_ImageRegion.GetIndex()[1] + m_ImageRegion.GetSize()[1] + m_TileHint[1] - 1) / m_TileHint[1] - firstTileCovered[1];
114 
115  unsigned int totalTiles = tilesPerDim[0] * tilesPerDim[1];
116 
117  // In this case, we have to group input tiles
118  if (totalTiles >= m_RequestedNumberOfSplits)
119  {
120  // Try to group splits
121  SizeType groupTiles;
122  groupTiles.Fill(1);
123 
124  unsigned int i = 0;
125 
126  // TODO: this should not fall in infinite loop, but add more
127  // security just in case.
128  while (totalTiles / (groupTiles[0] * groupTiles[1]) > m_RequestedNumberOfSplits)
129  {
130  if (groupTiles[i] < tilesPerDim[i])
131  {
132  groupTiles[i]++;
133  }
134  // TODO: We can be more generic here
135  i = (i + 1) % 2;
136  }
137 
138 
139  splitsPerDim[0] = tilesPerDim[0] / groupTiles[0];
140  splitsPerDim[1] = tilesPerDim[1] / groupTiles[1];
141 
142  // Handle the last small tile if any
143  if (tilesPerDim[0] % groupTiles[0] > 0)
144  splitsPerDim[0]++;
145 
146  if (tilesPerDim[1] % groupTiles[1] > 0)
147  splitsPerDim[1]++;
148 
149  // Fill the tiling scheme
150  for (unsigned int splity = 0; splity < splitsPerDim[1]; ++splity)
151  {
152  for (unsigned int splitx = 0; splitx < splitsPerDim[0]; ++splitx)
153  {
154  // Build the split
155  RegionType newSplit;
156  SizeType newSplitSize;
157  IndexType newSplitIndex;
158 
159  newSplitSize[0] = groupTiles[0] * m_TileHint[0];
160  newSplitSize[1] = groupTiles[1] * m_TileHint[1];
161 
162  newSplitIndex[0] = firstTileCovered[0] * m_TileHint[0] + splitx * newSplitSize[0];
163  newSplitIndex[1] = firstTileCovered[1] * m_TileHint[1] + splity * newSplitSize[1];
164 
165  newSplit.SetIndex(newSplitIndex);
166  newSplit.SetSize(newSplitSize);
167 
168  bool cropped = newSplit.Crop(m_ImageRegion);
169  // If newSplit could not be cropped, it means that it is
170  // outside m_ImageRegion. In this case we ignore it.
171  if (cropped)
172  {
173  m_StreamVector.push_back(newSplit);
174  }
175  }
176  }
177  }
178  // In this case, we must divide each tile
179  else
180  {
181  SizeType divideTiles;
182  divideTiles.Fill(1);
183 
184  unsigned int i = 1;
185 
186  // Exit condition if divideTiles=m_TileHint (i.e. no more subdivision available)
187  while (totalTiles * (divideTiles[0] * divideTiles[1]) < m_RequestedNumberOfSplits && (divideTiles[0] < m_TileHint[0] || divideTiles[1] < m_TileHint[1]))
188  {
189  if (divideTiles[i] < m_TileHint[i])
190  {
191  divideTiles[i]++;
192  }
193  // TODO: We can be more generic here
194  i = (i + 1) % 2;
195  }
196 
197  SizeType splitSize;
198  splitSize[0] = (m_TileHint[0] + divideTiles[0] - 1) / divideTiles[0];
199  splitSize[1] = (m_TileHint[1] + divideTiles[1] - 1) / divideTiles[1];
200 
201  RegionType tileHintRegion;
202  tileHintRegion.SetSize(m_TileHint);
203  // Fill the tiling scheme
204  for (unsigned int tiley = 0; tiley < tilesPerDim[1]; ++tiley)
205  {
206  for (unsigned int tilex = 0; tilex < tilesPerDim[0]; ++tilex)
207  {
208  for (unsigned int divy = 0; divy < divideTiles[1]; ++divy)
209  {
210  for (unsigned int divx = 0; divx < divideTiles[0]; ++divx)
211  {
212  // Build the split
213  RegionType newSplit;
214  IndexType newSplitIndex;
215 
216  newSplitIndex[0] = (tilex + firstTileCovered[0]) * m_TileHint[0] + divx * splitSize[0];
217  newSplitIndex[1] = (tiley + firstTileCovered[1]) * m_TileHint[1] + divy * splitSize[1];
218 
219  newSplit.SetIndex(newSplitIndex);
220  newSplit.SetSize(splitSize);
221 
222  tileHintRegion.SetIndex(0, tilex * m_TileHint[0]);
223  tileHintRegion.SetIndex(1, tiley * m_TileHint[1]);
224 
225  bool cropped = newSplit.Crop(m_ImageRegion);
226 
227  // If newSplit could not be cropped, it means that it is
228  // outside m_ImageRegion. In this case we ignore it.
229  if (cropped)
230  {
231  // check that the split stays inside its tile
232  cropped = newSplit.Crop(tileHintRegion);
233  if (cropped)
234  {
235  m_StreamVector.push_back(newSplit);
236  }
237  }
238  }
239  }
240  }
241  }
242  }
243  // Finally toggle the up-to-date flag
244  m_IsUpToDate = true;
245  return;
246 }
247 
251 template <unsigned int VImageDimension>
252 void ImageRegionAdaptativeSplitter<VImageDimension>::PrintSelf(std::ostream& os, itk::Indent indent) const
253 {
254  Superclass::PrintSelf(os, indent);
255  os << indent << "IsUpToDate: " << (m_IsUpToDate ? "true" : "false") << std::endl;
256  os << indent << "ImageRegion: " << m_ImageRegion << std::endl;
257  os << indent << "Tile hint: " << m_TileHint << std::endl;
258  os << indent << "Requested number of splits: " << m_RequestedNumberOfSplits << std::endl;
259  os << indent << "Actual number of splits: " << m_StreamVector.size() << std::endl;
260 }
262 
263 } // end namespace itk
264 
265 #endif
RegionType GetSplit(unsigned int i, unsigned int numberOfPieces, const RegionType &region) override
itk::ImageRegion< VImageDimension > RegionType
void PrintSelf(std::ostream &os, itk::Indent indent) const override
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
RegionType GetSplit(unsigned int i, unsigned int numberOfPieces, const RegionType &region) override
unsigned int GetNumberOfSplits(const RegionType &region, unsigned int requestedNumber) override
unsigned int GetNumberOfSplits(const RegionType &region, unsigned int requestedNumber) override