Newer
Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
/*
* Copyright (C) 2005-2020 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 "otbNormalCompute.h"
#include "otbRepack.h"
#include "otbPositionHelpers.h"
#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"
#include "otbFunctorImageFilter.h"
#include "otbDEMHandler.h"
#include "otbSarSensorModelAdapter.h"
// Elevation handler
#include "otbWrapperElevationParametersHandler.h"
#include "itkFixedArray.h"
#include <array>
#include <cmath>
namespace // anonymous
{
/**
* Returns the lambda that'll be used to produce the normal vector at the
* center of the neighbourhood.
*
* \note As a simplification, this method ignores Geiod correction on
* neighbourhood pixels. They are all supposed identical.
* \todo Handle cases with nodata => assume the data from the center; 0 if the
* center is nodata
*/
template <typename OutputPixelType, typename InputImageType>
inline
auto AppSimpleNormalMethod(
double x_spacing,
double y_spacing,
InputImageType & image)
using InputPixelType = typename InputImageType::PixelType;
using RealType = typename itk::PixelTraits<InputPixelType>::ValueType;
using V3 = vnl_vector_fixed<RealType, 3>;
using NeighborhoodIteratorType = itk::ConstNeighborhoodIterator<InputImageType>;
// x_spacing > 0 and y_spacing > 0 ==>
// 6 7 8
// 3 4 5
// 0 1 2
// x_spacing > 0 and y_spacing < 0 ==>
// 0 1 2
// 3 4 5
// 6 7 8
// x_spacing < 0 and y_spacing > 0 ==>
// 8 7 6
// 5 4 3
// 2 1 0
auto const above = [y_spacing](NeighborhoodIteratorType const& n) { return otb::Above<V3>(otb::repack<V3>(n.GetPixel(y_spacing > 0 ? 7 : 1)));};
auto const below = [y_spacing](NeighborhoodIteratorType const& n) { return otb::Below<V3>(otb::repack<V3>(n.GetPixel(y_spacing > 0 ? 1 : 7)));};
auto const left = [x_spacing](NeighborhoodIteratorType const& n) { return otb::Left <V3>(otb::repack<V3>(n.GetPixel(x_spacing > 0 ? 3 : 5)));};
auto const right = [x_spacing](NeighborhoodIteratorType const& n) { return otb::Right<V3>(otb::repack<V3>(n.GetPixel(x_spacing > 0 ? 5 : 3)));};
auto const center = [](NeighborhoodIteratorType const& n) { return n.GetPixel(4);};
auto l0 = otb::SimpleNormalMethodForCartesianPoints<vnl_vector_fixed<double, 3>>();
auto lambda = [=](NeighborhoodIteratorType const& in)
{
// Compute n-> at current point
assert(in.Size() == 9);
auto valid = [](auto v) /*-> decltype(v)*/ {
// TODO: remove if we can't have nodata
return v;
};
V3 const n = l0(above(valid(in)), valid(left(in)), valid(right(in)), valid(below(in)));
static int i = 0;
if (++i % 1000000 == 0)
std::cout << "-----@" << in.GetIndex() << " from " <<
V3(above(in)) << V3(left(in)) << V3(right(in)) << V3(below(in))
<< " --> " << n
<<std::endl;
auto const res = otb::repack<OutputPixelType>(n);
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
return res;
};
return lambda;
}
} // anonymous namespace.
namespace otb
{
namespace Wrapper
{
/**
* This application takes cares of building the normal vector from a DEM image.
*
* \author Luc Hermitte
* \copyright CS Group
* \ingroup App???
* \ingroup SARCalibrationExtended
*/
class ExtractNormalVector : public Application
{
public:
/** Standard class typedefs. */
using Self = ExtractNormalVector;
using InputPixelType = itk::FixedArray<double, 3>;
using InputImageType = otb::Image<InputPixelType, 2>;
using OutputPixelType = itk::VariableLengthVector<double>;
// using InputImageType = otb::Image<OutputPixelType, 2>;
// using WriterType = otb::ImageFileWriter<InputImageType>;
/** Standard macro */
itkNewMacro(Self);
itkTypeMacro(ExtractNormalVector, unused);
private:
void DoInit() override
{
SetName("ExtractNormalVector");
SetDescription("This application produces normal vectors from a DEM image");
// Documentation
SetDocLongDescription("This application produces normal vectors from a DEM image" );
SetDocLimitations("None");
SetDocAuthors("Luc Hermitte (CS Group)");
AddDocTag(Tags::Calibration);
AddParameter(ParameterType_InputImage, "xyz", "filename for the file containing XYZ cartesian coordinates aligned of their file geometry");
SetParameterDescription("xyz", "filename for the file containing XYZ cartesian coordinates aligned of their file geometry");
AddParameter(ParameterType_OutputImage, "out", "Image of normal vectors");
SetParameterDescription("out", "Image of normal vectors");
// AddParameter(ParameterType_Float, "nodata", "NoData value");
// SetParameterDescription("nodata", "DEM empty cells are filled with this value (optional -32768 by default)");
// SetDefaultParameterFloat("nodata", -32768);
// MandatoryOff("nodata");
AddRAMParameter();
SetDocExampleParameterValue("xyz", "xyz.tif");
SetDocExampleParameterValue("out", "normal.tif");
SetOfficialDocLink();
}
void DoUpdateParameters() override
{
}
void DoExecute() override
{
auto* inputImage = GetParameterImage<InputImageType>("xyz");
assert(inputImage);
// auto* inputImage = GetParameterFloatImage("dem");
// auto* inputImage = GetParameterDoubleImage("dem");
// auto* inputImage = GetParameterImage("dem");
// auto const nodata = GetParameterFloat("nodata");
// std::cout << "nodata => " << nodata << std::endl;
auto const spacing = inputImage->GetSignedSpacing();
double const x_spacing = spacing[0];
double const y_spacing = spacing[1];
auto const lambda = AppSimpleNormalMethod<OutputPixelType>(x_spacing, y_spacing, *inputImage);
auto filter = otb::NewFunctorFilter(lambda, 6, {{1,1}});
filter->SetInput(inputImage);
SetParameterOutputImage("out", filter->GetOutput());
// SetParameterOutputImagePixelType("out",ImagePixelType_float);
// Call register pipeline to allow streaming and garbage collection
RegisterPipeline();
}
};
} //end namespace Wrapper
} //end namespace otb
OTB_APPLICATION_EXPORT(otb::Wrapper::ExtractNormalVector)