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