diff --git a/Modules/Adapters/OSSIMAdapters/include/otbSarSensorModelAdapter.h b/Modules/Adapters/OSSIMAdapters/include/otbSarSensorModelAdapter.h index 0e63717b7f1a080563235e9edc4e8442f2d5dcc3..a9630c1d379f2789e88fc0b192301b38ab46714c 100644 --- a/Modules/Adapters/OSSIMAdapters/include/otbSarSensorModelAdapter.h +++ b/Modules/Adapters/OSSIMAdapters/include/otbSarSensorModelAdapter.h @@ -85,6 +85,10 @@ public: bool Deburst(std::vector<std::pair<unsigned long, unsigned long> > & lines, std::pair<unsigned long,unsigned long> & samples, bool onlyValidSample=false); + /** Burst extraction and return lines/samples to keep into image file (the required burst) */ + bool BurstExtraction(const unsigned int burst_index, std::pair<unsigned long,unsigned long> & lines, + std::pair<unsigned long,unsigned long> & samples); + /** Transform world point (lat,lon,hgt) to input image point (col,row) and YZ frame */ diff --git a/Modules/Adapters/OSSIMAdapters/src/otbSarSensorModelAdapter.cxx b/Modules/Adapters/OSSIMAdapters/src/otbSarSensorModelAdapter.cxx index 8e2dd04c56017d1d9da73819cc4f578cd88648b4..75b9fb5c7720a6f1952ba6ef03454f0e3cb9c4de 100644 --- a/Modules/Adapters/OSSIMAdapters/src/otbSarSensorModelAdapter.cxx +++ b/Modules/Adapters/OSSIMAdapters/src/otbSarSensorModelAdapter.cxx @@ -101,6 +101,19 @@ bool SarSensorModelAdapter::Deburst(std::vector<std::pair<unsigned long, unsigne return false; } +bool SarSensorModelAdapter::BurstExtraction(const unsigned int burst_index, + std::pair<unsigned long,unsigned long> & lines, + std::pair<unsigned long,unsigned long> & samples) +{ + if(m_SensorModel.get()) + { + return m_SensorModel->burstExtraction(burst_index, lines, samples); + } + + return false; +} + + bool SarSensorModelAdapter::ImageLineToDeburstLine(const std::vector<std::pair<unsigned long,unsigned long> >& lines, unsigned long imageLine, unsigned long & deburstLine) { return ossimplugins::ossimSarSensorModel::imageLineToDeburstLine(lines,imageLine,deburstLine); diff --git a/Modules/Applications/AppSARCalibration/app/CMakeLists.txt b/Modules/Applications/AppSARCalibration/app/CMakeLists.txt index 4360104d2a87f0b4995f15c2a36fde004f786096..8c3e3337e372276066ebe0f4105cb0c2fb19e18f 100644 --- a/Modules/Applications/AppSARCalibration/app/CMakeLists.txt +++ b/Modules/Applications/AppSARCalibration/app/CMakeLists.txt @@ -27,3 +27,8 @@ otb_create_application( NAME SARDeburst SOURCES otbSARDeburst.cxx LINK_LIBRARIES ${${otb-module}_LIBRARIES}) + +otb_create_application( + NAME SARBurstExtraction + SOURCES otbSARBurstExtraction.cxx + LINK_LIBRARIES ${${otb-module}_LIBRARIES}) diff --git a/Modules/Applications/AppSARCalibration/app/otbSARBurstExtraction.cxx b/Modules/Applications/AppSARCalibration/app/otbSARBurstExtraction.cxx new file mode 100644 index 0000000000000000000000000000000000000000..797c9c536bb6b1ad34ac5494323bcbb59ce60b04 --- /dev/null +++ b/Modules/Applications/AppSARCalibration/app/otbSARBurstExtraction.cxx @@ -0,0 +1,198 @@ +/* + * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES) + * + * This file is part of Orfeo Toolbox + * + * https://www.orfeo-toolbox.org/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "otbWrapperApplication.h" +#include "otbWrapperApplicationFactory.h" + +#include "otbSarBurstExtractionImageFilter.h" + +namespace otb +{ +namespace Wrapper +{ +class SARBurstExtraction : public Application +{ +public: + /** Standard class typedefs. */ + typedef SARBurstExtraction Self; + typedef Application Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + /** Standard macro */ + itkNewMacro(Self); + + itkTypeMacro(SARBurstExtraction, otb::Application); + + typedef otb::SarBurstExtractionImageFilter<FloatVectorImageType> BurstExtractionFilterType; + +private: + void DoInit() override + { + SetName("SARBurstExtraction"); + SetDescription("This application performs a burst extraction by keeping only lines and samples of a required burst."); + + // Documentation + SetDocName("SAR Burst Extraction"); + SetDocLongDescription("Sentinel1 IW SLC products are composed of several burst overlapping in" + " azimuth time for each subswath, separated by black lines [1]. The burst" + " extraction consist in extracting a single burst, by selecting only lines" + " and samples of the wanted burst.\n\n" + + "Note that the output sensor model is updated accordingly. This burst" + " extraction is the perfect preprocessing step for S1 IW SLC" + " product with OTB without suffering from artifacts caused by" + " bursts separation."); + + SetDocLimitations("Only Sentinel1 IW SLC products are supported for now. Processing of" + " other Sentinel1 modes or TerrasarX images will result in no changes in" + " the image and metadata. Images from other sensors will lead to an" + " error."); + + SetDocAuthors("OTB-Team"); + SetDocSeeAlso("[1] Sentinel1 User Handbook, p. 52: https://sentinel.esa.int/documents/247904/685163/Sentinel-1_User_Handbook\n"); + + AddDocTag(Tags::SAR); + AddDocTag(Tags::Calibration); + + AddParameter(ParameterType_InputImage, "in", "Input Sentinel1 IW SLC Image"); + SetParameterDescription("in", "Raw Sentinel1 IW SLC image, or any extract of such made by OTB (geom file needed)"); + + AddParameter(ParameterType_Int, "burstindex", "Index of Burst"); + SetParameterDescription("burstindex", "Index for the required Burst (By default -1). If this parameter remains at -1, all bursts will be extracted"); + MandatoryOff("burstindex"); + SetDefaultParameterInt("burstindex", -1); + + AddParameter(ParameterType_OutputImage, "out", "Output Image"); + SetParameterDescription("out", "The output filename will be used to get the prefix " + "and the extension of thise output written's image. For example with outimage.tif as" + "output filename, the generated images will had an indice (corresponding at each " + "burst) between the prefix and the extension, such as: outimage_Burst0.tif and " + "outimage_Burst1.tif (if 2 bursts)."); + + AddRAMParameter(); + + SetDocExampleParameterValue("in","s1_iw_slc.tif"); + SetDocExampleParameterValue("out","s1_iw_slc_burst0.tif"); + + SetOfficialDocLink(); + } + + void DoUpdateParameters() override + {} + + void DoExecute() override + { + // Get the input complex image + FloatVectorImageType* in = GetParameterImage("in"); + + // Get the Burst index + int burst_index = GetParameterInt("burstindex"); // If -1 or > nb_Bursts => all bursts will be extracted + + + // Get the path/fileWithoutextension/extension of the output images filename + std::string path, fname, ext; + std::string ofname = GetParameterString("out"); + + // Get the extension and the prefix of the filename + path = itksys::SystemTools::GetFilenamePath(ofname); + fname = itksys::SystemTools::GetFilenameWithoutExtension(ofname); + ext = itksys::SystemTools::GetFilenameExtension(ofname); + + // Set the filer input + m_BurstExtractionFilter = BurstExtractionFilterType::New(); + m_BurstExtractionFilter->SetInput(in); + + // Get the number of Bursts + unsigned int nbBursts = 1; + try + { + nbBursts = std::stoi(in->GetImageKeywordlist().GetMetadataByKey("support_data.geom.bursts.number")); + } + catch( ... ) + { + // Throw an execption + throw std::runtime_error("Failed to retrieve bursts.number value from .geom file."); + } + + bool extractAll = false; + if (burst_index <= -1 || burst_index >= static_cast<int>(nbBursts)) + { + extractAll = true; + } + + + // Extract burst index only + if (! extractAll) + { + // Set the burst index + m_BurstExtractionFilter->SetBurstIndex(burst_index); + + SetParameterOutputImage("out", m_BurstExtractionFilter->GetOutput()); + + } + // Extract all bursts + else + { + for (unsigned int i = 0; i < nbBursts; ++i) + { + // Set the burst index + m_BurstExtractionFilter->SetBurstIndex(i); + + // Build the current output filename + std::ostringstream oss; + if (!path.empty()) + { + oss <<path<<"/"; + } + oss <<fname<<"_burst"<<i<<ext; + + // Create an output parameter to write the current output image + OutputImageParameter::Pointer paramOut = OutputImageParameter::New(); + + // Writer label + std::ostringstream osswriter; + osswriter<< "writer (Burst : "<< i<<")"; + + // Set the filename of the current output image + paramOut->SetFileName(oss.str()); + otbAppLogINFO(<< "File: "<<paramOut->GetFileName() << " will be written."); + paramOut->SetValue(m_BurstExtractionFilter->GetOutput()); + paramOut->SetPixelType(this->GetParameterOutputImagePixelType("out")); + // Add the current level to be written + paramOut->InitializeWriters(); + AddProcess(paramOut->GetWriter(), osswriter.str()); + paramOut->Write(); + } + + // Disable the output Image parameter to avoid writing + // the last image (Application::ExecuteAndWriteOutput method) + DisableParameter("out"); + } + RegisterPipeline(); + } + + BurstExtractionFilterType::Pointer m_BurstExtractionFilter; + +}; +} +} + +OTB_APPLICATION_EXPORT(otb::Wrapper::SARBurstExtraction) diff --git a/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.h b/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.h new file mode 100644 index 0000000000000000000000000000000000000000..501c1f68394d864f869cb36c29d85d9f2ee8603f --- /dev/null +++ b/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.h @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES) + * + * This file is part of Orfeo Toolbox + * + * https://www.orfeo-toolbox.org/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef otbSarBurstExtractionImageFilter_h +#define otbSarBurstExtractionImageFilter_h + +#include "itkImageToImageFilter.h" +#include "itkSmartPointer.h" + +namespace otb +{ +/** \class SarBurstExtractionImageFilter + * \brief Performs a burst extraction by keeping only lines and samples + * of a required Burst + * + * This filter performs a burst extraction by keeping only lines and samples + * of a required burst. This operation is useful when dealing with + * Sentinel1 IW SLC products, where each subswath is composed of + * several overlapping burst separated by black lines. The aim is to separate + * bursts to be able to process each burst independently. + * The output image represents only one burst and is smaller in azimuth and range + * direction than the input line. This filter is the perfect preprocessing step + * to process each burst of S1 IW SLC product with OTB without suffering from + * artifacts caused by bursts separation. + * + * Note that currently only Sentinel1 IW SLC products are supported. + * + * \ingroup OTBSARCalibration + */ + +template <class TImage> class ITK_EXPORT SarBurstExtractionImageFilter : + public itk::ImageToImageFilter<TImage,TImage> +{ +public: + // Standard class typedefs + typedef SarBurstExtractionImageFilter Self; + typedef itk::ImageToImageFilter<TImage,TImage> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + + itkNewMacro(Self); + itkTypeMacro(SarBurstExtractionImageFilter,ImageToImageFilter); + + typedef TImage ImageType; + typedef typename ImageType::RegionType RegionType; + typedef typename ImageType::PointType PointType; + + typedef std::pair<unsigned long, unsigned long> RecordType; + typedef std::vector<RecordType> LinesRecordVectorType; + + // Setter + itkSetMacro(BurstIndex, unsigned int); + +protected: + // Constructor + SarBurstExtractionImageFilter(); + + // Destructor + virtual ~SarBurstExtractionImageFilter() override {}; + + // Needs to be re-implemented since size of output is modified + virtual void GenerateOutputInformation() override; + + // Needs to be re-implemented since size of output is modified + virtual void GenerateInputRequestedRegion() override; + + // Actual processing + virtual void ThreadedGenerateData(const RegionType& outputRegionForThread, itk::ThreadIdType threadId) override; + + RegionType OutputRegionToInputRegion(const RegionType& outputRegion) const; + +private: + SarBurstExtractionImageFilter(const Self&) = delete; + void operator=(const Self &) = delete; + + // Pair for sample valid selection + RecordType m_LinesRecord; + + // Pair for sample valid selection + RecordType m_SamplesRecord; + + unsigned int m_BurstIndex; + + +}; + +} // End namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbSarBurstExtractionImageFilter.hxx" +#endif + + + +#endif diff --git a/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.hxx b/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.hxx new file mode 100644 index 0000000000000000000000000000000000000000..da63ad09dbcdb3a62b3cd9567b3331da5dc8b711 --- /dev/null +++ b/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.hxx @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2005-2017 Centre National d'Etudes Spatiales (CNES) + * + * This file is part of Orfeo Toolbox + * + * https://www.orfeo-toolbox.org/ + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef otbSarBurstExtractionImageFilter_hxx +#define otbSarBurstExtractionImageFilter_hxx + +#include "otbSarBurstExtractionImageFilter.h" + +#include "otbSarSensorModelAdapter.h" +#include "otbImageKeywordlist.h" +#include "itkImageScanlineIterator.h" +#include "itkImageScanlineConstIterator.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" + +namespace otb +{ +// Constructor +template <class TImage> SarBurstExtractionImageFilter<TImage>::SarBurstExtractionImageFilter() + : m_LinesRecord(), m_SamplesRecord(), m_BurstIndex(0) +{} + +// Needs to be re-implemented since size of output is modified +template< class TImage> +void +SarBurstExtractionImageFilter<TImage>::GenerateOutputInformation() +{ + // Call superclass implementation + Superclass::GenerateOutputInformation(); + + // Retrieve the input image pointer + const ImageType * inputPtr = this->GetInput(); + ImageType * outputPtr = this->GetOutput(); + + // Check that azimuth spacing has not been modified + if(std::abs(inputPtr->GetSignedSpacing()[1]-1.)>=std::numeric_limits<double>::epsilon()) + itkExceptionMacro("Can not perform deburst if input image azimuth spacing is not 1."); + + // Check that the azimuth sampling grid has not been modified + if(std::abs(inputPtr->GetOrigin()[1]-static_cast<long>(inputPtr->GetOrigin()[1])-0.5)>=std::numeric_limits<double>::epsilon()) + itkExceptionMacro("Can not perform burst extraction if input image azimuth origin is not N.5"); + + // Retrieve input image keywordlist + ImageKeywordlist inputKwl = inputPtr->GetImageKeywordlist(); + + // Try to create a SarSensorModelAdapter + SarSensorModelAdapter::Pointer sarSensorModel = SarSensorModelAdapter::New(); + bool loadOk = sarSensorModel->LoadState(inputKwl); + + if(!loadOk || !sarSensorModel->IsValidSensorModel()) + itkExceptionMacro(<<"Input image does not contain a valid SAR sensor model."); + + // Try to call the burst extraction function + bool burstExtractionOk = sarSensorModel->BurstExtraction(m_BurstIndex, m_LinesRecord, m_SamplesRecord); + + if(!burstExtractionOk) + itkExceptionMacro(<<"Could not etract Burst from input image"); + + // Compute the actual lines to remove + typename ImageType::RegionType largestPossibleRegion = this->GetInput()->GetLargestPossibleRegion(); + typename ImageType::PointType origin = this->GetInput()->GetOrigin(); + + // Export the new keywordlist + ImageKeywordlist newKwl; + + bool saveOk = sarSensorModel->SaveState(newKwl); + + if(!saveOk) + itkExceptionMacro(<<"Could not export deburst SAR sensor model to keyword list"); + + outputPtr->SetOrigin(origin); + + // Compute deburst azimuth size + typename ImageType::SizeType burstSize = largestPossibleRegion.GetSize(); + + burstSize[0] = m_SamplesRecord.second - m_SamplesRecord.first + 1; + burstSize[1] = m_LinesRecord.second - m_LinesRecord.first + 1; + + + // Set largest possible region + typename ImageType::RegionType outputLargestPossibleRegion = largestPossibleRegion; + largestPossibleRegion.SetSize(burstSize); + outputPtr->SetLargestPossibleRegion(largestPossibleRegion); + + newKwl.AddKey("support_data_number_samples", std::to_string(burstSize[0])); + newKwl.AddKey("support_data_number_lines", std::to_string(burstSize[1])); + + // Set new keyword list to output image + outputPtr->SetImageKeywordList(newKwl); +} + +template<class TImage> +typename SarBurstExtractionImageFilter<TImage>::RegionType +SarBurstExtractionImageFilter<TImage>::OutputRegionToInputRegion(const RegionType& outputRegion) const +{ + RegionType inputRegion = outputRegion; + + typename RegionType::IndexType index = inputRegion.GetIndex(); + + index[0] += m_SamplesRecord.first; + index[1] += m_LinesRecord.first; + + inputRegion.SetIndex(index); + + return inputRegion; +} + + +// Needs to be re-implemented since size of output is modified +template <class TImage> void SarBurstExtractionImageFilter<TImage>::GenerateInputRequestedRegion() +{ + RegionType outputRequestedRegion = this->GetOutput()->GetRequestedRegion(); + RegionType inputRequestedRegion = OutputRegionToInputRegion(outputRequestedRegion); + + ImageType * inputPtr = const_cast<ImageType *>(this->GetInput()); + + inputPtr->SetRequestedRegion(inputRequestedRegion); +} + + +// Actual processing +template <class TImage> +void +SarBurstExtractionImageFilter<TImage>::ThreadedGenerateData(const RegionType& outputRegionForThread, + itk::ThreadIdType itkNotUsed(threadId)) +{ + // Compute corresponding input region + RegionType inputRegionForThread = OutputRegionToInputRegion(outputRegionForThread); + + itk::ImageRegionConstIterator<ImageType> inputIt(this->GetInput(),inputRegionForThread); + itk::ImageRegionIterator<ImageType> outputIt(this->GetOutput(),outputRegionForThread); + + inputIt.GoToBegin(); + outputIt.GoToBegin(); + + while(!inputIt.IsAtEnd()&&!outputIt.IsAtEnd()) + { + typename ImageType::IndexType currentInputIndex = inputIt.GetIndex(); + + bool lineToKeep = false; + bool sampleToKeep = false; + + // Check lines + if (currentInputIndex[1] >= static_cast<int>(m_LinesRecord.first) && + currentInputIndex[1] <= static_cast<int>(m_LinesRecord.second)) + { + lineToKeep = true; + } + + // Check samples + if (currentInputIndex[0] >= static_cast<int>(m_SamplesRecord.first) && + currentInputIndex[0] <= static_cast<int>(m_SamplesRecord.second)) + { + sampleToKeep = true; + } + + // If ok, copy input pixel into output image + if(lineToKeep && sampleToKeep) + { + outputIt.Set(inputIt.Get()); + + ++outputIt; + } + + ++inputIt; + } +} + +} // End namespace otb + +#endif diff --git a/Modules/ThirdParty/OssimPlugins/include/ossim/ossimSarSensorModel.h b/Modules/ThirdParty/OssimPlugins/include/ossim/ossimSarSensorModel.h index c3f6731c11f6c59effec84e1c101a476cc33c752..990bb434c70dabea4fdd78a986cbc1a2a2232c76 100644 --- a/Modules/ThirdParty/OssimPlugins/include/ossim/ossimSarSensorModel.h +++ b/Modules/ThirdParty/OssimPlugins/include/ossim/ossimSarSensorModel.h @@ -321,6 +321,20 @@ public: */ static void deburstLineToImageLine(const std::vector<std::pair<unsigned long,unsigned long> >& lines, unsigned long deburstLine, unsigned long & imageLine); + /** + * This method will perform an extration of one burst. It wil return the + * lines and samples to extract in the image file. + * \return true if the extraction operation succeeded. No changes is + * made to the object if the operation fails. + * \param burst_index Index of Burst. + * \param lines A container for the lines to keep in the + * standalone burst. + * \param samples A container for the samples to keep in the + * standalone burst. + */ + bool burstExtraction(const unsigned int burst_index, std::pair<unsigned long,unsigned long> & lines, + std::pair<unsigned long,unsigned long> & samples); + /** * Returns pointer to a new instance, copy of this. */ diff --git a/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSarSensorModel.cpp b/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSarSensorModel.cpp index 505bc70c2c1bd3bf0f6539be0949f39953d09f9a..89a8e82b9592316deccdc7b4531d413051d1a31f 100644 --- a/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSarSensorModel.cpp +++ b/Modules/ThirdParty/OssimPlugins/src/ossim/ossimSarSensorModel.cpp @@ -1583,7 +1583,7 @@ bool ossimSarSensorModel::deburst(std::vector<std::pair<unsigned long, unsigned // Adapt general metadata : theNearRangeTime, first_time_line, last_time_line - redaptMedataAfterDeburst = false; + redaptMedataAfterDeburst = true; theFirstLineTime = deburstBurst.azimuthStartTime; theLastLineTime = deburstBurst.azimuthStopTime; @@ -1594,6 +1594,97 @@ bool ossimSarSensorModel::deburst(std::vector<std::pair<unsigned long, unsigned return true; } + +bool +ossimSarSensorModel::burstExtraction(const unsigned int burst_index, + std::pair<unsigned long,unsigned long> & lines, + std::pair<unsigned long,unsigned long> & samples) +{ + if(theBurstRecords.empty()) + return false; + + // Check the single burst record case + if(theBurstRecords.size() == 1) + { + lines = std::make_pair(theBurstRecords.front().startLine,theBurstRecords.front().endLine); + return false; + } + + // Retrieve into TheBurstRecord, the required index + BurstRecordType burstInd_Record = theBurstRecords.at(burst_index); + lines = std::make_pair(burstInd_Record.startLine, burstInd_Record.endLine); + samples = std::make_pair(burstInd_Record.startSample, burstInd_Record.endSample); + TimeType burstAzimuthStartTime = burstInd_Record.azimuthStartTime; + TimeType burstAzimuthStopTime = burstInd_Record.azimuthStopTime; + + // Clear the previous burst records + theBurstRecords.clear(); + + // Create the single burst + BurstRecordType oneBurst; + oneBurst.startLine = 0; + oneBurst.azimuthStartTime = burstAzimuthStartTime; + oneBurst.endLine = lines.second - lines.first; + oneBurst.azimuthStopTime = burstAzimuthStopTime; + oneBurst.startSample = 0; + oneBurst.endSample = samples.second - samples.first; + + theBurstRecords.push_back(oneBurst); + + + std::vector<GCPRecordType> oneBurstGCPs; + + // Now move GCPs + for(std::vector<GCPRecordType>::iterator gcpIt = theGCPRecords.begin(); gcpIt!=theGCPRecords.end();++gcpIt) + { + GCPRecordType currentGCP = *gcpIt; + + unsigned long gcpLine = std::floor(currentGCP.imPt.y+0.5); + unsigned long gcpSample = std::floor(currentGCP.imPt.x+0.5); + + // Be careful about fractional part of GCPs + double fractionalLines = currentGCP.imPt.y - gcpLine; + double fractionalSamples = currentGCP.imPt.x - gcpSample; + + + // Gcp into valid samples and valid lines + unsigned long newSample = gcpSample; + bool samplesOk = false; + + if (gcpSample >= samples.first && gcpSample <= samples.second) + { + samplesOk = true; + newSample -= samples.first; // Offset with first valid sample + } + + unsigned long newLine = gcpLine; + bool linesOk = false; + + if (gcpLine >= lines.first && gcpLine <= lines.second) + { + linesOk = true; + newLine -= lines.first; // Offset with first valid line + } + + if(linesOk && samplesOk) + { + currentGCP.imPt.y = newLine + fractionalLines; + currentGCP.imPt.x = newSample + fractionalSamples; + oneBurstGCPs.push_back(currentGCP); + } + } + + theGCPRecords.swap(oneBurstGCPs); + + // Adapt general metadata : theNearRangeTime, first_time_line, last_time_line + redaptMedataAfterDeburst = true; + theFirstLineTime = oneBurst.azimuthStartTime; + theLastLineTime = oneBurst.azimuthStopTime; + theNearRangeTime += samples.first*(1/theRangeSamplingRate); + + return true; +} + bool ossimSarSensorModel::imageLineToDeburstLine(const std::vector<std::pair<unsigned long,unsigned long> >& lines, unsigned long imageLine, unsigned long & deburstLine) { std::vector<std::pair<unsigned long,unsigned long> >::const_iterator vit = lines.begin();