diff --git a/Modules/Applications/AppSARCalibration/app/otbSARBurstExtraction.cxx b/Modules/Applications/AppSARCalibration/app/otbSARBurstExtraction.cxx index 4a742ec73e71e5e4fffb907200064ccddd1939a6..b92fa4568413c721712c66a32391a7eae617b180 100644 --- a/Modules/Applications/AppSARCalibration/app/otbSARBurstExtraction.cxx +++ b/Modules/Applications/AppSARCalibration/app/otbSARBurstExtraction.cxx @@ -64,7 +64,10 @@ private: 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."); + " error." + " Burst extraction needs as inputs a image composed of several Bursts. A burst has to " + " contain all its lines in order to have a correct extraction. " + " ie : Careful with ROI."); SetDocAuthors("OTB-Team"); SetDocSeeAlso("[1] Sentinel1 User Handbook, p. 52: https://sentinel.esa.int/documents/247904/685163/Sentinel-1_User_Handbook\n"); diff --git a/Modules/Applications/AppSARCalibration/app/otbSARConcatenateBursts.cxx b/Modules/Applications/AppSARCalibration/app/otbSARConcatenateBursts.cxx index f048d701fa4daf32fe6b93cdfa0218860b83bcaf..36623f15b7ccf9757bf970f319c6bdb8279a8013 100644 --- a/Modules/Applications/AppSARCalibration/app/otbSARConcatenateBursts.cxx +++ b/Modules/Applications/AppSARCalibration/app/otbSARConcatenateBursts.cxx @@ -62,7 +62,9 @@ private: SetDocLongDescription("This application performs a burst concatenation and provides a SAR Deburst Image. " "It reads the input image list (single bursts) " "and generates a whole SAR image with deburst operations."); - SetDocLimitations("Only Sentinel1 IW SLC products are supported for now."); + SetDocLimitations("Only Sentinel1 IW SLC products are supported for now. In order to concatenate several" + " bursts, all valid lines of each burst are required as inputs." + "ie : Careful with ROI extraction inside a Burst."); SetDocAuthors("OTB-Team"); AddDocTag(Tags::SAR); @@ -118,10 +120,12 @@ private: throw std::runtime_error("Failed to retrieve bursts.number value from .geom file."); } - if (inList->Size() != nbBursts) + nbBursts = inList->Size(); + + /*if (inList->Size() != nbBursts) { throw std::runtime_error("Failed to concatenate bursts. Some bursts are missing."); - } + }*/ // Coniguration for fusion filter fusionFilter->SetSLCImageKeyWorList(in->GetImageKeywordlist()); @@ -133,13 +137,31 @@ private: FloatVectorImageType::Pointer vectIm = inList->GetNthElement(i); vectIm->UpdateOutputInformation(); + unsigned long originOffset_samples = static_cast<long>(vectIm->GetOrigin()[0]-0.5); + unsigned long originOffset_lines = static_cast<long>(vectIm->GetOrigin()[1]-0.5); + // Retrieve start and size for each burst std::pair<unsigned long,unsigned long> line = lines[i]; std::pair<unsigned long,unsigned long> sample = samples[i]; - unsigned long startL = line.first; - unsigned long startS = sample.first; - unsigned long sizeL = line.second - line.first + 1; - unsigned long sizeS = sample.second - sample.first + 1; + + int minSamples = std::min(sample.second, vectIm->GetLargestPossibleRegion().GetSize()[0]-1); + int minLines = std::min(line.second, vectIm->GetLargestPossibleRegion().GetSize()[1]-1); + + unsigned long startL = line.first - originOffset_lines; + unsigned long sizeL = minLines - line.first + 1; + unsigned long startS = sample.first - originOffset_samples; + unsigned long sizeS = minSamples - sample.first + 1; + // Readjust if origin is superior to the first selected line/sample for the current burst + if (line.first < originOffset_lines) + { + startL = 0; + sizeL = minLines - line.first - originOffset_lines + 1; + } + if (sample.first < originOffset_samples) + { + startS = 0; + sizeS = minSamples - sample.first - originOffset_samples + 1; + } ExtractROIFilterType::Pointer extractor = ExtractROIFilterType::New(); extractor->SetInput(vectIm); diff --git a/Modules/Applications/AppSARCalibration/test/CMakeLists.txt b/Modules/Applications/AppSARCalibration/test/CMakeLists.txt index 1ca0afb569f058654d1df161432d920c8eb66df2..eabd2ace9d092b6dea7faf1551f371b78fe67e8d 100644 --- a/Modules/Applications/AppSARCalibration/test/CMakeLists.txt +++ b/Modules/Applications/AppSARCalibration/test/CMakeLists.txt @@ -54,3 +54,23 @@ otb_test_application(NAME apTvRaSarDeburst_SENTINEL1 # Same baseline as filter test ${BASELINE}/saTvSarDeburstImageFilterTestOutput.tif ${TEMP}/apTvRaSarDeburst_SENTINEL1_output.tif) + +otb_test_application(NAME apTvRaSarBurstExtraction_SENTINEL1 + APP SARBurstExtraction + OPTIONS -in ${INPUTDATA}/s1a-iw1-slc-vv-20170111_Burst01_amp.tiff + -out ${TEMP}/apTvRaSarBurstExtraction_SENTINEL1_output.tif uint16 + -burstindex 0 + VALID --compare-image ${NOTOL} + # Same baseline as filter test + ${BASELINE}/apTvRaSarBurstExtraction_SENTINEL1_output.tif + ${TEMP}/apTvRaSarBurstExtraction_SENTINEL1_output.tif) + +otb_test_application(NAME apTvRaSarConcatenateBursts_SENTINEL1 + APP SARConcatenateBursts + OPTIONS -il ${INPUTDATA}/s1a-iw1-slc-vv-20170111_Burst0_amp.tif ${INPUTDATA}/s1a-iw1-slc-vv-20170111_Burst1_amp.tif + -insar ${INPUTDATA}/s1a-iw1-slc-vv-20170111_Burst01_amp.tiff + -out ${TEMP}/apTvRaSarConcatenateBursts_SENTINEL1_output.tif uint16 + VALID --compare-image ${NOTOL} + # Same baseline as filter test + ${BASELINE}/apTvRaSarConcatenateBursts_SENTINEL1_output.tif + ${TEMP}/apTvRaSarConcatenateBursts_SENTINEL1_output.tif) diff --git a/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.hxx b/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.hxx index 7c686bb1806d41b010823da3ea3ace802fa866f8..8c077a2e2d9467ee6a0bc8ca5901ecd24883a216 100644 --- a/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.hxx +++ b/Modules/Radiometry/SARCalibration/include/otbSarBurstExtractionImageFilter.hxx @@ -85,15 +85,46 @@ SarBurstExtractionImageFilter<TImage>::GenerateOutputInformation() if(!saveOk) itkExceptionMacro(<<"Could not export deburst SAR sensor model to keyword list"); - outputPtr->SetOrigin(origin); - - // Compute deburst azimuth size + // Move origin and size (if necessary) + long originOffset_samples = static_cast<long>(this->GetInput()->GetOrigin()[0]-0.5); + long originOffset_lines = static_cast<long>(this->GetInput()->GetOrigin()[1]-0.5); + unsigned long outputOriginSample = 0; + unsigned long outputOriginLine = 0; + typename ImageType::SizeType burstSize = largestPossibleRegion.GetSize(); - burstSize[0] = m_SamplesRecord.second - m_SamplesRecord.first + 1; - burstSize[1] = m_LinesRecord.second - m_LinesRecord.first + 1; - + if (static_cast<int>(m_SamplesRecord.first) > originOffset_samples) + { + outputOriginSample = 0; + } + else + { + outputOriginSample = originOffset_samples - static_cast<int>(m_SamplesRecord.first); + } + + if (static_cast<int>(m_LinesRecord.first) > originOffset_lines) + { + outputOriginLine = 0; + } + else + { + outputOriginLine = originOffset_lines - static_cast<int>(m_LinesRecord.first); + } + + long firstOutSample = static_cast<long>(std::max( static_cast<long>(m_SamplesRecord.first), originOffset_samples)); + long secondOutSample = static_cast<long>(std::min(m_SamplesRecord.second, largestPossibleRegion.GetSize()[0] + originOffset_samples - 1)); + + long firstOutLine = static_cast<long>(std::max(static_cast<long>(m_LinesRecord.first), originOffset_lines)); + long secondOutLine = static_cast<long>(std::min(m_LinesRecord.second, largestPossibleRegion.GetSize()[1] + originOffset_lines - 1)); + + burstSize[0] = secondOutSample - firstOutSample + 1; + burstSize[1] = secondOutLine - firstOutLine + 1; + + origin[0]=0.5+outputOriginSample; + origin[1]=0.5+outputOriginLine; + outputPtr->SetOrigin(origin); + // Set largest possible region typename ImageType::RegionType outputLargestPossibleRegion = largestPossibleRegion; largestPossibleRegion.SetSize(burstSize); @@ -117,9 +148,18 @@ SarBurstExtractionImageFilter<TImage>::OutputRegionToInputRegion(const RegionTyp typename RegionType::IndexType index = inputRegion.GetIndex(); - index[0] += m_SamplesRecord.first; - index[1] += m_LinesRecord.first; - + long originOffset = static_cast<long>(this->GetInput()->GetOrigin()[1]-0.5); + long originOffset_samples = static_cast<long>(this->GetInput()->GetOrigin()[0]-0.5); + + if (static_cast<int>(m_SamplesRecord.first) > originOffset_samples) + { + index[0] += m_SamplesRecord.first - originOffset_samples; + } + if (static_cast<int>(m_LinesRecord.first) > originOffset) + { + index[1] += m_LinesRecord.first - originOffset; + } + inputRegion.SetIndex(index); return inputRegion; @@ -161,20 +201,22 @@ SarBurstExtractionImageFilter<TImage>::ThreadedGenerateData(const RegionType& ou while(!inputIt.IsAtEnd()&&!outputIt.IsAtEnd()) { typename ImageType::IndexType currentInputIndex = inputIt.GetIndex(); - + PointType currentInputPoint; + this->GetInput()->TransformIndexToPhysicalPoint(currentInputIndex,currentInputPoint); + bool lineToKeep = false; bool sampleToKeep = false; // Check lines - if (currentInputIndex[1] >= linesRecordFirst && - currentInputIndex[1] <= linesRecordSecond) + if (currentInputPoint[1]-0.5 >= linesRecordFirst && + currentInputPoint[1]-0.5 <= linesRecordSecond) { lineToKeep = true; } // Check samples - if (currentInputIndex[0] >= samplesRecordFirst && - currentInputIndex[0] <= samplesRecordSecond) + if (currentInputPoint[0]-0.5 >= samplesRecordFirst && + currentInputPoint[0]-0.5 <= samplesRecordSecond) { sampleToKeep = true; } diff --git a/Modules/Radiometry/SARCalibration/include/otbSarDeburstImageFilter.hxx b/Modules/Radiometry/SARCalibration/include/otbSarDeburstImageFilter.hxx index 1058436ceb4b914fd1991c360b0a1a97989b4afe..7e919e0556eb0c4351b1e447f954c79651227eea 100644 --- a/Modules/Radiometry/SARCalibration/include/otbSarDeburstImageFilter.hxx +++ b/Modules/Radiometry/SARCalibration/include/otbSarDeburstImageFilter.hxx @@ -96,7 +96,20 @@ SarDeburstImageFilter<TImage>::GenerateOutputInformation() unsigned long outputOriginLine = 0; SarSensorModelAdapter::ImageLineToDeburstLine(m_LinesRecord,firstInputLine,outputOriginLine); - // std::cout<<"OutputOriginLine: "<<outputOriginLine<<std::endl; + long originOffset_samples = static_cast<long>(this->GetInput()->GetOrigin()[0]-0.5); + unsigned long outputOriginSample = 0; + if (m_OnlyValidSample) + { + if (static_cast<int>(m_SamplesRecord.first) > originOffset_samples) + { + outputOriginSample = 0; + } + else + { + outputOriginSample = originOffset_samples - static_cast<int>(m_SamplesRecord.first); + } + origin[0]=0.5+outputOriginSample; + } origin[1]=0.5+outputOriginLine; outputPtr->SetOrigin(origin); @@ -122,6 +135,8 @@ SarDeburstImageFilter<TImage>::GenerateOutputInformation() // TODO: Ensure that records are sorted ? + + // Compute deburst azimuth size typename ImageType::SizeType deburstSize = largestPossibleRegion.GetSize(); deburstSize[1]=0; @@ -135,9 +150,13 @@ SarDeburstImageFilter<TImage>::GenerateOutputInformation() if (m_OnlyValidSample) { - deburstSize[0] = m_SamplesRecord.second - m_SamplesRecord.first + 1; + long minEnd = static_cast<long>(std::min(m_SamplesRecord.second, + largestPossibleRegion.GetSize()[0] + originOffset_samples-1)); + long maxStart = static_cast<long>(std::max(static_cast<long>(m_SamplesRecord.first), + originOffset_samples)); + deburstSize[0] = minEnd - maxStart + 1; } - + // Set largest possible region typename ImageType::RegionType outputLargestPossibleRegion = largestPossibleRegion; largestPossibleRegion.SetSize(deburstSize); @@ -176,6 +195,7 @@ SarDeburstImageFilter<TImage>::OutputRegionToInputRegion(const RegionType& outpu SarSensorModelAdapter::DeburstLineToImageLine(m_LinesRecord,lowerLeftLine,inputLowerLeftLine); long originOffset = static_cast<long>(this->GetInput()->GetOrigin()[1]-0.5); + long originOffset_samples = static_cast<long>(this->GetInput()->GetOrigin()[0]-0.5); inputUpperLeftLine-=originOffset; inputLowerLeftLine-=originOffset; @@ -184,11 +204,13 @@ SarDeburstImageFilter<TImage>::OutputRegionToInputRegion(const RegionType& outpu typename RegionType::SizeType size = inputRegion.GetSize(); typename RegionType::IndexType index = inputRegion.GetIndex(); - + if (m_OnlyValidSample) { - index[0]+= m_SamplesRecord.first; - //size[0]+= m_SamplesRecord.first; + if (static_cast<int>(m_SamplesRecord.first) > originOffset_samples) + { + index[0]+= m_SamplesRecord.first - originOffset_samples; + } } index[1]=inputUpperLeftLine; @@ -309,8 +331,8 @@ SarDeburstImageFilter<TImage>::ThreadedGenerateDataWithOnlyValidSamples(const Re } } - if (currentInputIndex[0] >= static_cast<int>(m_SamplesRecord.first) && - currentInputIndex[0] <= static_cast<int>(m_SamplesRecord.second)) + if (currentInputPoint[0]-0.5 >= static_cast<int>(m_SamplesRecord.first) && + currentInputPoint[1]-0.5 <= static_cast<int>(m_SamplesRecord.second)) { sampleToKeep = true; } diff --git a/Modules/Radiometry/SARCalibration/test/CMakeLists.txt b/Modules/Radiometry/SARCalibration/test/CMakeLists.txt index 1c8f86f42639f2b3ffb247677b0ac42ad914323e..ae7b2bb8356bfc1a58de54394acefbd4ad9b1575 100644 --- a/Modules/Radiometry/SARCalibration/test/CMakeLists.txt +++ b/Modules/Radiometry/SARCalibration/test/CMakeLists.txt @@ -42,6 +42,7 @@ otbTerraSarBrightnessImageComplexFilterTest.cxx otbSarRadiometricCalibrationToImageFilterWithComplexPixelTest.cxx otbSarBrightnessToImageFilterTest.cxx otbSarDeburstFilterTest.cxx +otbSarBurstExtractionFilterTest.cxx ) add_executable(otbSARCalibrationTestDriver ${OTBSARCalibrationTests}) @@ -297,3 +298,39 @@ otb_add_test(NAME saTvSarDeburstImageFilterTest COMMAND otbSARCalibrationTestDri otbSarDeburstFilterTest ${INPUTDATA}/s1a-iw1-slc-vh-amp_xt.tif ${TEMP}/saTvSarDeburstImageFilterTestOutput.tif) + +otb_add_test(NAME saTvSarDeburstImageFilterTest2 COMMAND otbSARCalibrationTestDriver + --compare-image ${NOTOL} + ${BASELINE}/saTvSarDeburstImageFilterTest2Output.tif + ${TEMP}/saTvSarDeburstImageFilterTest2Output.tif + otbSarDeburstFilterTest + ${INPUTDATA}/s1a-iw1-slc-vv-20170111_Burst01_amp.tiff + ${TEMP}/saTvSarDeburstImageFilterTest2Output.tif) + +otb_add_test(NAME saTvSarDeburstImageFilterTest3 COMMAND otbSARCalibrationTestDriver + --compare-image ${NOTOL} + ${BASELINE}/saTvSarDeburstImageFilterTest3Output.tif + ${TEMP}/saTvSarDeburstImageFilterTest3Output.tif + otbSarDeburstFilterTest + ${INPUTDATA}/s1a-iw1-slc-vv-20170111_Burst01_amp.tiff + ${TEMP}/saTvSarDeburstImageFilterTest3Output.tif + WithOnlyValidSamples) + + +otb_add_test(NAME saTvSarBurstExtractionImageFilterTest1 COMMAND otbSARCalibrationTestDriver + --compare-image ${NOTOL} + ${BASELINE}/saTvSarBurstImageFilterTest1Output.tif + ${TEMP}/saTvSarBurstImageFilterTest1Output.tif + otbSarBurstExtractionFilterTest + ${INPUTDATA}/s1a-iw1-slc-vv-20170111_Burst01_amp.tiff + ${TEMP}/saTvSarBurstImageFilterTest1Output.tif + 0) + +otb_add_test(NAME saTvSarBurstExtractionImageFilterTest2 COMMAND otbSARCalibrationTestDriver + --compare-image ${NOTOL} + ${BASELINE}/saTvSarBurstImageFilterTest2Output.tif + ${TEMP}/saTvSarBurstImageFilterTest2Output.tif + otbSarBurstExtractionFilterTest + ${INPUTDATA}/s1a-iw1-slc-vv-20170111_Burst01_amp.tiff + ${TEMP}/saTvSarBurstImageFilterTest2Output.tif + 1) diff --git a/Modules/Radiometry/SARCalibration/test/otbSARCalibrationTestDriver.cxx b/Modules/Radiometry/SARCalibration/test/otbSARCalibrationTestDriver.cxx index 35733b76f1852d7435fcdf2c9f8d4a09dc7a4361..3438d9c62eaeda5ad791ba0a5e711bc953e4b416 100644 --- a/Modules/Radiometry/SARCalibration/test/otbSARCalibrationTestDriver.cxx +++ b/Modules/Radiometry/SARCalibration/test/otbSARCalibrationTestDriver.cxx @@ -42,4 +42,5 @@ void RegisterTests() REGISTER_TEST(otbSarRadiometricCalibrationToImageFilterWithComplexPixelTest); REGISTER_TEST(otbSarBrightnessToImageFilterTest); REGISTER_TEST(otbSarDeburstFilterTest); + REGISTER_TEST(otbSarBurstExtractionFilterTest); } diff --git a/Modules/Radiometry/SARCalibration/test/otbSarBurstExtractionFilterTest.cxx b/Modules/Radiometry/SARCalibration/test/otbSarBurstExtractionFilterTest.cxx new file mode 100644 index 0000000000000000000000000000000000000000..e0602f305e91da342a60b5e384258602cf542881 --- /dev/null +++ b/Modules/Radiometry/SARCalibration/test/otbSarBurstExtractionFilterTest.cxx @@ -0,0 +1,63 @@ +/* + * 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 "otbSarBurstExtractionImageFilter.h" +#include "otbImage.h" +#include "otbImageFileReader.h" +#include "otbImageFileWriter.h" + +typedef otb::Image<unsigned short> ImageType; +typedef otb::ImageFileReader<ImageType> ReaderType; +typedef otb::ImageFileWriter<ImageType> WriterType; +typedef otb::SarBurstExtractionImageFilter<ImageType> BurstExtractionFilterType; + +int otbSarBurstExtractionFilterTest(int itkNotUsed(argc), char * argv[]) +{ + ReaderType::Pointer reader = ReaderType::New(); + reader->SetFileName(argv[1]); + + BurstExtractionFilterType::Pointer filter = BurstExtractionFilterType::New(); + filter->SetInput(reader->GetOutput()); + filter->SetBurstIndex(std::stoi(argv[3])); + + WriterType::Pointer writer = WriterType::New(); + writer->SetInput(filter->GetOutput()); + writer->SetFileName(argv[2]); + writer->Update(); + + // check that there is now a single burst in data + reader = ReaderType::New(); + reader->SetFileName(argv[2]); + reader->UpdateOutputInformation(); + + unsigned int nb_bursts = atoi(reader->GetOutput()->GetImageKeywordlist().GetMetadataByKey("support_data.geom.bursts.number").c_str()); + + if(nb_bursts != 1) + { + std::cerr<<"Error: more than 1 burst ("<<nb_bursts<<" bursts) found in output metadata."<<std::endl; + } + else + { + std::cout<<"Metadata have a single burst as expected."<<std::endl; + } + + return EXIT_SUCCESS; +} + diff --git a/Modules/Radiometry/SARCalibration/test/otbSarDeburstFilterTest.cxx b/Modules/Radiometry/SARCalibration/test/otbSarDeburstFilterTest.cxx index d221088626f509462223f9cbbb93a6ce8d96c75a..deac69d67dfad7a7dc8b28a1126945dfe5676a7f 100644 --- a/Modules/Radiometry/SARCalibration/test/otbSarDeburstFilterTest.cxx +++ b/Modules/Radiometry/SARCalibration/test/otbSarDeburstFilterTest.cxx @@ -28,13 +28,20 @@ typedef otb::ImageFileReader<ImageType> ReaderType; typedef otb::ImageFileWriter<ImageType> WriterType; typedef otb::SarDeburstImageFilter<ImageType> DeburstFilterType; -int otbSarDeburstFilterTest(int itkNotUsed(argc), char * argv[]) +int otbSarDeburstFilterTest(int argc, char * argv[]) { ReaderType::Pointer reader = ReaderType::New(); reader->SetFileName(argv[1]); + bool onlyValidSamples = false; + if (argc == 4) + { + onlyValidSamples = true; + } + DeburstFilterType::Pointer filter = DeburstFilterType::New(); filter->SetInput(reader->GetOutput()); + filter->SetOnlyValidSample(onlyValidSamples); WriterType::Pointer writer = WriterType::New(); writer->SetInput(filter->GetOutput());