diff --git a/Code/SpatialReasoning/otbImageToImageRCC8Calculator.h b/Code/SpatialReasoning/otbImageToImageRCC8Calculator.h new file mode 100644 index 0000000000000000000000000000000000000000..dec582747c162bf87c749183c5a9de0998a1bcd9 --- /dev/null +++ b/Code/SpatialReasoning/otbImageToImageRCC8Calculator.h @@ -0,0 +1,182 @@ +/*========================================================================= + + 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. + +=========================================================================*/ +#ifndef _otbImageToImageRCC8Calculator_h +#define _otbImageToImageRCC8Calculator_h + +#include "itkImageToImageFilter.h" +#include "itkObjectFactory.h" +#include "otbRCC8Value.h" +#include "otbImage.h" + +namespace otb +{ +/** + * \class ImageToImageRCC8Calculator + * \brief + * + */ +template <class TInputImage> + class ImageToImageRCC8Calculator : public itk::ImageToImageFilter<TInputImage,TInputImage> +{ +public: + /** Standard class typedefs. */ + typedef ImageToImageRCC8Calculator Self; + typedef itk::ImageToImageFilter<TInputImage,TInputImage> Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; + /** Method for creation through the object factory. */ + itkNewMacro(Self); + /** Run-time type information (and related methods). */ + itkTypeMacro(ImageToImageRCC8Calculator,ImageToImageFilter); + /** Types definitions for the input image. */ + typedef TInputImage ImageType; + typedef typename ImageType::Pointer ImagePointerType; + typedef typename ImageType::ConstPointer ImageConstPointerType; + typedef typename ImageType::PixelType PixelType; + typedef typename ImageType::IndexType IndexType; + typedef typename ImageType::RegionType RegionType; + /** Internal bool image type */ + typedef bool BoolPixelType; + typedef otb::Image<BoolPixelType,ImageType::ImageDimension> BoolImageType; + typedef typename BoolImageType::Pointer BoolImagePointerType; + + /** RCC8 values type */ + typedef RCC8Value RCC8ValueType; + /** + * Get the RCC8 relation. + * \return The RCC8 relation value. + */ + RCC8ValueType GetValue(void); + /** + * Set the first input image. + * \param image + */ + void SetInput1(ImageType * image); + /** + * Set the second input image. + * \param image + */ + void SetInput2(ImageType * image); + /** + * Get the first input image. + * \return The first input image. + */ + ImageType * GetInput1(void); + /** + * Get the second input image. + * \return The second input image. + */ + ImageType * GetInput2(void); + /** Set/Get the inside value of the regions */ + itkSetMacro(InsideValue,PixelType); + itkGetMacro(InsideValue,PixelType); + /** Set/Get the outside value of the regions */ + itkSetMacro(OutsideValue,PixelType); + itkGetMacro(OutsideValue,PixelType); + + protected: + /** Constructor */ + ImageToImageRCC8Calculator(); + /** Destructor */ + virtual ~ImageToImageRCC8Calculator() {}; + /** + * Compute the minimal image region required. + * \return The minimal region required. + */ + RegionType ComputeMinimalRegion(void); + /** Set external knowledge to help the decision process */ + itkSetMacro(Level1APrioriKnowledge,bool); + itkSetMacro(Level3APrioriKnowledge,bool); + itkGetMacro(Level1APrioriKnowledge,bool); + itkGetMacro(Level3APrioriKnowledge,bool); + /** + * Compute the intersection between regions edges. + * \return true if the intersection is not empty. + */ + bool ComputeEdgeEdgeBool(void); + /** + * Compute the intersection between exterior of region1 and + * interior of region2. + * \return true if the intersection is not empty. + */ + bool ComputeExterInterBool(void); + /** + * Compute the intersection between interior of region1 and + * exterior of region2. + * \return true if the intersection is not empty. + */ + bool ComputeInterExterBool(void); + /** + * Compute the intersection between regions interiors. + * \return true if the intersection is not empty. + */ + bool ComputeInterInterBool(void); + /** + * Compute the relation value from the input booleans. Please note + * that the actual computed value is set to the m_Value parameters, and has + * nothing to do with the returned boolean, which indicates if the determination + * process was successful. + * \param edgeEdgeBool True if edge-edge intersection is not empty. + * \param interExterBool True if interior-exterior intersection is not empty. + * \param ExterInterBool True if exterior-interior intersection is not empty. + * \return True if the decision process was successful. + */ + bool ComputeRelation(bool edgeEdgeBool, bool interExterBool, bool exterInterBool); + /** + * Test if the boolean image is totally black or not. This is a based on the lazy operator + * paradigm. + * \param The image to test. + * \return True or false. + */ + bool IsBoolImageNotEmpty(BoolImagePointerType image); + /** + * Compute a bool image of minimal ROI size, surrounded by a false padding, and corresponding + * to the input image. + * \param image The image to convert. + * \return The converted image + */ + BoolImagePointerType ConvertToBoolImage(ImagePointerType image); + /** Main computation method */ + void GenerateData(void); + /** PrintSelf method */ + void PrintSelf(std::ostream& os, itk::Indent indent) const; + + private: + /** The RCC8 relation value */ + RCC8ValueType m_Value; + /** The minimal ROI needed to compute the relation value */ + RegionType m_MinimalROI; + /** Decision tree Level 1 A priori knowledge */ + bool m_Level1APrioriKnowledge; + /** Decision tree Level 3 A priori knowledge */ + bool m_Level3APrioriKnowledge; + /** Inside value */ + PixelType m_InsideValue; + /** Outside value */ + PixelType m_OutsideValue; + /** Internal bool image representation*/ + BoolImagePointerType m_BoolImage1; + BoolImagePointerType m_BoolImage2; +}; +} // end namespace otb + +#ifndef OTB_MANUAL_INSTANTIATION +#include "otbImageToImageRCC8Calculator.txx" +#endif + +#endif diff --git a/Code/SpatialReasoning/otbImageToImageRCC8Calculator.txx b/Code/SpatialReasoning/otbImageToImageRCC8Calculator.txx new file mode 100644 index 0000000000000000000000000000000000000000..27ac2c8ef4c4acc15b2d00e4e53b5bb7f940d033 --- /dev/null +++ b/Code/SpatialReasoning/otbImageToImageRCC8Calculator.txx @@ -0,0 +1,547 @@ +/*========================================================================= + + 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. + +=========================================================================*/ +#ifndef _otbImageToImageRCC8Calculator_txx +#define _otbImageToImageRCC8Calculator_txx + +#include "otbImageToImageRCC8Calculator.h" +#include "itkBinaryDilateImageFilter.h" +#include "itkBinaryBallStructuringElement.h" +#include "itkInvertIntensityImageFilter.h" +#include "itkSubtractImageFilter.h" +#include "itkAndImageFilter.h" +#include "itkImageRegionIterator.h" +#include "itkImageRegionConstIterator.h" +#include "itkImageSliceConstIteratorWithIndex.h" +#include "otbMacro.h" + +namespace otb +{ + /** + * Constructor + */ + template<class TInputImage> + ImageToImageRCC8Calculator<TInputImage> + ::ImageToImageRCC8Calculator() + { + m_Value = OTB_RCC8_DC; + m_InsideValue = static_cast<PixelType>(255); + m_OutsideValue = static_cast<PixelType>(0); + m_Level1APrioriKnowledge=false; + m_Level3APrioriKnowledge=false; + this->SetNumberOfRequiredInputs(2); +// this->SetNumberOfOutputs(0); +// this->SetNumberOfRequiredOutputs(0); + } + /** + * Set the first input image. + * \param image + */ + template<class TInputImage> + void + ImageToImageRCC8Calculator<TInputImage> + ::SetInput1(ImageType * image) + { + this->SetNthInput(0,const_cast<ImageType *>(image)); + } + /** + * Set the second input image. + * \param image + */ + template<class TInputImage> + void + ImageToImageRCC8Calculator<TInputImage> + ::SetInput2(ImageType * image) + { + this->SetNthInput(1,const_cast<ImageType *>(image)); + } + /** + * Get the first input image. + * \return The first input image. + */ + template<class TInputImage> + typename ImageToImageRCC8Calculator<TInputImage> + ::ImageType* + ImageToImageRCC8Calculator<TInputImage> + ::GetInput1(void) + { + return dynamic_cast<ImageType*>(this->itk::ProcessObject::GetInput(0)); + } + /** + * Get the second input image. + * \return The second input image. + */ + template<class TInputImage> + typename ImageToImageRCC8Calculator<TInputImage> + ::ImageType* + ImageToImageRCC8Calculator<TInputImage> + ::GetInput2(void) + { + return dynamic_cast<ImageType*>(this->itk::ProcessObject::GetInput(1)); + } + /** + * Get the RCC8 relation. + * \return The RCC8 relation value. + */ + template <class TInputImage> + typename ImageToImageRCC8Calculator<TInputImage> + ::RCC8ValueType + ImageToImageRCC8Calculator<TInputImage> + ::GetValue(void) + { + this->Update(); + return m_Value; + } + /** + * Compute the minimal image region required. + * \return The minimal region required. + */ + template <class TInputImage> + typename ImageToImageRCC8Calculator<TInputImage> + ::RegionType + ImageToImageRCC8Calculator<TInputImage> + ::ComputeMinimalRegion(void) + { + // Input images pointers + typename ImageType::Pointer image1 = this->GetInput1(); + typename ImageType::Pointer image2 = this->GetInput2(); + // Iterator definition + typedef itk::ImageSliceConstIteratorWithIndex<ImageType> SliceIteratorType; + // Indexes containing upper-left and lower-right corner + typename ImageType::IndexType min; + typename ImageType::IndexType max; + min[0]=0; + min[1]=0; + max[1]=0; + max[1]=0; + for ( unsigned int axis = 0; axis < ImageType::ImageDimension; axis++ ) + { // Create the forward iterator to find lower bound + SliceIteratorType fit1(image1,image1->GetLargestPossibleRegion()); + SliceIteratorType fit2(image2,image2->GetLargestPossibleRegion()); + fit1.SetFirstDirection( !axis ); + fit1.SetSecondDirection( axis ); + fit1.GoToBegin(); + fit2.SetFirstDirection( !axis ); + fit2.SetSecondDirection( axis ); + fit2.GoToBegin(); + // Walk through the two images line by line + while (!fit1.IsAtEnd()&&!fit2.IsAtEnd()) + { + while (!fit1.IsAtEndOfSlice()&&!fit2.IsAtEndOfSlice()) + { + while(!fit1.IsAtEndOfLine()&&!fit2.IsAtEndOfLine()) + { + // If a common intersection is found + if ((fit1.Get()==m_InsideValue)||(fit2.Get()==m_InsideValue)) + { + // then the lower bound is found + min[axis]=fit1.GetIndex()[axis]; + fit1.GoToReverseBegin(); // skip to the end + fit2.GoToReverseBegin(); + break; + } + ++fit1; + ++fit2; + } + fit1.NextLine(); + fit2.NextLine(); + } + fit1.NextSlice(); + fit2.NextSlice(); + } + // Create the reverse iterator to find upper bound + SliceIteratorType rit1(image1,image1->GetLargestPossibleRegion()); + SliceIteratorType rit2(image2,image2->GetLargestPossibleRegion()); + rit1.SetFirstDirection(!axis); + rit1.SetSecondDirection(axis); + rit1.GoToReverseBegin(); + rit2.SetFirstDirection(!axis); + rit2.SetSecondDirection(axis); + rit2.GoToReverseBegin(); + // Walk through the two images line by line + while (!rit1.IsAtReverseEnd()&&!rit2.IsAtReverseEnd()) + { + while (!rit1.IsAtReverseEndOfSlice()&&!rit2.IsAtReverseEndOfSlice()) + { + while (!rit1.IsAtReverseEndOfLine()&&!rit2.IsAtReverseEndOfLine()) + { + // If a common intersection is found + if ((rit1.Get()==m_InsideValue)||(rit2.Get()==m_InsideValue)) + { + max[axis]=rit1.GetIndex()[axis]; + rit1.GoToBegin(); + rit2.GoToBegin(); //Skip to reverse end + break; + } + --rit1; + --rit2; + } + rit1.PreviousLine(); + rit2.PreviousLine(); + } + rit1.PreviousSlice(); + rit2.PreviousSlice(); + } + } + typename ImageType::RegionType region; + typename ImageType::SizeType size; + size[0]=max[0]-min[0]; + size[1]=max[1]-min[1]; + region.SetIndex(min); + region.SetSize(size); + otbMsgDebugMacro(<<"RCC8Calculator->ComputeMinimalRegion(): index: "<<min<<" size: "<<size); + return region; + } +/** + * Compute a bool image of minimal ROI size, surrounded by a false padding, and corresponding + * to the input image. + * \param image The image to convert. + * \return The converted image + */ + template<class TInputImage> +typename ImageToImageRCC8Calculator<TInputImage> +::BoolImagePointerType +ImageToImageRCC8Calculator<TInputImage> +::ConvertToBoolImage(ImagePointerType image) +{ + typedef itk::ImageRegionConstIterator<ImageType> ConstIterator; + typedef itk::ImageRegionIterator<BoolImageType> Iterator; + typename BoolImageType::Pointer output = BoolImageType::New(); + typename BoolImageType::SizeType boolImageSize; + boolImageSize[0]=m_MinimalROI.GetSize()[0]+2; + boolImageSize[1]=m_MinimalROI.GetSize()[1]+2; + typename BoolImageType::IndexType boolImageIndex; + boolImageIndex[0]=m_MinimalROI.GetIndex()[0]-1; + boolImageIndex[1]=m_MinimalROI.GetIndex()[1]-1; + typename BoolImageType::RegionType boolRegion; + boolRegion.SetSize(boolImageSize); + boolRegion.SetIndex(boolImageIndex); + output->SetRegions(boolRegion); + output->Allocate(); + output->FillBuffer(false); + + ConstIterator inputIt(image,m_MinimalROI); + Iterator outputIt(output,m_MinimalROI); + inputIt.GoToBegin(); + outputIt.GoToBegin(); + while(!inputIt.IsAtEnd()&&!outputIt.IsAtEnd()) + { + outputIt.Set(inputIt.Get()==m_InsideValue); + ++inputIt; + ++outputIt; + } + otbMsgDebugMacro(<<"RCC8Calculator->ConvertToBoolImage() size: "<<output->GetLargestPossibleRegion().GetSize()); + return output; +} + /** + * Compute the intersection between regions edges. + * \return true if the intersection is not empty. + */ + template<class TInputImage> + bool + ImageToImageRCC8Calculator<TInputImage> + ::ComputeEdgeEdgeBool(void) + { + + /// Definition of the Filters used to compute the boolean + typedef itk::SubtractImageFilter<BoolImageType,BoolImageType,BoolImageType> SubtractFilterType; + typedef itk::BinaryBallStructuringElement<bool,BoolImageType::ImageDimension> BinaryBallStructuringElementType; + typedef itk::BinaryDilateImageFilter<BoolImageType,BoolImageType,BinaryBallStructuringElementType> DilateFilterType; + typedef itk::AndImageFilter<BoolImageType,BoolImageType,BoolImageType> AndFilterType; + /// Declaration and instantiation + typename DilateFilterType::Pointer dilateFilter1 = DilateFilterType::New(); + typename DilateFilterType::Pointer dilateFilter2 = DilateFilterType::New(); + typename SubtractFilterType::Pointer subtractFilter1 = SubtractFilterType::New(); + typename SubtractFilterType::Pointer subtractFilter2 = SubtractFilterType::New(); + typename AndFilterType::Pointer andFilter = AndFilterType::New(); + /// Configuration of the erosion filter + BinaryBallStructuringElementType structElement1,structElement2; + structElement1.SetRadius(1); + structElement2.SetRadius(1); + structElement1.CreateStructuringElement(); + structElement2.CreateStructuringElement(); + dilateFilter1->SetKernel(structElement1); + dilateFilter2->SetKernel(structElement2); + /// The erosion is performed to get the surounding edge of this + /// region by substraction to the original image + dilateFilter1->SetInput(m_BoolImage1); + dilateFilter1->Update(); + subtractFilter1->SetInput2(m_BoolImage1); + subtractFilter1->SetInput1(dilateFilter1->GetOutput()); + subtractFilter1->Update(); + /// The erosion is performed to get the surounding edge of this + /// region by substraction to the original image + dilateFilter2->SetInput(m_BoolImage2); + dilateFilter2->Update(); + subtractFilter2->SetInput2(m_BoolImage2); + subtractFilter2->SetInput1(dilateFilter2->GetOutput()); + subtractFilter2->Update(); + /// Now we can compute the intersection between the 2 edges + andFilter->SetInput1(subtractFilter1->GetOutput()); + andFilter->SetInput2(subtractFilter2->GetOutput()); + andFilter->Update(); + /// test if the intersection is empty or not + return this->IsBoolImageNotEmpty(andFilter->GetOutput()); + } + /** + * Compute the intersection between exterior of region1 and + * interior of region2. + * \return true if the intersection is not empty. + */ + template<class TInputImage> + bool + ImageToImageRCC8Calculator<TInputImage> + ::ComputeExterInterBool(void) + { + /// Definition of the filters used + typedef itk::InvertIntensityImageFilter<BoolImageType,BoolImageType> InvertFilterType; + typedef itk::AndImageFilter<BoolImageType,BoolImageType,BoolImageType> AndFilterType; + /// Declaration and instantiation + typename InvertFilterType::Pointer invert = InvertFilterType::New(); + typename AndFilterType::Pointer andFilter = AndFilterType::New(); + /// The exterior is the inverted input image + invert->SetInput(m_BoolImage1); + andFilter->SetInput1(m_BoolImage2); + andFilter->SetInput2(invert->GetOutput()); + andFilter->Update(); + /// test if the intersection is empty or not + return IsBoolImageNotEmpty(andFilter->GetOutput()); + } + /** + * Compute the intersection between interior of region1 and + * exterior of region2. + * \return true if the intersection is not empty. + */ + template<class TInputImage> + bool + ImageToImageRCC8Calculator<TInputImage> + ::ComputeInterExterBool(void) + { + /// Definition of the filters used + typedef itk::InvertIntensityImageFilter<BoolImageType,BoolImageType> InvertFilterType; + typedef itk::AndImageFilter<BoolImageType,BoolImageType,BoolImageType> AndFilterType; + /// Declaration and instantiation + typename InvertFilterType::Pointer invert = InvertFilterType::New(); + typename AndFilterType::Pointer andFilter = AndFilterType::New(); + /// The exterior is the inverted input image + invert->SetInput(m_BoolImage2); + andFilter->SetInput1(m_BoolImage1); + andFilter->SetInput2(invert->GetOutput()); + andFilter->Update(); + /// test if the intersection is empty or not + return IsBoolImageNotEmpty(andFilter->GetOutput()); + } + /** + * Compute the intersection between regions interiors. + * \return true if the intersection is not empty. + */ + template<class TInputImage> + bool + ImageToImageRCC8Calculator<TInputImage> + ::ComputeInterInterBool(void) + { + /// Definition of the filters used + typedef itk::AndImageFilter<BoolImageType,BoolImageType,BoolImageType> AndFilterType; + typedef itk::MinimumMaximumImageCalculator<BoolImageType> MinMaxCalculatorType; + /// Declaration and instantiation + typename AndFilterType::Pointer andFilter = AndFilterType::New(); + /// The exterior is the inverted input image + andFilter->SetInput1(m_BoolImage1); + andFilter->SetInput2(m_BoolImage2); + andFilter->Update(); + /// test if the intersection is empty or not + return IsBoolImageNotEmpty(andFilter->GetOutput()); + } + /** + * Compute the relation value from the input booleans. Please note + * that the actual computed value is set to the m_Value parameters, and has + * nothing to do with the returned boolean, which indicates if the determination + * process was successful. + * \param edgeEdgeBool True if edge-edge intersection is not empty. + * \param interExterBool True if interior-exterior intersection is not empty. + * \param ExterInterBool True if exterior-interior intersection is not empty. + * \return True if the decision process was successful. + */ + template<class TInputImage> + bool + ImageToImageRCC8Calculator<TInputImage> + ::ComputeRelation(bool edgeEdgeBool, bool interExterBool, bool exterInterBool) + { + otbMsgDebugMacro(<<"RCC8Calculator->ComputeRelation()"); + // This decision process is based on a decision tree + if ((!interExterBool)&&(edgeEdgeBool)&&(!exterInterBool)) + { + m_Value=OTB_RCC8_EQ; + return true; + } + else if ((!interExterBool)&&(edgeEdgeBool)&&(exterInterBool)) + { + m_Value=OTB_RCC8_TPP; + return true; + } + else if ((interExterBool)&&(!edgeEdgeBool)&&(!exterInterBool)) + { + m_Value=OTB_RCC8_NTPPI; + return true; + } + else if ((interExterBool)&&(!edgeEdgeBool)&&(exterInterBool)) + { + m_Value=OTB_RCC8_DC; + return true; + } + else if ((interExterBool)&&(edgeEdgeBool)&&(!exterInterBool)) + { + m_Value=OTB_RCC8_TPPI; + return true; + } + else + { + return false; + } + } + /** + * Test if the boolean image is totally black or not. This is a based on the lazy operator + * paradigm. + * \param The image to test. + * \return True or false. + */ + template<class TInputImage> + bool + ImageToImageRCC8Calculator<TInputImage> + ::IsBoolImageNotEmpty(BoolImagePointerType image) + { + typedef itk::ImageRegionConstIterator<BoolImageType> IteratorType; + // TODO : il faudra éventuellement changer qq chose ici. + IteratorType it(image,image->GetLargestPossibleRegion()); + it.GoToBegin(); + while(!it.IsAtEnd()) + { + if(it.Get()) + { + return true; + } + ++it; + } + return false; + } + /** + * Main computation method. + */ + template <class TInputImage> + void + ImageToImageRCC8Calculator<TInputImage> + ::GenerateData(void) + { + otbMsgDebugMacro(<<"RCC8Calculator->GenerateData()"); + /// First we compute the minimal region of interest we will use for the relation computation + m_MinimalROI=this->ComputeMinimalRegion(); + /// If they are disjoint, the answer is trivial + if((m_MinimalROI.GetSize()[0]==0)||(m_MinimalROI.GetSize()[1]==0)) + { + /// The relation is DC + m_Value=OTB_RCC8_DC; + otbMsgDebugMacro(<<"RCC8Calculator->GenerateData(): Disjoint regions"); + } + else + { + /// else each input images is cast to boolean type and reduced to + // the minimal region + m_BoolImage1=ConvertToBoolImage(this->GetInput1()); + m_BoolImage2=ConvertToBoolImage(this->GetInput2()); + otbMsgDebugMacro(<<"RCC8Calculator->GenerateData(): Bool images computed: "<<m_BoolImage1->GetLargestPossibleRegion().GetSize()); + /// Then the boolean which will be used to determine the relation + /// are declared + bool edgeEdgeBool,interExterBool,exterInterBool,interInterBool; + /// The boolean edgeEdge is needed in each case, so it si computed + /// now + edgeEdgeBool = ComputeEdgeEdgeBool(); + otbMsgDebugMacro(<<"RCC8Calculator->GenerateData(): edgeEdge "<<edgeEdgeBool); + /// Here comes the outside knowledge + if(this->GetLevel1APrioriKnowledge()) + { + /// If the Level1APrioriKnowledge is set, then the + /// interExterBool is set to true + interExterBool=true; + } + else + { + /// Else it must be computed + interExterBool = ComputeInterExterBool(); + otbMsgDebugMacro(<<"RCC8Calculator->GenerateData(): interExter "<<interExterBool); + } + /// At this stage we can determine if the relation is of type NTPP + if((!interExterBool)&&(!edgeEdgeBool)) + { + m_Value=OTB_RCC8_NTPP; + } + else + { + /// If not, we must consider the intersection between exterior + if(this->GetLevel3APrioriKnowledge()) + { + /// If the Level3APRioriKnowledge flag is set, this boolean + /// can be determined from the two others + exterInterBool=(edgeEdgeBool!=interExterBool); + } + else + { + /// Else it must be computed + exterInterBool = ComputeExterInterBool(); + otbMsgDebugMacro(<<"RCC8Calculator->GenerateData(): ExterInter "<<exterInterBool); + } + /// If it is not sufficient to compute the relation + if(!ComputeRelation(edgeEdgeBool,interExterBool,exterInterBool)) + { + /// Compute the last boolean + interInterBool = ComputeInterInterBool(); + otbMsgDebugMacro(<<"RCC8Calculator->GenerateData(): InterInter "<<interInterBool); + /// Which allow the full determination + if ((interExterBool)&&(edgeEdgeBool)&&(exterInterBool)&&(!interInterBool)) + { + m_Value=OTB_RCC8_EC; + } + else + { + m_Value=OTB_RCC8_PO; + } + } + } + } + } + /** + * PrintSelf method + */ + template<class TInputImage> + void + ImageToImageRCC8Calculator<TInputImage> + ::PrintSelf( std::ostream& os,itk::Indent indent ) const + { + Superclass::PrintSelf(os,indent); + + // os << indent << "RelationIndex: " + // << m_RelationIndex + // << std::endl; + // os << indent << "RelationName: " + // << m_RelationName + // << std::endl; + } + +} // end namespace itk + +#endif + + diff --git a/Code/SpatialReasoning/otbRCC8Value.h b/Code/SpatialReasoning/otbRCC8Value.h new file mode 100644 index 0000000000000000000000000000000000000000..9e084cb33b1a23a05fc6b4131c9be7af69ce7b6b --- /dev/null +++ b/Code/SpatialReasoning/otbRCC8Value.h @@ -0,0 +1,36 @@ +/*========================================================================= + + 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. + +=========================================================================*/ +#ifndef _otbRCC8Value_h +#define _otbRCC8Value_h + +namespace otb +{ + // Coding enum system to represent the RCC8 relation values. +typedef enum { +OTB_RCC8_DC, +OTB_RCC8_EC, +OTB_RCC8_PO, +OTB_RCC8_TPP, +OTB_RCC8_TPPI, +OTB_RCC8_NTPP, +OTB_RCC8_NTPPI, +OTB_RCC8_EQ +} +RCC8Value; +}// End namespace otb +#endif diff --git a/Testing/Code/SpatialReasoning/CMakeLists.txt b/Testing/Code/SpatialReasoning/CMakeLists.txt index 613a61cf2c1953e3c3d810cbc18a6b13b9e9a5c4..89e18f45f9568525dc9b82f0319cf9ac76d3361d 100644 --- a/Testing/Code/SpatialReasoning/CMakeLists.txt +++ b/Testing/Code/SpatialReasoning/CMakeLists.txt @@ -15,11 +15,30 @@ SET(TOL 0.0) SET(SPATIALREASONING_TESTS ${CXX_TEST_PATH}/otbSpatialReasoningTests) -# ------- Fichiers sources CXX ----------------------------------- -SET(BasicSpatialReasoning_SRCS +# ------- otb::ImageToImageRCC8Calculator ---------- + +ADD_TEST(srTuRCC8CalculatorNew ${SPATIALREASONING_TESTS} + otbImageToImageRCC8CalculatorNew) + +ADD_TEST(srTvRCC8Calculator ${SPATIALREASONING_TESTS} + --compare-ascii ${TOL} + ${BASELINE_FILES}/srRCC8CalculatorOutput.txt + ${TEMP}/srRCC8CalculatorOutput.txt + otbImageToImageRCC8Calculator + 4 + ${TEMP}/srRCC8CalculatorOutput.txt + ${INPUTDATA}/rcc8_mire1.png + ${INPUTDATA}/rcc8_mire2.png + ${INPUTDATA}/rcc8_mire3.png + ${INPUTDATA}/rcc8_mire4.png ) +# ------- Fichiers sources CXX ----------------------------------- +SET(BasicSpatialReasoning_SRCS +otbImageToImageRCC8CalculatorNew.cxx +otbImageToImageRCC8Calculator.cxx +) INCLUDE_DIRECTORIES("${OTBTesting_BINARY_DIR}") diff --git a/Testing/Code/SpatialReasoning/otbImageToImageRCC8Calculator.cxx b/Testing/Code/SpatialReasoning/otbImageToImageRCC8Calculator.cxx new file mode 100644 index 0000000000000000000000000000000000000000..bba223dfa0368102c73fd35efb93a18f1637aa1d --- /dev/null +++ b/Testing/Code/SpatialReasoning/otbImageToImageRCC8Calculator.cxx @@ -0,0 +1,89 @@ +/*========================================================================= + + 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 "otbImageToImageRCC8Calculator.h" +#include "otbImage.h" +#include "otbImageList.h" +#include "otbImageFileReader.h" + +int otbImageToImageRCC8Calculator(int argc, char* argv[]) +{ +try + { + const unsigned int Dimension = 2; + + int nbImages = atoi(argv[1]); + char * outfile = argv[2]; + + typedef unsigned char PixelType; + typedef otb::Image<PixelType,Dimension> ImageType; + typedef otb::ImageFileReader<ImageType> ReaderType; + typedef otb::ImageToImageRCC8Calculator<ImageType> CalculatorType; + typedef otb::ImageList<ImageType> ImageListType; + typedef ImageListType::Iterator IteratorType; + // reference image list + ImageListType::Pointer images = ImageListType::New(); + + // Reading input images + std::ofstream out; + out.open(outfile,std::ios::out); + out<<"Test results from otbImageToImageRCC8calculator test."<<std::endl; + for(int i=1;i<=nbImages;++i) + { + ReaderType::Pointer reader = ReaderType::New(); + out<<argv[2+i]<<std::endl; + reader->SetFileName(argv[2+i]); + reader->Update(); + images->PushBack(reader->GetOutput()); + } + out<<std::endl; + // Declaration + CalculatorType::Pointer calc; + // Computing relations for each images couple + int i =1; + int j = 1; + for(IteratorType it1=images->Begin();it1!=images->End();++it1) + { + for(IteratorType it2=images->Begin();it2!=images->End();++it2) + { + std::cout<<"Test: computing relation "<<i<<","<<j<<std::endl; + calc=CalculatorType::New(); + calc->SetInput1(it1.Get()); + calc->SetInput2(it2.Get()); + out<<calc->GetValue()<<"\t"; + j++; + } + j=1; + i++; + out<<std::endl; + } + out.close(); + } + catch( itk::ExceptionObject & err ) + { + std::cout << "Exception itk::ExceptionObject thrown !" << std::endl; + std::cout << err << std::endl; + return EXIT_FAILURE; + } + catch( ... ) + { + std::cout << "Unknown exception thrown !" << std::endl; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/Testing/Code/SpatialReasoning/otbImageToImageRCC8CalculatorNew.cxx b/Testing/Code/SpatialReasoning/otbImageToImageRCC8CalculatorNew.cxx new file mode 100644 index 0000000000000000000000000000000000000000..135a8f2e1d7758d6b2f92a451798ac58a7474ea4 --- /dev/null +++ b/Testing/Code/SpatialReasoning/otbImageToImageRCC8CalculatorNew.cxx @@ -0,0 +1,46 @@ +/*========================================================================= + + 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 "otbImageToImageRCC8Calculator.h" +#include "otbImage.h" + +int otbImageToImageRCC8CalculatorNew(int argc, char* argv[]) +{ +try + { + const unsigned int Dimension = 2; + typedef unsigned char PixelType; + typedef otb::Image<PixelType,Dimension> ImageType; + typedef otb::ImageToImageRCC8Calculator<ImageType> CalculatorType; + + //Instantiation + CalculatorType::Pointer calc = CalculatorType::New(); + } + catch( itk::ExceptionObject & err ) + { + std::cout << "Exception itk::ExceptionObject thrown !" << std::endl; + std::cout << err << std::endl; + return EXIT_FAILURE; + } + catch( ... ) + { + std::cout << "Unknown exception thrown !" << std::endl; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; +} diff --git a/Testing/Code/SpatialReasoning/otbSpatialReasoningTests.cxx b/Testing/Code/SpatialReasoning/otbSpatialReasoningTests.cxx index e2bba57dcda668b526089d58073ae2be883f71ed..53819f4e54306878530e2215a92a72bee56443d4 100644 --- a/Testing/Code/SpatialReasoning/otbSpatialReasoningTests.cxx +++ b/Testing/Code/SpatialReasoning/otbSpatialReasoningTests.cxx @@ -26,4 +26,6 @@ void RegisterTests() { +REGISTER_TEST(otbImageToImageRCC8CalculatorNew); +REGISTER_TEST(otbImageToImageRCC8Calculator); }