21 #ifndef otbPersistentSamplingFilterBase_hxx
22 #define otbPersistentSamplingFilterBase_hxx
26 #include "itkImageRegionConstIteratorWithOnlyIndex.h"
27 #include "itkImageRegionConstIterator.h"
30 #include "itkProgressReporter.h"
31 #include "itkMultiThreaderBase.h"
36 template <
class TInputImage,
class TMaskImage>
38 : m_FieldName(std::string(
"class")),
41 m_OutLayerName(std::string(
"output")),
42 m_OGRLayerCreationOptions(),
47 this->SetNthOutput(0, TInputImage::New());
51 template <
class TInputImage,
class TMaskImage>
57 template <
class TInputImage,
class TMaskImage>
60 if (this->GetNumberOfInputs() < 2)
67 template <
class TInputImage,
class TMaskImage>
70 this->SetNthInput(2,
const_cast<TMaskImage*
>(mask));
73 template <
class TInputImage,
class TMaskImage>
76 if (this->GetNumberOfInputs() < 3)
80 return static_cast<const TMaskImage*
>(this->itk::ProcessObject::GetInput(2));
83 template <
class TInputImage,
class TMaskImage>
86 m_OGRLayerCreationOptions.clear();
87 m_OGRLayerCreationOptions = options;
90 template <
class TInputImage,
class TMaskImage>
93 return m_OGRLayerCreationOptions;
96 template <
class TInputImage,
class TMaskImage>
99 Superclass::GenerateOutputInformation();
104 int fieldIndex = featIt->ogr().GetFieldIndex(this->m_FieldName.c_str());
107 itkGenericExceptionMacro(
"Field named " << this->m_FieldName <<
" not found!");
109 this->m_FieldIndex = fieldIndex;
115 if (mask->GetLargestPossibleRegion() != input->GetLargestPossibleRegion())
117 itkGenericExceptionMacro(
"Mask and input image have a different size!");
119 if (mask->GetOrigin() != input->GetOrigin())
121 itkGenericExceptionMacro(
"Mask and input image have a different origin!");
123 if (mask->GetSignedSpacing() != input->GetSignedSpacing())
125 itkGenericExceptionMacro(
"Mask and input image have a different spacing!");
130 template <
class TInputImage,
class TMaskImage>
136 RegionType requested = this->GetOutput()->GetRequestedRegion();
137 RegionType emptyRegion = input->GetLargestPossibleRegion();
138 emptyRegion.SetSize(0, 0);
139 emptyRegion.SetSize(1, 0);
141 input->SetRequestedRegion(emptyRegion);
145 mask->SetRequestedRegion(requested);
149 template <
class TInputImage,
class TMaskImage>
152 this->AllocateOutputs();
153 this->BeforeThreadedGenerateData();
156 this->DispatchInputVectors();
159 VectorThreadStruct str;
165 this->GetMultiThreader()->SetNumberOfWorkUnits(this->GetNumberOfWorkUnits());
166 this->GetMultiThreader()->SetSingleMethod(this->VectorThreaderCallback, &str);
169 this->GetMultiThreader()->SingleMethodExecute();
172 this->GatherOutputVectors();
174 this->AfterThreadedGenerateData();
177 template <
class TInputImage,
class TMaskImage>
180 Superclass::AllocateOutputs();
185 unsigned int numberOfThreads = this->GetNumberOfWorkUnits();
188 this->m_InMemoryInputs.clear();
189 this->m_InMemoryInputs.reserve(numberOfThreads);
190 std::string tmpLayerName(
"thread");
191 OGRSpatialReference* oSRS =
nullptr;
198 for (
unsigned int i = 0; i < numberOfThreads; i++)
203 for (
int k = 0; k < layerDefn.GetFieldCount(); k++)
205 OGRFieldDefn originDefn(layerDefn.GetFieldDefn(k));
209 this->m_InMemoryInputs.push_back(tmpOgrDS);
213 this->m_InMemoryOutputs.clear();
214 this->m_InMemoryOutputs.reserve(numberOfThreads);
215 tmpLayerName = std::string(
"threadOut");
216 for (
unsigned int i = 0; i < numberOfThreads; i++)
218 std::vector<OGRDataPointer> tmpContainer;
220 for (
unsigned int k = 0; k < this->GetNumberOfOutputs(); k++)
222 ogr::DataSource* realOutput =
dynamic_cast<ogr::DataSource*
>(this->itk::ProcessObject::GetOutput(k));
225 ogr::Layer realLayer = realOutput->GetLayersCount() == 1 ? realOutput->GetLayer(0) : realOutput->GetLayer(m_OutLayerName);
226 OGRFeatureDefn& outLayerDefn = realLayer.GetLayerDefn();
227 ogr::DataSource::Pointer tmpOutput = ogr::DataSource::New();
228 ogr::Layer tmpLayer = tmpOutput->CreateLayer(tmpLayerName, oSRS, realLayer.GetGeomType());
230 for (
int f = 0; f < outLayerDefn.GetFieldCount(); f++)
232 OGRFieldDefn originDefn(outLayerDefn.GetFieldDefn(f));
233 tmpLayer.CreateField(originDefn);
235 tmpContainer.push_back(tmpOutput);
238 this->m_InMemoryOutputs.push_back(tmpContainer);
247 template <
class TInputImage,
class TMaskImage>
251 this->m_InMemoryInputs.clear();
256 unsigned int count = 0;
257 for (
unsigned int k = 0; k < this->GetNumberOfOutputs(); k++)
262 this->FillOneOutput(count, realOutput,
bool(vectors == realOutput));
269 this->m_InMemoryOutputs.clear();
272 template <
class TInputImage,
class TMaskImage>
277 OGRErr err = outLayer.
ogr().StartTransaction();
278 if (err != OGRERR_NONE)
280 itkExceptionMacro(<<
"Unable to start transaction for OGR layer " << outLayer.
ogr().GetName() <<
".");
283 unsigned int numberOfThreads = this->GetNumberOfWorkUnits();
284 for (
unsigned int thread = 0; thread < numberOfThreads; thread++)
286 ogr::Layer inLayer = this->m_InMemoryOutputs[thread][outIdx]->GetLayerChecked(0);
297 for (; tmpIt != inLayer.
end(); ++tmpIt)
305 for (; tmpIt != inLayer.
end(); ++tmpIt)
308 dstFeature.
SetFrom(*tmpIt, TRUE);
314 err = outLayer.
ogr().CommitTransaction();
315 if (err != OGRERR_NONE)
317 itkExceptionMacro(<<
"Unable to commit transaction for OGR layer " << outLayer.
ogr().GetName() <<
".");
321 template <
class TInputImage,
class TMaskImage>
325 TInputImage* inputImage =
const_cast<TInputImage*
>(this->GetInput());
326 TInputImage* outputImage = this->GetOutput();
327 RegionType requestedRegion = outputImage->GetRequestedRegion();
329 itk::ProgressReporter progress(
this, threadid, layerForThread.
GetFeatureCount(
true));
333 for (; featIt != layerForThread.
end(); ++featIt)
337 RegionType consideredRegion = FeatureBoundingRegion(inputImage, featIt);
338 bool regionNotEmpty = consideredRegion.Crop(requestedRegion);
341 this->PrepareFeature(*featIt, threadid);
342 this->ExploreGeometry(*featIt, featIt->ogr().GetGeometryRef(), consideredRegion, threadid);
344 progress.CompletedPixel();
348 template <
class TInputImage,
class TMaskImage>
350 itk::ThreadIdType& threadid)
352 typename TInputImage::PointType imgPoint;
353 typename TInputImage::IndexType imgIndex;
355 switch (geom->getGeometryType())
360 OGRPoint* castPoint =
dynamic_cast<OGRPoint*
>(geom);
361 if (castPoint ==
nullptr)
364 imgPoint[0] = castPoint->getX();
365 imgPoint[1] = castPoint->getY();
366 const TInputImage* img = this->GetInput();
367 const TMaskImage* mask = this->GetMask();
368 img->TransformPhysicalPointToIndex(imgPoint, imgIndex);
369 if ((mask ==
nullptr) || mask->GetPixel(imgIndex))
371 this->ProcessSample(feature, imgIndex, imgPoint, threadid);
376 case wkbLineString25D:
378 OGRLineString* castLineString =
dynamic_cast<OGRLineString*
>(geom);
380 if (castLineString ==
nullptr)
382 this->ProcessLine(feature, castLineString, region, threadid);
388 OGRPolygon* castPolygon =
dynamic_cast<OGRPolygon*
>(geom);
389 if (castPolygon ==
nullptr)
391 this->ProcessPolygon(feature, castPolygon, region, threadid);
395 case wkbMultiPoint25D:
396 case wkbMultiLineString:
397 case wkbMultiLineString25D:
398 case wkbMultiPolygon:
399 case wkbMultiPolygon25D:
400 case wkbGeometryCollection:
401 case wkbGeometryCollection25D:
403 OGRGeometryCollection* geomCollection =
dynamic_cast<OGRGeometryCollection*
>(geom);
406 unsigned int nbGeom = geomCollection->getNumGeometries();
407 for (
unsigned int i = 0; i < nbGeom; ++i)
409 this->ExploreGeometry(feature, geomCollection->getGeometryRef(i), region, threadid);
414 otbWarningMacro(
"Geometry not recognized as a collection : " << geom->getGeometryName());
426 template <
class TInputImage,
class TMaskImage>
428 itk::ThreadIdType& threadid)
430 OGRPolygon tmpPolygon;
432 ring.addPoint(0.0, 0.0, 0.0);
433 ring.addPoint(1.0, 0.0, 0.0);
434 ring.addPoint(1.0, 1.0, 0.0);
435 ring.addPoint(0.0, 1.0, 0.0);
436 ring.addPoint(0.0, 0.0, 0.0);
437 tmpPolygon.addRing(&ring);
438 const TInputImage* img = this->GetInput();
439 TMaskImage* mask =
const_cast<TMaskImage*
>(this->GetMask());
440 typename TInputImage::IndexType imgIndex;
441 typename TInputImage::PointType imgPoint;
442 typename TInputImage::SpacingType imgAbsSpacing = img->GetSignedSpacing();
443 if (imgAbsSpacing[0] < 0)
444 imgAbsSpacing[0] = -imgAbsSpacing[0];
445 if (imgAbsSpacing[1] < 0)
446 imgAbsSpacing[1] = -imgAbsSpacing[1];
452 MaskedIteratorType it(mask, mask, region);
454 while (!it.IsAtEnd())
456 imgIndex = it.GetIndex();
457 img->TransformIndexToPhysicalPoint(imgIndex, imgPoint);
458 bool isInside = this->IsSampleOnLine(line, imgPoint, imgAbsSpacing, tmpPolygon);
461 this->ProcessSample(feature, imgIndex, imgPoint, threadid);
468 typedef itk::ImageRegionConstIteratorWithOnlyIndex<TInputImage> NoValueIteratorType;
469 NoValueIteratorType it(img, region);
471 while (!it.IsAtEnd())
473 imgIndex = it.GetIndex();
474 img->TransformIndexToPhysicalPoint(imgIndex, imgPoint);
475 bool isInside = this->IsSampleOnLine(line, imgPoint, imgAbsSpacing, tmpPolygon);
478 this->ProcessSample(feature, imgIndex, imgPoint, threadid);
485 template <
class TInputImage,
class TMaskImage>
487 itk::ThreadIdType& threadid)
489 const TInputImage* img = this->GetInput();
490 TMaskImage* mask =
const_cast<TMaskImage*
>(this->GetMask());
491 typename TInputImage::IndexType imgIndex;
492 typename TInputImage::PointType imgPoint;
499 MaskedIteratorType it(mask, mask, region);
501 while (!it.IsAtEnd())
503 imgIndex = it.GetIndex();
504 img->TransformIndexToPhysicalPoint(imgIndex, imgPoint);
505 tmpPoint.setX(imgPoint[0]);
506 tmpPoint.setY(imgPoint[1]);
507 bool isInside = this->IsSampleInsidePolygon(polygon, &tmpPoint);
510 this->ProcessSample(feature, imgIndex, imgPoint, threadid);
517 typedef itk::ImageRegionConstIteratorWithOnlyIndex<TInputImage> NoValueIteratorType;
518 NoValueIteratorType it(img, region);
520 while (!it.IsAtEnd())
522 imgIndex = it.GetIndex();
523 img->TransformIndexToPhysicalPoint(imgIndex, imgPoint);
524 tmpPoint.setX(imgPoint[0]);
525 tmpPoint.setY(imgPoint[1]);
526 bool isInside = this->IsSampleInsidePolygon(polygon, &tmpPoint);
529 this->ProcessSample(feature, imgIndex, imgPoint, threadid);
536 template <
class TInputImage,
class TMaskImage>
538 typename TInputImage::PointType&, itk::ThreadIdType&)
540 itkExceptionMacro(
"Method ProcessSample not implemented !");
543 template <
class TInputImage,
class TMaskImage>
549 template <
class TInputImage,
class TMaskImage>
552 bool ret = poly->getExteriorRing()->isPointInRing(tmpPoint);
555 for (
int k = 0; k < poly->getNumInteriorRings(); k++)
557 if (poly->getInteriorRing(k)->isPointInRing(tmpPoint))
567 template <
class TInputImage,
class TMaskImage>
569 typename TInputImage::SpacingType& absSpacing, OGRPolygon& tmpPolygon)
571 tmpPolygon.getExteriorRing()->setPoint(0, position[0] - 0.5 * absSpacing[0], position[1] - 0.5 * absSpacing[1], 0.0);
572 tmpPolygon.getExteriorRing()->setPoint(1, position[0] + 0.5 * absSpacing[0], position[1] - 0.5 * absSpacing[1], 0.0);
573 tmpPolygon.getExteriorRing()->setPoint(2, position[0] + 0.5 * absSpacing[0], position[1] + 0.5 * absSpacing[1], 0.0);
574 tmpPolygon.getExteriorRing()->setPoint(3, position[0] - 0.5 * absSpacing[0], position[1] + 0.5 * absSpacing[1], 0.0);
575 tmpPolygon.getExteriorRing()->setPoint(4, position[0] - 0.5 * absSpacing[0], position[1] - 0.5 * absSpacing[1], 0.0);
576 return line->Intersects(&tmpPolygon);
579 template <
class TInputImage,
class TMaskImage>
584 OGREnvelope envelope;
585 featIt->GetGeometry()->getEnvelope(&envelope);
586 itk::Point<double, 2> lowerPoint, upperPoint;
587 lowerPoint[0] = envelope.MinX;
588 lowerPoint[1] = envelope.MinY;
589 upperPoint[0] = envelope.MaxX;
590 upperPoint[1] = envelope.MaxY;
592 typename TInputImage::IndexType lowerIndex;
593 typename TInputImage::IndexType upperIndex;
595 image->TransformPhysicalPointToIndex(lowerPoint, lowerIndex);
596 image->TransformPhysicalPointToIndex(upperPoint, upperIndex);
599 if (lowerIndex[0] > upperIndex[0])
601 int tmp = lowerIndex[0];
602 lowerIndex[0] = upperIndex[0];
605 if (lowerIndex[1] > upperIndex[1])
607 int tmp = lowerIndex[1];
608 lowerIndex[1] = upperIndex[1];
613 region.SetIndex(lowerIndex);
614 region.SetUpperIndex(upperIndex);
619 template <
class TInputImage,
class TMaskImage>
622 TInputImage* outputImage = this->GetOutput();
626 const RegionType& requestedRegion = outputImage->GetRequestedRegion();
627 itk::ContinuousIndex<double> startIndex(requestedRegion.GetIndex());
628 itk::ContinuousIndex<double> endIndex(requestedRegion.GetUpperIndex());
629 startIndex[0] += -0.5;
630 startIndex[1] += -0.5;
633 itk::Point<double, 2> startPoint;
634 itk::Point<double, 2> endPoint;
635 outputImage->TransformContinuousIndexToPhysicalPoint(startIndex, startPoint);
636 outputImage->TransformContinuousIndexToPhysicalPoint(endIndex, endPoint);
639 OGRPolygon tmpPolygon;
641 ring.addPoint(startPoint[0], startPoint[1], 0.0);
642 ring.addPoint(startPoint[0], endPoint[1], 0.0);
643 ring.addPoint(endPoint[0], endPoint[1], 0.0);
644 ring.addPoint(endPoint[0], startPoint[1], 0.0);
645 ring.addPoint(startPoint[0], startPoint[1], 0.0);
646 tmpPolygon.addRing(&ring);
650 unsigned int numberOfThreads = this->GetNumberOfWorkUnits();
651 std::vector<ogr::Layer> tmpLayers;
652 tmpLayers.reserve(numberOfThreads);
653 for (
unsigned int i = 0; i < numberOfThreads; i++)
655 tmpLayers.push_back(this->GetInMemoryInput(i));
658 const unsigned int nbFeatThread = std::ceil(inLayer.
GetFeatureCount(
true) / (
float)numberOfThreads);
663 unsigned int counter = 0;
664 unsigned int cptFeat = 0;
665 for (; featIt != inLayer.
end(); ++featIt)
668 dstFeature.
SetFrom(*featIt, TRUE);
669 dstFeature.
SetFID(featIt->GetFID());
670 tmpLayers[counter].CreateFeature(dstFeature);
672 if (cptFeat > nbFeatThread && (counter + 1) < numberOfThreads)
682 template <
class TInputImage,
class TMaskImage>
685 TInputImage* inputImage =
const_cast<TInputImage*
>(this->GetInput());
686 inputImage->UpdateOutputInformation();
690 bool updateMode =
false;
691 if (inputDS == outputDS)
695 m_OutLayerName = inLayer.
GetName();
700 std::map<std::string, OGRFieldType> currentFields;
701 for (
int k = 0; k < layerDefn.GetFieldCount(); k++)
703 OGRFieldDefn fieldDefn(layerDefn.GetFieldDefn(k));
704 std::string currentName(fieldDefn.GetNameRef());
705 currentFields[currentName] = fieldDefn.GetType();
712 bool projectionInformationAvailable = !projectionRefWkt.empty();
713 OGRSpatialReference* oSRS =
nullptr;
714 if (projectionInformationAvailable)
716 oSRS =
static_cast<OGRSpatialReference*
>(OSRNewSpatialReference(projectionRefWkt.c_str()));
719 outLayer = outputDS->
CreateLayer(this->GetOutLayerName(), oSRS, wkbPoint, this->GetOGRLayerCreationOptions());
721 for (
int k = 0; k < layerDefn.GetFieldCount(); k++)
723 OGRFieldDefn fieldDefn(layerDefn.GetFieldDefn(k));
734 for (
unsigned int k = 0; k < m_AdditionalFields.size(); k++)
736 OGRFieldDefn ogrFieldDefinition(m_AdditionalFields[k].Name.c_str(), m_AdditionalFields[k].Type);
737 ogrFieldDefinition.SetWidth(m_AdditionalFields[k].Width);
738 ogrFieldDefinition.SetPrecision(m_AdditionalFields[k].Precision);
741 if (currentFields.count(fieldDef.
GetName()))
746 itkExceptionMacro(
"Field name " << fieldDef.
GetName() <<
" already exists with a different type!");
757 template <
class TInputImage,
class TMaskImage>
760 this->m_AdditionalFields.clear();
763 template <
class TInputImage,
class TMaskImage>
771 this->m_AdditionalFields.push_back(defn);
774 template <
class TInputImage,
class TMaskImage>
775 const std::vector<typename PersistentSamplingFilterBase<TInputImage, TMaskImage>::SimpleFieldDefn>&
778 return this->m_AdditionalFields;
781 template<
class TInputImage,
class TMaskImage>
782 itk::ITK_THREAD_RETURN_TYPE
787 int threadId = ((itk::MultiThreaderBase::WorkUnitInfo *)(arg))->WorkUnitID;
788 int threadCount = ((itk::MultiThreaderBase::WorkUnitInfo *)(arg))->NumberOfWorkUnits;
792 if (threadId < threadCount)
794 str->
Filter->ThreadedGenerateVectorData(layer,threadId);
797 return itk::ITK_THREAD_RETURN_DEFAULT_VALUE;
800 template <
class TInputImage,
class TMaskImage>
803 if (threadId >= m_InMemoryInputs.size())
805 itkExceptionMacro(<<
"Requested in-memory input layer not available " << threadId <<
" (total size : " << m_InMemoryInputs.size() <<
").");
807 return m_InMemoryInputs[threadId]->GetLayerChecked(0);
810 template <
class TInputImage,
class TMaskImage>
813 if (threadId >= m_InMemoryOutputs.size())
815 itkExceptionMacro(<<
"Requested in-memory output layer not available " << threadId <<
" (total size : " << m_InMemoryOutputs.size() <<
").");
817 if (index >= m_InMemoryOutputs[threadId].size())
819 itkExceptionMacro(<<
"Requested output dataset not available " << index <<
" (available : " << m_InMemoryOutputs[threadId].size() <<
").");
821 return m_InMemoryOutputs[threadId][index]->GetLayerChecked(0);
Decorate an iterator to ignore masked pixels.
TInputImage InputImageType
Base class for persistent filter doing sampling tasks.
PersistentSamplingFilterBase()
void SetOGRData(const ogr::DataSource *vector)
TInputImage::RegionType RegionType
static Stopwatch StartNew()
DurationType GetElapsedMilliseconds() const
Collection of geometric objects.
int GetLayersCount() const
Layer CreateLayer(std::string const &name, OGRSpatialReference *poSpatialRef=nullptr, OGRwkbGeometryType eGType=wkbUnknown, std::vector< std::string > const &papszOptions=std::vector< std::string >())
Layer GetLayer(vcl_size_t i)
itk::SmartPointer< Self > Pointer
Geometric object with descriptive fields.
void SetFrom(Feature const &rhs, int *map, bool mustForgive=true)
Encapsulation of OGRFieldDefn: field definition.
OGRFieldType GetType() const
Field type accessor.
std::string GetName() const
Field name accessor.
Implementation class for Feature iterator. This iterator is a single pass iterator....
Layer of geometric objects.
const_iterator end() const
std::string GetProjectionRef() const
OGRSpatialReference const * GetSpatialRef() const
OGRwkbGeometryType GetGeomType() const
int GetFeatureCount(bool doForceComputation) const
void SetFeature(Feature feature)
const_iterator begin() const
void SetSpatialFilter(OGRGeometry const *spatialFilter)
void CreateFeature(Feature feature)
std::string GetName() const
void CreateField(FieldDefn const &field, bool bApproxOK=true)
OGRFeatureDefn & GetLayerDefn() const
The "otb" namespace contains all Orfeo Toolbox (OTB) classes.
#define otbMsgDebugMacro(x)
#define otbWarningMacro(x)