OTB  9.0.0
Orfeo Toolbox
otbLabelImageToVectorDataFilter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2022 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"
28 
29 // gdal libraries
30 #include "gdal.h"
31 #include "gdal_priv.h"
32 #include "cpl_conv.h"
33 #include "gdal_alg.h"
34 
35 namespace otb
36 {
37 
38 template <class TInputImage, class TPrecision>
40 {
41  this->SetNumberOfRequiredInputs(2);
42  this->SetNumberOfRequiredInputs(1);
43  this->SetNumberOfRequiredOutputs(1);
44 
45  GDALAllRegister();
46 }
47 
48 template <class TInputImage, class TPrecision>
50 {
51  this->Superclass::SetNthInput(0, const_cast<InputImageType*>(input));
52 }
53 
54 template <class TInputImage, class TPrecision>
56 {
57  if (this->GetNumberOfInputs() < 1)
58  {
59  return nullptr;
60  }
61 
62  return static_cast<const InputImageType*>(this->Superclass::GetInput(0));
63 }
64 
65 template <class TInputImage, class TPrecision>
67 {
68  this->Superclass::SetNthInput(1, const_cast<InputImageType*>(input));
69 }
70 
71 template <class TInputImage, class TPrecision>
73 {
74  if (this->GetNumberOfInputs() < 2)
75  {
76  return nullptr;
77  }
78 
79  return static_cast<const InputImageType*>(this->Superclass::GetInput(1));
80 }
81 
82 template <class TInputImage, class TPrecision>
84 {
85  // call the superclass' implementation of this method
86  Superclass::GenerateInputRequestedRegion();
87 
88  // get pointers to the inputs
89  typename InputImageType::Pointer input = const_cast<InputImageType*>(this->GetInput());
90 
91  if (!input)
92  {
93  return;
94  }
95  // The input is necessarily the largest possible region.
96  input->SetRequestedRegionToLargestPossibleRegion();
97 
98  typename InputImageType::Pointer mask = const_cast<InputImageType*>(this->GetInputMask());
99  if (!mask)
100  {
101  return;
102  }
103  // The input is necessarily the largest possible region.
104  mask->SetRequestedRegionToLargestPossibleRegion();
105 }
106 
107 
108 template <class TInputImage, class TPrecision>
110 {
111  if (this->GetInput()->GetRequestedRegion() != this->GetInput()->GetLargestPossibleRegion())
112  {
113  itkExceptionMacro(<< "Not streamed filter. ERROR : requested region is not the largest possible region.");
114  }
115 
116  typename InputImageType::Pointer inImage = const_cast<InputImageType*>(this->GetInput());
117 
118  SizeType size = this->GetInput()->GetLargestPossibleRegion().GetSize();
119 
120  unsigned int nbBands = this->GetInput()->GetNumberOfComponentsPerPixel();
121  unsigned int bytePerPixel = sizeof(InputPixelType);
122 
124  // buffer casted in unsigned long cause under Win32 the address
125  // don't begin with 0x, the address in not interpreted as
126  // hexadecimal but alpha numeric value, then the conversion to
127  // integer make us pointing to an non allowed memory block => Crash.
128  std::ostringstream stream;
129  stream << "MEM:::"
130  << "DATAPOINTER=" << (uintptr_t)(this->GetInput()->GetBufferPointer()) << ","
131  << "PIXELS=" << size[0] << ","
132  << "LINES=" << size[1] << ","
133  << "BANDS=" << nbBands << ","
134  << "DATATYPE=" << GDALGetDataTypeName(GdalDataTypeBridge::GetGDALDataType<InputPixelType>()) << ","
135  << "PIXELOFFSET=" << bytePerPixel * nbBands << ","
136  << "LINEOFFSET=" << bytePerPixel * nbBands * size[0] << ","
137  << "BANDOFFSET=" << bytePerPixel;
139 
140  GDALDataset* dataset = static_cast<GDALDataset*>(GDALOpen(stream.str().c_str(), GA_ReadOnly));
141 
142  // Set input Projection ref and Geo transform to the dataset.
143  dataset->SetProjection(this->GetInput()->GetProjectionRef().c_str());
144 
145  unsigned int projSize = this->GetInput()->GetGeoTransform().size();
146  double geoTransform[6];
147 
148  // Set the geo transform of the input image (if any)
149  // Reporting origin and spacing of the buffered region
150  // the spacing is unchanged, the origin is relative to the buffered region
151  IndexType bufferIndexOrigin = this->GetInput()->GetBufferedRegion().GetIndex();
152  OriginType bufferOrigin;
153  this->GetInput()->TransformIndexToPhysicalPoint(bufferIndexOrigin, bufferOrigin);
154  geoTransform[0] = bufferOrigin[0] - 0.5 * this->GetInput()->GetSignedSpacing()[0];
155  geoTransform[3] = bufferOrigin[1] - 0.5 * this->GetInput()->GetSignedSpacing()[1];
156  geoTransform[1] = this->GetInput()->GetSignedSpacing()[0];
157  geoTransform[5] = this->GetInput()->GetSignedSpacing()[1];
158  // FIXME: Here component 1 and 4 should be replaced by the orientation parameters
159  if (projSize == 0)
160  {
161  geoTransform[2] = 0.;
162  geoTransform[4] = 0.;
163  }
164  else
165  {
166  geoTransform[2] = this->GetInput()->GetGeoTransform()[2];
167  geoTransform[4] = this->GetInput()->GetGeoTransform()[4];
168  }
169  dataset->SetGeoTransform(geoTransform);
170 
171  // Create the output layer for GDALPolygonize().
173 
174  OGRLayerType outputLayer = ogrDS->CreateLayer("layer", nullptr, wkbPolygon);
175 
176  OGRFieldDefn field(m_FieldName.c_str(), OFTInteger);
177  outputLayer.CreateField(field, true);
178 
179  // Call GDALPolygonize()
180  char** options;
181  options = nullptr;
182  char* option[1];
183  if (m_Use8Connected == true)
184  {
185  std::string opt("8CONNECTED:8");
186  option[0] = const_cast<char*>(opt.c_str());
187  options = option;
188  }
189 
190  /* Convert the mask input into a GDAL raster needed by GDALPolygonize */
191  typename InputImageType::ConstPointer inputMask = this->GetInputMask();
192  if (!inputMask.IsNull())
193  {
194  size = this->GetInputMask()->GetLargestPossibleRegion().GetSize();
195  nbBands = this->GetInputMask()->GetNumberOfComponentsPerPixel();
196  bytePerPixel = sizeof(InputPixelType);
197  // buffer casted in unsigned long cause under Win32 the address
198  // don't begin with 0x, the address in not interpreted as
199  // hexadecimal but alpha numeric value, then the conversion to
200  // integer make us pointing to an non allowed memory block => Crash.
201  std::ostringstream maskstream;
202  maskstream << "MEM:::"
203  << "DATAPOINTER=" << (uintptr_t)(this->GetInputMask()->GetBufferPointer()) << ","
204  << "PIXELS=" << size[0] << ","
205  << "LINES=" << size[1] << ","
206  << "BANDS=" << nbBands << ","
207  << "DATATYPE=" << GDALGetDataTypeName(GdalDataTypeBridge::GetGDALDataType<InputPixelType>()) << ","
208  << "PIXELOFFSET=" << bytePerPixel * nbBands << ","
209  << "LINEOFFSET=" << bytePerPixel * nbBands * size[0] << ","
210  << "BANDOFFSET=" << bytePerPixel;
211 
212  GDALDataset* maskDataset = static_cast<GDALDataset*>(GDALOpen(maskstream.str().c_str(), GA_ReadOnly));
213 
214  // Set input Projection ref and Geo transform to the dataset.
215  maskDataset->SetProjection(this->GetInputMask()->GetProjectionRef().c_str());
216 
217  projSize = this->GetInputMask()->GetGeoTransform().size();
218 
219  // Set the geo transform of the input mask image (if any)
220  // Reporting origin and spacing of the buffered region
221  // the spacing is unchanged, the origin is relative to the buffered region
222  bufferIndexOrigin = this->GetInputMask()->GetBufferedRegion().GetIndex();
223  this->GetInputMask()->TransformIndexToPhysicalPoint(bufferIndexOrigin, bufferOrigin);
224  geoTransform[0] = bufferOrigin[0] - 0.5 * this->GetInputMask()->GetSignedSpacing()[0];
225  geoTransform[3] = bufferOrigin[1] - 0.5 * this->GetInputMask()->GetSignedSpacing()[1];
226  geoTransform[1] = this->GetInputMask()->GetSignedSpacing()[0];
227  geoTransform[5] = this->GetInputMask()->GetSignedSpacing()[1];
228  // FIXME: Here component 1 and 4 should be replaced by the orientation parameters
229  if (projSize == 0)
230  {
231  geoTransform[2] = 0.;
232  geoTransform[4] = 0.;
233  }
234  else
235  {
236  geoTransform[2] = this->GetInputMask()->GetGeoTransform()[2];
237  geoTransform[4] = this->GetInputMask()->GetGeoTransform()[4];
238  }
239  maskDataset->SetGeoTransform(geoTransform);
240 
241  GDALPolygonize(dataset->GetRasterBand(1), maskDataset->GetRasterBand(1), &outputLayer.ogr(), 0, options, nullptr, nullptr);
242  GDALClose(maskDataset);
243  }
244  else
245  {
246  GDALPolygonize(dataset->GetRasterBand(1), nullptr, &outputLayer.ogr(), 0, options, nullptr, nullptr);
247  }
248 
249 
252  // Create the document node
253  DataNodePointerType document = DataNodeType::New();
254  document->SetNodeType(DOCUMENT);
255  document->SetNodeId(outputLayer.GetLayerDefn().GetName());
256 
257  // Adding the layer to the data tree
258  VectorDataPointerType data = dynamic_cast<VectorDataType*>(this->GetOutput());
259  data->SetProjectionRef(this->GetInput()->GetProjectionRef());
260 
261  DataTreePointerType tree = data->GetDataTree();
262  DataNodePointerType root = tree->GetRoot()->Get();
263  tree->Add(document, root);
264 
265  // This is not good but we do not have the choice if we want to
266  // get a hook on the internal structure
267  InternalTreeNodeType* documentPtr = const_cast<InternalTreeNodeType*>(tree->GetNode(document));
268 
269  OGRIOHelper::Pointer OGRConversion = OGRIOHelper::New();
270  OGRConversion->ConvertOGRLayerToDataTreeNode(&outputLayer.ogr(), documentPtr);
271 
272  // Clear memory
273  GDALClose(dataset);
274 }
275 
276 
277 } // end namespace otb
278 
279 #endif
otb::LabelImageToVectorDataFilter::SetInput
virtual void SetInput(const InputImageType *input)
Definition: otbLabelImageToVectorDataFilter.hxx:49
otb::LabelImageToVectorDataFilter::GenerateInputRequestedRegion
void GenerateInputRequestedRegion() override
Definition: otbLabelImageToVectorDataFilter.hxx:83
otb::LabelImageToVectorDataFilter::SetInputMask
virtual void SetInputMask(const InputImageType *input)
Definition: otbLabelImageToVectorDataFilter.hxx:66
otb::DOCUMENT
@ DOCUMENT
Definition: otbDataNode.h:41
otbOGRIOHelper.h
otbLabelImageToVectorDataFilter.h
otb::VectorData
This class represents a hierarchy of vector data.
Definition: otbVectorData.h:58
otb
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
Definition: otbJoinContainer.h:32
otb::LabelImageToVectorDataFilter::InputImageType
TInputImage InputImageType
Definition: otbLabelImageToVectorDataFilter.h:57
otb::LabelImageToVectorDataFilter::GetInputMask
virtual const InputImageType * GetInputMask(void)
Definition: otbLabelImageToVectorDataFilter.hxx:72
otb::LabelImageToVectorDataFilter::GetInput
virtual const InputImageType * GetInput(void)
Definition: otbLabelImageToVectorDataFilter.hxx:55
otb::LabelImageToVectorDataFilter::VectorDataPointerType
VectorDataType::Pointer VectorDataPointerType
Definition: otbLabelImageToVectorDataFilter.h:71
otb::OGRIOHelper::Pointer
itk::SmartPointer< Self > Pointer
Definition: otbOGRIOHelper.h:53
otb::OGRIOHelper::New
static Pointer New()
otb::LabelImageToVectorDataFilter::GenerateData
void GenerateData() override
Definition: otbLabelImageToVectorDataFilter.hxx:109
otb::LabelImageToVectorDataFilter::InternalTreeNodeType
DataTreeType::TreeNodeType InternalTreeNodeType
Definition: otbLabelImageToVectorDataFilter.h:74
otb::LabelImageToVectorDataFilter::IndexType
InputImageType::IndexType IndexType
Definition: otbLabelImageToVectorDataFilter.h:67
otb::ogr::Layer::ogr
OGRLayer & ogr()
otb::ogr::Layer::CreateField
void CreateField(FieldDefn const &field, bool bApproxOK=true)
otbGdalDataTypeBridge.h
otb::LabelImageToVectorDataFilter::DataTreePointerType
DataTreeType::Pointer DataTreePointerType
Definition: otbLabelImageToVectorDataFilter.h:73
otb::ogr::DataSource::Pointer
itk::SmartPointer< Self > Pointer
Definition: otbOGRDataSourceWrapper.h:90
otb::LabelImageToVectorDataFilter::SizeType
InputImageType::SizeType SizeType
Definition: otbLabelImageToVectorDataFilter.h:63
otb::LabelImageToVectorDataFilter::LabelImageToVectorDataFilter
LabelImageToVectorDataFilter()
Definition: otbLabelImageToVectorDataFilter.hxx:39
otb::LabelImageToVectorDataFilter::OriginType
InputImageType::PointType OriginType
Definition: otbLabelImageToVectorDataFilter.h:66
otb::VectorData::SetProjectionRef
virtual void SetProjectionRef(const std::string &projectionRef)
Definition: otbVectorData.hxx:43
otb::LabelImageToVectorDataFilter::InputPixelType
InputImageType::PixelType InputPixelType
Definition: otbLabelImageToVectorDataFilter.h:61
otb::ogr::Layer
Layer of geometric objects.
Definition: otbOGRLayerWrapper.h:80
otb::LabelImageToVectorDataFilter::DataNodePointerType
DataNodeType::Pointer DataNodePointerType
Definition: otbLabelImageToVectorDataFilter.h:76
otb::ogr::DataSource::New
static Pointer New()
otb::ogr::Layer::GetLayerDefn
OGRFeatureDefn & GetLayerDefn() const