Commit b0193e0e authored by Guillaume Pasero's avatar Guillaume Pasero

Merge branch 'appli_new_services' into 'develop'

ApplicationEngine new services

See merge request orfeotoolbox/otb!29
parents f799a74a c9f5f978
......@@ -173,6 +173,142 @@ implementation does not break it, for instance by using an internal
writer to write intermediate data. In this case, execution should
still be correct, but some intermediate data will be read or written.
Interactions with OTB pipeline
------------------------------
[Since OTB 6.6]
The application framework has been extended in order to provide ways to
interact with the pipelines inside each application. It applies only to
applications that use input or output images. Let's check what are the
functions added to the ``Application`` class. There are a lot of getter
functions:
+---------------------------------+---------------------------------------+
| Function name | return value |
+=================================+=======================================+
| ``GetImageOrigin(...)`` | origin of the image (physical position|
| | of the first pixel center) |
+---------------------------------+---------------------------------------+
| ``GetImageSpacing(...)`` | signed spacing of the image |
+---------------------------------+---------------------------------------+
| ``GetImageSize(...)`` | size of the LargestPossibleRegion |
+---------------------------------+---------------------------------------+
| ``GetImageNbBands(...)`` | number of components per pixel |
+---------------------------------+---------------------------------------+
| ``GetImageProjection(...)`` | Projection WKT string |
+---------------------------------+---------------------------------------+
| ``GetImageKeywordlist(...)`` | Ossim keywordlist (sensor model) |
+---------------------------------+---------------------------------------+
| ``GetImageMetaData(...)`` | the entire MetaDataDictionary |
+---------------------------------+---------------------------------------+
| ``GetImageRequestedRegion(...)``| requested region |
+---------------------------------+---------------------------------------+
| ``GetImageBasePixelType(...)`` | pixel type of the underlying |
| | Image/VectorImage. |
+---------------------------------+---------------------------------------+
All these getters functions use the following arguments:
* ``key``: a string containing the key of the image parameter
* ``idx``: an optional index (default is 0) that can be used to access ImageList
parameters transparently
There is also a function to send orders to the pipeline:
``PropagateRequestedRegion(key, region, idx=0)``: sets a given RequestedRegion
on the image and propagate it, returns the memory print estimation. This function
can be used to measure the requested portion of input images necessary to produce
an extract of the full output.
Note: a requested region (like other regions in the C++ API of otb::Image) is
just a pair of an image index and a size, that define a rectangular extract of
the full image.
This set of function has been used to enhance the bridge between OTB images
and Numpy arrays. There are now import and export functions available in
Python that preserve the metadata of the image during conversions to Numpy
arrays:
* ``ExportImage(self, key)``: exports an output image parameter into a Python
dictionary.
* ``ImportImage(self, key, dict, index=0)``: imports the image from a Python
dictionary into an image parameter (as a monoband image).
* ``ImportVectorImage(self, key, dict, index=0)``: imports the image from a
Python dictionary into an image parameter (as a multiband image).
The Python dictionary used has the following entries:
* ``'array'``: the Numpy array containing the pixel buffer
* ``'origin'``: origin of the image
* ``'spacing'``: signed spacing of the image
* ``'size'``: full size of the image
* ``'region'``: region of the image present in the buffer
* ``'metadata'``: metadata dictionary (contains projection, sensor model,...)
Now some basic Q&A about this interface:
Q: What portion of the image is exported to Numpy array?
A: By default, the whole image is exported. If you had a non-empty requested
region (the result of calling PropagateRequestedRegion()), then this region
is exported.
Q: What is the difference between ImportImage and ImportVectorImage?
A: The first one is here for Applications that expect a monoband otb::Image.
In most cases, you will use the second one: ImportVectorImage.
Q: What kind of object are there in this dictionary export?
A: The array is a numpy.ndarray. The other fields are wrapped
objects from the OTB library but you can interact with them in a
Python way: they support ``len()`` and ``str()`` operator, as well as
bracket operator ``[]``. Some of them also have a ``keys()`` function just like
dictionaries.
This interface allows you to export OTB images (or extracts) to Numpy array,
process them by other means, and re-import them with preserved metadatas. Please
note that this is different from an in-memory connection.
Here is a small example of what can be done:
.. code-block:: python
import otbApplication as otb
# Create a smoothing application
app = otb.Registry.CreateApplication("Smoothing")
app.SetParameterString("in",argv[1])
# only call Execute() to setup the pipeline, not ExecuteAndWriteOutput() which would
# run it and write the output image
app.Execute()
# Setup a special requested region
myRegion = otb.itkRegion()
myRegion['size'][0] = 20
myRegion['size'][1] = 25
myRegion['index'].Fill(10)
ram = app.PropagateRequestedRegion("out",myRegion)
# Check the requested region on the input image
print(app.GetImageRequestedRegion("in"))
# Create a ReadImageInfo application
app2 = otb.Registry.CreateApplication("ReadImageInfo")
# export "out" from Smoothing and import it as "in" in ReadImageInfo
ex = app.ExportImage("out")
app2.ImportVectorImage("in", ex)
app2.Execute()
# Check the result of ReadImageInfo
someKeys = ['sizex', 'sizey', 'spacingx', 'spacingy', 'sensor', 'projectionref']
for key in someKeys:
print(key + ' : ' + str(app2.GetParameterValue(key)) )
# Only a portion of "out" was exported but ReadImageInfo is still able to detect the
# correct full size of the image
Corner cases
------------
......
......@@ -49,18 +49,18 @@ namespace internal
}
template < class InputImage , typename SpacingType >
void SetSignedSpacing( InputImage input , SpacingType spacing )
void SetSignedSpacing( InputImage *input , SpacingType spacing )
{
// TODO check for spacing size ==> error
typename InputImage::DirectionType direction = input->GetDirection();
for ( unsigned int i = 0 ; i < InputImage::VImageDimension ; i++ )
for ( unsigned int i = 0 ; i < InputImage::ImageDimension ; i++ )
{
// TODO check if spacing[i] = 0 ==> error
if ( spacing[ i ] < 0 )
{
if ( direction[i][i] > 0 )
{
for ( unsigned int j = 0 ; j < InputImage::VImageDimension ; j++ )
for ( unsigned int j = 0 ; j < InputImage::ImageDimension ; j++ )
{
direction[j][i] = - direction[j][i];
}
......
......@@ -114,7 +114,7 @@ public:
itkSetObjectMacro(DataToWrite, DataObjectType);
/** Compute pipeline memory print */
void Compute();
void Compute(bool propagate=true);
/** Const conversion factor */
static const double ByteToMegabyte;
......
......@@ -71,15 +71,18 @@ PipelineMemoryPrintCalculator
void
PipelineMemoryPrintCalculator
::Compute()
::Compute(bool propagate)
{
// Clear the visited process objects set
m_VisitedProcessObjects.clear();
// Dry run of pipeline synchronisation
m_DataToWrite->UpdateOutputInformation();
m_DataToWrite->SetRequestedRegionToLargestPossibleRegion();
m_DataToWrite->PropagateRequestedRegion();
if (propagate)
{
m_DataToWrite->UpdateOutputInformation();
m_DataToWrite->SetRequestedRegionToLargestPossibleRegion();
m_DataToWrite->PropagateRequestedRegion();
}
// Get the source process object
ProcessObjectType * source = m_DataToWrite->GetSource();
......
......@@ -478,7 +478,7 @@ public:
* \throw itk::Exception if parameter is not found or not an
* InputImageParameter
*/
void SetParameterInputImage(std::string parameter, InputImageParameter::ImageBaseType * inputImage);
void SetParameterInputImage(std::string parameter, ImageBaseType * inputImage);
/**
* Get the output image parameter as an ImageBase * instead
......@@ -489,7 +489,7 @@ public:
* \throw itk::Exception if parameter is not found or not an
* OutputImageParameter
*/
OutputImageParameter::ImageBaseType * GetParameterOutputImage(std::string parameter);
ImageBaseType * GetParameterOutputImage(std::string parameter);
/**
* Set the input complex image parameter as an ImageBase * instead
......@@ -500,7 +500,7 @@ public:
* \throw itk::Exception if parameter is not found or not an
* ComplexInputImageParameter
*/
void SetParameterComplexInputImage(std::string parameter, ComplexInputImageParameter::ImageBaseType * inputImage);
void SetParameterComplexInputImage(std::string parameter, ImageBaseType * inputImage);
/**
* Get the complex output image parameter as an ImageBase * instead
......@@ -511,7 +511,7 @@ public:
* \throw itk::Exception if parameter is not found or not an
* ComplexOutputImageParameter
*/
ComplexOutputImageParameter::ImageBaseType * GetParameterComplexOutputImage(std::string parameter);
ImageBaseType * GetParameterComplexOutputImage(std::string parameter);
/**
* Add an image to an InputImageList parameter as an ImageBase
......@@ -522,7 +522,7 @@ public:
* \throw itk::Exception if parameter is not found or not an
* InputImageList parameter
*/
void AddImageToParameterInputImageList(std::string parameter, InputImageListParameter::ImageBaseType * img);
void AddImageToParameterInputImageList(std::string parameter, ImageBaseType * img);
/**
* Set the nth image of an InputImageList parameter as an ImageBase pointer
......@@ -534,7 +534,7 @@ public:
* \throw itk::Exception if parameter is not found or not an
* InputImageList parameter or if id is out of bounds
*/
void SetNthParameterInputImageList(std::string parameter, const unsigned int &id, InputImageListParameter::ImageBaseType * img);
void SetNthParameterInputImageList(std::string parameter, const unsigned int &id, ImageBaseType * img);
/**
* Add a value to a parameter list as a string
......@@ -847,6 +847,73 @@ public:
this->SetDocLink(link);
}
/** Get the origin of the image parameter 'key'. The optional 'idx' allows
* to select the image in an InputImageList. */
ImageBaseType::PointType GetImageOrigin(const std::string & key, unsigned int idx = 0);
/** Get the spacing of the image parameter 'key'. The optional 'idx' allows to
* select the image in an InputImageList. We use the signed spacing convention. */
ImageBaseType::SpacingType GetImageSpacing(const std::string & key, unsigned int idx = 0);
/** Get the size of the image parameter 'key'. The optional 'idx' allows to
* select the image in an InputImageList. It corresponds to the size of LargestPossibleRegion*/
ImageBaseType::SizeType GetImageSize(const std::string & key, unsigned int idx = 0);
/** Get the number of bands in the image parameter 'key'. The optional 'idx'
* allows to select the image in an InputImageList.*/
unsigned int GetImageNbBands(const std::string & key, unsigned int idx = 0);
/** Get the projection of the image parameter 'key'. The optional 'idx' allows
* to select the image in an InputImageList.*/
std::string GetImageProjection(const std::string & key, unsigned int idx = 0);
/** Get the keywordlist of the image parameter 'key'. The optional 'idx'
* allows to select the image in an InputImageList.*/
otb::ImageKeywordlist GetImageKeywordlist(const std::string & key, unsigned int idx = 0);
/** Set the requested region on the image parameter 'key' and propagate it.
* The returned value is an estimate of the RAM usage (in Bytes) to process
* this region. It should be assumed that the index of the largest possible
* region starts at (0,0). The optional 'idx' allows to select the image in
* an InputImageList*/
unsigned long PropagateRequestedRegion(const std::string & key, ImageBaseType::RegionType region, unsigned int idx = 0);
/** Get the requested region of the image parameter 'key'. The optional 'idx'
* allows to select the image in an InputImageList. It should be assumed that
* the index of the largest possible region starts at (0,0).*/
ImageBaseType::RegionType GetImageRequestedRegion(const std::string & key, unsigned int idx = 0);
/** Returns a copy of the metadata dictionary of the image */
itk::MetaDataDictionary GetImageMetaData(const std::string & key, unsigned int idx = 0);
/** Find out what is the pixel type from an image parameter
* This function assumes that the underlying object is either an otb::Image
* or an otb::VectorImage. The optional 'idx' allows to access InputImageList.
*/
ImagePixelType GetImageBasePixelType(const std::string & key, unsigned int idx = 0);
/** Return the image from parameter 'key' as a base type. The optional 'idx'
* allows to access InputImageList.
*
* Works on parameters:
* \li ParameterType_InputImage
* \li ParameterType_InputImageList
* \li ParameterType_OutputImage
* \li ParameterType_ComplexInputImage
* \li ParameterType_ComplexOutputImage
*/
ImageBaseType* GetParameterImageBase(const std::string & key, unsigned int idx = 0);
/** Set the image in parameter 'key' as a base type. The optional 'idx'
* allows to access InputImageList.
*
* Works on parameters:
* \li ParameterType_InputImage
* \li ParameterType_InputImageList
* \li ParameterType_ComplexInputImage
*/
void SetParameterImageBase(const std::string & key, ImageBaseType* img, unsigned int idx = 0);
protected:
/** Constructor */
Application();
......
......@@ -44,8 +44,6 @@ public:
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
typedef itk::ImageBase<2> ImageBaseType;
/** Defining ::New() static method */
itkNewMacro(Self);
......
......@@ -132,6 +132,10 @@ ComplexInputImageParameter::GetImage()
}
}
/** declare a specialization for ImageBaseType */
template <>
ImageBaseType*
ComplexInputImageParameter::GetImage();
template <class TComplexInputImage, class TOutputImage>
TOutputImage*
......
......@@ -44,8 +44,6 @@ public:
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
typedef itk::ImageBase<2> ImageBaseType;
/** Defining ::New() static method */
itkNewMacro(Self);
......
......@@ -48,8 +48,6 @@ public:
typedef itk::SmartPointer< Self > Pointer;
typedef itk::SmartPointer< const Self > ConstPointer;
typedef itk::ImageBase< 2 > ImageBaseType;
/** Defining ::New() static method */
itkNewMacro( Self );
......
......@@ -44,8 +44,6 @@ public:
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
typedef itk::ImageBase<2> ImageBaseType;
/** Defining ::New() static method */
itkNewMacro(Self);
......
......@@ -215,6 +215,10 @@ InputImageParameter::GetImage()
}
}
/** declare a specialization for ImageBaseType */
template <>
ImageBaseType*
InputImageParameter::GetImage();
template <class TInputImage, class TOutputImage>
TOutputImage*
......
/*
* 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 otbWrapperMetaDataHelper_h
#define otbWrapperMetaDataHelper_h
#include "otbMetaDataKey.h"
#include "otbImageKeywordlist.h"
#include "otbVectorDataKeywordlist.h"
#include "itkMetaDataDictionary.h"
#include "OTBApplicationEngineExport.h"
namespace otb
{
namespace Wrapper
{
/**
* \namespace MetaDataHelper
*
* \brief Contains small helper functions to manipulate itk::MetaDataDictionary
*
* These functions are only here to instanciate the different template function that
* allow to get/set values in MetaDataDictionary.
*
*/
namespace MetaDataHelper
{
enum class MDType
{
String,
Int,
Double,
GCP,
Vector,
ImageKWL,
VectorDataKWL,
BoolVector
};
OTBApplicationEngine_EXPORT MDType GetType(const std::string &val);
OTBApplicationEngine_EXPORT std::string GetString(
const itk::MetaDataDictionary &dict,
const std::string &key);
OTBApplicationEngine_EXPORT void SetString(
itk::MetaDataDictionary &dict,
const std::string &key,
const std::string &val);
OTBApplicationEngine_EXPORT unsigned int GetInt(
const itk::MetaDataDictionary &dict,
const std::string &key);
OTBApplicationEngine_EXPORT void SetInt(
itk::MetaDataDictionary &dict,
const std::string &key,
unsigned int val);
OTBApplicationEngine_EXPORT double GetDouble(
const itk::MetaDataDictionary &dict,
const std::string &key);
OTBApplicationEngine_EXPORT void SetDouble(
itk::MetaDataDictionary &dict,
const std::string &key,
double val);
OTBApplicationEngine_EXPORT otb::OTB_GCP GetGCP(
const itk::MetaDataDictionary &dict,
const std::string &key);
OTBApplicationEngine_EXPORT void SetGCP(
itk::MetaDataDictionary &dict,
const std::string &key,
const otb::OTB_GCP &val);
OTBApplicationEngine_EXPORT otb::MetaDataKey::VectorType GetVector(
const itk::MetaDataDictionary &dict,
const std::string &key);
OTBApplicationEngine_EXPORT void SetVector(
itk::MetaDataDictionary &dict,
const std::string &key,
const otb::MetaDataKey::VectorType &val);
OTBApplicationEngine_EXPORT otb::ImageKeywordlist GetImageKWL(
const itk::MetaDataDictionary &dict,
const std::string &key);
OTBApplicationEngine_EXPORT void SetImageKWL(
itk::MetaDataDictionary &dict,
const std::string &key,
const otb::ImageKeywordlist &val);
OTBApplicationEngine_EXPORT otb::VectorDataKeywordlist GetVectorDataKWL(
const itk::MetaDataDictionary &dict,
const std::string &key);
OTBApplicationEngine_EXPORT void SetVectorDataKWL(
itk::MetaDataDictionary &dict,
const std::string &key,
const otb::VectorDataKeywordlist &val);
OTBApplicationEngine_EXPORT otb::MetaDataKey::BoolVectorType GetBoolVector(
const itk::MetaDataDictionary &dict,
const std::string &key);
OTBApplicationEngine_EXPORT void SetBoolVector(
itk::MetaDataDictionary &dict,
const std::string &key,
const otb::MetaDataKey::BoolVectorType &val);
} // end of namespace MetaDataHelper
} // end of namespace Wrapper
} // end of namespace otb
#endif
......@@ -45,8 +45,6 @@ public:
typedef itk::SmartPointer<Self> Pointer;
typedef itk::SmartPointer<const Self> ConstPointer;
typedef itk::ImageBase<2> ImageBaseType;
/** Defining ::New() static method */
itkNewMacro(Self);
......
......@@ -154,6 +154,8 @@ typedef otb::ObjectList<VectorDataType> VectorDataListType;
typedef otb::ObjectList<FloatVectorImageType> FloatVectorImageListType;
typedef otb::ObjectList<FloatImageType> FloatImageListType;
typedef itk::ImageBase<2> ImageBaseType;
} // end namespace Wrapper
} // end namespace otb
......
......@@ -57,6 +57,7 @@ set( OTBApplicationEngine_SRC
otbWrapperAbstractParameterList.cxx
otbWrapperParameterList.cxx
otbWrapperBoolParameter.cxx
otbWrapperMetaDataHelper.cxx
)
add_library(OTBApplicationEngine ${OTBApplicationEngine_SRC})
......
......@@ -1223,7 +1223,7 @@ Application
return ret;
}
void Application::SetParameterInputImage(std::string parameter, InputImageParameter::ImageBaseType * inputImage)
void Application::SetParameterInputImage(std::string parameter, ImageBaseType * inputImage)
{
Parameter* param = GetParameterByKey(parameter);
......@@ -1239,7 +1239,7 @@ void Application::SetParameterInputImage(std::string parameter, InputImageParame
}
}
OutputImageParameter::ImageBaseType * Application::GetParameterOutputImage(std::string parameter)
ImageBaseType * Application::GetParameterOutputImage(std::string parameter)
{
Parameter* param = GetParameterByKey(parameter);
......@@ -1256,7 +1256,7 @@ OutputImageParameter::ImageBaseType * Application::GetParameterOutputImage(std::
}
void Application::SetParameterComplexInputImage(std::string parameter, ComplexInputImageParameter::ImageBaseType * inputImage)
void Application::SetParameterComplexInputImage(std::string parameter, ImageBaseType * inputImage)
{
Parameter* param = GetParameterByKey(parameter);
......@@ -1272,7 +1272,7 @@ void Application::SetParameterComplexInputImage(std::string parameter, ComplexIn
}
}
ComplexOutputImageParameter::ImageBaseType * Application::GetParameterComplexOutputImage(std::string parameter)
ImageBaseType * Application::GetParameterComplexOutputImage(std::string parameter)
{
Parameter* param = GetParameterByKey(parameter);
......@@ -1288,7 +1288,7 @@ ComplexOutputImageParameter::ImageBaseType * Application::GetParameterComplexOut
}
}
void Application::AddImageToParameterInputImageList(std::string parameter, InputImageListParameter::ImageBaseType * img)
void Application::AddImageToParameterInputImageList(std::string parameter, ImageBaseType * img)
{
Parameter* param = GetParameterByKey(parameter);
......@@ -1305,7 +1305,7 @@ void Application::AddImageToParameterInputImageList(std::string parameter, Input
}
void Application::SetNthParameterInputImageList(std::string parameter, const unsigned int &id, InputImageListParameter::ImageBaseType * img)
void Application::SetNthParameterInputImageList(std::string parameter, const unsigned int &id, ImageBaseType * img)
{
Parameter* param = GetParameterByKey(parameter);
......@@ -1747,5 +1747,217 @@ double Application::GetLastExecutionTiming() const
return m_Chrono.GetElapsedMilliseconds() / 1000.0;
}
ImageBaseType::PointType
Application::GetImageOrigin(const std::string & key, unsigned int idx)
{
return this->GetParameterImageBase(key, idx)->GetOrigin();
}
ImageBaseType::SpacingType
Application::GetImageSpacing(const std::string & key, unsigned int idx)
{
return otb::internal::GetSignedSpacing(this->GetParameterImageBase(key, idx));
}
ImageBaseType::SizeType
Application::GetImageSize(const std::string & key, unsigned int idx)
{
return this->GetParameterImageBase(key, idx)->GetLargestPossibleRegion().GetSize();
}
unsigned int
Application::GetImageNbBands(const std::string & key, unsigned int idx)
{
return this->GetParameterImageBase(key, idx)->GetNumberOfComponentsPerPixel();
}
std::string
Application::GetImageProjection(const std::string & key, unsigned int idx)
{
std::string proj;
const itk::MetaDataDictionary& dict =
this->GetParameterImageBase(key, idx)->GetMetaDataDictionary();
if (!dict.HasKey(MetaDataKey::ProjectionRefKey))
return std::string("");
itk::ExposeMetaData<std::string>(dict, MetaDataKey::ProjectionRefKey, proj);
return proj;
}
otb::ImageKeywordlist
Application::GetImageKeywordlist(const std::string & key, unsigned int idx)
{
ImageKeywordlist kwl;
const itk::MetaDataDictionary& dict =
this->GetParameterImageBase(key, idx)->GetMetaDataDictionary();
if (dict.HasKey(MetaDataKey::OSSIMKeywordlistKey))
itk::ExposeMetaData<ImageKeywordlist>(dict, MetaDataKey::OSSIMKeywordlistKey, kwl);
return kwl;
}
unsigned long
Application::PropagateRequestedRegion(const std::string & key, ImageBaseType::RegionType region, unsigned int idx)
{
ImageBaseType* image = this->GetParameterImageBase(key, idx);
ImageBaseType::RegionType largest = image->GetLargestPossibleRegion();
ImageBaseType::RegionType requested = region;
requested.SetIndex(0, requested.GetIndex(0) + largest.GetIndex(0));
requested.SetIndex(1, requested.GetIndex(1) + largest.GetIndex(1));
image->SetRequestedRegion(requested);
image->PropagateRequestedRegion();
// estimate RAM usage
otb::PipelineMemoryPrintCalculator::Pointer memoryPrintCalculator =
otb::PipelineMemoryPrintCalculator::New();
memoryPrintCalculator->SetDataToWrite(image);
memoryPrintCalculator->SetBiasCorrectionFactor(1);
memoryPrintCalculator->Compute(false);
return memoryPrintCalculator->GetMemoryPrint();
}
ImageBaseType::RegionType
Application::GetImageRequestedRegion(const std::string & key, unsigned int idx)
{
ImageBaseType* image = this->GetParameterImageBase(key, idx);
ImageBaseType::RegionType largest = image->GetLargestPossibleRegion();
ImageBaseType::RegionType requested = image->GetRequestedRegion();
requested.SetIndex(0, requested.GetIndex(0) - largest.GetIndex(0));
requested.SetIndex(1, requested.GetIndex(1) - largest.GetIndex(1));
return requested;
}
itk::MetaDataDictionary
Application::GetImageMetaData(const std::string & key, unsigned int idx)
{
ImageBaseType* image = this->GetParameterImageBase(key, idx);
return image->GetMetaDataDictionary();
}
ImageBaseType*