diff --git a/Code/Learning/otbConfusionMatrixCalculator.h b/Code/Learning/otbConfusionMatrixCalculator.h index cd4a01f1ba25d7a3bc819848a3f6455aba815ecc..87a93726b009fbd9d7ec53df0c8f59a29606e32b 100644 --- a/Code/Learning/otbConfusionMatrixCalculator.h +++ b/Code/Learning/otbConfusionMatrixCalculator.h @@ -25,10 +25,14 @@ namespace otb { /** \class ConfusionMatrixCalculator + * This class computes a confusion matrix from 2 lists of labels. It + * assumes that the 2 lists have the same length and uses the + * position of the labels in the lists to build the pairs + * reference/produced labels. * \brief TODO * */ -template < class TListLabel > +template < class TRefListLabel, class TProdListLabel > class ITK_EXPORT ConfusionMatrixCalculator : public itk::ProcessObject { @@ -46,27 +50,27 @@ public: itkNewMacro(Self); /** List to store the corresponding labels */ - typedef TListLabel ListLabelType; - typedef typename ListLabelType::Pointer ListLabelPointerType; + typedef TRefListLabel RefListLabelType; + typedef typename RefListLabelType::Pointer RefListLabelPointerType; + + typedef TProdListLabel ProdListLabelType; + typedef typename ProdListLabelType::Pointer ProdListLabelPointerType; /** Type for the confusion matrix */ typedef itk::VariableSizeMatrix<double> ConfusionMatrixType; - /** Sets the reference labels (i.e. ground truth) */ - void SetReferenceLabels( const ListLabelType * ); - - /** Sets the produced labels (i.e. output of a classifier) */ - void SetProducedLabels( const ListLabelType * ); - virtual void Update(); /** Accessors */ - itkGetObjectMacro(ReferenceLabels, ListLabelType); - itkGetObjectMacro(ProducedLabels, ListLabelType); - itkGetConstMacro(KappaIndex, double); - itkGetConstMacro(OverallAccuracy, double); - itkGetConstMacro(NumberOfClasses, unsigned short); + itkSetObjectMacro(ReferenceLabels, RefListLabelType); + itkGetConstObjectMacro(ReferenceLabels, RefListLabelType); + itkSetObjectMacro(ProducedLabels, ProdListLabelType); + itkGetConstObjectMacro(ProducedLabels, ProdListLabelType); + itkGetMacro(KappaIndex, double); + itkGetMacro(OverallAccuracy, double); + itkGetMacro(NumberOfClasses, unsigned short); + itkGetMacro(NumberOfSamples, unsigned long); itkGetMacro(ConfusionMatrix, ConfusionMatrixType); protected: @@ -81,15 +85,18 @@ private: ConfusionMatrixCalculator(const Self&); //purposely not implemented void operator=(const Self&); //purposely not implemented - ListLabelPointerType m_ReferenceLabels; - ListLabelPointerType m_ProducedLabels; + double m_KappaIndex; + double m_OverallAccuracy; + + std::map<int,int> m_MapOfClasses; - double m_KappaIndex; - double m_OverallAccuracy; + unsigned short m_NumberOfClasses; + unsigned long m_NumberOfSamples; - unsigned short m_NumberOfClasses; + ConfusionMatrixType m_ConfusionMatrix; - ConfusionMatrixType m_ConfusionMatrix; + RefListLabelPointerType m_ReferenceLabels; + ProdListLabelPointerType m_ProducedLabels; }; }// end of namespace otb diff --git a/Code/Learning/otbConfusionMatrixCalculator.txx b/Code/Learning/otbConfusionMatrixCalculator.txx index c9bfee767174bbde5aa644bd601d01c13bbd9cd5..609f82be44f6b0ea5eae2ccd91acd84cee4e54fb 100644 --- a/Code/Learning/otbConfusionMatrixCalculator.txx +++ b/Code/Learning/otbConfusionMatrixCalculator.txx @@ -18,72 +18,132 @@ #ifndef __otbConfusionMatrixCalculator_txx #define __otbConfusionMatrixCalculator_txx +#include <algorithm> +#include "otbMacro.h" namespace otb { -template<class TListLabel> -ConfusionMatrixCalculator<TListLabel> +template<class TRefListLabel, class TProdListLabel> +ConfusionMatrixCalculator<TRefListLabel,TProdListLabel> ::ConfusionMatrixCalculator() : - m_KappaIndex(0.0), m_OverallAccuracy(0.0), m_NumberOfClasses(2) + m_KappaIndex(0.0), m_OverallAccuracy(0.0), m_NumberOfClasses(0) { this->SetNumberOfRequiredInputs(2); this->SetNumberOfRequiredOutputs(1); - m_ReferenceLabels = ListLabelType::New(); - m_ProducedLabels = ListLabelType::New(); m_ConfusionMatrix = ConfusionMatrixType(m_NumberOfClasses,m_NumberOfClasses); m_ConfusionMatrix.Fill(0); + m_ReferenceLabels = RefListLabelType::New(); + m_ProducedLabels = ProdListLabelType::New(); } -template < class TListLabel > +template < class TRefListLabel, class TProdListLabel > void -ConfusionMatrixCalculator<TListLabel> +ConfusionMatrixCalculator<TRefListLabel,TProdListLabel> ::Update() { this->GenerateData(); } -template < class TListLabel > + +template < class TRefListLabel, class TProdListLabel > void -ConfusionMatrixCalculator<TListLabel> +ConfusionMatrixCalculator<TRefListLabel,TProdListLabel> ::GenerateData() { - typename ListLabelType::ConstPointer refLabels = this->GetReferenceLabels(); - typename ListLabelType::ConstPointer prodLabels = this->GetProducedLabels(); - - std::vector<int> vecOfClasses; + typename RefListLabelType::ConstIterator refIterator = m_ReferenceLabels->Begin(); + typename ProdListLabelType::ConstIterator prodIterator = m_ProducedLabels->Begin(); - typename ListLabelType::ConstIterator refIterator = refLabels->Begin(); + //check that both lists have the same number of samples - //vecOfClasses.push_back(refIterator.GetMeasurementVector()[0]); + if( m_ReferenceLabels->Size() != m_ProducedLabels->Size() ) + { + otbMsgDebugMacro(<< "refLabels size = " << m_ReferenceLabels->Size() << + " / proLabels size = " << m_ProducedLabels->Size()); + throw itk::ExceptionObject(__FILE__, __LINE__, "ListSample size missmatch", ITK_LOCATION); + } - while( refIterator != refLabels->End() ) + m_NumberOfSamples = m_ReferenceLabels->Size(); + + // count de number of classes + + int countClasses = 0; + while( refIterator != m_ReferenceLabels->End() ) { int currentLabel = refIterator.GetMeasurementVector()[0]; - //if(find(vecOfClasses.begin(), vecOfClasses.end(), currentLabel) == vecOfClasses.end()) - //vecOfClasses.push_back(currentLabel); + if(m_MapOfClasses.find(currentLabel) == m_MapOfClasses.end()) + { + m_MapOfClasses[currentLabel] = countClasses; + ++countClasses; + } + ++refIterator; + + } + + m_NumberOfClasses = countClasses; + + std::vector< long int > samplesPerClass; + + for(unsigned int i=0; i<m_NumberOfClasses; i++) + samplesPerClass.push_back(0); + + m_ConfusionMatrix = ConfusionMatrixType(m_NumberOfClasses, m_NumberOfClasses); + m_ConfusionMatrix.Fill(0); + + refIterator = m_ReferenceLabels->Begin(); + prodIterator = m_ProducedLabels->Begin(); + + while( refIterator != m_ReferenceLabels->End() ) + { + int refLabel = refIterator.GetMeasurementVector()[0]; + int prodLabel = prodIterator.GetMeasurementVector()[0]; + + int refPos = m_MapOfClasses[refLabel]; + int prodPos = m_MapOfClasses[prodLabel]; + + ++samplesPerClass[refPos]; + m_ConfusionMatrix( refPos,prodPos )+=1; ++refIterator; + ++prodIterator; } - m_NumberOfClasses = vecOfClasses.size(); - + this->m_OverallAccuracy = 0.; + for (unsigned int i = 0;i<m_NumberOfClasses;++i) + { + this->m_OverallAccuracy += m_ConfusionMatrix(i,i); + } + + this->m_OverallAccuracy/=static_cast<double>(m_NumberOfSamples); + + double luckyRate = 0.; + for (unsigned int i = 0;i<m_NumberOfClasses;++i) + { + double sum_ij = 0.; + double sum_ji = 0.; + for (unsigned int j = 0;j<m_NumberOfClasses;++j) + { + sum_ij +=m_ConfusionMatrix(i,j); + sum_ji +=m_ConfusionMatrix(j,i); + } + luckyRate+=sum_ij*sum_ji; + } - - typename ListLabelType::ConstIterator prodIterator = prodLabels->Begin(); + luckyRate/=vcl_pow(m_NumberOfSamples,2.0); + m_KappaIndex = (m_OverallAccuracy-luckyRate)/(1-luckyRate); } -template < class TListLabel > +template < class TRefListLabel, class TProdListLabel > void -ConfusionMatrixCalculator<TListLabel> +ConfusionMatrixCalculator<TRefListLabel,TProdListLabel> ::PrintSelf(std::ostream& os, itk::Indent indent) const { os << indent << "TODO"; diff --git a/Examples/Projections/CMakeLists.txt b/Examples/Projections/CMakeLists.txt index fbe1fe6bff9f047878296a54d48d5a0f2becf444..07da170b06e3d2cf5afc1cb2a846954fc1c10a03 100644 --- a/Examples/Projections/CMakeLists.txt +++ b/Examples/Projections/CMakeLists.txt @@ -119,7 +119,7 @@ ADD_TEST(prTeEstimateRPCSensorModelExampleTest ${EXE_TESTS} --compare-ascii ${EPSILON_4} ${BASELINE}/otbGCPsToRPCSensorModelImageFilterWithoutDEMOutput.txt ${TEMP}/otbGCPsToRPCSensorModelImageFilterWithoutDEMOutput.txt - --ignore-lines-with 1 PipelineMTime + --ignore-lines-with 4 PipelineMTime ImportImageContaine Source: Image EstimateRPCSensorModelExample ${INPUTLARGEDATA}/SPOT4/RIO_DE_JANEIRO/IMAG_01.DAT ${TEMP}/otbGCPsToRPCSensorModelImageFilterWithoutDEMOutput.txt diff --git a/Testing/Code/Learning/CMakeLists.txt b/Testing/Code/Learning/CMakeLists.txt index 0628d1d96531620b69422247b4cc05e86491b9ce..171df13ed8af40cacc2e804c50ffdfd5c9444659 100644 --- a/Testing/Code/Learning/CMakeLists.txt +++ b/Testing/Code/Learning/CMakeLists.txt @@ -410,6 +410,10 @@ ADD_TEST(leTuSVMCrossValidationCostFunctionNew ${LEARNING_TESTS4} ADD_TEST(leTuExhaustiveExponentialOptimizerNew ${LEARNING_TESTS4} otbExhaustiveExponentialOptimizerNew) + +# ------- otb::ListSampleGenerator ----------------------------- +ADD_TEST(leTuListSampleGeneratorNew ${LEARNING_TESTS4} + otbListSampleGeneratorNew) ADD_TEST(leTvListSampleGenerator1 ${LEARNING_TESTS4} --compare-n-ascii ${NOTOL} 2 @@ -460,8 +464,20 @@ ADD_TEST(leTvListSampleGenerator3 ${LEARNING_TESTS4} 200 0.5 ) +# ------- otb::ConfusionMatrixCalculator ----------------------------- +ADD_TEST(leTuConfusionMatrixCalculatorNew ${LEARNING_TESTS4} +otbConfusionMatrixCalculatorNew) + +ADD_TEST(leTVConfusionMatrixCalculatorSetListSamples ${LEARNING_TESTS4} +otbConfusionMatrixCalculatorSetListSamples 1000 4) + +ADD_TEST(leTvConfusionMatrixCalculatorWrongSize ${LEARNING_TESTS4} +otbConfusionMatrixCalculatorWrongSize 1000 4) +SET_TESTS_PROPERTIES(leTvConfusionMatrixCalculatorWrongSize PROPERTIES WILL_FAIL true) + +ADD_TEST(leTvConfusionMatrixCalculatorUpdate ${LEARNING_TESTS4} +otbConfusionMatrixCalculatorUpdate 1000 4) -ADD_TEST(leTuConfusionMatrixCalculatorNew ${LEARNING_TESTS4} otbConfusionMatrixCalculatorNew) # A enrichir SET(BasicLearning_SRCS1 diff --git a/Testing/Code/Learning/otbConfusionMatrixCalculatorTest.cxx b/Testing/Code/Learning/otbConfusionMatrixCalculatorTest.cxx index ab5bfc07da4c1cffef58dd3baeed526244501286..465e53e2ec2b5dd2ad7a6e0ef8034b2d87369d07 100644 --- a/Testing/Code/Learning/otbConfusionMatrixCalculatorTest.cxx +++ b/Testing/Code/Learning/otbConfusionMatrixCalculatorTest.cxx @@ -19,16 +19,205 @@ #include "itkListSample.h" #include "otbConfusionMatrixCalculator.h" +int otbConfusionMatrixCalculatorNew(int argc, char* argv[]) +{ + typedef itk::VariableLengthVector<int> PLabelType; + typedef itk::Statistics::ListSample<PLabelType> PListLabelType; + typedef itk::FixedArray<int, 1> RLabelType; + typedef itk::Statistics::ListSample<RLabelType> RListLabelType; + typedef otb::ConfusionMatrixCalculator< RListLabelType, + PListLabelType > CalculatorType; -int otbConfusionMatrixCalculatorNew(int argc, char* argv[]) + CalculatorType::Pointer calculator = CalculatorType::New(); + + return EXIT_SUCCESS; +} + +int otbConfusionMatrixCalculatorSetListSamples(int argc, char* argv[]) +{ + + if( argc!= 3) + { + std::cerr << "Usage: " << argv[0] << " nbSamples nbClasses " << std::endl; + return EXIT_FAILURE; + } + + typedef itk::VariableLengthVector<int> PLabelType; + typedef itk::Statistics::ListSample<PLabelType> PListLabelType; + typedef itk::FixedArray<int, 1> RLabelType; + typedef itk::Statistics::ListSample<RLabelType> RListLabelType; + typedef otb::ConfusionMatrixCalculator< RListLabelType, + PListLabelType > CalculatorType; + + CalculatorType::Pointer calculator = CalculatorType::New(); + + RListLabelType::Pointer refLabels = RListLabelType::New(); + PListLabelType::Pointer prodLabels = PListLabelType::New(); + + int nbSamples = atoi(argv[1]); + int nbClasses = atoi(argv[2]); + + + for(int i=0; i<nbSamples; i++) + { + int label = (i%nbClasses)+1; + PLabelType plab; + plab.SetSize(1); + plab[0] = label; + refLabels->PushBack( label ); + prodLabels->PushBack( plab ); + } + + calculator->SetReferenceLabels( refLabels ); + calculator->SetProducedLabels( prodLabels ); + + return EXIT_SUCCESS; +} + +int otbConfusionMatrixCalculatorWrongSize(int argc, char* argv[]) +{ + + if( argc!= 3) + { + std::cerr << "Usage: " << argv[0] << " nbSamples nbClasses " << std::endl; + return EXIT_FAILURE; + } + + typedef itk::VariableLengthVector<int> PLabelType; + typedef itk::Statistics::ListSample<PLabelType> PListLabelType; + typedef itk::FixedArray<int, 1> RLabelType; + typedef itk::Statistics::ListSample<RLabelType> RListLabelType; + typedef otb::ConfusionMatrixCalculator< RListLabelType, + PListLabelType > CalculatorType; + + CalculatorType::Pointer calculator = CalculatorType::New(); + + RListLabelType::Pointer refLabels = RListLabelType::New(); + PListLabelType::Pointer prodLabels = PListLabelType::New(); + + int nbSamples = atoi(argv[1]); + int nbClasses = atoi(argv[2]); + + + for(int i=0; i<nbSamples; i++) + { + int label = (i%nbClasses)+1; + PLabelType plab; + plab.SetSize(1); + plab[0] = label; + refLabels->PushBack( label ); + prodLabels->PushBack( plab ); + } + + PLabelType plab; + plab.SetSize(1); + plab[0] = 0; + prodLabels->PushBack( plab ); + + calculator->SetReferenceLabels( refLabels ); + calculator->SetProducedLabels( prodLabels ); + + try + { + calculator->Update(); + } + catch (itk::ExceptionObject) + { + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} + + +int otbConfusionMatrixCalculatorUpdate(int argc, char* argv[]) { - typedef itk::FixedArray<int, 1> LabelType; - typedef itk::Statistics::ListSample<LabelType> ListLabelType; - typedef otb::ConfusionMatrixCalculator< ListLabelType > CalculatorType; + if( argc!= 3) + { + std::cerr << "Usage: " << argv[0] << " nbSamples nbClasses " << std::endl; + return EXIT_FAILURE; + } + + typedef itk::VariableLengthVector<int> PLabelType; + typedef itk::Statistics::ListSample<PLabelType> PListLabelType; + typedef itk::FixedArray<int, 1> RLabelType; + typedef itk::Statistics::ListSample<RLabelType> RListLabelType; + typedef otb::ConfusionMatrixCalculator< RListLabelType, + PListLabelType > CalculatorType; CalculatorType::Pointer calculator = CalculatorType::New(); + + RListLabelType::Pointer refLabels = RListLabelType::New(); + PListLabelType::Pointer prodLabels = PListLabelType::New(); + + int nbSamples = atoi(argv[1]); + int nbClasses = atoi(argv[2]); + + + for(int i=0; i<nbSamples; i++) + { + int label = (i%nbClasses)+1; + PLabelType plab; + plab.SetSize(1); + plab[0] = label; + refLabels->PushBack( label ); + prodLabels->PushBack( plab ); + } + + + calculator->SetReferenceLabels( refLabels ); + calculator->SetProducedLabels( prodLabels ); + + calculator->Update(); + + if( calculator->GetNumberOfClasses() != nbClasses ) + { + std::cerr << "Wrong number of classes" << std::endl; + return EXIT_FAILURE; + } + if( calculator->GetNumberOfSamples() != nbSamples ) + { + std::cerr << "Wrong number of samples" << std::endl; + return EXIT_FAILURE; + } + + CalculatorType::ConfusionMatrixType confmat = calculator->GetConfusionMatrix(); + + double totalError = 0.0; + + for (int i = 0; i < nbClasses; i++) + for (int j = 0; j < nbClasses; j++) + { + double goodValue = 0.0; + if (i == j) + goodValue = nbSamples / nbClasses; + else + if (confmat(i, j) != goodValue) + totalError += confmat(i, j); + } + + if( totalError > 0.001 ) + { + std::cerr << confmat << std::endl; + std::cerr<< "Error = " << totalError << std::endl; + return EXIT_FAILURE; + } + + if( calculator->GetKappaIndex() != 1.0 ) + { + std::cerr<< "Kappa = " << calculator->GetKappaIndex() << std::endl; + return EXIT_FAILURE; + } + + if( calculator->GetOverallAccuracy() != 1.0 ) + { + std::cerr<< "OA = " << calculator->GetOverallAccuracy() << std::endl; + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; } diff --git a/Testing/Code/Learning/otbLearningTests4.cxx b/Testing/Code/Learning/otbLearningTests4.cxx index 47e02085f5fd14d58ab03c17c14fcee885d91161..56c8e3cf09ddfa6f6505126a0e07a934e479f8ba 100644 --- a/Testing/Code/Learning/otbLearningTests4.cxx +++ b/Testing/Code/Learning/otbLearningTests4.cxx @@ -30,6 +30,10 @@ void RegisterTests() REGISTER_TEST(otbROIdataConversion); REGISTER_TEST(otbSVMCrossValidationCostFunctionNew); REGISTER_TEST(otbExhaustiveExponentialOptimizerNew); + REGISTER_TEST(otbListSampleGeneratorNew); REGISTER_TEST(otbListSampleGenerator); REGISTER_TEST(otbConfusionMatrixCalculatorNew); + REGISTER_TEST(otbConfusionMatrixCalculatorSetListSamples); + REGISTER_TEST(otbConfusionMatrixCalculatorWrongSize); + REGISTER_TEST(otbConfusionMatrixCalculatorUpdate); } diff --git a/Testing/Code/Learning/otbListSampleGenerator.cxx b/Testing/Code/Learning/otbListSampleGenerator.cxx index de9e56d7b11b4c7991cb833973c07aaf5b9f5804..0869918a644cc229f0fa415c82ff26798dd4b9b6 100644 --- a/Testing/Code/Learning/otbListSampleGenerator.cxx +++ b/Testing/Code/Learning/otbListSampleGenerator.cxx @@ -24,6 +24,16 @@ #include "otbListSampleGenerator.h" +int otbListSampleGeneratorNew(int argc, char* argv[]) +{ + typedef otb::VectorImage<float, 2> ImageType; + typedef otb::VectorData<double, 2> VectorDataType; + typedef otb::ListSampleGenerator<ImageType, VectorDataType> ListSampleGeneratorType; + ListSampleGeneratorType::Pointer generator = ListSampleGeneratorType::New(); + + return EXIT_SUCCESS; +} + int otbListSampleGenerator(int argc, char* argv[]) { diff --git a/Testing/Fa/0000169-fftcomplextocomplex.cxx b/Testing/Fa/0000169-fftcomplextocomplex.cxx new file mode 100644 index 0000000000000000000000000000000000000000..38cc24ae09c45e59b8570f4794ef07f50c74a396 --- /dev/null +++ b/Testing/Fa/0000169-fftcomplextocomplex.cxx @@ -0,0 +1,30 @@ +/*========================================================================= + + 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 "itkExceptionObject.h" +#include "itkFFTComplexToComplexImageFilter.h" + +int main( int argc, char * argv [] ) +{ + typedef itk::FFTComplexToComplexImageFilter < float, 2> FFTFilterType; + + FFTFilterType::Pointer fftFilter = FFTFilterType::New(); + fftFilter->DebugOn(); + + return EXIT_SUCCESS; +} diff --git a/Testing/Fa/CMakeLists.txt b/Testing/Fa/CMakeLists.txt index 63e4a31a3d64c89c3067acc932cbb1869fa0130d..e8e187156943925ffa956b8ee20c66d429f16168 100644 --- a/Testing/Fa/CMakeLists.txt +++ b/Testing/Fa/CMakeLists.txt @@ -230,6 +230,9 @@ ADD_TEST(FA-0000132-jpg ${CXX_TEST_PATH}/0000132-jpg ) ENDIF(OTB_USE_VISU_GUI) +ADD_TEST(FA-0000169-fftcomplextocomplex ${CXX_TEST_PATH}/0000169-fftcomplextocomplex + ) + # ------- Vectorization issue ----------------------------------- # FIXME Desactivated until http://bugs.orfeo-toolbox.org/view.php?id=94 # has somebody working on it @@ -262,4 +265,7 @@ ENDIF(OTB_USE_VISU_GUI) ADD_EXECUTABLE(PolygonsVectorization PolygonsVectorization.cxx) TARGET_LINK_LIBRARIES(PolygonsVectorization OTBIO OTBCommon) +ADD_EXECUTABLE(0000169-fftcomplextocomplex 0000169-fftcomplextocomplex.cxx) +TARGET_LINK_LIBRARIES(0000169-fftcomplextocomplex OTBIO OTBCommon) + ENDIF( NOT OTB_DISABLE_CXX_TESTING AND BUILD_TESTING )