Skip to content
Snippets Groups Projects
Commit 5d1cd018 authored by Cyrille Valladeau's avatar Cyrille Valladeau
Browse files

SARPol : latex description, small correction, warning correction and add missing tests

parent f3a5d2e5
No related branches found
No related tags found
No related merge requests found
Showing
with 147 additions and 91 deletions
File mode changed from 100644 to 100755
/*=========================================================================
Program: Insight Segmentation & Registration Toolkit
Module: $RCSfile: otbHermitianEigenAnalysis.h, v $
Program: ORFEO Toolbox
Language: C++
Date: $Date: 2005/07/09 22:43:35 $
Version: $Revision: 1.5 $
Date: $Date$
Version: $Revision$
Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
See OTBCopyright.txt for details.
Copyright (c) Insight Software Consortium. All rights reserved.
See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
This software is distributed WITHOUT ANY WARRANTY; without even
the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
......@@ -56,6 +57,8 @@ namespace otb
* num. math. 11, 293-306(1968) by bowdler, martin, reinsch, and
* wilkinson.
* handbook for auto. comp., vol.ii-linear algebra, 227-240(1971).
*
* \ingroup SARPolarimetry
*/
template < typename TMatrix, typename TVector, typename TEigenMatrix=TMatrix >
......@@ -85,7 +88,7 @@ public:
m_OrderEigenValues(OrderByValue)
{};
~HermitianEigenAnalysis() {};
virtual ~HermitianEigenAnalysis() {};
typedef TMatrix MatrixType;
typedef TEigenMatrix EigenMatrixType;
......
File mode changed from 100644 to 100755
......@@ -45,6 +45,12 @@ namespace Functor {
* \f$ S_{ll} = S_{ll}^{*} = 1/2 * ( -S_{xx} - j*2*S_{xy} + S_{yy}) \f$
* \f$ S_{lr} = S_{rl} = 1/2 * ( -S_{xx} - S_{yy}) \f$
*
* \infgroup Functor
* \ingroup SARPolarimetry
*
* \sa MLCToCoherencyDegreeImageFilter
* \sa MLCToCoherencyImageFilter
*
*/
template< class TInput, class TOutput>
class MLCToCircularCoherencyDegreeFunctor
......@@ -60,24 +66,24 @@ public:
result.SetSize(m_NumberOfComponentsPerPixel);
result.Fill(0.0);
RealType C1 = static_cast<RealType>(Covariance[0].real()); // C1 <hh.hh*>
RealType C2 = static_cast<RealType>(Covariance[3].real()); // C2 <hv.hv*>
RealType C3 = static_cast<RealType>(Covariance[5].real()); // C3 <vv.vv*>
RealType C4 = static_cast<RealType>(Covariance[1].real()); // C4 Re<hh.hv*>
RealType C5 = static_cast<RealType>(Covariance[1].imag()); // C5 Im<hh.hv*>
RealType C6 = static_cast<RealType>(Covariance[2].real()); // C6 Re<hh.vv*>
RealType C7 = static_cast<RealType>(Covariance[2].imag()); // C7 Im<hh.vv*>
RealType C8 = static_cast<RealType>(Covariance[4].real()); // C8 Re<hv.vv*>
RealType C9 = static_cast<RealType>(Covariance[4].imag()); // C9 Im<hv.vv*>
const RealType C1 = static_cast<RealType>(Covariance[0].real()); // C1 <hh.hh*>
const RealType C2 = static_cast<RealType>(Covariance[3].real()); // C2 <hv.hv*>
const RealType C3 = static_cast<RealType>(Covariance[5].real()); // C3 <vv.vv*>
const RealType C4 = static_cast<RealType>(Covariance[1].real()); // C4 Re<hh.hv*>
const RealType C5 = static_cast<RealType>(Covariance[1].imag()); // C5 Im<hh.hv*>
const RealType C6 = static_cast<RealType>(Covariance[2].real()); // C6 Re<hh.vv*>
const RealType C7 = static_cast<RealType>(Covariance[2].imag()); // C7 Im<hh.vv*>
const RealType C8 = static_cast<RealType>(Covariance[4].real()); // C8 Re<hv.vv*>
const RealType C9 = static_cast<RealType>(Covariance[4].imag()); // C9 Im<hv.vv*>
RealType llrrReal = 0.25 * ( C1 + C3 -4*C2 -2*C6);
RealType llrrImag = -(C4 + C8);
const RealType llrrReal = 0.25 * ( C1 + C3 -4*C2 -2*C6);
const RealType llrrImag = -(C4 + C8);
RealType lllrReal = 0.25 * ( C1 - C3 - 2*C5 + 2*C9);
RealType lllrImag = -0.5*(C7+C4+C8);
const RealType lllrReal = 0.25 * ( C1 - C3 - 2*C5 + 2*C9);
const RealType lllrImag = -0.5*(C7+C4+C8);
RealType rrlrReal = 0.25 * ( C1 -C3 + 2*C5 - 2*C9);
RealType rrlrImag = 0.5 * (C4+C8-C7);
const RealType rrlrReal = 0.25 * ( C1 -C3 + 2*C5 - 2*C9);
const RealType rrlrImag = 0.5 * (C4+C8-C7);
RealType ll2 = 0.25 * ( C1 + C3 + 4*C2 - 2*C6 - 4*C5 - 4*C9);
RealType rr2 = 0.25 * ( C1 + C3 + 4*C2 - 2*C6 + 4*C5 + 4*C9);
......@@ -114,7 +120,7 @@ public:
MLCToCircularCoherencyDegreeFunctor() : m_NumberOfComponentsPerPixel(3) {}
/** Destructor */
~MLCToCircularCoherencyDegreeFunctor() {}
virtual ~MLCToCircularCoherencyDegreeFunctor() {}
private:
unsigned int m_NumberOfComponentsPerPixel;
......
......@@ -29,11 +29,16 @@ namespace Functor {
/** \class otbMLCToCoherencyDegreeFunctor
* \brief Evaluate the Coherency Degree coefficient from from the MLC image
*
* * Output value are:
* Output value are:
* channel #0 : \f$ abs(S_{hh}*S_{vv}}^{*}) / sqrt(S_{hh}*S_{hh}}^{*}) / sqrt(S_{vv}*S_{vv}}^{*})\f$
* channel #1 : \f$ abs(S_{hv}*S_{vv}}^{*}) / sqrt(S_{hv}*S_{hv}}^{*}) / sqrt(S_{vv}*S_{vv}}^{*}) \f$
* channel #2 : \f$ abs(S_{hh}*S_{hv}}^{*}) / sqrt(S_{hh}*S_{hh}}^{*}) / sqrt(S_{hv}*S_{hv}}^{*}) \f$
*
* \infgroup Functor
* \ingroup SARPolarimetry
*
* \sa MLCToCircularCoherencyDegreeImageFilter
* \sa MLCToCoherencyImageFilter
*/
template< class TInput, class TOutput>
class MLCToCoherencyDegreeFunctor
......@@ -49,12 +54,12 @@ public:
result.SetSize(m_NumberOfComponentsPerPixel);
result.Fill(0.0);
RealType C11 = static_cast<RealType>(Covariance[0].real());
ComplexType C12 = static_cast<ComplexType>(Covariance[1]);
ComplexType C13 = static_cast<ComplexType>(Covariance[2]);
RealType C22 = static_cast<RealType>(Covariance[3].real());
ComplexType C23 = static_cast<ComplexType>(Covariance[4]);
RealType C33 = static_cast<RealType>(Covariance[5].real());
const RealType C11 = static_cast<RealType>(Covariance[0].real());
const ComplexType C12 = static_cast<ComplexType>(Covariance[1]);
const ComplexType C13 = static_cast<ComplexType>(Covariance[2]);
const RealType C22 = static_cast<RealType>(Covariance[3].real());
const ComplexType C23 = static_cast<ComplexType>(Covariance[4]);
const RealType C33 = static_cast<RealType>(Covariance[5].real());
if ((C11 >0.00001) && (C33 > 0.0001))
{
......@@ -83,7 +88,7 @@ public:
MLCToCoherencyDegreeFunctor() : m_NumberOfComponentsPerPixel(3) {}
/** Destructor */
~MLCToCoherencyDegreeFunctor() {}
virtual ~MLCToCoherencyDegreeFunctor() {}
private:
unsigned int m_NumberOfComponentsPerPixel;
......
......@@ -29,7 +29,7 @@ namespace Functor {
/** \class otbMLCToCoherencyFunctor
* \brief Evaluate the Coherency matrix from from the MLC image
*
* * Output value are:
* Output value are:
* channel #0 : \f$ 0.5 * (S_{hh}+S_{vv}.(S_{hh}+S_{vv})^{*} \f$
* channel #1 : \f$ 0.5 * (S_{hh}+S_{vv}.(S_{hh}-S_{vv})^{*} \f$
* channel #2 : \f$ (S_{hh}+S_{vv}.(S_{hv})^{*} \f$
......@@ -37,6 +37,11 @@ namespace Functor {
* channel #4 : \f$ (S_{hh}-S_{vv}.(S_{hv})^{*} \f$
* channel #5 : \f$ 2.0*S_{hv}.S_{hv}^{*} \f$
*
* \infgroup Functor
* \ingroup SARPolarimetry
*
* \sa MLCToCircularCoherencyDegreeImageFilter
* \sa MLCToCoherencyDegreeImageFilter
*/
template< class TInput, class TOutput>
class MLCToCoherencyFunctor
......@@ -50,16 +55,16 @@ public:
TOutput result;
result.SetSize(m_NumberOfComponentsPerPixel);
ComplexType C11 = static_cast<ComplexType>(Covariance[0]);
ComplexType C12 = static_cast<ComplexType>(Covariance[1]);
ComplexType C13 = static_cast<ComplexType>(Covariance[2]);
ComplexType C22 = static_cast<ComplexType>(Covariance[3]);
ComplexType C23 = static_cast<ComplexType>(Covariance[4]);
ComplexType C33 = static_cast<ComplexType>(Covariance[5]);
const ComplexType C11 = static_cast<ComplexType>(Covariance[0]);
const ComplexType C12 = static_cast<ComplexType>(Covariance[1]);
const ComplexType C13 = static_cast<ComplexType>(Covariance[2]);
const ComplexType C22 = static_cast<ComplexType>(Covariance[3]);
const ComplexType C23 = static_cast<ComplexType>(Covariance[4]);
const ComplexType C33 = static_cast<ComplexType>(Covariance[5]);
ComplexType C21 = vcl_conj(C12);
ComplexType C31 = vcl_conj(C13);
ComplexType C32 = vcl_conj(C23);
const ComplexType C21 = vcl_conj(C12);
const ComplexType C31 = vcl_conj(C13);
const ComplexType C32 = vcl_conj(C23);
result[0] = static_cast<OutputValueType>( 0.5*(C11 + C13 + C31 + C33) );
result[1] = static_cast<OutputValueType>( 0.5*(C11 - C13 + C31 - C33) );
......@@ -80,7 +85,7 @@ public:
MLCToCoherencyFunctor() : m_NumberOfComponentsPerPixel(6) {}
/** Destructor */
~MLCToCoherencyFunctor() {}
virtual ~MLCToCoherencyFunctor() {}
private:
unsigned int m_NumberOfComponentsPerPixel;
......
......@@ -30,6 +30,11 @@ namespace Functor {
* \brief Evaluate the Circular Polarisation image
* (3 channels : LL, RR and LR) from the Mueller image
*
* \ingroup Functor
* \ingroup SARPolarimetry
*
* \sa MuellerToMLCImageFilter
* \sa MuellerToPolarisationDegreeAndPowerImageFilter
*
*/
template< class TInput, class TOutput>
......@@ -44,10 +49,10 @@ public:
TOutput result;
result.SetSize(m_NumberOfComponentsPerPixel);
RealType M11 = static_cast<RealType>(Mueller[0]);
RealType M14 = static_cast<RealType>(Mueller[3]);
RealType M41 = static_cast<RealType>(Mueller[12]);
RealType M44 = static_cast<RealType>(Mueller[15]);
const RealType M11 = static_cast<RealType>(Mueller[0]);
const RealType M14 = static_cast<RealType>(Mueller[3]);
const RealType M41 = static_cast<RealType>(Mueller[12]);
const RealType M44 = static_cast<RealType>(Mueller[15]);
result[0] = static_cast<OutputValueType>( M11 + M14 + M41 + M44 ); // LL
result[1] = static_cast<OutputValueType>( M11 - M14 - M41 + M44 ); // RR
......@@ -65,7 +70,7 @@ public:
MuellerToCircularPolarisationFunctor() : m_NumberOfComponentsPerPixel(3) {}
/** Destructor */
~MuellerToCircularPolarisationFunctor() {}
virtual ~MuellerToCircularPolarisationFunctor() {}
private:
unsigned int m_NumberOfComponentsPerPixel;
......
......@@ -29,6 +29,12 @@ namespace Functor {
/** \class otbMuellerToMLCFunctor
* \brief Evaluate the MLC image from the Mueller image
*
* \ingroup Functor
* \ingroup SARPolarimetry
*
* \sa MuellerToCircularPolarisationImageFilter
* \sa MuellerToPolarisationDegreeAndPowerImageFilter
*
*/
template< class TInput, class TOutput>
class MuellerToMLCFunctor
......@@ -44,29 +50,29 @@ public:
TOutput result;
result.SetSize(m_NumberOfComponentsPerPixel);
RealType M11 = static_cast<RealType>(Mueller[0]);
RealType M12 = static_cast<RealType>(Mueller[1]);
RealType M13 = static_cast<RealType>(Mueller[2]);
RealType M14 = static_cast<RealType>(Mueller[3]);
RealType M21 = static_cast<RealType>(Mueller[4]);
RealType M22 = static_cast<RealType>(Mueller[5]);
RealType M23 = static_cast<RealType>(Mueller[6]);
RealType M24 = static_cast<RealType>(Mueller[7]);
RealType M31 = static_cast<RealType>(Mueller[8]);
RealType M32 = static_cast<RealType>(Mueller[9]);
RealType M33 = static_cast<RealType>(Mueller[10]);
RealType M34 = static_cast<RealType>(Mueller[11]);
RealType M41 = static_cast<RealType>(Mueller[12]);
RealType M42 = static_cast<RealType>(Mueller[13]);
RealType M43 = static_cast<RealType>(Mueller[14]);
RealType M44 = static_cast<RealType>(Mueller[15]);
ComplexType hhhh(M11+M22+2.*M12, 0.0);
ComplexType hvhv(M11-M22, 0.0);
ComplexType vvvv(M11+M22-2.*M12, 0.0);
ComplexType hhhv(M13+M23, -1.*(M14+M24));
ComplexType hhvv(M33-M44, -2.*M34);
ComplexType hvvv(M13-M23, -1.*(M14-M24));
const RealType M11 = static_cast<RealType>(Mueller[0]);
const RealType M12 = static_cast<RealType>(Mueller[1]);
const RealType M13 = static_cast<RealType>(Mueller[2]);
const RealType M14 = static_cast<RealType>(Mueller[3]);
const RealType M21 = static_cast<RealType>(Mueller[4]);
const RealType M22 = static_cast<RealType>(Mueller[5]);
const RealType M23 = static_cast<RealType>(Mueller[6]);
const RealType M24 = static_cast<RealType>(Mueller[7]);
const RealType M31 = static_cast<RealType>(Mueller[8]);
const RealType M32 = static_cast<RealType>(Mueller[9]);
const RealType M33 = static_cast<RealType>(Mueller[10]);
const RealType M34 = static_cast<RealType>(Mueller[11]);
const RealType M41 = static_cast<RealType>(Mueller[12]);
const RealType M42 = static_cast<RealType>(Mueller[13]);
const RealType M43 = static_cast<RealType>(Mueller[14]);
const RealType M44 = static_cast<RealType>(Mueller[15]);
const ComplexType hhhh(M11+M22+2.*M12, 0.0);
const ComplexType hvhv(M11-M22, 0.0);
const ComplexType vvvv(M11+M22-2.*M12, 0.0);
const ComplexType hhhv(M13+M23, -1.*(M14+M24));
const ComplexType hhvv(M33-M44, -2.*M34);
const ComplexType hvvv(M13-M23, -1.*(M14-M24));
result[0] = static_cast<OutputValueType>( hhhh );
result[1] = static_cast<OutputValueType>( 2.* hhhv );
......@@ -87,7 +93,7 @@ public:
MuellerToMLCFunctor() : m_NumberOfComponentsPerPixel(6) {}
/** Destructor */
~MuellerToMLCFunctor() {}
virtual ~MuellerToMLCFunctor() {}
private:
unsigned int m_NumberOfComponentsPerPixel;
......
......@@ -34,6 +34,12 @@ namespace Functor {
* \brief Evaluate the min and max polarisation degree and min and max power
* from the Mueller image
*
* \ingroup Functor
* \ingroup SARPolarimetry
*
* \sa MuellerToCircularPolarisationImageFilter
* \sa MuellerToMLCImageFilter
*
*/
template< class TInput, class TOutput>
class MuellerToPolarisationDegreeAndPowerFunctor
......@@ -151,7 +157,7 @@ public:
MuellerToPolarisationDegreeAndPowerFunctor() : m_NumberOfComponentsPerPixel(4) {}
/** Destructor */
~MuellerToPolarisationDegreeAndPowerFunctor() {}
virtual ~MuellerToPolarisationDegreeAndPowerFunctor() {}
private:
unsigned int m_NumberOfComponentsPerPixel;
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -40,9 +40,10 @@ typedef enum
/** \class PolarimetricData
* \brief This class allows to determine the type of architecture we get.
*
* HH_HV_VH_VV (0), HH_HV_VV (1), HH_VH_VV (2), HH_HV(3), VH_VV (4), HH_VV (5).
*
*
* \sa
* \ingroup SARPolarimetry
*/
class ITK_EXPORT PolarimetricData : public itk::DataObject
......@@ -73,7 +74,7 @@ protected:
/** Constructor */
PolarimetricData();
/** Destructor */
~PolarimetricData() {}
virtual ~PolarimetricData() {}
/**PrintSelf method */
void PrintSelf(std::ostream& os, itk::Indent indent) const;
......
......@@ -54,6 +54,10 @@ namespace otb
* the type of the output image. It is also parameterized by the
* operation to be applied, using a Functor style.
*
*
* \ingroup SARPolarimetry
* \sa PolarimetricSynthesisFunctor
*
*/
template <class TInputImageHH, class TInputImageHV, class TInputImageVH, class TInputImageVV, class TOutputImage,
......
File mode changed from 100644 to 100755
......@@ -32,6 +32,7 @@ namespace Functor
\vec(E_{r})\cdot\left[ S \right] \vec(E_{i}) \f$
*
* \ingroup Functor
* \ingroup SARPolarimetry
*/
template <class TInput1, class TInput2, class TInput3, class TInput4, class TOutput>
class PolarimetricSynthesisFunctor
......@@ -69,7 +70,7 @@ public:
tmp = vcl_conj(m_Er[0]) * (m_Ei[0] * static_cast<ComplexType>(Shh) + m_Ei[1] * static_cast<ComplexType>(Shv))
+ vcl_conj(m_Er[1]) * (m_Ei[0] * static_cast<ComplexType>(Svh) + m_Ei[1] * static_cast<ComplexType>(Svv));
scalar = (double) (vcl_pow(vcl_abs(tmp), 2));
scalar = static_cast<double>(vcl_abs(tmp)) * static_cast<double>(vcl_abs(tmp));
return (static_cast<TOutput>(scalar));
}
......
......@@ -29,6 +29,7 @@ namespace Functor {
/** \class otbCoherencyToMuellerFunctor
* \brief Evaluate the Mueller matrix from the reciprocal coherency matrix image
*
* \ingroup SARPolarimetry
*/
template< class TInput, class TOutput>
class ReciprocalCoherencyToMuellerFunctor
......@@ -76,7 +77,7 @@ public:
ReciprocalCoherencyToMuellerFunctor() {}
/** Destructor */
~ReciprocalCoherencyToMuellerFunctor() {}
virtual ~ReciprocalCoherencyToMuellerFunctor() {}
private:
itkStaticConstMacro(NumberOfComponentsPerPixel, unsigned int, 10);
......
......@@ -32,11 +32,13 @@ namespace Functor {
/** \class otbHAlphaFunctor
* \brief Evaluate the H-Alpha parameters from the reciprocal coherency matrix image
*
* * Output value are:
* Output value are:
* channel #0 : entropy
* channel #1 : \f$ \alpha \f$ parameter
* channel #2 : anisotropy
*
* \ingroup SARPolarimetry
*
*/
template< class TInput, class TOutput>
class ReciprocalHAlphaFunctor
......@@ -71,7 +73,7 @@ public:
inline TOutput operator()( const TInput & Coherency ) const
{
TOutput result;
result.SetSize(NumberOfComponentsPerPixel);
result.SetSize(m_NumberOfComponentsPerPixel);
CoherencyMatrixType T;
EigenvalueType eigenValues;
......@@ -95,7 +97,7 @@ public:
RealType entropy;
RealType alpha;
RealType anisotropy;
const RealType epsilon = 1.0E-4;
//const RealType epsilon = 1.0E-4;
totalEigenValues = static_cast<RealType>( eigenValues[0] + eigenValues[1] + eigenValues[2]);
......@@ -110,7 +112,7 @@ public:
p[k] = static_cast<RealType>(eigenValues[k]) / totalEigenValues;
}
if ( (p[0] < epsilon) || (p[1] < epsilon) || (p[2] < epsilon) )
if ( (p[0] < m_Epsilon) || (p[1] < m_Epsilon) || (p[2] < m_Epsilon) )
{
entropy =0.0;
}
......@@ -131,14 +133,14 @@ public:
if (p[k] > 1.) p[k] = 1.;
}
val0=sqrt(eigenVectors[0][0]*eigenVectors[0][0] + eigenVectors[0][1]*eigenVectors[0][1]);
a0=acos(abs(val0)) * CONST_180_PI;
val0=sqrt(static_cast<double>(eigenVectors[0][0]*eigenVectors[0][0]) + static_cast<double>(eigenVectors[0][1]*eigenVectors[0][1]));
a0=acos(vcl_abs(val0)) * CONST_180_PI;
val1=sqrt(eigenVectors[0][2]*eigenVectors[0][2] + eigenVectors[0][3]*eigenVectors[0][3]);
a1=acos(abs(val1)) * CONST_180_PI;
val1=sqrt(static_cast<double>(eigenVectors[0][2]*eigenVectors[0][2]) + static_cast<double>(eigenVectors[0][3]*eigenVectors[0][3]));
a1=acos(vcl_abs(val1)) * CONST_180_PI;
val2=sqrt(eigenVectors[0][4]*eigenVectors[0][4] + eigenVectors[0][5]*eigenVectors[0][5]);
a2=acos(abs(val2)) * CONST_180_PI;
val2=sqrt(static_cast<double>(eigenVectors[0][4]*eigenVectors[0][4]) + static_cast<double>(eigenVectors[0][5]*eigenVectors[0][5]));
a2=acos(vcl_abs(val2)) * CONST_180_PI;
alpha=p[0]*a0 + p[1]*a1 + p[2]*a2;
......@@ -156,17 +158,18 @@ public:
unsigned int GetOutputSize()
{
return NumberOfComponentsPerPixel;
return m_NumberOfComponentsPerPixel;
}
/** Constructor */
ReciprocalHAlphaFunctor() {}
ReciprocalHAlphaFunctor() : m_Epsilon(1e-4) {}
/** Destructor */
~ReciprocalHAlphaFunctor() {}
virtual ~ReciprocalHAlphaFunctor() {}
private:
itkStaticConstMacro(NumberOfComponentsPerPixel, unsigned int, 3);
itkStaticConstMacro(m_NumberOfComponentsPerPixel, unsigned int, 3);
const double m_Epsilon;
};
}
......
......@@ -33,6 +33,16 @@ namespace otb
* the type of the output image. It is also parameterized by the
* operation to be applied, using a Functor style.
*
* \ingroup SARPolarimetry
*
* \sa SinclairImageFilter
* \sa SinclairToCircularCovarianceMatrixFunctor
* \sa SinclairToCoherencyFunctor
* \sa SinclairToCovarianceFunctor
* \sa SinclairToMuellerFunctor
* \sa SinclairToReciprocalCircularCovarianceMatrixFunctor
* \sa SinclairToReciprocalCoherencyFunctor
* \sa SinclairToReciprocalCovarianceFunctor
*/
template <class TInputImageHH, class TInputImageHV,
......
File mode changed from 100644 to 100755
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment