21 #ifndef otbPersistentSamplingFilterBase_hxx
22 #define otbPersistentSamplingFilterBase_hxx
26 #include "itkImageRegionConstIteratorWithOnlyIndex.h"
27 #include "itkImageRegionConstIterator.h"
30 #include "itkProgressReporter.h"
35 template <
class TInputImage,
class TMaskImage>
37 : m_FieldName(std::string(
"class")),
40 m_OutLayerName(std::string(
"output")),
41 m_OGRLayerCreationOptions(),
46 this->SetNthOutput(0, TInputImage::New());
50 template <
class TInputImage,
class TMaskImage>
56 template <
class TInputImage,
class TMaskImage>
59 if (this->GetNumberOfInputs() < 2)
66 template <
class TInputImage,
class TMaskImage>
69 this->SetNthInput(2,
const_cast<TMaskImage*
>(mask));
72 template <
class TInputImage,
class TMaskImage>
75 if (this->GetNumberOfInputs() < 3)
79 return static_cast<const TMaskImage*
>(this->itk::ProcessObject::GetInput(2));
82 template <
class TInputImage,
class TMaskImage>
85 m_OGRLayerCreationOptions.clear();
86 m_OGRLayerCreationOptions = options;
89 template <
class TInputImage,
class TMaskImage>
92 return m_OGRLayerCreationOptions;
95 template <
class TInputImage,
class TMaskImage>
98 Superclass::GenerateOutputInformation();
103 int fieldIndex = featIt->ogr().GetFieldIndex(this->m_FieldName.c_str());
106 itkGenericExceptionMacro(
"Field named " << this->m_FieldName <<
" not found!");
108 this->m_FieldIndex = fieldIndex;
114 if (mask->GetLargestPossibleRegion() != input->GetLargestPossibleRegion())
116 itkGenericExceptionMacro(
"Mask and input image have a different size!");
118 if (mask->GetOrigin() != input->GetOrigin())
120 itkGenericExceptionMacro(
"Mask and input image have a different origin!");
124 itkGenericExceptionMacro(
"Mask and input image have a different spacing!");
129 template <
class TInputImage,
class TMaskImage>
135 RegionType requested = this->GetOutput()->GetRequestedRegion();
136 RegionType emptyRegion = input->GetLargestPossibleRegion();
137 emptyRegion.SetSize(0, 0);
138 emptyRegion.SetSize(1, 0);
140 input->SetRequestedRegion(emptyRegion);
144 mask->SetRequestedRegion(requested);
148 template <
class TInputImage,
class TMaskImage>
151 this->AllocateOutputs();
152 this->BeforeThreadedGenerateData();
155 this->DispatchInputVectors();
158 VectorThreadStruct str;
164 this->GetMultiThreader()->SetNumberOfThreads(this->GetNumberOfThreads());
165 this->GetMultiThreader()->SetSingleMethod(this->VectorThreaderCallback, &str);
168 this->GetMultiThreader()->SingleMethodExecute();
171 this->GatherOutputVectors();
173 this->AfterThreadedGenerateData();
176 template <
class TInputImage,
class TMaskImage>
179 Superclass::AllocateOutputs();
184 unsigned int numberOfThreads = this->GetNumberOfThreads();
187 this->m_InMemoryInputs.clear();
188 this->m_InMemoryInputs.reserve(numberOfThreads);
189 std::string tmpLayerName(
"thread");
190 OGRSpatialReference* oSRS =
nullptr;
197 for (
unsigned int i = 0; i < numberOfThreads; i++)
202 for (
int k = 0; k < layerDefn.GetFieldCount(); k++)
204 OGRFieldDefn originDefn(layerDefn.GetFieldDefn(k));
208 this->m_InMemoryInputs.push_back(tmpOgrDS);
212 this->m_InMemoryOutputs.clear();
213 this->m_InMemoryOutputs.reserve(numberOfThreads);
214 tmpLayerName = std::string(
"threadOut");
215 for (
unsigned int i = 0; i < numberOfThreads; i++)
217 std::vector<OGRDataPointer> tmpContainer;
219 for (
unsigned int k = 0; k < this->GetNumberOfOutputs(); k++)
225 OGRFeatureDefn& outLayerDefn = realLayer.
GetLayerDefn();
229 for (
int f = 0; f < outLayerDefn.GetFieldCount(); f++)
231 OGRFieldDefn originDefn(outLayerDefn.GetFieldDefn(f));
234 tmpContainer.push_back(tmpOutput);
237 this->m_InMemoryOutputs.push_back(tmpContainer);
246 template <
class TInputImage,
class TMaskImage>
250 this->m_InMemoryInputs.clear();
255 unsigned int count = 0;
256 for (
unsigned int k = 0; k < this->GetNumberOfOutputs(); k++)
261 this->FillOneOutput(count, realOutput,
bool(vectors == realOutput));
268 this->m_InMemoryOutputs.clear();
271 template <
class TInputImage,
class TMaskImage>
276 OGRErr err = outLayer.
ogr().StartTransaction();
277 if (err != OGRERR_NONE)
279 itkExceptionMacro(<<
"Unable to start transaction for OGR layer " << outLayer.
ogr().GetName() <<
".");
282 unsigned int numberOfThreads = this->GetNumberOfThreads();
283 for (
unsigned int thread = 0; thread < numberOfThreads; thread++)
285 ogr::Layer inLayer = this->m_InMemoryOutputs[thread][outIdx]->GetLayerChecked(0);
296 for (; tmpIt != inLayer.
end(); ++tmpIt)
304 for (; tmpIt != inLayer.
end(); ++tmpIt)
307 dstFeature.
SetFrom(*tmpIt, TRUE);
313 err = outLayer.
ogr().CommitTransaction();
314 if (err != OGRERR_NONE)
316 itkExceptionMacro(<<
"Unable to commit transaction for OGR layer " << outLayer.
ogr().GetName() <<
".");
320 template <
class TInputImage,
class TMaskImage>
324 TInputImage* inputImage =
const_cast<TInputImage*
>(this->GetInput());
325 TInputImage* outputImage = this->GetOutput();
326 RegionType requestedRegion = outputImage->GetRequestedRegion();
328 itk::ProgressReporter progress(
this, threadid, layerForThread.
GetFeatureCount(
true));
332 for (; featIt != layerForThread.
end(); ++featIt)
336 RegionType consideredRegion = FeatureBoundingRegion(inputImage, featIt);
337 bool regionNotEmpty = consideredRegion.Crop(requestedRegion);
340 this->PrepareFeature(*featIt, threadid);
341 this->ExploreGeometry(*featIt, featIt->ogr().GetGeometryRef(), consideredRegion, threadid);
343 progress.CompletedPixel();
347 template <
class TInputImage,
class TMaskImage>
349 itk::ThreadIdType& threadid)
351 typename TInputImage::PointType imgPoint;
352 typename TInputImage::IndexType imgIndex;
354 switch (geom->getGeometryType())
359 OGRPoint* castPoint =
dynamic_cast<OGRPoint*
>(geom);
360 if (castPoint ==
nullptr)
363 imgPoint[0] = castPoint->getX();
364 imgPoint[1] = castPoint->getY();
365 const TInputImage* img = this->GetInput();
366 const TMaskImage* mask = this->GetMask();
367 img->TransformPhysicalPointToIndex(imgPoint, imgIndex);
368 if ((mask ==
nullptr) || mask->GetPixel(imgIndex))
370 this->ProcessSample(feature, imgIndex, imgPoint, threadid);
375 case wkbLineString25D:
377 OGRLineString* castLineString =
dynamic_cast<OGRLineString*
>(geom);
379 if (castLineString ==
nullptr)
381 this->ProcessLine(feature, castLineString, region, threadid);
387 OGRPolygon* castPolygon =
dynamic_cast<OGRPolygon*
>(geom);
388 if (castPolygon ==
nullptr)
390 this->ProcessPolygon(feature, castPolygon, region, threadid);
394 case wkbMultiPoint25D:
395 case wkbMultiLineString:
396 case wkbMultiLineString25D:
397 case wkbMultiPolygon:
398 case wkbMultiPolygon25D:
399 case wkbGeometryCollection:
400 case wkbGeometryCollection25D:
402 OGRGeometryCollection* geomCollection =
dynamic_cast<OGRGeometryCollection*
>(geom);
405 unsigned int nbGeom = geomCollection->getNumGeometries();
406 for (
unsigned int i = 0; i < nbGeom; ++i)
408 this->ExploreGeometry(feature, geomCollection->getGeometryRef(i), region, threadid);
413 otbWarningMacro(
"Geometry not recognized as a collection : " << geom->getGeometryName());
425 template <
class TInputImage,
class TMaskImage>
427 itk::ThreadIdType& threadid)
429 OGRPolygon tmpPolygon;
431 ring.addPoint(0.0, 0.0, 0.0);
432 ring.addPoint(1.0, 0.0, 0.0);
433 ring.addPoint(1.0, 1.0, 0.0);
434 ring.addPoint(0.0, 1.0, 0.0);
435 ring.addPoint(0.0, 0.0, 0.0);
436 tmpPolygon.addRing(&ring);
437 const TInputImage* img = this->GetInput();
438 TMaskImage* mask =
const_cast<TMaskImage*
>(this->GetMask());
439 typename TInputImage::IndexType imgIndex;
440 typename TInputImage::PointType imgPoint;
441 typename TInputImage::SpacingType imgAbsSpacing = img->GetSignedSpacing();
442 if (imgAbsSpacing[0] < 0)
443 imgAbsSpacing[0] = -imgAbsSpacing[0];
444 if (imgAbsSpacing[1] < 0)
445 imgAbsSpacing[1] = -imgAbsSpacing[1];
451 MaskedIteratorType it(mask, mask, region);
453 while (!it.IsAtEnd())
455 imgIndex = it.GetIndex();
456 img->TransformIndexToPhysicalPoint(imgIndex, imgPoint);
457 bool isInside = this->IsSampleOnLine(line, imgPoint, imgAbsSpacing, tmpPolygon);
460 this->ProcessSample(feature, imgIndex, imgPoint, threadid);
467 typedef itk::ImageRegionConstIteratorWithOnlyIndex<TInputImage> NoValueIteratorType;
468 NoValueIteratorType it(img, region);
470 while (!it.IsAtEnd())
472 imgIndex = it.GetIndex();
473 img->TransformIndexToPhysicalPoint(imgIndex, imgPoint);
474 bool isInside = this->IsSampleOnLine(line, imgPoint, imgAbsSpacing, tmpPolygon);
477 this->ProcessSample(feature, imgIndex, imgPoint, threadid);
484 template <
class TInputImage,
class TMaskImage>
486 itk::ThreadIdType& threadid)
488 const TInputImage* img = this->GetInput();
489 TMaskImage* mask =
const_cast<TMaskImage*
>(this->GetMask());
490 typename TInputImage::IndexType imgIndex;
491 typename TInputImage::PointType imgPoint;
498 MaskedIteratorType it(mask, mask, region);
500 while (!it.IsAtEnd())
502 imgIndex = it.GetIndex();
503 img->TransformIndexToPhysicalPoint(imgIndex, imgPoint);
504 tmpPoint.setX(imgPoint[0]);
505 tmpPoint.setY(imgPoint[1]);
506 bool isInside = this->IsSampleInsidePolygon(polygon, &tmpPoint);
509 this->ProcessSample(feature, imgIndex, imgPoint, threadid);
516 typedef itk::ImageRegionConstIteratorWithOnlyIndex<TInputImage> NoValueIteratorType;
517 NoValueIteratorType it(img, region);
519 while (!it.IsAtEnd())
521 imgIndex = it.GetIndex();
522 img->TransformIndexToPhysicalPoint(imgIndex, imgPoint);
523 tmpPoint.setX(imgPoint[0]);
524 tmpPoint.setY(imgPoint[1]);
525 bool isInside = this->IsSampleInsidePolygon(polygon, &tmpPoint);
528 this->ProcessSample(feature, imgIndex, imgPoint, threadid);
535 template <
class TInputImage,
class TMaskImage>
537 typename TInputImage::PointType&, itk::ThreadIdType&)
539 itkExceptionMacro(
"Method ProcessSample not implemented !");
542 template <
class TInputImage,
class TMaskImage>
548 template <
class TInputImage,
class TMaskImage>
551 bool ret = poly->getExteriorRing()->isPointInRing(tmpPoint);
554 for (
int k = 0; k < poly->getNumInteriorRings(); k++)
556 if (poly->getInteriorRing(k)->isPointInRing(tmpPoint))
566 template <
class TInputImage,
class TMaskImage>
568 typename TInputImage::SpacingType& absSpacing, OGRPolygon& tmpPolygon)
570 tmpPolygon.getExteriorRing()->setPoint(0, position[0] - 0.5 * absSpacing[0], position[1] - 0.5 * absSpacing[1], 0.0);
571 tmpPolygon.getExteriorRing()->setPoint(1, position[0] + 0.5 * absSpacing[0], position[1] - 0.5 * absSpacing[1], 0.0);
572 tmpPolygon.getExteriorRing()->setPoint(2, position[0] + 0.5 * absSpacing[0], position[1] + 0.5 * absSpacing[1], 0.0);
573 tmpPolygon.getExteriorRing()->setPoint(3, position[0] - 0.5 * absSpacing[0], position[1] + 0.5 * absSpacing[1], 0.0);
574 tmpPolygon.getExteriorRing()->setPoint(4, position[0] - 0.5 * absSpacing[0], position[1] - 0.5 * absSpacing[1], 0.0);
575 return line->Intersects(&tmpPolygon);
578 template <
class TInputImage,
class TMaskImage>
583 OGREnvelope envelope;
584 featIt->GetGeometry()->getEnvelope(&envelope);
585 itk::Point<double, 2> lowerPoint, upperPoint;
586 lowerPoint[0] = envelope.MinX;
587 lowerPoint[1] = envelope.MinY;
588 upperPoint[0] = envelope.MaxX;
589 upperPoint[1] = envelope.MaxY;
591 typename TInputImage::IndexType lowerIndex;
592 typename TInputImage::IndexType upperIndex;
594 image->TransformPhysicalPointToIndex(lowerPoint, lowerIndex);
595 image->TransformPhysicalPointToIndex(upperPoint, upperIndex);
598 if (lowerIndex[0] > upperIndex[0])
600 int tmp = lowerIndex[0];
601 lowerIndex[0] = upperIndex[0];
604 if (lowerIndex[1] > upperIndex[1])
606 int tmp = lowerIndex[1];
607 lowerIndex[1] = upperIndex[1];
612 region.SetIndex(lowerIndex);
613 region.SetUpperIndex(upperIndex);
618 template <
class TInputImage,
class TMaskImage>
621 TInputImage* outputImage = this->GetOutput();
625 const RegionType& requestedRegion = outputImage->GetRequestedRegion();
626 itk::ContinuousIndex<double> startIndex(requestedRegion.GetIndex());
627 itk::ContinuousIndex<double> endIndex(requestedRegion.GetUpperIndex());
628 startIndex[0] += -0.5;
629 startIndex[1] += -0.5;
632 itk::Point<double, 2> startPoint;
633 itk::Point<double, 2> endPoint;
634 outputImage->TransformContinuousIndexToPhysicalPoint(startIndex, startPoint);
635 outputImage->TransformContinuousIndexToPhysicalPoint(endIndex, endPoint);
638 OGRPolygon tmpPolygon;
640 ring.addPoint(startPoint[0], startPoint[1], 0.0);
641 ring.addPoint(startPoint[0], endPoint[1], 0.0);
642 ring.addPoint(endPoint[0], endPoint[1], 0.0);
643 ring.addPoint(endPoint[0], startPoint[1], 0.0);
644 ring.addPoint(startPoint[0], startPoint[1], 0.0);
645 tmpPolygon.addRing(&ring);
649 unsigned int numberOfThreads = this->GetNumberOfThreads();
650 std::vector<ogr::Layer> tmpLayers;
651 tmpLayers.reserve(numberOfThreads);
652 for (
unsigned int i = 0; i < numberOfThreads; i++)
654 tmpLayers.push_back(this->GetInMemoryInput(i));
657 const unsigned int nbFeatThread = std::ceil(inLayer.
GetFeatureCount(
true) / (
float)numberOfThreads);
662 unsigned int counter = 0;
663 unsigned int cptFeat = 0;
664 for (; featIt != inLayer.
end(); ++featIt)
667 dstFeature.
SetFrom(*featIt, TRUE);
668 dstFeature.
SetFID(featIt->GetFID());
669 tmpLayers[counter].CreateFeature(dstFeature);
671 if (cptFeat > nbFeatThread && (counter + 1) < numberOfThreads)
681 template <
class TInputImage,
class TMaskImage>
684 TInputImage* inputImage =
const_cast<TInputImage*
>(this->GetInput());
685 inputImage->UpdateOutputInformation();
689 bool updateMode =
false;
690 if (inputDS == outputDS)
694 m_OutLayerName = inLayer.
GetName();
699 std::map<std::string, OGRFieldType> currentFields;
700 for (
int k = 0; k < layerDefn.GetFieldCount(); k++)
702 OGRFieldDefn fieldDefn(layerDefn.GetFieldDefn(k));
703 std::string currentName(fieldDefn.GetNameRef());
704 currentFields[currentName] = fieldDefn.GetType();
711 bool projectionInformationAvailable = !projectionRefWkt.empty();
712 OGRSpatialReference* oSRS =
nullptr;
713 if (projectionInformationAvailable)
715 oSRS =
static_cast<OGRSpatialReference*
>(OSRNewSpatialReference(projectionRefWkt.c_str()));
718 outLayer = outputDS->
CreateLayer(this->GetOutLayerName(), oSRS, wkbPoint, this->GetOGRLayerCreationOptions());
720 for (
int k = 0; k < layerDefn.GetFieldCount(); k++)
722 OGRFieldDefn fieldDefn(layerDefn.GetFieldDefn(k));
733 for (
unsigned int k = 0; k < m_AdditionalFields.size(); k++)
735 OGRFieldDefn ogrFieldDefinition(m_AdditionalFields[k].Name.c_str(), m_AdditionalFields[k].Type);
736 ogrFieldDefinition.SetWidth(m_AdditionalFields[k].Width);
737 ogrFieldDefinition.SetPrecision(m_AdditionalFields[k].Precision);
740 if (currentFields.count(fieldDef.
GetName()))
745 itkExceptionMacro(
"Field name " << fieldDef.
GetName() <<
" already exists with a different type!");
756 template <
class TInputImage,
class TMaskImage>
759 this->m_AdditionalFields.clear();
762 template <
class TInputImage,
class TMaskImage>
765 SimpleFieldDefn defn;
769 defn.Precision = precision;
770 this->m_AdditionalFields.push_back(defn);
773 template <
class TInputImage,
class TMaskImage>
774 const std::vector<typename PersistentSamplingFilterBase<TInputImage, TMaskImage>::SimpleFieldDefn>&
777 return this->m_AdditionalFields;
780 template <
class TInputImage,
class TMaskImage>
783 VectorThreadStruct* str = (VectorThreadStruct*)(((itk::MultiThreader::ThreadInfoStruct*)(arg))->UserData);
785 int threadId = ((itk::MultiThreader::ThreadInfoStruct*)(arg))->ThreadID;
786 int threadCount = ((itk::MultiThreader::ThreadInfoStruct*)(arg))->NumberOfThreads;
788 ogr::Layer layer = str->Filter->GetInMemoryInput(threadId);
790 if (threadId < threadCount)
792 str->Filter->ThreadedGenerateVectorData(layer, threadId);
795 return ITK_THREAD_RETURN_VALUE;
798 template <
class TInputImage,
class TMaskImage>
801 if (threadId >= m_InMemoryInputs.size())
803 itkExceptionMacro(<<
"Requested in-memory input layer not available " << threadId <<
" (total size : " << m_InMemoryInputs.size() <<
").");
805 return m_InMemoryInputs[threadId]->GetLayerChecked(0);
808 template <
class TInputImage,
class TMaskImage>
811 if (threadId >= m_InMemoryOutputs.size())
813 itkExceptionMacro(<<
"Requested in-memory output layer not available " << threadId <<
" (total size : " << m_InMemoryOutputs.size() <<
").");
815 if (index >= m_InMemoryOutputs[threadId].size())
817 itkExceptionMacro(<<
"Requested output dataset not available " << index <<
" (available : " << m_InMemoryOutputs[threadId].size() <<
").");
819 return m_InMemoryOutputs[threadId][index]->GetLayerChecked(0);