OTB  10.0.0
Orfeo Toolbox
otbLabelImageToOGRDataSourceFilter.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 otbLabelImageToOGRDataSourceFilter_hxx
22 #define otbLabelImageToOGRDataSourceFilter_hxx
23 
25 #include "otbGdalDataTypeBridge.h"
27 
28 // gdal libraries
29 #include "gdal.h"
30 #include "gdal_priv.h"
31 #include "cpl_conv.h"
32 #include "gdal_alg.h"
33 
34 #include "stdint.h" //needed for uintptr_t
35 
36 namespace otb
37 {
38 template <class TInputImage>
40 {
41  this->SetNumberOfRequiredInputs(2);
42  this->SetNumberOfRequiredInputs(1);
43  this->SetNumberOfRequiredOutputs(1);
44 
45  this->ProcessObject::SetNthOutput(0, this->MakeOutput(0));
46 }
47 
48 
49 template <class TInputImage>
52 {
53  return static_cast<DataObjectPointer>(OGRDataSourceType::New().GetPointer());
54 }
55 
56 template <class TInputImage>
58 {
59  return static_cast<const OGRDataSourceType*>(this->ProcessObject::GetOutput(0));
60 }
61 
62 template <class TInputImage>
64 {
65  this->Superclass::SetNthInput(0, const_cast<InputImageType*>(input));
66 }
67 
68 template <class TInputImage>
70 {
71  if (this->GetNumberOfInputs() < 1)
72  {
73  return nullptr;
74  }
75 
76  return static_cast<const InputImageType*>(this->Superclass::GetInput(0));
77 }
78 
79 template <class TInputImage>
81 {
82  this->Superclass::SetNthInput(1, const_cast<InputImageType*>(input));
83 }
84 
85 template <class TInputImage>
87 {
88  if (this->GetNumberOfInputs() < 2)
89  {
90  return nullptr;
91  }
92 
93  return static_cast<const InputImageType*>(this->Superclass::GetInput(1));
94 }
95 
96 template <class TInputImage>
98 {
99  // call the superclass' implementation of this method
100  Superclass::GenerateInputRequestedRegion();
101 
102  // get pointers to the inputs
103  typename InputImageType::Pointer input = const_cast<InputImageType*>(this->GetInput());
104 
105  if (!input)
106  {
107  return;
108  }
109  // The input is necessarily the largest possible region.
110  input->SetRequestedRegionToLargestPossibleRegion();
111 
112  typename InputImageType::Pointer mask = const_cast<InputImageType*>(this->GetInputMask());
113  if (!mask)
114  {
115  return;
116  }
117  // The input is necessarily the largest possible region.
118  mask->SetRequestedRegionToLargestPossibleRegion();
119 }
120 
121 
122 template <class TInputImage>
124 {
125  if (this->GetInput()->GetRequestedRegion() != this->GetInput()->GetLargestPossibleRegion())
126  {
127  itkExceptionMacro(<< "Not streamed filter. ERROR : requested region is not the largest possible region.");
128  }
129 
130  SizeType size;
131  unsigned int nbBands = 0;
132  unsigned int bytePerPixel = 0;
133 
134  /* Convert the input image into a GDAL raster needed by GDALPolygonize */
135  size = this->GetInput()->GetLargestPossibleRegion().GetSize();
136  nbBands = this->GetInput()->GetNumberOfComponentsPerPixel();
137  bytePerPixel = sizeof(InputPixelType);
138 
141  const_cast<InputPixelType*>(this->GetInput()->GetBufferPointer()),
142  this->GetInput()->GetLargestPossibleRegion().GetSize()[0],
143  this->GetInput()->GetLargestPossibleRegion().GetSize()[1],
144  GdalDataTypeBridge::GetGDALDataType<InputPixelType>(), bytePerPixel, nbBands, bytePerPixel);
145 
146  // Set input Projection ref and Geo transform to the dataset.
147  dataset->GetDataSet()->SetProjection(this->GetInput()->GetProjectionRef().c_str());
148 
149  unsigned int projSize = this->GetInput()->GetGeoTransform().size();
150  double geoTransform[6];
151 
152  // Set the geo transform of the input image (if any)
153  // Reporting origin and spacing of the buffered region
154  // the spacing is unchanged, the origin is relative to the buffered region
155  IndexType bufferIndexOrigin = this->GetInput()->GetBufferedRegion().GetIndex();
156  OriginType bufferOrigin;
157  this->GetInput()->TransformIndexToPhysicalPoint(bufferIndexOrigin, bufferOrigin);
158  geoTransform[0] = bufferOrigin[0] - 0.5 * this->GetInput()->GetSignedSpacing()[0];
159  geoTransform[3] = bufferOrigin[1] - 0.5 * this->GetInput()->GetSignedSpacing()[1];
160  geoTransform[1] = this->GetInput()->GetSignedSpacing()[0];
161  geoTransform[5] = this->GetInput()->GetSignedSpacing()[1];
162  // FIXME: Here component 1 and 4 should be replaced by the orientation parameters
163  if (projSize == 0)
164  {
165  geoTransform[2] = 0.;
166  geoTransform[4] = 0.;
167  }
168  else
169  {
170  geoTransform[2] = this->GetInput()->GetGeoTransform()[2];
171  geoTransform[4] = this->GetInput()->GetGeoTransform()[4];
172  }
173  dataset->GetDataSet()->SetGeoTransform(geoTransform);
174 
175  // Create the output layer for GDALPolygonize().
177 
178  OGRLayerType outputLayer = ogrDS->CreateLayer("layer", nullptr, wkbPolygon);
179 
180  OGRFieldDefn field(m_FieldName.c_str(), OFTInteger);
181  outputLayer.CreateField(field, true);
182 
183  // Call GDALPolygonize()
184  char** options;
185  options = nullptr;
186  char* option[2] = {nullptr, nullptr};
187  if (m_Use8Connected == true)
188  {
189  std::string opt("8CONNECTED:8");
190  option[0] = const_cast<char*>(opt.c_str());
191  options = option;
192  }
193 
194  /* Convert the mask input into a GDAL raster needed by GDALPolygonize */
195  typename InputImageType::ConstPointer inputMask = this->GetInputMask();
196  if (!inputMask.IsNull())
197  {
198  nbBands = this->GetInputMask()->GetNumberOfComponentsPerPixel();
199  bytePerPixel = sizeof(InputPixelType);
200 
201  GDALDatasetWrapper::Pointer maskDataset =
203  const_cast<InputPixelType*>(this->GetInputMask()->GetBufferPointer()),
204  this->GetInput()->GetLargestPossibleRegion().GetSize()[0],
205  this->GetInput()->GetLargestPossibleRegion().GetSize()[1],
206  GdalDataTypeBridge::GetGDALDataType<InputPixelType>(), bytePerPixel, nbBands, bytePerPixel);
207 
208  // Set input Projection ref and Geo transform to the dataset.
209  maskDataset->GetDataSet()->SetProjection(this->GetInputMask()->GetProjectionRef().c_str());
210 
211  projSize = this->GetInputMask()->GetGeoTransform().size();
212 
213  // Set the geo transform of the input mask image (if any)
214  // Reporting origin and spacing of the buffered region
215  // the spacing is unchanged, the origin is relative to the buffered region
216  bufferIndexOrigin = this->GetInputMask()->GetBufferedRegion().GetIndex();
217  this->GetInputMask()->TransformIndexToPhysicalPoint(bufferIndexOrigin, bufferOrigin);
218  geoTransform[0] = bufferOrigin[0] - 0.5 * this->GetInputMask()->GetSignedSpacing()[0];
219  geoTransform[3] = bufferOrigin[1] - 0.5 * this->GetInputMask()->GetSignedSpacing()[1];
220  geoTransform[1] = this->GetInputMask()->GetSignedSpacing()[0];
221  geoTransform[5] = this->GetInputMask()->GetSignedSpacing()[1];
222  // FIXME: Here component 1 and 4 should be replaced by the orientation parameters
223  if (projSize == 0)
224  {
225  geoTransform[2] = 0.;
226  geoTransform[4] = 0.;
227  }
228  else
229  {
230  geoTransform[2] = this->GetInputMask()->GetGeoTransform()[2];
231  geoTransform[4] = this->GetInputMask()->GetGeoTransform()[4];
232  }
233  maskDataset->GetDataSet()->SetGeoTransform(geoTransform);
234 
235  GDALPolygonize(dataset->GetDataSet()->GetRasterBand(1),
236  maskDataset->GetDataSet()->GetRasterBand(1),
237  &outputLayer.ogr(), 0,
238  options, nullptr, nullptr);
239  }
240  else
241  {
242  GDALPolygonize(dataset->GetDataSet()->GetRasterBand(1), nullptr,
243  &outputLayer.ogr(), 0, options, nullptr, nullptr);
244  }
245 
246  this->SetNthOutput(0, ogrDS);
247 }
248 
249 
250 } // end namespace otb
251 
252 #endif
itk::SmartPointer< Self > Pointer
static GDALDriverManagerWrapper & GetInstance()
GDALDatasetWrapper::Pointer OpenFromMemory(void *mem_ptr, const uint64_t &width, const uint64_t &height, const GDALDataType pix_type, const uint32_t byte_per_pixel, const uint16_t nb_bands=1, const uint64_t &band_offset=1) const
virtual const InputImageType * GetInputMask(void)
virtual void SetInput(const InputImageType *input)
DataObjectPointer MakeOutput(DataObjectPointerArraySizeType idx) override
itk::ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType
virtual void SetInputMask(const InputImageType *input)
Collection of geometric objects.
static Pointer New()
itk::SmartPointer< Self > Pointer
Layer of geometric objects.
OGRLayer & ogr()
void CreateField(FieldDefn const &field, bool bApproxOK=true)
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.