Commit 0e622ec8 authored by Cédric Traizet's avatar Cédric Traizet
Browse files

ENH: implements otb::SarSensorModel::DeburstAndConcatenate (adapted from ossimplugins)

parent 64423db9
Pipeline #7945 failed with stages
in 66 minutes and 26 seconds
......@@ -86,6 +86,26 @@ public:
bool BurstExtraction(const unsigned int burst_index, std::pair<unsigned long,unsigned long> & lines,
std::pair<unsigned long,unsigned long> & samples, bool allPixels = false);
/**
* This method will perform a deburst and concatenation operation, and return the
* vector of lines and the vector of samples to keep in the
* image file. The lines and samples represents start/size into each independent bursts.
* Note that the deburst operation has no effect if theBurstRecords
* contains a single burst. Otherwise it will merge burst together
* into a single burst, and update GCPs accordingly.
* \return true if the deburst operation succeeded. No changes is
* made to the object if the operation fails.
* \param lines A container for the lines ranges to keep in the
* deburst image.
* \param samples A container for the samples ranges to keep in the
* deburst image.
* \param lines A Boolean to indicate only valids samples are required.
*/
bool DeburstAndConcatenate(std::vector<std::pair<unsigned long,unsigned long> >& linesBursts,
std::vector<std::pair<unsigned long,unsigned long> >& samplesBursts,
unsigned int & linesOffset, unsigned int first_burstInd,
bool inputWithInvalidPixels=false);
protected:
private:
......
......@@ -858,7 +858,7 @@ bool SarSensorModel::BurstExtraction(const unsigned int burst_index,
}
std::vector<GCP> oneBurstGCPs;
// Now move GCPs
for (auto const& token : m_GCP.GCPs)
{
......@@ -904,6 +904,203 @@ bool SarSensorModel::BurstExtraction(const unsigned int burst_index,
}
bool SarSensorModel::DeburstAndConcatenate(std::vector<std::pair<unsigned long,unsigned long> >& linesBursts,
std::vector<std::pair<unsigned long,unsigned long> >& samplesBursts,
unsigned int & linesOffset,
unsigned int first_burstInd,
bool inputWithInvalidPixels)
{
auto & burstRecords = m_SarParam.burstRecords;
if (burstRecords.empty())
{
return false;
}
// declare lines and samples
std::vector<std::pair<unsigned long,unsigned long> > lines;
lines.reserve(burstRecords.size());
std::pair<unsigned long,unsigned long> samples;
// First, clear lines record
linesBursts.clear();
samplesBursts.clear();
// Check the single burst record case
if(burstRecords.size() == 1)
{
linesBursts.push_back({burstRecords.front().startLine, burstRecords.front().endLine});
samplesBursts.push_back({burstRecords.front().startLine, burstRecords.front().endLine});
return false;
}
///////// deburst operation ////////
// Process each burst
auto it = burstRecords.cbegin();
// Correct since we have at least 2 bursts records
auto next = it+1;
unsigned long currentStart = it->startLine;
TimeType deburstAzimuthStartTime = it->azimuthStartTime;
double deburstAzimuthAnxTime = it->azimuthAnxTime;
unsigned long deburstEndLine = 0;
samples = {it->startSample, it->endSample};
// Store halfLineOverlapBegin/End
std::vector<unsigned long> halfLineOverlapBegin(burstRecords.size());
std::vector<unsigned long> halfLineOverlapEnd(burstRecords.size());
halfLineOverlapBegin[0] = 0;
unsigned int counterBegin = 1;
unsigned int counterEnd = 0;
for(; next!= burstRecords.cend() ;++it,++next)
{
DurationType timeOverlapEnd = (it->azimuthStopTime - next->azimuthStartTime);
unsigned long overlapLength = timeOverlapEnd / m_SarParam.azimuthTimeInterval;
halfLineOverlapEnd[counterEnd] = overlapLength/2;
TimeType endTimeInNextBurst = it->azimuthStopTime-(halfLineOverlapEnd[counterEnd]-1)*m_SarParam.azimuthTimeInterval;
halfLineOverlapBegin[counterBegin] = std::floor(0.5+(endTimeInNextBurst-next->azimuthStartTime)/m_SarParam.azimuthTimeInterval);
unsigned long currentStop = it->endLine-halfLineOverlapEnd[counterEnd];
deburstEndLine+= currentStop - currentStart + 1; // +1 because currentStart/Stop are both valids
lines.push_back({currentStart,currentStop});
// Find the first and last valid sampleburst
if (it->startSample > samples.first)
{
samples.first = it->startSample;
}
if (it->endSample < samples.second)
{
samples.second = it->endSample;
}
++counterBegin;
++counterEnd;
}
halfLineOverlapEnd[burstRecords.size() - 1] = 0;
TimeType deburstAzimuthStopTime = it->azimuthStopTime;
deburstEndLine+=it->endLine - currentStart;
lines.push_back({currentStart,it->endLine});
if (it->startSample > samples.first)
{
samples.first = it->startSample;
}
if (it->endSample < samples.second)
{
samples.second = it->endSample;
}
// Now, update other metadata accordingly
std::vector<GCP> deburstGCPs;
for (auto gcp : m_GCP.GCPs)
{
unsigned long newLine=0;
unsigned long gcpLine = std::floor(gcp.m_GCPY + 0.5);
unsigned long gcpSample = std::floor(gcp.m_GCPX + 0.5);
// Be careful about fractional part of GCPs
double fractionalLines = gcp.m_GCPY - gcpLine;
double fractionalSamples = gcp.m_GCPX - gcpSample;
bool linesOk = ImageLineToDeburstLine(lines,gcpLine,newLine);
// Gcp into valid samples
unsigned long newSample = gcpSample;
if (linesOk && gcpSample >= samples.first && gcpSample <= samples.second)
{
newSample -= samples.first; // Offset with first valid sample
gcp.m_GCPY = newLine + fractionalLines;
gcp.m_GCPX = newSample + fractionalSamples;
deburstGCPs.push_back(gcp);
}
}
m_GCP.GCPs.swap(deburstGCPs);
///// linesBursts and samplesBursts (into Burst geometry) /////
unsigned int counter = 0;
for (const auto & burst: burstRecords)
{
unsigned long currentStart_L = halfLineOverlapBegin[counter];
if (inputWithInvalidPixels)
{
currentStart_L += burst.startLine - counter * m_SarParam.numberOfLinesPerBurst;
}
unsigned long currentStop_L = burst.endLine - burst.startLine - halfLineOverlapEnd[counter];
if (inputWithInvalidPixels)
{
currentStop_L = burst.endLine - counter * m_SarParam.numberOfLinesPerBurst - halfLineOverlapEnd[counter];
}
linesBursts.push_back({currentStart_L, currentStop_L});
unsigned long currentStart_S = 0;
unsigned long currentStop_S = samples.second-samples.first;
if (inputWithInvalidPixels)
{
currentStart_S = samples.first;
}
else if (burst.startSample < samples.first)
{
currentStart_S = samples.first - burst.startSample;
}
currentStop_S += currentStart_S;
samplesBursts.push_back({currentStart_S, currentStop_S});
++counter;
}
// Define linesOffset
linesOffset = (burstRecords[first_burstInd].azimuthStartTime - burstRecords[0].azimuthStartTime)/m_SarParam.azimuthTimeInterval;
// Clear the previous burst records
burstRecords.clear();
// Create the single burst
BurstRecord deburstBurst;
deburstBurst.startLine = 0;
deburstBurst.azimuthStartTime = deburstAzimuthStartTime;
deburstBurst.endLine = deburstEndLine;
deburstBurst.azimuthStopTime = deburstAzimuthStopTime;
deburstBurst.startSample = 0;
deburstBurst.endSample = samples.second - samples.first;
deburstBurst.azimuthAnxTime = deburstAzimuthAnxTime;
burstRecords.push_back(deburstBurst);
// Adapt general metadata : theNearRangeTime, first_time_line, last_time_line
//redaptMedataAfterDeburst = true;
m_FirstLineTime = deburstBurst.azimuthStartTime;
m_LastLineTime = deburstBurst.azimuthStopTime;
m_SarParam.nearRangeTime += samples.first*(1/m_SarParam.rangeSamplingRate);
return true;
}
bool SarSensorModel::ImageLineToDeburstLine(const std::vector<std::pair<unsigned long,unsigned long> >& lines,
unsigned long imageLine,
unsigned long & deburstLine) const
......
......@@ -51,6 +51,20 @@
using namespace boost::unit_test;
template<class T>
void PrintVectorOfPair(T input, const std::string & name)
{
std::cout << name << ": ";
for (const auto & elem: input)
{
std::cout << "[" << elem.first << "," << elem.second << "] ";
}
std::cout << std::endl;
}
BOOST_AUTO_TEST_CASE(SARDeburst)
{
BOOST_TEST_REQUIRE( framework::master_test_suite().argc == 2 );
......@@ -80,12 +94,8 @@ BOOST_AUTO_TEST_CASE(SARDeburst)
BOOST_TEST(model.Deburst(deburstLines, deburstSamples));
}
std::cout << "Deburst lines: ";
for (const auto & elem: deburstLines)
{
std::cout << "[" << elem.first << "," << elem.second << "] ";
}
std::cout << std::endl;
PrintVectorOfPair(deburstLines, "Deburst lines");
std::cout << "Deburst Samples: " << deburstSamples.first << " " << deburstSamples.second << std::endl;
......@@ -100,6 +110,23 @@ BOOST_AUTO_TEST_CASE(SARDeburst)
BOOST_TEST(model.BurstExtraction(burstIndex, burstExtractionLines, burstExtractionSamples, allPixel));
}
std::cout << "Deburst and concatenate" << std::endl;
std::vector<std::pair<unsigned long,unsigned long> > linesBursts;
std::vector<std::pair<unsigned long,unsigned long> > samplesBursts;
unsigned int linesOffset;
unsigned int first_burstInd = 3;
bool inputWithInvalidPixels = false;
{
otb::SarSensorModel model(productType, sarParam, gcpParam);
BOOST_TEST(model.DeburstAndConcatenate(linesBursts, samplesBursts, linesOffset, first_burstInd, inputWithInvalidPixels));
}
PrintVectorOfPair(linesBursts, "DeburstAndConcatenate: LinesBursts");
PrintVectorOfPair(samplesBursts, "DeburstAndConcatenate: SamplesBursts");
std::cout << "DeburstAndConcatenate: lines Offset: " << linesOffset << std::endl;
// the code below uses OssimPlugins to validate the results OTB (see ossimSentinel1ModelTest).
// TODO: generate baselines instead.
......@@ -127,15 +154,9 @@ BOOST_AUTO_TEST_CASE(SARDeburst)
std::cout<<"Deburst succeed: "<<(deburstOk?"yes":"no")<<std::endl;
for (const auto & elem: deburstLinesOssim)
{
std::cout << "[" << elem.first << "," << elem.second << "] ";
}
std::cout << std::endl;
PrintVectorOfPair(deburstLinesOssim, "deburstLinesOssim");
std::cout << deburstSamplesOssim.first << " " << deburstSamplesOssim.second << std::endl;
std::cout << "-------------------------------------------------" << std::endl;
BOOST_CHECK(deburstSamples == deburstSamplesOssim);
BOOST_CHECK(deburstLines.size() == deburstLinesOssim.size()
&& std::equal(deburstLines.begin(), deburstLines.end(), deburstLinesOssim.begin()));
......@@ -171,4 +192,28 @@ BOOST_AUTO_TEST_CASE(SARDeburst)
BOOST_CHECK(burstExtractionLines == ossimBurstExtractionLines);
BOOST_CHECK(burstExtractionSamples == ossimBurstExtractionSamples);
std::auto_ptr<ossimProjection> projection3
(ossimplugins::ossimPluginProjectionFactory::instance()->createProjection(annotationXml, 42));
auto * sensor3 = dynamic_cast<ossimplugins::ossimSentinel1Model*>(projection3.get());
if (!sensor3)
{
throw std::runtime_error(
"Unlike Expectations, the annotation file ("+annotationXml+") is not a Sentinel Annotation File");
}
std::cout << "Deburst and concatenate" << std::endl;
unsigned int ossimLinesOffset;
std::vector<std::pair<unsigned long,unsigned long> > ossimLinesBursts;
std::vector<std::pair<unsigned long,unsigned long> > ossimSamplesBursts;
BOOST_TEST(sensor3->deburstAndConcatenate(ossimLinesBursts, ossimSamplesBursts, ossimLinesOffset, first_burstInd, inputWithInvalidPixels));
PrintVectorOfPair(ossimLinesBursts, "DeburstAndConcatenate: ossimLinesBursts");
PrintVectorOfPair(ossimSamplesBursts, "DeburstAndConcatenate: ossimSamplesBursts");
std::cout << "DeburstAndConcatenate: lines Offset ossim: " << linesOffset << std::endl;
BOOST_CHECK(linesBursts == ossimLinesBursts);
BOOST_CHECK(samplesBursts == ossimSamplesBursts);
BOOST_CHECK(linesOffset == ossimLinesOffset);
}
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment