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