-
Julien Michel authoredJulien Michel authored
otbSuperimpose.cxx 13.91 KiB
/*=========================================================================
Program: ORFEO Toolbox
Language: C++
Date: $Date$
Version: $Revision$
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
PURPOSE. See the above copyright notices for more information.
=========================================================================*/
#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"
#include "otbGenericRSResampleImageFilter.h"
#include "itkLinearInterpolateImageFunction.h"
#include "otbBCOInterpolateImageFunction.h"
#include "itkNearestNeighborInterpolateImageFunction.h"
#include "otbPleiadesImageMetadataInterface.h"
#include "itkScalableAffineTransform.h"
// Elevation handler
#include "otbWrapperElevationParametersHandler.h"
#include "otbDateTimeAdapter.h"
#include "otbStreamingResampleImageFilter.h"
namespace otb
{
enum
{
Interpolator_BCO,
Interpolator_NNeighbor,
Interpolator_Linear
};
enum
{
Mode_Default,
Mode_PHR
};
namespace Wrapper
{
class Superimpose : public Application
{
public:
/** Standard class typedefs. */
typedef Superimpose Self;
typedef Application Superclass;
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
/** Standard macro */
itkNewMacro(Self);
itkTypeMacro(Superimpose, Application);
typedef unsigned short int PixelType;
typedef itk::LinearInterpolateImageFunction
<FloatVectorImageType,
double> LinInterpolatorType;
typedef itk::NearestNeighborInterpolateImageFunction
<FloatVectorImageType,
double> NNInterpolatorType;
typedef otb::BCOInterpolateImageFunction
<FloatVectorImageType> BCOInterpolatorType;
typedef otb::GenericRSResampleImageFilter<FloatVectorImageType,
FloatVectorImageType> ResamplerType;
typedef itk::ScalableAffineTransform<double, 2> TransformType;
typedef otb::StreamingResampleImageFilter
<FloatVectorImageType,
FloatVectorImageType> BasicResamplerType;
private:
void DoInit()
{
SetName("Superimpose");
SetDescription("Using available image metadata, project one image onto another one");
// Documentation
SetDocName("Superimpose sensor");
SetDocLongDescription("This application performs the projection of an image into the geometry of another one.");
SetDocLimitations("None");
SetDocAuthors("OTB-Team");
SetDocSeeAlso(" ");
AddDocTag(Tags::Geometry);
AddDocTag("Superimposition");
AddParameter(ParameterType_InputImage, "inr", "Reference input");
SetParameterDescription("inr","The input reference image.");
AddParameter(ParameterType_InputImage, "inm", "The image to reproject");
SetParameterDescription("inm","The image to reproject into the geometry of the reference input.");
// Elevation
ElevationParametersHandler::AddElevationParameters(this, "elev");
AddParameter(ParameterType_Float, "lms", "Spacing of the deformation field");
SetParameterDescription("lms","Generate a coarser deformation field with the given spacing");
SetDefaultParameterFloat("lms", 4.);
MandatoryOff("lms");
AddParameter(ParameterType_OutputImage, "out", "Output image");
SetParameterDescription("out","Output reprojected image.");
// Superposition mode
AddParameter(ParameterType_Choice,"mode", "Mode");
SetParameterDescription("mode", "Superimposition mode");
AddChoice("mode.default", "Default mode");
SetParameterDescription("mode.default", "Default superimposition mode : "
"uses any projection reference or sensor model found in the images");
AddChoice("mode.phr", "Pleiades mode");
SetParameterDescription("mode.phr", "Pleiades superimposition mode, "
"designed for the case of a P+XS bundle in SENSOR geometry. It uses"
" a simple transform on the XS image : a scaling and a residual "
"translation.");
// Interpolators
AddParameter(ParameterType_Choice, "interpolator", "Interpolation");
SetParameterDescription("interpolator","This group of parameters allows to define how the input image will be interpolated during resampling.");
AddChoice("interpolator.bco", "Bicubic interpolation");
SetParameterDescription("interpolator.bco", "Bicubic interpolation leads to very good image quality but is slow.");
AddParameter(ParameterType_Radius, "interpolator.bco.radius", "Radius for bicubic interpolation");
SetParameterDescription("interpolator.bco.radius","This parameter allows to control the size of the bicubic interpolation filter. If the target pixel size is higher than the input pixel size, increasing this parameter will reduce aliasing artefacts.");
SetDefaultParameterInt("interpolator.bco.radius", 2);
AddChoice("interpolator.nn", "Nearest Neighbor interpolation");
SetParameterDescription("interpolator.nn","Nearest neighbor interpolation leads to poor image quality, but it is very fast.");
AddChoice("interpolator.linear", "Linear interpolation");
SetParameterDescription("interpolator.linear","Linear interpolation leads to average image quality but is quite fast");
AddRAMParameter();
// Doc example parameter settings
SetDocExampleParameterValue("inr", "QB_Toulouse_Ortho_PAN.tif");
SetDocExampleParameterValue("inm", "QB_Toulouse_Ortho_XS.tif");
SetDocExampleParameterValue("out", "SuperimposedXS_to_PAN.tif");
}
void DoUpdateParameters()
{
if (!HasUserValue("mode") &&
GetParameterInt("mode") == Mode_Default &&
HasValue("inr") &&
HasValue("inm"))
{
FloatVectorImageType* refImage = GetParameterImage("inr");
FloatVectorImageType* movingImage = GetParameterImage("inm");
bool isRefPHR = false;
bool isMovingPHR = false;
otb::PleiadesImageMetadataInterface::Pointer phrIMI =
otb::PleiadesImageMetadataInterface::New();
phrIMI->SetMetaDataDictionary(refImage->GetMetaDataDictionary());
isRefPHR = phrIMI->CanRead();
phrIMI->SetMetaDataDictionary(movingImage->GetMetaDataDictionary());
isMovingPHR = phrIMI->CanRead();
if (isRefPHR && isMovingPHR)
{
ImageKeywordlist kwlPan;
ImageKeywordlist kwlXS;
itk::ExposeMetaData<ImageKeywordlist>(
refImage->GetMetaDataDictionary(),
MetaDataKey::OSSIMKeywordlistKey,
kwlPan);
itk::ExposeMetaData<ImageKeywordlist>(
movingImage->GetMetaDataDictionary(),
MetaDataKey::OSSIMKeywordlistKey,
kwlXS);
// Get geometric processing
std::string panProcessing = kwlPan.GetMetadataByKey("support_data.processing_level");
std::string xsProcessing = kwlXS.GetMetadataByKey("support_data.processing_level");
if (panProcessing.compare("SENSOR") == 0 &&
xsProcessing.compare("SENSOR") == 0)
{
SetParameterInt("mode",Mode_PHR);
}
}
}
}
void DoExecute()
{
// Get the inputs
FloatVectorImageType* refImage = GetParameterImage("inr");
FloatVectorImageType* movingImage = GetParameterImage("inm");
// Resample filter
m_Resampler = ResamplerType::New();
m_BasicResampler = BasicResamplerType::New();
// Get Interpolator
switch ( GetParameterInt("interpolator") )
{
case Interpolator_Linear:
{
LinInterpolatorType::Pointer interpolator = LinInterpolatorType::New();
m_Resampler->SetInterpolator(interpolator);
m_BasicResampler->SetInterpolator(interpolator);
}
break;
case Interpolator_NNeighbor:
{
NNInterpolatorType::Pointer interpolator = NNInterpolatorType::New();
m_Resampler->SetInterpolator(interpolator);
m_BasicResampler->SetInterpolator(interpolator);
}
break;
case Interpolator_BCO:
{
BCOInterpolatorType::Pointer interpolator = BCOInterpolatorType::New();
interpolator->SetRadius(GetParameterInt("interpolator.bco.radius"));
m_Resampler->SetInterpolator(interpolator);
m_BasicResampler->SetInterpolator(interpolator);
}
break;
}
// Setup the DEM Handler
otb::Wrapper::ElevationParametersHandler::SetupDEMHandlerFromElevationParameters(this,"elev");
// Set up output image informations
FloatVectorImageType::SpacingType spacing = refImage->GetSpacing();
FloatVectorImageType::IndexType start = refImage->GetLargestPossibleRegion().GetIndex();
FloatVectorImageType::SizeType size = refImage->GetLargestPossibleRegion().GetSize();
FloatVectorImageType::PointType origin = refImage->GetOrigin();
FloatVectorImageType::PixelType defaultValue;
itk::NumericTraits<FloatVectorImageType::PixelType>::SetLength(defaultValue, movingImage->GetNumberOfComponentsPerPixel());
switch ( GetParameterInt("mode") )
{
case Mode_Default:
{
if(IsParameterEnabled("lms"))
{
float defScalarSpacing = vcl_abs(GetParameterFloat("lms"));
otbAppLogDEBUG("Generating coarse deformation field (spacing="<<defScalarSpacing<<")");
FloatVectorImageType::SpacingType defSpacing;
defSpacing[0] = defScalarSpacing;
defSpacing[1] = defScalarSpacing;
if (spacing[0]<0.0) defSpacing[0] *= -1.0;
if (spacing[1]<0.0) defSpacing[1] *= -1.0;
m_Resampler->SetDisplacementFieldSpacing(defSpacing);
}
// Setup transform through projRef and Keywordlist
m_Resampler->SetInputKeywordList(movingImage->GetImageKeywordlist());
m_Resampler->SetInputProjectionRef(movingImage->GetProjectionRef());
m_Resampler->SetOutputKeywordList(refImage->GetImageKeywordlist());
m_Resampler->SetOutputProjectionRef(refImage->GetProjectionRef());
m_Resampler->SetInput(movingImage);
m_Resampler->SetOutputOrigin(origin);
m_Resampler->SetOutputSpacing(spacing);
m_Resampler->SetOutputSize(size);
m_Resampler->SetOutputStartIndex(start);
m_Resampler->SetEdgePaddingValue(defaultValue);
// Set the output image
SetParameterOutputImage("out", m_Resampler->GetOutput());
}
break;
case Mode_PHR:
{
otbAppLogINFO("Using the PHR mode");
// Setup a simple affine transform using PHR support data
ImageKeywordlist kwlPan;
ImageKeywordlist kwlXS;
itk::ExposeMetaData<ImageKeywordlist>(
refImage->GetMetaDataDictionary(),
MetaDataKey::OSSIMKeywordlistKey,
kwlPan);
itk::ExposeMetaData<ImageKeywordlist>(
movingImage->GetMetaDataDictionary(),
MetaDataKey::OSSIMKeywordlistKey,
kwlXS);
// Compute time delta
std::string strStartTimePan = kwlPan.GetMetadataByKey("support_data.time_range_start");
std::string strStartTimeXS = kwlXS.GetMetadataByKey("support_data.time_range_start");
DateTimeAdapter::Pointer startTimePan = DateTimeAdapter::New();
DateTimeAdapter::Pointer startTimeXS = DateTimeAdapter::New();
startTimePan->SetFromIso8601(strStartTimePan);
startTimeXS->SetFromIso8601(strStartTimeXS);
double timeDelta = startTimeXS->GetDeltaInSeconds(startTimePan);
// Retrieve line period in Pan
std::string tmpStr = kwlPan.GetMetadataByKey("support_data.line_period");
double linePeriodPan = atof(tmpStr.c_str());
// Retrieve column start
tmpStr = kwlPan.GetMetadataByKey("support_data.swath_first_col");
int colStartPan = atoi(tmpStr.c_str());
tmpStr = kwlXS.GetMetadataByKey("support_data.swath_first_col");
int colStartXS = atoi(tmpStr.c_str());
// Compute shift between MS and P (in Pan pixels)
int lineShift_MS_P =int(vcl_floor((timeDelta/(linePeriodPan/1000)) + 0.5)) + 0.375;
int colShift_MS_P = colStartXS*4 - colStartPan - 4 + 0.375;
// Apply the scaling
TransformType::Pointer transform = TransformType::New();
transform->Scale(4.0);
// Resample filter assumes the origin is attached to the pixel center
// in order to keep the top left corners unchanged, apply a 3/2 pixels
// shift in each direction
TransformType::OutputVectorType offset;
offset[0] = 1.5 + static_cast<double>(colShift_MS_P);
offset[1] = 1.5 + static_cast<double>(lineShift_MS_P);
transform->Translate(offset);
// Invert the transform as the resampler filter expect an output-to-input
// transform (we have computed the input-to-output transform)
TransformType::Pointer realTransform = TransformType::New();
transform->GetInverse(realTransform);
m_BasicResampler->SetTransform(realTransform);
m_BasicResampler->SetInput(movingImage);
m_BasicResampler->SetOutputOrigin(origin);
m_BasicResampler->SetOutputSpacing(spacing);
m_BasicResampler->SetOutputSize(size);
m_BasicResampler->SetOutputStartIndex(start);
m_BasicResampler->SetEdgePaddingValue(defaultValue);
// Set the output image
SetParameterOutputImage("out", m_BasicResampler->GetOutput());
otbAppLogINFO("Line shift (in pix) : "<< lineShift_MS_P);
otbAppLogINFO("Col shift (in pix) : "<< colShift_MS_P);
}
break;
default:
{
otbAppLogWARNING("Unknown mode");
}
break;
}
}
ResamplerType::Pointer m_Resampler;
BasicResamplerType::Pointer m_BasicResampler;
};
} // end namespace Wrapper
} // end namespace otb
OTB_APPLICATION_EXPORT(otb::Wrapper::Superimpose)