OTB  10.0.0
Orfeo Toolbox
otbImageRegionAdaptativeSplitter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2024 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  std::lock_guard<std::mutex> mutexHolder(m_Lock);
42  // Check if we need to compute split map agagin
43  if (!m_IsUpToDate)
44  {
45  // Do so if we need to
46  this->EstimateSplitMap();
47  }
48 
49  // Return the size of the split map
50  return m_StreamVector.size();
51 }
52 
53 template <unsigned int VImageDimension>
54 itk::ImageRegion<VImageDimension> ImageRegionAdaptativeSplitter<VImageDimension>::GetSplit(unsigned int i, unsigned int itkNotUsed(numberOfPieces),
55  const RegionType& region)
56 {
57  // Set parameters
58  this->SetImageRegion(region);
59  std::lock_guard<std::mutex> mutexHolder(m_Lock);
60  // Check if we need to compute split map agagin
61  if (!m_IsUpToDate)
62  {
63  // Do so if we need to
64  this->EstimateSplitMap();
65  }
66 
67  // Return the requested split
68  return m_StreamVector.at(i);
69 }
70 
71 template <unsigned int VImageDimension>
73 {
74  // Clear previous split map
75  m_StreamVector.clear();
76 
77  // Handle trivial case
78  if (m_RequestedNumberOfSplits == 1 || m_RequestedNumberOfSplits == 0)
79  {
80  m_StreamVector.push_back(m_ImageRegion);
81  m_IsUpToDate = true;
82  return;
83  }
84  // Handle the empty hint case and the case where VImageDimension != 2
85  if (m_TileHint[0] == 0 || m_TileHint[1] == 0 || VImageDimension != 2)
86  {
87  // In this case we fallback to the classical tile splitter
89 
90  // Retrieve nb splits
91  unsigned int nbSplits = splitter->GetNumberOfSplits(m_ImageRegion, m_RequestedNumberOfSplits);
92 
93  for (unsigned int i = 0; i < nbSplits; ++i)
94  {
95  m_StreamVector.push_back(splitter->GetSplit(i, m_RequestedNumberOfSplits, m_ImageRegion));
96  }
97  m_IsUpToDate = true;
98  return;
99  }
100 
101  // Now we can handle the case where we have a tile hint and a
102  // non-trivial requested number of splits
103  SizeType tilesPerDim, splitsPerDim;
104  IndexType firstTileCovered;
105 
106  // First, we need to get which tiles are covered by ROI
107  firstTileCovered[0] = m_ImageRegion.GetIndex()[0] / m_TileHint[0];
108  firstTileCovered[1] = m_ImageRegion.GetIndex()[1] / m_TileHint[1];
109  tilesPerDim[0] = (m_ImageRegion.GetIndex()[0] + m_ImageRegion.GetSize()[0] + m_TileHint[0] - 1) / m_TileHint[0] - firstTileCovered[0];
110  tilesPerDim[1] = (m_ImageRegion.GetIndex()[1] + m_ImageRegion.GetSize()[1] + m_TileHint[1] - 1) / m_TileHint[1] - firstTileCovered[1];
111 
112  unsigned int totalTiles = tilesPerDim[0] * tilesPerDim[1];
113 
114  // In this case, we have to group input tiles
115  if (totalTiles >= m_RequestedNumberOfSplits)
116  {
117  // Try to group splits
118  SizeType groupTiles;
119  groupTiles.Fill(1);
120 
121  unsigned int i = 0;
122 
123  // TODO: this should not fall in infinite loop, but add more
124  // security just in case.
125  while (totalTiles / (groupTiles[0] * groupTiles[1]) > m_RequestedNumberOfSplits)
126  {
127  if (groupTiles[i] < tilesPerDim[i])
128  {
129  groupTiles[i]++;
130  }
131  // TODO: We can be more generic here
132  i = (i + 1) % 2;
133  }
134 
135 
136  splitsPerDim[0] = tilesPerDim[0] / groupTiles[0];
137  splitsPerDim[1] = tilesPerDim[1] / groupTiles[1];
138 
139  // Handle the last small tile if any
140  if (tilesPerDim[0] % groupTiles[0] > 0)
141  splitsPerDim[0]++;
142 
143  if (tilesPerDim[1] % groupTiles[1] > 0)
144  splitsPerDim[1]++;
145 
146  // Fill the tiling scheme
147  for (unsigned int splity = 0; splity < splitsPerDim[1]; ++splity)
148  {
149  for (unsigned int splitx = 0; splitx < splitsPerDim[0]; ++splitx)
150  {
151  // Build the split
152  RegionType newSplit;
153  SizeType newSplitSize;
154  IndexType newSplitIndex;
155 
156  newSplitSize[0] = groupTiles[0] * m_TileHint[0];
157  newSplitSize[1] = groupTiles[1] * m_TileHint[1];
158 
159  newSplitIndex[0] = firstTileCovered[0] * m_TileHint[0] + splitx * newSplitSize[0];
160  newSplitIndex[1] = firstTileCovered[1] * m_TileHint[1] + splity * newSplitSize[1];
161 
162  newSplit.SetIndex(newSplitIndex);
163  newSplit.SetSize(newSplitSize);
164 
165  bool cropped = newSplit.Crop(m_ImageRegion);
166  // If newSplit could not be cropped, it means that it is
167  // outside m_ImageRegion. In this case we ignore it.
168  if (cropped)
169  {
170  m_StreamVector.push_back(newSplit);
171  }
172  }
173  }
174  }
175  // In this case, we must divide each tile
176  else
177  {
178  SizeType divideTiles;
179  divideTiles.Fill(1);
180 
181  unsigned int i = 1;
182 
183  // Exit condition if divideTiles=m_TileHint (i.e. no more subdivision available)
184  while (totalTiles * (divideTiles[0] * divideTiles[1]) < m_RequestedNumberOfSplits && (divideTiles[0] < m_TileHint[0] || divideTiles[1] < m_TileHint[1]))
185  {
186  if (divideTiles[i] < m_TileHint[i])
187  {
188  divideTiles[i]++;
189  }
190  // TODO: We can be more generic here
191  i = (i + 1) % 2;
192  }
193 
194  SizeType splitSize;
195  splitSize[0] = (m_TileHint[0] + divideTiles[0] - 1) / divideTiles[0];
196  splitSize[1] = (m_TileHint[1] + divideTiles[1] - 1) / divideTiles[1];
197 
198  RegionType tileHintRegion;
199  tileHintRegion.SetSize(m_TileHint);
200  // Fill the tiling scheme
201  for (unsigned int tiley = 0; tiley < tilesPerDim[1]; ++tiley)
202  {
203  for (unsigned int tilex = 0; tilex < tilesPerDim[0]; ++tilex)
204  {
205  for (unsigned int divy = 0; divy < divideTiles[1]; ++divy)
206  {
207  for (unsigned int divx = 0; divx < divideTiles[0]; ++divx)
208  {
209  // Build the split
210  RegionType newSplit;
211  IndexType newSplitIndex;
212 
213  newSplitIndex[0] = (tilex + firstTileCovered[0]) * m_TileHint[0] + divx * splitSize[0];
214  newSplitIndex[1] = (tiley + firstTileCovered[1]) * m_TileHint[1] + divy * splitSize[1];
215 
216  newSplit.SetIndex(newSplitIndex);
217  newSplit.SetSize(splitSize);
218 
219  tileHintRegion.SetIndex(0, tilex * m_TileHint[0]);
220  tileHintRegion.SetIndex(1, tiley * m_TileHint[1]);
221 
222  bool cropped = newSplit.Crop(m_ImageRegion);
223 
224  // If newSplit could not be cropped, it means that it is
225  // outside m_ImageRegion. In this case we ignore it.
226  if (cropped)
227  {
228  // check that the split stays inside its tile
229  cropped = newSplit.Crop(tileHintRegion);
230  if (cropped)
231  {
232  m_StreamVector.push_back(newSplit);
233  }
234  }
235  }
236  }
237  }
238  }
239  }
240  // Finally toggle the up-to-date flag
241  m_IsUpToDate = true;
242  return;
243 }
244 
248 template <unsigned int VImageDimension>
249 void ImageRegionAdaptativeSplitter<VImageDimension>::PrintSelf(std::ostream& os, itk::Indent indent) const
250 {
251  Superclass::PrintSelf(os, indent);
252  os << indent << "IsUpToDate: " << (m_IsUpToDate ? "true" : "false") << std::endl;
253  os << indent << "ImageRegion: " << m_ImageRegion << std::endl;
254  os << indent << "Tile hint: " << m_TileHint << std::endl;
255  os << indent << "Requested number of splits: " << m_RequestedNumberOfSplits << std::endl;
256  os << indent << "Actual number of splits: " << m_StreamVector.size() << std::endl;
257 }
259 
260 } // end namespace itk
261 
262 #endif
itk::ImageRegion< VImageDimension > RegionType
void PrintSelf(std::ostream &os, itk::Indent indent) const override
unsigned int GetNumberOfSplits(const RegionType &region, unsigned int requestedNumber) override
RegionType GetSplit(unsigned int i, unsigned int numberOfPieces, const RegionType &region) override
RegionType GetSplit(unsigned int i, unsigned int numberOfPieces, const RegionType &region) override
unsigned int GetNumberOfSplits(const RegionType &region, unsigned int requestedNumber) override
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.